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