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