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