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