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