non-interactive csh/children fix; bug report 4.3BSD/bin/42
[unix-history] / usr / src / bin / csh / proc.c
CommitLineData
b79f4fa9
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
094e80ed 3 * All rights reserved. The Berkeley Software License Agreement
b79f4fa9
DF
4 * specifies the terms and conditions for redistribution.
5 */
6
35371dec 7#ifndef lint
a4c18cd6 8static char *sccsid = "@(#)proc.c 5.7 (Berkeley) %G%";
094e80ed 9#endif
2d4bbda8
BJ
10
11#include "sh.h"
12#include "sh.dir.h"
13#include "sh.proc.h"
3ffa6b49 14#include <sys/wait.h>
2d4bbda8
BJ
15#include <sys/ioctl.h>
16
17/*
18 * C Shell - functions that manage processes, handling hanging, termination
19 */
20
21#define BIGINDEX 9 /* largest desirable job index */
22
23/*
24 * pchild - called at interrupt level by the SIGCHLD signal
25 * indicating that at least one child has terminated or stopped
26 * thus at least one wait system call will definitely return a
27 * childs status. Top level routines (like pwait) must be sure
28 * to mask interrupts when playing with the proclist data structures!
29 */
30pchild()
31{
32 register struct process *pp;
33 register struct process *fp;
34 register int pid;
35 union wait w;
36 int jobflags;
ea775389 37 struct rusage ru;
2d4bbda8 38
2d4bbda8 39loop:
a4c18cd6 40 pid = wait3(&w, ((setintr && intty) ? WNOHANG|WUNTRACED:WNOHANG), &ru);
2d4bbda8
BJ
41 if (pid <= 0) {
42 if (errno == EINTR) {
43 errno = 0;
44 goto loop;
45 }
46 pnoprocesses = pid == -1;
47 return;
48 }
49 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
50 if (pid == pp->p_pid)
51 goto found;
52 goto loop;
53found:
54 if (pid == atoi(value("child")))
55 unsetv("child");
56 pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
57 if (WIFSTOPPED(w)) {
58 pp->p_flags |= PSTOPPED;
59 pp->p_reason = w.w_stopsig;
60 } else {
35371dec
EW
61 if (pp->p_flags & (PTIME|PPTIME) || adrof("time"))
62 (void) gettimeofday(&pp->p_etime, (struct timezone *)0);
ea775389 63 pp->p_rusage = ru;
2d4bbda8
BJ
64 if (WIFSIGNALED(w)) {
65 if (w.w_termsig == SIGINT)
66 pp->p_flags |= PINTERRUPTED;
67 else
68 pp->p_flags |= PSIGNALED;
69 if (w.w_coredump)
70 pp->p_flags |= PDUMPED;
71 pp->p_reason = w.w_termsig;
72 } else {
73 pp->p_reason = w.w_retcode;
2d4bbda8 74 if (pp->p_reason != 0)
2d4bbda8
BJ
75 pp->p_flags |= PAEXITED;
76 else
77 pp->p_flags |= PNEXITED;
78 }
79 }
80 jobflags = 0;
81 fp = pp;
82 do {
83 if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
84 !child && adrof("time") &&
35371dec 85 fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
2d4bbda8
BJ
86 atoi(value("time")))
87 fp->p_flags |= PTIME;
88 jobflags |= fp->p_flags;
89 } while ((fp = fp->p_friends) != pp);
90 pp->p_flags &= ~PFOREGND;
91 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
92 pp->p_flags &= ~PPTIME;
93 pp->p_flags |= PTIME;
94 }
95 if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
96 fp = pp;
97 do {
98 if (fp->p_flags&PSTOPPED)
99 fp->p_flags |= PREPORTED;
100 } while((fp = fp->p_friends) != pp);
101 while(fp->p_pid != fp->p_jobid)
102 fp = fp->p_friends;
a132d4ed
BJ
103 if (jobflags&PSTOPPED) {
104 if (pcurrent && pcurrent != fp)
105 pprevious = pcurrent;
106 pcurrent = fp;
107 } else
108 pclrcurr(fp);
2d4bbda8 109 if (jobflags&PFOREGND) {
2d4bbda8
BJ
110 if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
111#ifdef IIASA
112 jobflags & PAEXITED ||
113#endif
114 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
401149be 115 ; /* print in pjwait */
b3409321
BJ
116 }
117/*
118 else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
2d4bbda8 119 ptprint(fp);
b3409321 120*/
2d4bbda8
BJ
121 } else {
122 if (jobflags&PNOTIFY || adrof("notify")) {
123 printf("\215\n");
35371dec 124 (void) pprint(pp, NUMBER|NAME|REASON);
2d4bbda8
BJ
125 if ((jobflags&PSTOPPED) == 0)
126 pflush(pp);
127 } else {
2d4bbda8
BJ
128 fp->p_flags |= PNEEDNOTE;
129 neednote++;
130 }
131 }
132 }
133 goto loop;
134}
135
136pnote()
137{
138 register struct process *pp;
1f7b623f
KB
139 int flags;
140 long omask;
2d4bbda8
BJ
141
142 neednote = 0;
143 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
144 if (pp->p_flags & PNEEDNOTE) {
d33af40e 145 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
146 pp->p_flags &= ~PNEEDNOTE;
147 flags = pprint(pp, NUMBER|NAME|REASON);
148 if ((flags&(PRUNNING|PSTOPPED)) == 0)
149 pflush(pp);
35371dec 150 (void) sigsetmask(omask);
2d4bbda8
BJ
151 }
152 }
153}
154
155/*
156 * pwait - wait for current job to terminate, maintaining integrity
157 * of current and previous job indicators.
158 */
159pwait()
160{
161 register struct process *fp, *pp;
1f7b623f 162 long omask;
2d4bbda8
BJ
163
164 /*
165 * Here's where dead procs get flushed.
166 */
d33af40e 167 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
168 for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
169 if (pp->p_pid == 0) {
170 fp->p_next = pp->p_next;
171 xfree(pp->p_command);
172 if (pp->p_cwd && --pp->p_cwd->di_count == 0)
173 if (pp->p_cwd->di_next == 0)
174 dfree(pp->p_cwd);
175 xfree((char *)pp);
176 pp = fp;
177 }
35371dec 178 (void) sigsetmask(omask);
2d4bbda8
BJ
179 pjwait(pcurrjob);
180}
181
182/*
183 * pjwait - wait for a job to finish or become stopped
184 * It is assumed to be in the foreground state (PFOREGND)
185 */
186pjwait(pp)
187 register struct process *pp;
188{
189 register struct process *fp;
1f7b623f
KB
190 int jobflags, reason;
191 long omask;
d33af40e 192
525f24a3
SL
193 while (pp->p_pid != pp->p_jobid)
194 pp = pp->p_friends;
2d4bbda8
BJ
195 fp = pp;
196 do {
197 if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
198 printf("BUG: waiting for background job!\n");
199 } while ((fp = fp->p_friends) != pp);
200 /*
201 * Now keep pausing as long as we are not interrupted (SIGINT),
202 * and the target process, or any of its friends, are running
203 */
204 fp = pp;
d33af40e 205 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8 206 for (;;) {
2d4bbda8
BJ
207 jobflags = 0;
208 do
209 jobflags |= fp->p_flags;
d33af40e 210 while ((fp = (fp->p_friends)) != pp);
2d4bbda8
BJ
211 if ((jobflags & PRUNNING) == 0)
212 break;
1f7b623f 213 sigpause(sigblock(0L) &~ sigmask(SIGCHLD));
2d4bbda8 214 }
35371dec
EW
215 (void) sigsetmask(omask);
216 if (tpgrp > 0) /* get tty back */
217 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
cd4a3dcb
BJ
218 if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
219 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
220 if (jobflags&PSTOPPED)
221 printf("\n");
35371dec 222 (void) pprint(pp, AREASON|SHELLDIR);
cd4a3dcb 223 }
401149be 224 if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2d4bbda8 225 (!gointr || !eq(gointr, "-"))) {
401149be
BJ
226 if ((jobflags & PSTOPPED) == 0)
227 pflush(pp);
401149be 228 pintr1(0);
2d4bbda8
BJ
229 /*NOTREACHED*/
230 }
231 reason = 0;
232 fp = pp;
233 do {
234 if (fp->p_reason)
235 reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
236 fp->p_reason | QUOTE : fp->p_reason;
237 } while ((fp = fp->p_friends) != pp);
238 set("status", putn(reason));
239 if (reason && exiterr)
240 exitstat();
241 pflush(pp);
242}
243
244/*
245 * dowait - wait for all processes to finish
246 */
247dowait()
248{
249 register struct process *pp;
1f7b623f 250 long omask;
2d4bbda8
BJ
251
252 pjobs++;
d33af40e 253 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8 254loop:
2d4bbda8 255 for (pp = proclist.p_next; pp; pp = pp->p_next)
525f24a3 256 if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
2d4bbda8 257 pp->p_flags&PRUNNING) {
1f7b623f 258 sigpause(0L);
2d4bbda8
BJ
259 goto loop;
260 }
35371dec 261 (void) sigsetmask(omask);
2d4bbda8
BJ
262 pjobs = 0;
263}
264
265/*
266 * pflushall - flush all jobs from list (e.g. at fork())
267 */
268pflushall()
269{
270 register struct process *pp;
271
272 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
273 if (pp->p_pid)
274 pflush(pp);
275}
276
277/*
278 * pflush - flag all process structures in the same job as the
279 * the argument process for deletion. The actual free of the
280 * space is not done here since pflush is called at interrupt level.
281 */
282pflush(pp)
283 register struct process *pp;
284{
285 register struct process *np;
286 register int index;
287
288 if (pp->p_pid == 0) {
289 printf("BUG: process flushed twice");
290 return;
291 }
292 while (pp->p_pid != pp->p_jobid)
293 pp = pp->p_friends;
294 pclrcurr(pp);
295 if (pp == pcurrjob)
296 pcurrjob = 0;
297 index = pp->p_index;
298 np = pp;
299 do {
300 np->p_index = np->p_pid = 0;
301 np->p_flags &= ~PNEEDNOTE;
302 } while ((np = np->p_friends) != pp);
303 if (index == pmaxindex) {
304 for (np = proclist.p_next, index = 0; np; np = np->p_next)
305 if (np->p_index > index)
306 index = np->p_index;
307 pmaxindex = index;
308 }
309}
310
311/*
312 * pclrcurr - make sure the given job is not the current or previous job;
313 * pp MUST be the job leader
314 */
315pclrcurr(pp)
316 register struct process *pp;
317{
318
319 if (pp == pcurrent)
320 if (pprevious != PNULL) {
321 pcurrent = pprevious;
322 pprevious = pgetcurr(pp);
323 } else {
324 pcurrent = pgetcurr(pp);
325 pprevious = pgetcurr(pp);
326 }
327 else if (pp == pprevious)
328 pprevious = pgetcurr(pp);
329}
330
331/* +4 here is 1 for '\0', 1 ea for << >& >> */
332char command[PMAXLEN+4];
333int cmdlen;
334char *cmdp;
335/*
336 * palloc - allocate a process structure and fill it up.
337 * an important assumption is made that the process is running.
338 */
339palloc(pid, t)
340 int pid;
341 register struct command *t;
342{
343 register struct process *pp;
344 int i;
345
346 pp = (struct process *)calloc(1, sizeof(struct process));
347 pp->p_pid = pid;
348 pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
349 if (t->t_dflg & FTIME)
350 pp->p_flags |= PPTIME;
351 cmdp = command;
352 cmdlen = 0;
353 padd(t);
354 *cmdp++ = 0;
355 if (t->t_dflg & FPOU) {
356 pp->p_flags |= PPOU;
357 if (t->t_dflg & FDIAG)
358 pp->p_flags |= PDIAG;
359 }
360 pp->p_command = savestr(command);
361 if (pcurrjob) {
362 struct process *fp;
363 /* careful here with interrupt level */
364 pp->p_cwd = 0;
365 pp->p_index = pcurrjob->p_index;
366 pp->p_friends = pcurrjob;
367 pp->p_jobid = pcurrjob->p_pid;
368 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
369 ;
370 fp->p_friends = pp;
371 } else {
372 pcurrjob = pp;
373 pp->p_jobid = pid;
374 pp->p_friends = pp;
375 pp->p_cwd = dcwd;
376 dcwd->di_count++;
377 if (pmaxindex < BIGINDEX)
378 pp->p_index = ++pmaxindex;
379 else {
380 struct process *np;
381
382 for (i = 1; ; i++) {
383 for (np = proclist.p_next; np; np = np->p_next)
384 if (np->p_index == i)
385 goto tryagain;
a132d4ed
BJ
386 pp->p_index = i;
387 if (i > pmaxindex)
388 pmaxindex = i;
2d4bbda8
BJ
389 break;
390 tryagain:;
391 }
392 }
393 if (pcurrent == PNULL)
394 pcurrent = pp;
395 else if (pprevious == PNULL)
396 pprevious = pp;
397 }
398 pp->p_next = proclist.p_next;
399 proclist.p_next = pp;
35371dec 400 (void) gettimeofday(&pp->p_btime, (struct timezone *)0);
2d4bbda8
BJ
401}
402
403padd(t)
404 register struct command *t;
405{
406 char **argp;
407
408 if (t == 0)
409 return;
410 switch (t->t_dtyp) {
411
412 case TPAR:
413 pads("( ");
414 padd(t->t_dspr);
415 pads(" )");
416 break;
417
418 case TCOM:
419 for (argp = t->t_dcom; *argp; argp++) {
420 pads(*argp);
421 if (argp[1])
422 pads(" ");
423 }
424 break;
425
1544707d
EW
426 case TOR:
427 case TAND:
2d4bbda8 428 case TFIL:
2d4bbda8
BJ
429 case TLST:
430 padd(t->t_dcar);
1544707d
EW
431 switch (t->t_dtyp) {
432 case TOR:
433 pads(" || ");
434 break;
435 case TAND:
436 pads(" && ");
437 break;
438 case TFIL:
439 pads(" | ");
440 break;
441 case TLST:
442 pads("; ");
443 break;
444 }
2d4bbda8
BJ
445 padd(t->t_dcdr);
446 return;
447 }
448 if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
449 pads((t->t_dflg & FHERE) ? " << " : " < ");
450 pads(t->t_dlef);
451 }
452 if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
453 pads((t->t_dflg & FCAT) ? " >>" : " >");
454 if (t->t_dflg & FDIAG)
455 pads("&");
456 pads(" ");
457 pads(t->t_drit);
458 }
459}
460
461pads(cp)
462 char *cp;
463{
464 register int i = strlen(cp);
465
466 if (cmdlen >= PMAXLEN)
467 return;
468 if (cmdlen + i >= PMAXLEN) {
35371dec 469 (void) strcpy(cmdp, " ...");
2d4bbda8
BJ
470 cmdlen = PMAXLEN;
471 cmdp += 4;
472 return;
473 }
35371dec 474 (void) strcpy(cmdp, cp);
2d4bbda8
BJ
475 cmdp += i;
476 cmdlen += i;
477}
478
479/*
480 * psavejob - temporarily save the current job on a one level stack
481 * so another job can be created. Used for { } in exp6
482 * and `` in globbing.
483 */
484psavejob()
485{
486
487 pholdjob = pcurrjob;
488 pcurrjob = PNULL;
489}
490
491/*
492 * prestjob - opposite of psavejob. This may be missed if we are interrupted
493 * somewhere, but pendjob cleans up anyway.
494 */
495prestjob()
496{
497
498 pcurrjob = pholdjob;
499 pholdjob = PNULL;
500}
501
502/*
503 * pendjob - indicate that a job (set of commands) has been completed
504 * or is about to begin.
505 */
506pendjob()
507{
508 register struct process *pp, *tp;
509
510 if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
511 pp = pcurrjob;
512 while (pp->p_pid != pp->p_jobid)
513 pp = pp->p_friends;
514 printf("[%d]", pp->p_index);
515 tp = pp;
516 do {
517 printf(" %d", pp->p_pid);
518 pp = pp->p_friends;
519 } while (pp != tp);
520 printf("\n");
521 }
522 pholdjob = pcurrjob = 0;
523}
524
525/*
526 * pprint - print a job
527 */
528pprint(pp, flag)
529 register struct process *pp;
530{
531 register status, reason;
532 struct process *tp;
533 extern char *linp, linbuf[];
534 int jobflags, pstatus;
535 char *format;
536
537 while (pp->p_pid != pp->p_jobid)
538 pp = pp->p_friends;
539 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
540 pp->p_flags &= ~PPTIME;
541 pp->p_flags |= PTIME;
542 }
543 tp = pp;
544 status = reason = -1;
545 jobflags = 0;
546 do {
547 jobflags |= pp->p_flags;
548 pstatus = pp->p_flags & PALLSTATES;
549 if (tp != pp && linp != linbuf && !(flag&FANCY) &&
550 (pstatus == status && pp->p_reason == reason ||
551 !(flag&REASON)))
552 printf(" ");
553 else {
554 if (tp != pp && linp != linbuf)
555 printf("\n");
556 if(flag&NUMBER)
557 if (pp == tp)
558 printf("[%d]%s %c ", pp->p_index,
559 pp->p_index < 10 ? " " : "",
560 pp==pcurrent ? '+' :
561 (pp == pprevious ? '-' : ' '));
562 else
563 printf(" ");
564 if (flag&FANCY)
565 printf("%5d ", pp->p_pid);
566 if (flag&(REASON|AREASON)) {
567 if (flag&NAME)
568 format = "%-21s";
569 else
570 format = "%s";
571 if (pstatus == status)
572 if (pp->p_reason == reason) {
573 printf(format, "");
574 goto prcomd;
575 } else
576 reason = pp->p_reason;
577 else {
578 status = pstatus;
579 reason = pp->p_reason;
580 }
581 switch (status) {
582
583 case PRUNNING:
584 printf(format, "Running ");
585 break;
586
587 case PINTERRUPTED:
588 case PSTOPPED:
589 case PSIGNALED:
793f6534
JL
590 if ((flag&(REASON|AREASON))
591 && reason != SIGINT
592 && reason != SIGPIPE)
2d4bbda8
BJ
593 printf(format, mesg[pp->p_reason].pname);
594 break;
595
596 case PNEXITED:
597 case PAEXITED:
598 if (flag & REASON)
599 if (pp->p_reason)
600 printf("Exit %-16d", pp->p_reason);
601 else
602 printf(format, "Done");
603 break;
604
605 default:
606 printf("BUG: status=%-9o", status);
607 }
608 }
609 }
610prcomd:
611 if (flag&NAME) {
612 printf("%s", pp->p_command);
613 if (pp->p_flags & PPOU)
614 printf(" |");
615 if (pp->p_flags & PDIAG)
616 printf("&");
617 }
618 if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
619 printf(" (core dumped)");
620 if (tp == pp->p_friends) {
621 if (flag&AMPERSAND)
622 printf(" &");
623 if (flag&JOBDIR &&
624 !eq(tp->p_cwd->di_name, dcwd->di_name)) {
625 printf(" (wd: ");
626 dtildepr(value("home"), tp->p_cwd->di_name);
627 printf(")");
628 }
629 }
630 if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
631 if (linp != linbuf)
632 printf("\n\t");
ea775389 633 { static struct rusage zru;
ae3d9709
SL
634 prusage(&zru, &pp->p_rusage, &pp->p_etime,
635 &pp->p_btime);
ea775389 636 }
2d4bbda8
BJ
637 }
638 if (tp == pp->p_friends) {
639 if (linp != linbuf)
640 printf("\n");
641 if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
642 printf("(wd now: ");
643 dtildepr(value("home"), dcwd->di_name);
644 printf(")\n");
645 }
646 }
647 } while ((pp = pp->p_friends) != tp);
648 if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
649 if (jobflags & NUMBER)
650 printf(" ");
651 ptprint(tp);
652 }
653 return (jobflags);
654}
655
656ptprint(tp)
657 register struct process *tp;
658{
ae3d9709
SL
659 struct timeval tetime, diff;
660 static struct timeval ztime;
ea775389
SL
661 struct rusage ru;
662 static struct rusage zru;
2d4bbda8
BJ
663 register struct process *pp = tp;
664
ea775389 665 ru = zru;
ae3d9709 666 tetime = ztime;
2d4bbda8 667 do {
ea775389 668 ruadd(&ru, &pp->p_rusage);
ae3d9709
SL
669 tvsub(&diff, &pp->p_etime, &pp->p_btime);
670 if (timercmp(&diff, &tetime, >))
671 tetime = diff;
2d4bbda8 672 } while ((pp = pp->p_friends) != tp);
ae3d9709 673 prusage(&zru, &ru, &tetime, &ztime);
2d4bbda8
BJ
674}
675
676/*
677 * dojobs - print all jobs
678 */
679dojobs(v)
680 char **v;
681{
682 register struct process *pp;
683 register int flag = NUMBER|NAME|REASON;
684 int i;
685
686 if (chkstop)
687 chkstop = 2;
688 if (*++v) {
689 if (v[1] || !eq(*v, "-l"))
690 error("Usage: jobs [ -l ]");
691 flag |= FANCY|JOBDIR;
692 }
693 for (i = 1; i <= pmaxindex; i++)
694 for (pp = proclist.p_next; pp; pp = pp->p_next)
695 if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
696 pp->p_flags &= ~PNEEDNOTE;
697 if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
698 pflush(pp);
699 break;
700 }
701}
702
703/*
704 * dofg - builtin - put the job into the foreground
705 */
706dofg(v)
707 char **v;
708{
709 register struct process *pp;
710
711 okpcntl();
712 ++v;
713 do {
714 pp = pfind(*v);
715 pstart(pp, 1);
2d4bbda8
BJ
716 pjwait(pp);
717 } while (*v && *++v);
718}
719
720/*
721 * %... - builtin - put the job into the foreground
722 */
723dofg1(v)
724 char **v;
725{
726 register struct process *pp;
727
728 okpcntl();
729 pp = pfind(v[0]);
730 pstart(pp, 1);
2d4bbda8
BJ
731 pjwait(pp);
732}
733
734/*
735 * dobg - builtin - put the job into the background
736 */
737dobg(v)
738 char **v;
739{
740 register struct process *pp;
741
742 okpcntl();
743 ++v;
744 do {
745 pp = pfind(*v);
746 pstart(pp, 0);
747 } while (*v && *++v);
748}
749
750/*
751 * %... & - builtin - put the job into the background
752 */
753dobg1(v)
754 char **v;
755{
756 register struct process *pp;
757
758 pp = pfind(v[0]);
759 pstart(pp, 0);
760}
761
762/*
763 * dostop - builtin - stop the job
764 */
765dostop(v)
766 char **v;
767{
768
769 pkill(++v, SIGSTOP);
770}
771
772/*
773 * dokill - builtin - superset of kill (1)
774 */
775dokill(v)
776 char **v;
777{
778 register int signum;
779 register char *name;
780
781 v++;
782 if (v[0] && v[0][0] == '-') {
783 if (v[0][1] == 'l') {
784 for (signum = 1; signum <= NSIG; signum++) {
785 if (name = mesg[signum].iname)
786 printf("%s ", name);
787 if (signum == 16)
35371dec 788 putchar('\n');
2d4bbda8 789 }
35371dec 790 putchar('\n');
2d4bbda8
BJ
791 return;
792 }
793 if (digit(v[0][1])) {
794 signum = atoi(v[0]+1);
793f6534 795 if (signum < 0 || signum > NSIG)
2d4bbda8
BJ
796 bferr("Bad signal number");
797 } else {
798 name = &v[0][1];
799 for (signum = 1; signum <= NSIG; signum++)
800 if (mesg[signum].iname &&
801 eq(name, mesg[signum].iname))
802 goto gotsig;
803 setname(name);
804 bferr("Unknown signal; kill -l lists signals");
805 }
806gotsig:
807 v++;
808 } else
809 signum = SIGTERM;
810 pkill(v, signum);
811}
812
813pkill(v, signum)
814 char **v;
815 int signum;
816{
817 register struct process *pp, *np;
818 register int jobflags = 0;
1f7b623f
KB
819 int pid, err = 0;
820 long omask;
525f24a3 821 char *cp;
2d4bbda8 822 extern char *sys_errlist[];
2d4bbda8 823
d33af40e 824 omask = sigmask(SIGCHLD);
2d4bbda8 825 if (setintr)
d33af40e
RC
826 omask |= sigmask(SIGINT);
827 omask = sigblock(omask) & ~omask;
2d4bbda8 828 while (*v) {
525f24a3
SL
829 cp = globone(*v);
830 if (*cp == '%') {
831 np = pp = pfind(cp);
2d4bbda8
BJ
832 do
833 jobflags |= np->p_flags;
834 while ((np = np->p_friends) != pp);
835 switch (signum) {
836
837 case SIGSTOP:
838 case SIGTSTP:
839 case SIGTTIN:
840 case SIGTTOU:
841 if ((jobflags & PRUNNING) == 0) {
525f24a3 842 printf("%s: Already stopped\n", cp);
2d4bbda8
BJ
843 err++;
844 goto cont;
845 }
846 }
9f4aa2a3
KM
847 if (killpg(pp->p_jobid, signum) < 0) {
848 printf("%s: ", cp);
849 printf("%s\n", sys_errlist[errno]);
850 err++;
851 }
2d4bbda8 852 if (signum == SIGTERM || signum == SIGHUP)
35371dec 853 (void) killpg(pp->p_jobid, SIGCONT);
793f6534 854 } else if (!(digit(*cp) || *cp == '-'))
2d4bbda8
BJ
855 bferr("Arguments should be jobs or process id's");
856 else {
525f24a3 857 pid = atoi(cp);
2d4bbda8
BJ
858 if (kill(pid, signum) < 0) {
859 printf("%d: ", pid);
860 printf("%s\n", sys_errlist[errno]);
861 err++;
862 goto cont;
863 }
864 if (signum == SIGTERM || signum == SIGHUP)
35371dec 865 (void) kill(pid, SIGCONT);
2d4bbda8
BJ
866 }
867cont:
525f24a3 868 xfree(cp);
2d4bbda8
BJ
869 v++;
870 }
35371dec 871 (void) sigsetmask(omask);
2d4bbda8
BJ
872 if (err)
873 error(NOSTR);
874}
875
876/*
877 * pstart - start the job in foreground/background
878 */
879pstart(pp, foregnd)
880 register struct process *pp;
881 int foregnd;
882{
883 register struct process *np;
1f7b623f
KB
884 int jobflags = 0;
885 long omask;
2d4bbda8 886
d33af40e 887 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
888 np = pp;
889 do {
890 jobflags |= np->p_flags;
891 if (np->p_flags&(PRUNNING|PSTOPPED)) {
892 np->p_flags |= PRUNNING;
893 np->p_flags &= ~PSTOPPED;
894 if (foregnd)
895 np->p_flags |= PFOREGND;
896 else
897 np->p_flags &= ~PFOREGND;
898 }
899 } while((np = np->p_friends) != pp);
a132d4ed
BJ
900 if (!foregnd)
901 pclrcurr(pp);
35371dec 902 (void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
2d4bbda8 903 if (foregnd)
35371dec 904 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid);
2d4bbda8 905 if (jobflags&PSTOPPED)
35371dec
EW
906 (void) killpg(pp->p_jobid, SIGCONT);
907 (void) sigsetmask(omask);
2d4bbda8
BJ
908}
909
910panystop(neednl)
911{
912 register struct process *pp;
913
914 chkstop = 2;
915 for (pp = proclist.p_next; pp; pp = pp->p_next)
916 if (pp->p_flags & PSTOPPED)
917 error("\nThere are stopped jobs" + 1 - neednl);
918}
919
920struct process *
921pfind(cp)
922 char *cp;
923{
924 register struct process *pp, *np;
925
926 if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
927 if (pcurrent == PNULL)
928 bferr("No current job");
929 return (pcurrent);
930 }
931 if (eq(cp, "%-") || eq(cp, "%#")) {
932 if (pprevious == PNULL)
933 bferr("No previous job");
934 return (pprevious);
935 }
936 if (digit(cp[1])) {
937 int index = atoi(cp+1);
938 for (pp = proclist.p_next; pp; pp = pp->p_next)
939 if (pp->p_index == index && pp->p_pid == pp->p_jobid)
940 return (pp);
941 bferr("No such job");
942 }
943 np = PNULL;
944 for (pp = proclist.p_next; pp; pp = pp->p_next)
945 if (pp->p_pid == pp->p_jobid) {
946 if (cp[1] == '?') {
947 register char *dp;
948 for (dp = pp->p_command; *dp; dp++) {
949 if (*dp != cp[2])
950 continue;
951 if (prefix(cp+2, dp))
952 goto match;
953 }
954 } else if (prefix(cp+1, pp->p_command)) {
955match:
956 if (np)
957 bferr("Ambiguous");
958 np = pp;
959 }
960 }
961 if (np)
962 return (np);
963 if (cp[1] == '?')
964 bferr("No job matches pattern");
965 else
966 bferr("No such job");
35371dec 967 /*NOTREACHED*/
2d4bbda8
BJ
968}
969
970/*
a132d4ed 971 * pgetcurr - find most recent job that is not pp, preferably stopped
2d4bbda8
BJ
972 */
973struct process *
974pgetcurr(pp)
975 register struct process *pp;
976{
977 register struct process *np;
a132d4ed 978 register struct process *xp = PNULL;
2d4bbda8
BJ
979
980 for (np = proclist.p_next; np; np = np->p_next)
981 if (np != pcurrent && np != pp && np->p_pid &&
982 np->p_pid == np->p_jobid) {
a132d4ed
BJ
983 if (np->p_flags & PSTOPPED)
984 return (np);
985 if (xp == PNULL)
986 xp = np;
2d4bbda8 987 }
a132d4ed 988 return (xp);
2d4bbda8
BJ
989}
990
991/*
992 * donotify - flag the job so as to report termination asynchronously
993 */
994donotify(v)
995 char **v;
996{
997 register struct process *pp;
998
999 pp = pfind(*++v);
1000 pp->p_flags |= PNOTIFY;
1001}
1002
1003/*
1004 * Do the fork and whatever should be done in the child side that
1005 * should not be done if we are not forking at all (like for simple builtin's)
1006 * Also do everything that needs any signals fiddled with in the parent side
1007 *
1008 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1009 * -1: leave tty alone; inherit pgrp from parent
1010 * 0: already have tty; manipulate process pgrps only
1011 * 1: want to claim tty; manipulate process and tty pgrps
1012 * It is usually just the value of tpgrp.
1013 */
1014pfork(t, wanttty)
1015 struct command *t; /* command we are forking for */
1016 int wanttty;
1017{
1018 register int pid;
1019 bool ignint = 0;
1f7b623f
KB
1020 int pgrp;
1021 long omask;
2d4bbda8
BJ
1022
1023 /*
1024 * A child will be uninterruptible only under very special
1025 * conditions. Remember that the semantics of '&' is
1026 * implemented by disconnecting the process from the tty so
1027 * signals do not need to ignored just for '&'.
1028 * Thus signals are set to default action for children unless:
1029 * we have had an "onintr -" (then specifically ignored)
1030 * we are not playing with signals (inherit action)
1031 */
1032 if (setintr)
1033 ignint = (tpgrp == -1 && (t->t_dflg&FINT))
1034 || (gointr && eq(gointr, "-"));
1035 /*
1036 * Hold SIGCHLD until we have the process installed in our table.
1037 */
d33af40e 1038 omask = sigblock(sigmask(SIGCHLD));
2d4bbda8
BJ
1039 while ((pid = fork()) < 0)
1040 if (setintr == 0)
1041 sleep(FORKSLEEP);
1042 else {
35371dec 1043 (void) sigsetmask(omask);
2d4bbda8
BJ
1044 error("No more processes");
1045 }
1046 if (pid == 0) {
1047 settimes();
1048 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1049 pflushall();
1050 pcurrjob = PNULL;
2d4bbda8
BJ
1051 child++;
1052 if (setintr) {
1053 setintr = 0; /* until I think otherwise */
2d4bbda8
BJ
1054 /*
1055 * Children just get blown away on SIGINT, SIGQUIT
1056 * unless "onintr -" seen.
1057 */
35371dec
EW
1058 (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1059 (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
2d4bbda8
BJ
1060 if (wanttty >= 0) {
1061 /* make stoppable */
35371dec
EW
1062 (void) signal(SIGTSTP, SIG_DFL);
1063 (void) signal(SIGTTIN, SIG_DFL);
1064 (void) signal(SIGTTOU, SIG_DFL);
2d4bbda8 1065 }
35371dec 1066 (void) signal(SIGTERM, parterm);
2d4bbda8 1067 } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
35371dec
EW
1068 (void) signal(SIGINT, SIG_IGN);
1069 (void) signal(SIGQUIT, SIG_IGN);
2d4bbda8
BJ
1070 }
1071 if (wanttty > 0)
35371dec 1072 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp);
2d4bbda8 1073 if (wanttty >= 0 && tpgrp >= 0)
35371dec 1074 (void) setpgrp(0, pgrp);
2d4bbda8
BJ
1075 if (tpgrp > 0)
1076 tpgrp = 0; /* gave tty away */
1077 /*
1078 * Nohup and nice apply only to TCOM's but it would be
1079 * nice (?!?) if you could say "nohup (foo;bar)"
1080 * Then the parser would have to know about nice/nohup/time
1081 */
1082 if (t->t_dflg & FNOHUP)
35371dec 1083 (void) signal(SIGHUP, SIG_IGN);
d33af40e 1084 if (t->t_dflg & FNICE)
793f6534 1085 (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
2d4bbda8
BJ
1086 } else {
1087 palloc(pid, t);
35371dec 1088 (void) sigsetmask(omask);
2d4bbda8
BJ
1089 }
1090
1091 return (pid);
1092}
1093
1094okpcntl()
1095{
1096
1097 if (tpgrp == -1)
1098 error("No job control in this shell");
1099 if (tpgrp == 0)
1100 error("No job control in subshells");
1101}