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