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