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