fixed job control bug, improved choice of + and - jobs
[unix-history] / usr / src / bin / csh / proc.c
CommitLineData
a132d4ed 1static char *sccsid = "@(#)proc.c 4.2 %G%";
2d4bbda8
BJ
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 */
22pchild()
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);
35loop:
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;
54found:
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;
a132d4ed
BJ
118 if (jobflags&PSTOPPED) {
119 if (pcurrent && pcurrent != fp)
120 pprevious = pcurrent;
121 pcurrent = fp;
122 } else
123 pclrcurr(fp);
2d4bbda8 124 if (jobflags&PFOREGND) {
2d4bbda8
BJ
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 {
2d4bbda8
BJ
142 fp->p_flags |= PNEEDNOTE;
143 neednote++;
144 }
145 }
146 }
147 goto loop;
148}
149
150pnote()
151{
152 register struct process *pp;
153 int flags;
154
155 neednote = 0;
156 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
157 if (pp->p_flags & PNEEDNOTE) {
158 sighold(SIGCHLD);
159 pp->p_flags &= ~PNEEDNOTE;
160 flags = pprint(pp, NUMBER|NAME|REASON);
161 if ((flags&(PRUNNING|PSTOPPED)) == 0)
162 pflush(pp);
163 sigrelse(SIGCHLD);
164 }
165 }
166}
167
168/*
169 * pwait - wait for current job to terminate, maintaining integrity
170 * of current and previous job indicators.
171 */
172pwait()
173{
174 register struct process *fp, *pp;
175
176 /*
177 * Here's where dead procs get flushed.
178 */
179 sighold(SIGCHLD);
180 for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
181 if (pp->p_pid == 0) {
182 fp->p_next = pp->p_next;
183 xfree(pp->p_command);
184 if (pp->p_cwd && --pp->p_cwd->di_count == 0)
185 if (pp->p_cwd->di_next == 0)
186 dfree(pp->p_cwd);
187 xfree((char *)pp);
188 pp = fp;
189 }
190 sigrelse(SIGCHLD);
191 if (setintr)
192 sigignore(SIGINT);
193 pjwait(pcurrjob);
194}
195
196/*
197 * pjwait - wait for a job to finish or become stopped
198 * It is assumed to be in the foreground state (PFOREGND)
199 */
200pjwait(pp)
201 register struct process *pp;
202{
203 register struct process *fp;
204 int jobflags, reason;
205
206 fp = pp;
207 do {
208 if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
209 printf("BUG: waiting for background job!\n");
210 } while ((fp = fp->p_friends) != pp);
211 /*
212 * Now keep pausing as long as we are not interrupted (SIGINT),
213 * and the target process, or any of its friends, are running
214 */
215 fp = pp;
216 for (;;) {
217 sighold(SIGCHLD);
218 jobflags = 0;
219 do
220 jobflags |= fp->p_flags;
221 while((fp = (fp->p_friends)) != pp);
222 if ((jobflags & PRUNNING) == 0)
223 break;
224 sigpause(SIGCHLD);
225 }
226 sigrelse(SIGCHLD);
227 if (tpgrp > 0)
228 ioctl(FSHTTY, TIOCSPGRP, &tpgrp); /* get tty back */
229 if (jobflags & PSTOPPED)
230 return;
231 if ((jobflags&PINTERRUPTED) && setintr &&
232 (!gointr || !eq(gointr, "-"))) {
233 pflush(pp);
234 pintr();
235 /*NOTREACHED*/
236 }
237 reason = 0;
238 fp = pp;
239 do {
240 if (fp->p_reason)
241 reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
242 fp->p_reason | QUOTE : fp->p_reason;
243 } while ((fp = fp->p_friends) != pp);
244 set("status", putn(reason));
245 if (reason && exiterr)
246 exitstat();
247 pflush(pp);
248}
249
250/*
251 * dowait - wait for all processes to finish
252 */
253dowait()
254{
255 register struct process *pp;
256
257 pjobs++;
258 if (setintr)
259 sigrelse(SIGINT);
260loop:
261 sighold(SIGCHLD);
262 for (pp = proclist.p_next; pp; pp = pp->p_next)
263 if (pp->p_pid && pp->p_pid == pp->p_jobid &&
264 pp->p_flags&PRUNNING) {
265 sigpause(SIGCHLD);
266 goto loop;
267 }
268 sigrelse(SIGCHLD);
269 pjobs = 0;
270}
271
272/*
273 * pflushall - flush all jobs from list (e.g. at fork())
274 */
275pflushall()
276{
277 register struct process *pp;
278
279 for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
280 if (pp->p_pid)
281 pflush(pp);
282}
283
284/*
285 * pflush - flag all process structures in the same job as the
286 * the argument process for deletion. The actual free of the
287 * space is not done here since pflush is called at interrupt level.
288 */
289pflush(pp)
290 register struct process *pp;
291{
292 register struct process *np;
293 register int index;
294
295 if (pp->p_pid == 0) {
296 printf("BUG: process flushed twice");
297 return;
298 }
299 while (pp->p_pid != pp->p_jobid)
300 pp = pp->p_friends;
301 pclrcurr(pp);
302 if (pp == pcurrjob)
303 pcurrjob = 0;
304 index = pp->p_index;
305 np = pp;
306 do {
307 np->p_index = np->p_pid = 0;
308 np->p_flags &= ~PNEEDNOTE;
309 } while ((np = np->p_friends) != pp);
310 if (index == pmaxindex) {
311 for (np = proclist.p_next, index = 0; np; np = np->p_next)
312 if (np->p_index > index)
313 index = np->p_index;
314 pmaxindex = index;
315 }
316}
317
318/*
319 * pclrcurr - make sure the given job is not the current or previous job;
320 * pp MUST be the job leader
321 */
322pclrcurr(pp)
323 register struct process *pp;
324{
325
326 if (pp == pcurrent)
327 if (pprevious != PNULL) {
328 pcurrent = pprevious;
329 pprevious = pgetcurr(pp);
330 } else {
331 pcurrent = pgetcurr(pp);
332 pprevious = pgetcurr(pp);
333 }
334 else if (pp == pprevious)
335 pprevious = pgetcurr(pp);
336}
337
338/* +4 here is 1 for '\0', 1 ea for << >& >> */
339char command[PMAXLEN+4];
340int cmdlen;
341char *cmdp;
342/*
343 * palloc - allocate a process structure and fill it up.
344 * an important assumption is made that the process is running.
345 */
346palloc(pid, t)
347 int pid;
348 register struct command *t;
349{
350 register struct process *pp;
351 int i;
352
353 pp = (struct process *)calloc(1, sizeof(struct process));
354 pp->p_pid = pid;
355 pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
356 if (t->t_dflg & FTIME)
357 pp->p_flags |= PPTIME;
358 cmdp = command;
359 cmdlen = 0;
360 padd(t);
361 *cmdp++ = 0;
362 if (t->t_dflg & FPOU) {
363 pp->p_flags |= PPOU;
364 if (t->t_dflg & FDIAG)
365 pp->p_flags |= PDIAG;
366 }
367 pp->p_command = savestr(command);
368 if (pcurrjob) {
369 struct process *fp;
370 /* careful here with interrupt level */
371 pp->p_cwd = 0;
372 pp->p_index = pcurrjob->p_index;
373 pp->p_friends = pcurrjob;
374 pp->p_jobid = pcurrjob->p_pid;
375 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
376 ;
377 fp->p_friends = pp;
378 } else {
379 pcurrjob = pp;
380 pp->p_jobid = pid;
381 pp->p_friends = pp;
382 pp->p_cwd = dcwd;
383 dcwd->di_count++;
384 if (pmaxindex < BIGINDEX)
385 pp->p_index = ++pmaxindex;
386 else {
387 struct process *np;
388
389 for (i = 1; ; i++) {
390 for (np = proclist.p_next; np; np = np->p_next)
391 if (np->p_index == i)
392 goto tryagain;
a132d4ed
BJ
393 pp->p_index = i;
394 if (i > pmaxindex)
395 pmaxindex = i;
2d4bbda8
BJ
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
410padd(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
458pads(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 */
481psavejob()
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 */
492prestjob()
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 */
503pendjob()
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 */
525pprint(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 }
606prcomd:
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&AMPERSAND)
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
653ptprint(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 */
685dojobs(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 */
712dofg(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 */
731dofg1(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 */
747dobg(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 */
763dobg1(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 */
775dostop(v)
776 char **v;
777{
778
779 pkill(++v, SIGSTOP);
780}
781
782/*
783 * dokill - builtin - superset of kill (1)
784 */
785dokill(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 }
816gotsig:
817 v++;
818 } else
819 signum = SIGTERM;
820 pkill(v, signum);
821}
822
823pkill(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 }
870cont:
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 */
883pstart(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);
a132d4ed
BJ
903 if (!foregnd)
904 pclrcurr(pp);
2d4bbda8
BJ
905 pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
906 if (foregnd)
907 ioctl(FSHTTY, TIOCSPGRP, &pp->p_jobid);
908 if (jobflags&PSTOPPED)
909 killpg(pp->p_jobid, SIGCONT);
910 sigrelse(SIGCHLD);
911}
912
913panystop(neednl)
914{
915 register struct process *pp;
916
917 chkstop = 2;
918 for (pp = proclist.p_next; pp; pp = pp->p_next)
919 if (pp->p_flags & PSTOPPED)
920 error("\nThere are stopped jobs" + 1 - neednl);
921}
922
923struct process *
924pfind(cp)
925 char *cp;
926{
927 register struct process *pp, *np;
928
929 if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
930 if (pcurrent == PNULL)
931 bferr("No current job");
932 return (pcurrent);
933 }
934 if (eq(cp, "%-") || eq(cp, "%#")) {
935 if (pprevious == PNULL)
936 bferr("No previous job");
937 return (pprevious);
938 }
939 if (digit(cp[1])) {
940 int index = atoi(cp+1);
941 for (pp = proclist.p_next; pp; pp = pp->p_next)
942 if (pp->p_index == index && pp->p_pid == pp->p_jobid)
943 return (pp);
944 bferr("No such job");
945 }
946 np = PNULL;
947 for (pp = proclist.p_next; pp; pp = pp->p_next)
948 if (pp->p_pid == pp->p_jobid) {
949 if (cp[1] == '?') {
950 register char *dp;
951 for (dp = pp->p_command; *dp; dp++) {
952 if (*dp != cp[2])
953 continue;
954 if (prefix(cp+2, dp))
955 goto match;
956 }
957 } else if (prefix(cp+1, pp->p_command)) {
958match:
959 if (np)
960 bferr("Ambiguous");
961 np = pp;
962 }
963 }
964 if (np)
965 return (np);
966 if (cp[1] == '?')
967 bferr("No job matches pattern");
968 else
969 bferr("No such job");
970}
971
972/*
a132d4ed 973 * pgetcurr - find most recent job that is not pp, preferably stopped
2d4bbda8
BJ
974 */
975struct process *
976pgetcurr(pp)
977 register struct process *pp;
978{
979 register struct process *np;
a132d4ed 980 register struct process *xp = PNULL;
2d4bbda8
BJ
981
982 for (np = proclist.p_next; np; np = np->p_next)
983 if (np != pcurrent && np != pp && np->p_pid &&
984 np->p_pid == np->p_jobid) {
a132d4ed
BJ
985 if (np->p_flags & PSTOPPED)
986 return (np);
987 if (xp == PNULL)
988 xp = np;
2d4bbda8 989 }
a132d4ed 990 return (xp);
2d4bbda8
BJ
991}
992
993/*
994 * donotify - flag the job so as to report termination asynchronously
995 */
996donotify(v)
997 char **v;
998{
999 register struct process *pp;
1000
1001 pp = pfind(*++v);
1002 pp->p_flags |= PNOTIFY;
1003}
1004
1005/*
1006 * Do the fork and whatever should be done in the child side that
1007 * should not be done if we are not forking at all (like for simple builtin's)
1008 * Also do everything that needs any signals fiddled with in the parent side
1009 *
1010 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1011 * -1: leave tty alone; inherit pgrp from parent
1012 * 0: already have tty; manipulate process pgrps only
1013 * 1: want to claim tty; manipulate process and tty pgrps
1014 * It is usually just the value of tpgrp.
1015 */
1016pfork(t, wanttty)
1017 struct command *t; /* command we are forking for */
1018 int wanttty;
1019{
1020 register int pid;
1021 bool ignint = 0;
1022 int pgrp;
1023
1024 /*
1025 * A child will be uninterruptible only under very special
1026 * conditions. Remember that the semantics of '&' is
1027 * implemented by disconnecting the process from the tty so
1028 * signals do not need to ignored just for '&'.
1029 * Thus signals are set to default action for children unless:
1030 * we have had an "onintr -" (then specifically ignored)
1031 * we are not playing with signals (inherit action)
1032 */
1033 if (setintr)
1034 ignint = (tpgrp == -1 && (t->t_dflg&FINT))
1035 || (gointr && eq(gointr, "-"));
1036 /*
1037 * Hold SIGCHLD until we have the process installed in our table.
1038 */
1039 sighold(SIGCHLD);
1040 while ((pid = fork()) < 0)
1041 if (setintr == 0)
1042 sleep(FORKSLEEP);
1043 else {
1044 sigrelse(SIGINT);
1045 sigrelse(SIGCHLD);
1046 error("No more processes");
1047 }
1048 if (pid == 0) {
1049 settimes();
1050 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1051 pflushall();
1052 pcurrjob = PNULL;
1053 timesdone = 0;
1054 child++;
1055 if (setintr) {
1056 setintr = 0; /* until I think otherwise */
1057 sigrelse(SIGCHLD);
1058 /*
1059 * Children just get blown away on SIGINT, SIGQUIT
1060 * unless "onintr -" seen.
1061 */
1062 signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1063 signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1064 if (wanttty >= 0) {
1065 /* make stoppable */
1066 signal(SIGTSTP, SIG_DFL);
1067 signal(SIGTTIN, SIG_DFL);
1068 signal(SIGTTOU, SIG_DFL);
1069 }
1070 signal(SIGTERM, parterm);
1071 } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
1072 signal(SIGINT, SIG_IGN);
1073 signal(SIGQUIT, SIG_IGN);
1074 }
1075 if (wanttty > 0)
1076 ioctl(FSHTTY, TIOCSPGRP, &pgrp);
1077 if (wanttty >= 0 && tpgrp >= 0)
1078 setpgrp(0, pgrp);
1079 if (tpgrp > 0)
1080 tpgrp = 0; /* gave tty away */
1081 /*
1082 * Nohup and nice apply only to TCOM's but it would be
1083 * nice (?!?) if you could say "nohup (foo;bar)"
1084 * Then the parser would have to know about nice/nohup/time
1085 */
1086 if (t->t_dflg & FNOHUP)
1087 signal(SIGHUP, SIG_IGN);
1088 if (t->t_dflg & FNICE) {
1089/* sigh...
1090 nice(20);
1091 nice(-10);
1092*/
1093 nice(t->t_nice);
1094 }
1095
1096 } else {
1097 palloc(pid, t);
1098 sigrelse(SIGCHLD);
1099 }
1100
1101 return (pid);
1102}
1103
1104okpcntl()
1105{
1106
1107 if (tpgrp == -1)
1108 error("No job control in this shell");
1109 if (tpgrp == 0)
1110 error("No job control in subshells");
1111}