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