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