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