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