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