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