xref: /original-bsd/bin/csh/proc.c (revision fac0c393)
1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)proc.c	8.2 (Berkeley) 03/22/95";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #if __STDC__
19 # include <stdarg.h>
20 #else
21 # include <varargs.h>
22 #endif
23 
24 #include "csh.h"
25 #include "dir.h"
26 #include "proc.h"
27 #include "extern.h"
28 
29 #define BIGINDEX	9	/* largest desirable job index */
30 
31 static struct rusage zru;
32 
33 static void	 pflushall __P((void));
34 static void	 pflush __P((struct process *));
35 static void	 pclrcurr __P((struct process *));
36 static void	 padd __P((struct command *));
37 static int	 pprint __P((struct process *, int));
38 static void	 ptprint __P((struct process *));
39 static void	 pads __P((Char *));
40 static void	 pkill __P((Char **v, int));
41 static struct	process
42 		*pgetcurr __P((struct process *));
43 static void	 okpcntl __P((void));
44 
45 /*
46  * pchild - called at interrupt level by the SIGCHLD signal
47  *	indicating that at least one child has terminated or stopped
48  *	thus at least one wait system call will definitely return a
49  *	childs status.  Top level routines (like pwait) must be sure
50  *	to mask interrupts when playing with the proclist data structures!
51  */
52 /* ARGUSED */
53 void
54 pchild(notused)
55 	int notused;
56 {
57     register struct process *pp;
58     register struct process *fp;
59     register int pid;
60     extern int insource;
61     union wait w;
62     int     jobflags;
63     struct rusage ru;
64 
65 loop:
66     errno = 0;			/* reset, just in case */
67     pid = wait3(&w.w_status,
68        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
69 
70     if (pid <= 0) {
71 	if (errno == EINTR) {
72 	    errno = 0;
73 	    goto loop;
74 	}
75 	pnoprocesses = pid == -1;
76 	return;
77     }
78     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
79 	if (pid == pp->p_pid)
80 	    goto found;
81     goto loop;
82 found:
83     if (pid == atoi(short2str(value(STRchild))))
84 	unsetv(STRchild);
85     pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
86     if (WIFSTOPPED(w)) {
87 	pp->p_flags |= PSTOPPED;
88 	pp->p_reason = w.w_stopsig;
89     }
90     else {
91 	if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
92 	    (void) gettimeofday(&pp->p_etime, NULL);
93 
94 	pp->p_rusage = ru;
95 	if (WIFSIGNALED(w)) {
96 	    if (w.w_termsig == SIGINT)
97 		pp->p_flags |= PINTERRUPTED;
98 	    else
99 		pp->p_flags |= PSIGNALED;
100 	    if (w.w_coredump)
101 		pp->p_flags |= PDUMPED;
102 	    pp->p_reason = w.w_termsig;
103 	}
104 	else {
105 	    pp->p_reason = w.w_retcode;
106 	    if (pp->p_reason != 0)
107 		pp->p_flags |= PAEXITED;
108 	    else
109 		pp->p_flags |= PNEXITED;
110 	}
111     }
112     jobflags = 0;
113     fp = pp;
114     do {
115 	if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
116 	    !child && adrof(STRtime) &&
117 	    fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
118 	    >= atoi(short2str(value(STRtime))))
119 	    fp->p_flags |= PTIME;
120 	jobflags |= fp->p_flags;
121     } while ((fp = fp->p_friends) != pp);
122     pp->p_flags &= ~PFOREGND;
123     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
124 	pp->p_flags &= ~PPTIME;
125 	pp->p_flags |= PTIME;
126     }
127     if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
128 	fp = pp;
129 	do {
130 	    if (fp->p_flags & PSTOPPED)
131 		fp->p_flags |= PREPORTED;
132 	} while ((fp = fp->p_friends) != pp);
133 	while (fp->p_pid != fp->p_jobid)
134 	    fp = fp->p_friends;
135 	if (jobflags & PSTOPPED) {
136 	    if (pcurrent && pcurrent != fp)
137 		pprevious = pcurrent;
138 	    pcurrent = fp;
139 	}
140 	else
141 	    pclrcurr(fp);
142 	if (jobflags & PFOREGND) {
143 	    if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
144 #ifdef IIASA
145 		jobflags & PAEXITED ||
146 #endif
147 		!eq(dcwd->di_name, fp->p_cwd->di_name)) {
148 		;		/* print in pjwait */
149 	    }
150 	    /* PWP: print a newline after ^C */
151 	    else if (jobflags & PINTERRUPTED) {
152 		(void) vis_fputc('\r' | QUOTE, cshout);
153 		(void) fputc('\n', cshout);
154 	    }
155 	}
156 	else {
157 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
158 		(void) vis_fputc('\r' | QUOTE, cshout);
159 		(void) fputc('\n', cshout);
160 		(void) pprint(pp, NUMBER | NAME | REASON);
161 		if ((jobflags & PSTOPPED) == 0)
162 		    pflush(pp);
163 	    }
164 	    else {
165 		fp->p_flags |= PNEEDNOTE;
166 		neednote++;
167 	    }
168 	}
169     }
170     goto loop;
171 }
172 
173 void
174 pnote()
175 {
176     register struct process *pp;
177     int     flags;
178     sigset_t sigset, osigset;
179 
180     neednote = 0;
181     sigemptyset(&sigset);
182     sigaddset(&sigset, SIGCHLD);
183     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
184 	if (pp->p_flags & PNEEDNOTE) {
185 	    sigprocmask(SIG_BLOCK, &sigset, &osigset);
186 	    pp->p_flags &= ~PNEEDNOTE;
187 	    flags = pprint(pp, NUMBER | NAME | REASON);
188 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
189 		pflush(pp);
190 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
191 	}
192     }
193 }
194 
195 /*
196  * pwait - wait for current job to terminate, maintaining integrity
197  *	of current and previous job indicators.
198  */
199 void
200 pwait()
201 {
202     register struct process *fp, *pp;
203     sigset_t sigset, osigset;
204 
205     /*
206      * Here's where dead procs get flushed.
207      */
208     sigemptyset(&sigset);
209     sigaddset(&sigset, SIGCHLD);
210     sigprocmask(SIG_BLOCK, &sigset, &osigset);
211     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
212 	if (pp->p_pid == 0) {
213 	    fp->p_next = pp->p_next;
214 	    xfree((ptr_t) pp->p_command);
215 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
216 		if (pp->p_cwd->di_next == 0)
217 		    dfree(pp->p_cwd);
218 	    xfree((ptr_t) pp);
219 	    pp = fp;
220 	}
221     sigprocmask(SIG_SETMASK, &osigset, NULL);
222     pjwait(pcurrjob);
223 }
224 
225 
226 /*
227  * pjwait - wait for a job to finish or become stopped
228  *	It is assumed to be in the foreground state (PFOREGND)
229  */
230 void
231 pjwait(pp)
232     register struct process *pp;
233 {
234     register struct process *fp;
235     int     jobflags, reason;
236     sigset_t sigset, osigset;
237 
238     while (pp->p_pid != pp->p_jobid)
239 	pp = pp->p_friends;
240     fp = pp;
241 
242     do {
243 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
244 	    (void) fprintf(csherr, "BUG: waiting for background job!\n");
245     } while ((fp = fp->p_friends) != pp);
246     /*
247      * Now keep pausing as long as we are not interrupted (SIGINT), and the
248      * target process, or any of its friends, are running
249      */
250     fp = pp;
251     sigemptyset(&sigset);
252     sigaddset(&sigset, SIGCHLD);
253     sigprocmask(SIG_BLOCK, &sigset, &osigset);
254     for (;;) {
255 	sigemptyset(&sigset);
256 	sigaddset(&sigset, SIGCHLD);
257 	sigprocmask(SIG_BLOCK, &sigset, NULL);
258 	jobflags = 0;
259 	do
260 	    jobflags |= fp->p_flags;
261 	while ((fp = (fp->p_friends)) != pp);
262 	if ((jobflags & PRUNNING) == 0)
263 	    break;
264 #ifdef JOBDEBUG
265 	(void) fprintf(csherr, "starting to sigsuspend for  SIGCHLD on %d\n",
266 		       fp->p_pid);
267 #endif				/* JOBDEBUG */
268 	sigset = osigset;
269 	sigdelset(&sigset, SIGCHLD);
270 	sigsuspend(&sigset);
271     }
272     sigprocmask(SIG_SETMASK, &osigset, NULL);
273     if (tpgrp > 0)		/* get tty back */
274 	(void) tcsetpgrp(FSHTTY, tpgrp);
275     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
276 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
277 	if (jobflags & PSTOPPED) {
278 	    (void) fputc('\n', cshout);
279 	    if (adrof(STRlistjobs)) {
280 		Char   *jobcommand[3];
281 
282 		jobcommand[0] = STRjobs;
283 		if (eq(value(STRlistjobs), STRlong))
284 		    jobcommand[1] = STRml;
285 		else
286 		    jobcommand[1] = NULL;
287 		jobcommand[2] = NULL;
288 
289 		dojobs(jobcommand, NULL);
290 		(void) pprint(pp, SHELLDIR);
291 	    }
292 	    else
293 		(void) pprint(pp, AREASON | SHELLDIR);
294 	}
295 	else
296 	    (void) pprint(pp, AREASON | SHELLDIR);
297     }
298     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
299 	(!gointr || !eq(gointr, STRminus))) {
300 	if ((jobflags & PSTOPPED) == 0)
301 	    pflush(pp);
302 	pintr1(0);
303 	/* NOTREACHED */
304     }
305     reason = 0;
306     fp = pp;
307     do {
308 	if (fp->p_reason)
309 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
310 		fp->p_reason | META : fp->p_reason;
311     } while ((fp = fp->p_friends) != pp);
312     if ((reason != 0) && (adrof(STRprintexitvalue))) {
313 	(void) fprintf(cshout, "Exit %d\n", reason);
314     }
315     set(STRstatus, putn(reason));
316     if (reason && exiterr)
317 	exitstat();
318     pflush(pp);
319 }
320 
321 /*
322  * dowait - wait for all processes to finish
323  */
324 void
325 /*ARGSUSED*/
326 dowait(v, t)
327     Char **v;
328     struct command *t;
329 {
330     register struct process *pp;
331     sigset_t sigset, osigset;
332 
333     pjobs++;
334     sigemptyset(&sigset);
335     sigaddset(&sigset, SIGCHLD);
336     sigprocmask(SIG_BLOCK, &sigset, &osigset);
337 loop:
338     for (pp = proclist.p_next; pp; pp = pp->p_next)
339 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
340 	    pp->p_flags & PRUNNING) {
341 	    sigemptyset(&sigset);
342 	    sigsuspend(&sigset);
343 	    goto loop;
344 	}
345     sigprocmask(SIG_SETMASK, &osigset, NULL);
346     pjobs = 0;
347 }
348 
349 /*
350  * pflushall - flush all jobs from list (e.g. at fork())
351  */
352 static void
353 pflushall()
354 {
355     register struct process *pp;
356 
357     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
358 	if (pp->p_pid)
359 	    pflush(pp);
360 }
361 
362 /*
363  * pflush - flag all process structures in the same job as the
364  *	the argument process for deletion.  The actual free of the
365  *	space is not done here since pflush is called at interrupt level.
366  */
367 static void
368 pflush(pp)
369     register struct process *pp;
370 {
371     register struct process *np;
372     register int idx;
373 
374     if (pp->p_pid == 0) {
375 	(void) fprintf(csherr, "BUG: process flushed twice");
376 	return;
377     }
378     while (pp->p_pid != pp->p_jobid)
379 	pp = pp->p_friends;
380     pclrcurr(pp);
381     if (pp == pcurrjob)
382 	pcurrjob = 0;
383     idx = pp->p_index;
384     np = pp;
385     do {
386 	np->p_index = np->p_pid = 0;
387 	np->p_flags &= ~PNEEDNOTE;
388     } while ((np = np->p_friends) != pp);
389     if (idx == pmaxindex) {
390 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
391 	    if (np->p_index > idx)
392 		idx = np->p_index;
393 	pmaxindex = idx;
394     }
395 }
396 
397 /*
398  * pclrcurr - make sure the given job is not the current or previous job;
399  *	pp MUST be the job leader
400  */
401 static void
402 pclrcurr(pp)
403     register struct process *pp;
404 {
405 
406     if (pp == pcurrent)
407 	if (pprevious != NULL) {
408 	    pcurrent = pprevious;
409 	    pprevious = pgetcurr(pp);
410 	}
411 	else {
412 	    pcurrent = pgetcurr(pp);
413 	    pprevious = pgetcurr(pp);
414 	}
415     else if (pp == pprevious)
416 	pprevious = pgetcurr(pp);
417 }
418 
419 /* +4 here is 1 for '\0', 1 ea for << >& >> */
420 static Char command[PMAXLEN + 4];
421 static int cmdlen;
422 static Char *cmdp;
423 
424 /*
425  * palloc - allocate a process structure and fill it up.
426  *	an important assumption is made that the process is running.
427  */
428 void
429 palloc(pid, t)
430     int     pid;
431     register struct command *t;
432 {
433     register struct process *pp;
434     int     i;
435 
436     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
437     pp->p_pid = pid;
438     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
439     if (t->t_dflg & F_TIME)
440 	pp->p_flags |= PPTIME;
441     cmdp = command;
442     cmdlen = 0;
443     padd(t);
444     *cmdp++ = 0;
445     if (t->t_dflg & F_PIPEOUT) {
446 	pp->p_flags |= PPOU;
447 	if (t->t_dflg & F_STDERR)
448 	    pp->p_flags |= PERR;
449     }
450     pp->p_command = Strsave(command);
451     if (pcurrjob) {
452 	struct process *fp;
453 
454 	/* careful here with interrupt level */
455 	pp->p_cwd = 0;
456 	pp->p_index = pcurrjob->p_index;
457 	pp->p_friends = pcurrjob;
458 	pp->p_jobid = pcurrjob->p_pid;
459 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
460 	    continue;
461 	fp->p_friends = pp;
462     }
463     else {
464 	pcurrjob = pp;
465 	pp->p_jobid = pid;
466 	pp->p_friends = pp;
467 	pp->p_cwd = dcwd;
468 	dcwd->di_count++;
469 	if (pmaxindex < BIGINDEX)
470 	    pp->p_index = ++pmaxindex;
471 	else {
472 	    struct process *np;
473 
474 	    for (i = 1;; i++) {
475 		for (np = proclist.p_next; np; np = np->p_next)
476 		    if (np->p_index == i)
477 			goto tryagain;
478 		pp->p_index = i;
479 		if (i > pmaxindex)
480 		    pmaxindex = i;
481 		break;
482 	tryagain:;
483 	    }
484 	}
485 	if (pcurrent == NULL)
486 	    pcurrent = pp;
487 	else if (pprevious == NULL)
488 	    pprevious = pp;
489     }
490     pp->p_next = proclist.p_next;
491     proclist.p_next = pp;
492     (void) gettimeofday(&pp->p_btime, NULL);
493 }
494 
495 static void
496 padd(t)
497     register struct command *t;
498 {
499     Char  **argp;
500 
501     if (t == 0)
502 	return;
503     switch (t->t_dtyp) {
504 
505     case NODE_PAREN:
506 	pads(STRLparensp);
507 	padd(t->t_dspr);
508 	pads(STRspRparen);
509 	break;
510 
511     case NODE_COMMAND:
512 	for (argp = t->t_dcom; *argp; argp++) {
513 	    pads(*argp);
514 	    if (argp[1])
515 		pads(STRspace);
516 	}
517 	break;
518 
519     case NODE_OR:
520     case NODE_AND:
521     case NODE_PIPE:
522     case NODE_LIST:
523 	padd(t->t_dcar);
524 	switch (t->t_dtyp) {
525 	case NODE_OR:
526 	    pads(STRspor2sp);
527 	    break;
528 	case NODE_AND:
529 	    pads(STRspand2sp);
530 	    break;
531 	case NODE_PIPE:
532 	    pads(STRsporsp);
533 	    break;
534 	case NODE_LIST:
535 	    pads(STRsemisp);
536 	    break;
537 	}
538 	padd(t->t_dcdr);
539 	return;
540     }
541     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
542 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
543 	pads(t->t_dlef);
544     }
545     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
546 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
547 	if (t->t_dflg & F_STDERR)
548 	    pads(STRand);
549 	pads(STRspace);
550 	pads(t->t_drit);
551     }
552 }
553 
554 static void
555 pads(cp)
556     Char   *cp;
557 {
558     register int i;
559 
560     /*
561      * Avoid the Quoted Space alias hack! Reported by:
562      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
563      */
564     if (cp[0] == STRQNULL[0])
565 	cp++;
566 
567     i = Strlen(cp);
568 
569     if (cmdlen >= PMAXLEN)
570 	return;
571     if (cmdlen + i >= PMAXLEN) {
572 	(void) Strcpy(cmdp, STRsp3dots);
573 	cmdlen = PMAXLEN;
574 	cmdp += 4;
575 	return;
576     }
577     (void) Strcpy(cmdp, cp);
578     cmdp += i;
579     cmdlen += i;
580 }
581 
582 /*
583  * psavejob - temporarily save the current job on a one level stack
584  *	so another job can be created.  Used for { } in exp6
585  *	and `` in globbing.
586  */
587 void
588 psavejob()
589 {
590 
591     pholdjob = pcurrjob;
592     pcurrjob = NULL;
593 }
594 
595 /*
596  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
597  *	somewhere, but pendjob cleans up anyway.
598  */
599 void
600 prestjob()
601 {
602 
603     pcurrjob = pholdjob;
604     pholdjob = NULL;
605 }
606 
607 /*
608  * pendjob - indicate that a job (set of commands) has been completed
609  *	or is about to begin.
610  */
611 void
612 pendjob()
613 {
614     register struct process *pp, *tp;
615 
616     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
617 	pp = pcurrjob;
618 	while (pp->p_pid != pp->p_jobid)
619 	    pp = pp->p_friends;
620 	(void) fprintf(cshout, "[%d]", pp->p_index);
621 	tp = pp;
622 	do {
623 	    (void) fprintf(cshout, " %d", pp->p_pid);
624 	    pp = pp->p_friends;
625 	} while (pp != tp);
626 	(void) fputc('\n', cshout);
627     }
628     pholdjob = pcurrjob = 0;
629 }
630 
631 /*
632  * pprint - print a job
633  */
634 static int
635 pprint(pp, flag)
636     register struct process *pp;
637     bool    flag;
638 {
639     register status, reason;
640     struct process *tp;
641     int     jobflags, pstatus;
642     bool hadnl = 1;	/* did we just have a newline */
643     char   *format;
644 
645     (void) fpurge(cshout);
646 
647     while (pp->p_pid != pp->p_jobid)
648 	pp = pp->p_friends;
649     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
650 	pp->p_flags &= ~PPTIME;
651 	pp->p_flags |= PTIME;
652     }
653     tp = pp;
654     status = reason = -1;
655     jobflags = 0;
656     do {
657 	jobflags |= pp->p_flags;
658 	pstatus = pp->p_flags & PALLSTATES;
659 	if (tp != pp && !hadnl && !(flag & FANCY) &&
660 	    ((pstatus == status && pp->p_reason == reason) ||
661 	     !(flag & REASON))) {
662 	    (void) fputc(' ', cshout);
663 	    hadnl = 0;
664 	}
665 	else {
666 	    if (tp != pp && !hadnl) {
667 		(void) fputc('\n', cshout);
668 		hadnl = 1;
669 	    }
670 	    if (flag & NUMBER) {
671 		if (pp == tp)
672 		    (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
673 			    pp->p_index < 10 ? " " : "",
674 			    pp == pcurrent ? '+' :
675 			    (pp == pprevious ? '-' : ' '));
676 		else
677 		    (void) fprintf(cshout, "       ");
678 		hadnl = 0;
679 	    }
680 	    if (flag & FANCY) {
681 		(void) fprintf(cshout, "%5d ", pp->p_pid);
682 		hadnl = 0;
683 	    }
684 	    if (flag & (REASON | AREASON)) {
685 		if (flag & NAME)
686 		    format = "%-23s";
687 		else
688 		    format = "%s";
689 		if (pstatus == status)
690 		    if (pp->p_reason == reason) {
691 			(void) fprintf(cshout, format, "");
692 			hadnl = 0;
693 			goto prcomd;
694 		    }
695 		    else
696 			reason = pp->p_reason;
697 		else {
698 		    status = pstatus;
699 		    reason = pp->p_reason;
700 		}
701 		switch (status) {
702 
703 		case PRUNNING:
704 		    (void) fprintf(cshout, format, "Running ");
705 		    hadnl = 0;
706 		    break;
707 
708 		case PINTERRUPTED:
709 		case PSTOPPED:
710 		case PSIGNALED:
711                     /*
712                      * tell what happened to the background job
713                      * From: Michael Schroeder
714                      * <mlschroe@immd4.informatik.uni-erlangen.de>
715                      */
716                     if ((flag & REASON)
717                         || ((flag & AREASON)
718                             && reason != SIGINT
719                             && (reason != SIGPIPE
720                                 || (pp->p_flags & PPOU) == 0))) {
721 			(void) fprintf(cshout, format,
722 				       sys_siglist[(unsigned char)
723 						   pp->p_reason]);
724 			hadnl = 0;
725 		    }
726 		    break;
727 
728 		case PNEXITED:
729 		case PAEXITED:
730 		    if (flag & REASON) {
731 			if (pp->p_reason)
732 			    (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
733 			else
734 			    (void) fprintf(cshout, format, "Done");
735 			hadnl = 0;
736 		    }
737 		    break;
738 
739 		default:
740 		    (void) fprintf(csherr, "BUG: status=%-9o", status);
741 		}
742 	    }
743 	}
744 prcomd:
745 	if (flag & NAME) {
746 	    (void) fprintf(cshout, "%s", vis_str(pp->p_command));
747 	    if (pp->p_flags & PPOU)
748 		(void) fprintf(cshout, " |");
749 	    if (pp->p_flags & PERR)
750 		(void) fputc('&', cshout);
751 	    hadnl = 0;
752 	}
753 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
754 	    (void) fprintf(cshout, " (core dumped)");
755 	    hadnl = 0;
756 	}
757 	if (tp == pp->p_friends) {
758 	    if (flag & AMPERSAND) {
759 		(void) fprintf(cshout, " &");
760 		hadnl = 0;
761 	    }
762 	    if (flag & JOBDIR &&
763 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
764 		(void) fprintf(cshout, " (wd: ");
765 		dtildepr(value(STRhome), tp->p_cwd->di_name);
766 		(void) fputc(')', cshout);
767 		hadnl = 0;
768 	    }
769 	}
770 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
771 	    if (!hadnl)
772 		(void) fprintf(cshout, "\n\t");
773 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
774 		    &pp->p_btime);
775 	    hadnl = 1;
776 	}
777 	if (tp == pp->p_friends) {
778 	    if (!hadnl) {
779 		(void) fputc('\n', cshout);
780 		hadnl = 1;
781 	    }
782 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
783 		(void) fprintf(cshout, "(wd now: ");
784 		dtildepr(value(STRhome), dcwd->di_name);
785 		(void) fprintf(cshout, ")\n");
786 		hadnl = 1;
787 	    }
788 	}
789     } while ((pp = pp->p_friends) != tp);
790     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
791 	if (jobflags & NUMBER)
792 	    (void) fprintf(cshout, "       ");
793 	ptprint(tp);
794 	hadnl = 1;
795     }
796     (void) fflush(cshout);
797     return (jobflags);
798 }
799 
800 static void
801 ptprint(tp)
802     register struct process *tp;
803 {
804     struct timeval tetime, diff;
805     static struct timeval ztime;
806     struct rusage ru;
807     static struct rusage zru;
808     register struct process *pp = tp;
809 
810     ru = zru;
811     tetime = ztime;
812     do {
813 	ruadd(&ru, &pp->p_rusage);
814 	tvsub(&diff, &pp->p_etime, &pp->p_btime);
815 	if (timercmp(&diff, &tetime, >))
816 	    tetime = diff;
817     } while ((pp = pp->p_friends) != tp);
818     prusage(&zru, &ru, &tetime, &ztime);
819 }
820 
821 /*
822  * dojobs - print all jobs
823  */
824 void
825 /*ARGSUSED*/
826 dojobs(v, t)
827     Char **v;
828     struct command *t;
829 {
830     register struct process *pp;
831     register int flag = NUMBER | NAME | REASON;
832     int     i;
833 
834     if (chkstop)
835 	chkstop = 2;
836     if (*++v) {
837 	if (v[1] || !eq(*v, STRml))
838 	    stderror(ERR_JOBS);
839 	flag |= FANCY | JOBDIR;
840     }
841     for (i = 1; i <= pmaxindex; i++)
842 	for (pp = proclist.p_next; pp; pp = pp->p_next)
843 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
844 		pp->p_flags &= ~PNEEDNOTE;
845 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
846 		    pflush(pp);
847 		break;
848 	    }
849 }
850 
851 /*
852  * dofg - builtin - put the job into the foreground
853  */
854 void
855 /*ARGSUSED*/
856 dofg(v, t)
857     Char **v;
858     struct command *t;
859 {
860     register struct process *pp;
861 
862     okpcntl();
863     ++v;
864     do {
865 	pp = pfind(*v);
866 	pstart(pp, 1);
867 	pjwait(pp);
868     } while (*v && *++v);
869 }
870 
871 /*
872  * %... - builtin - put the job into the foreground
873  */
874 void
875 /*ARGSUSED*/
876 dofg1(v, t)
877     Char **v;
878     struct command *t;
879 {
880     register struct process *pp;
881 
882     okpcntl();
883     pp = pfind(v[0]);
884     pstart(pp, 1);
885     pjwait(pp);
886 }
887 
888 /*
889  * dobg - builtin - put the job into the background
890  */
891 void
892 /*ARGSUSED*/
893 dobg(v, t)
894     Char **v;
895     struct command *t;
896 {
897     register struct process *pp;
898 
899     okpcntl();
900     ++v;
901     do {
902 	pp = pfind(*v);
903 	pstart(pp, 0);
904     } while (*v && *++v);
905 }
906 
907 /*
908  * %... & - builtin - put the job into the background
909  */
910 void
911 /*ARGSUSED*/
912 dobg1(v, t)
913     Char **v;
914     struct command *t;
915 {
916     register struct process *pp;
917 
918     pp = pfind(v[0]);
919     pstart(pp, 0);
920 }
921 
922 /*
923  * dostop - builtin - stop the job
924  */
925 void
926 /*ARGSUSED*/
927 dostop(v, t)
928     Char **v;
929     struct command *t;
930 {
931     pkill(++v, SIGSTOP);
932 }
933 
934 /*
935  * dokill - builtin - superset of kill (1)
936  */
937 void
938 /*ARGSUSED*/
939 dokill(v, t)
940     Char **v;
941     struct command *t;
942 {
943     register int signum = SIGTERM;
944     register char *name;
945 
946     v++;
947     if (v[0] && v[0][0] == '-') {
948 	if (v[0][1] == 'l') {
949 	    for (signum = 1; signum < NSIG; signum++) {
950 		(void) fprintf(cshout, "%s ", sys_signame[signum]);
951 		if (signum == NSIG / 2)
952 		    (void) fputc('\n', cshout);
953 	    }
954 	    (void) fputc('\n', cshout);
955 	    return;
956 	}
957 	if (Isdigit(v[0][1])) {
958 	    signum = atoi(short2str(v[0] + 1));
959 	    if (signum < 0 || signum > NSIG)
960 		stderror(ERR_NAME | ERR_BADSIG);
961 	}
962 	else {
963 	    name = short2str(&v[0][1]);
964 	    if (!strncasecmp(name, "sig", 3))
965 		name += 3;
966 
967 	    for (signum = 1; signum < NSIG; signum++)
968 		if (!strcasecmp(sys_signame[signum], name))
969 		    break;
970 
971 	    if (signum == NSIG) {
972 		setname(vis_str(&v[0][1]));
973 		stderror(ERR_NAME | ERR_UNKSIG);
974 	    }
975 	}
976 	v++;
977     }
978     pkill(v, signum);
979 }
980 
981 static void
982 pkill(v, signum)
983     Char  **v;
984     int     signum;
985 {
986     register struct process *pp, *np;
987     register int jobflags = 0;
988     int     pid, err1 = 0;
989     sigset_t sigset;
990     Char   *cp;
991 
992     sigemptyset(&sigset);
993     sigaddset(&sigset, SIGCHLD);
994     if (setintr)
995 	sigaddset(&sigset, SIGINT);
996     sigprocmask(SIG_BLOCK, &sigset, NULL);
997     gflag = 0, tglob(v);
998     if (gflag) {
999 	v = globall(v);
1000 	if (v == 0)
1001 	    stderror(ERR_NAME | ERR_NOMATCH);
1002     }
1003     else {
1004 	v = gargv = saveblk(v);
1005 	trim(v);
1006     }
1007 
1008     while (v && (cp = *v)) {
1009 	if (*cp == '%') {
1010 	    np = pp = pfind(cp);
1011 	    do
1012 		jobflags |= np->p_flags;
1013 	    while ((np = np->p_friends) != pp);
1014 	    switch (signum) {
1015 
1016 	    case SIGSTOP:
1017 	    case SIGTSTP:
1018 	    case SIGTTIN:
1019 	    case SIGTTOU:
1020 		if ((jobflags & PRUNNING) == 0) {
1021 		    (void) fprintf(csherr, "%s: Already suspended\n",
1022 				   vis_str(cp));
1023 		    err1++;
1024 		    goto cont;
1025 		}
1026 		break;
1027 		/*
1028 		 * suspend a process, kill -CONT %, then type jobs; the shell
1029 		 * says it is suspended, but it is running; thanks jaap..
1030 		 */
1031 	    case SIGCONT:
1032 		pstart(pp, 0);
1033 		goto cont;
1034 	    }
1035 	    if (killpg((pid_t) pp->p_jobid, signum) < 0) {
1036 		(void) fprintf(csherr, "%s: %s\n", vis_str(cp),
1037 			       strerror(errno));
1038 		err1++;
1039 	    }
1040 	    if (signum == SIGTERM || signum == SIGHUP)
1041 		(void) killpg((pid_t) pp->p_jobid, SIGCONT);
1042 	}
1043 	else if (!(Isdigit(*cp) || *cp == '-'))
1044 	    stderror(ERR_NAME | ERR_JOBARGS);
1045 	else {
1046 	    pid = atoi(short2str(cp));
1047 	    if (kill((pid_t) pid, signum) < 0) {
1048 		(void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
1049 		err1++;
1050 		goto cont;
1051 	    }
1052 	    if (signum == SIGTERM || signum == SIGHUP)
1053 		(void) kill((pid_t) pid, SIGCONT);
1054 	}
1055 cont:
1056 	v++;
1057     }
1058     if (gargv)
1059 	blkfree(gargv), gargv = 0;
1060     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1061     if (err1)
1062 	stderror(ERR_SILENT);
1063 }
1064 
1065 /*
1066  * pstart - start the job in foreground/background
1067  */
1068 void
1069 pstart(pp, foregnd)
1070     register struct process *pp;
1071     int     foregnd;
1072 {
1073     register struct process *np;
1074     sigset_t sigset, osigset;
1075     long    jobflags = 0;
1076 
1077     sigemptyset(&sigset);
1078     sigaddset(&sigset, SIGCHLD);
1079     sigprocmask(SIG_BLOCK, &sigset, &osigset);
1080     np = pp;
1081     do {
1082 	jobflags |= np->p_flags;
1083 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
1084 	    np->p_flags |= PRUNNING;
1085 	    np->p_flags &= ~PSTOPPED;
1086 	    if (foregnd)
1087 		np->p_flags |= PFOREGND;
1088 	    else
1089 		np->p_flags &= ~PFOREGND;
1090 	}
1091     } while ((np = np->p_friends) != pp);
1092     if (!foregnd)
1093 	pclrcurr(pp);
1094     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1095     if (foregnd)
1096 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
1097     if (jobflags & PSTOPPED)
1098 	(void) killpg((pid_t) pp->p_jobid, SIGCONT);
1099     sigprocmask(SIG_SETMASK, &osigset, NULL);
1100 }
1101 
1102 void
1103 panystop(neednl)
1104     bool    neednl;
1105 {
1106     register struct process *pp;
1107 
1108     chkstop = 2;
1109     for (pp = proclist.p_next; pp; pp = pp->p_next)
1110 	if (pp->p_flags & PSTOPPED)
1111 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
1112 }
1113 
1114 struct process *
1115 pfind(cp)
1116     Char   *cp;
1117 {
1118     register struct process *pp, *np;
1119 
1120     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1121 	if (pcurrent == NULL)
1122 	    stderror(ERR_NAME | ERR_JOBCUR);
1123 	return (pcurrent);
1124     }
1125     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1126 	if (pprevious == NULL)
1127 	    stderror(ERR_NAME | ERR_JOBPREV);
1128 	return (pprevious);
1129     }
1130     if (Isdigit(cp[1])) {
1131 	int     idx = atoi(short2str(cp + 1));
1132 
1133 	for (pp = proclist.p_next; pp; pp = pp->p_next)
1134 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
1135 		return (pp);
1136 	stderror(ERR_NAME | ERR_NOSUCHJOB);
1137     }
1138     np = NULL;
1139     for (pp = proclist.p_next; pp; pp = pp->p_next)
1140 	if (pp->p_pid == pp->p_jobid) {
1141 	    if (cp[1] == '?') {
1142 		register Char *dp;
1143 
1144 		for (dp = pp->p_command; *dp; dp++) {
1145 		    if (*dp != cp[2])
1146 			continue;
1147 		    if (prefix(cp + 2, dp))
1148 			goto match;
1149 		}
1150 	    }
1151 	    else if (prefix(cp + 1, pp->p_command)) {
1152 	match:
1153 		if (np)
1154 		    stderror(ERR_NAME | ERR_AMBIG);
1155 		np = pp;
1156 	    }
1157 	}
1158     if (np)
1159 	return (np);
1160     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
1161     /* NOTREACHED */
1162     return (0);
1163 }
1164 
1165 
1166 /*
1167  * pgetcurr - find most recent job that is not pp, preferably stopped
1168  */
1169 static struct process *
1170 pgetcurr(pp)
1171     register struct process *pp;
1172 {
1173     register struct process *np;
1174     register struct process *xp = NULL;
1175 
1176     for (np = proclist.p_next; np; np = np->p_next)
1177 	if (np != pcurrent && np != pp && np->p_pid &&
1178 	    np->p_pid == np->p_jobid) {
1179 	    if (np->p_flags & PSTOPPED)
1180 		return (np);
1181 	    if (xp == NULL)
1182 		xp = np;
1183 	}
1184     return (xp);
1185 }
1186 
1187 /*
1188  * donotify - flag the job so as to report termination asynchronously
1189  */
1190 void
1191 /*ARGSUSED*/
1192 donotify(v, t)
1193     Char **v;
1194     struct command *t;
1195 {
1196     register struct process *pp;
1197 
1198     pp = pfind(*++v);
1199     pp->p_flags |= PNOTIFY;
1200 }
1201 
1202 /*
1203  * Do the fork and whatever should be done in the child side that
1204  * should not be done if we are not forking at all (like for simple builtin's)
1205  * Also do everything that needs any signals fiddled with in the parent side
1206  *
1207  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1208  *	-1:	leave tty alone; inherit pgrp from parent
1209  *	 0:	already have tty; manipulate process pgrps only
1210  *	 1:	want to claim tty; manipulate process and tty pgrps
1211  * It is usually just the value of tpgrp.
1212  */
1213 
1214 int
1215 pfork(t, wanttty)
1216     struct command *t;		/* command we are forking for */
1217     int     wanttty;
1218 {
1219     register int pid;
1220     bool    ignint = 0;
1221     int     pgrp;
1222     sigset_t sigset, osigset;
1223 
1224     /*
1225      * A child will be uninterruptible only under very special conditions.
1226      * Remember that the semantics of '&' is implemented by disconnecting the
1227      * process from the tty so signals do not need to ignored just for '&'.
1228      * Thus signals are set to default action for children unless: we have had
1229      * an "onintr -" (then specifically ignored) we are not playing with
1230      * signals (inherit action)
1231      */
1232     if (setintr)
1233 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1234 	    || (gointr && eq(gointr, STRminus));
1235     /*
1236      * Check for maximum nesting of 16 processes to avoid Forking loops
1237      */
1238     if (child == 16)
1239 	stderror(ERR_NESTING, 16);
1240     /*
1241      * Hold SIGCHLD until we have the process installed in our table.
1242      */
1243     sigemptyset(&sigset);
1244     sigaddset(&sigset, SIGCHLD);
1245     sigprocmask(SIG_BLOCK, &sigset, &osigset);
1246     while ((pid = fork()) < 0)
1247 	if (setintr == 0)
1248 	    (void) sleep(FORKSLEEP);
1249 	else {
1250 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
1251 	    stderror(ERR_NOPROC);
1252 	}
1253     if (pid == 0) {
1254 	settimes();
1255 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1256 	pflushall();
1257 	pcurrjob = NULL;
1258 	child++;
1259 	if (setintr) {
1260 	    setintr = 0;	/* until I think otherwise */
1261 	    /*
1262 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1263 	     * -" seen.
1264 	     */
1265 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1266 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1267 	    if (wanttty >= 0) {
1268 		/* make stoppable */
1269 		(void) signal(SIGTSTP, SIG_DFL);
1270 		(void) signal(SIGTTIN, SIG_DFL);
1271 		(void) signal(SIGTTOU, SIG_DFL);
1272 	    }
1273 	    (void) signal(SIGTERM, parterm);
1274 	}
1275 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1276 	    (void) signal(SIGINT, SIG_IGN);
1277 	    (void) signal(SIGQUIT, SIG_IGN);
1278 	}
1279 	pgetty(wanttty, pgrp);
1280 	/*
1281 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1282 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1283 	 * to know about nice/nohup/time
1284 	 */
1285 	if (t->t_dflg & F_NOHUP)
1286 	    (void) signal(SIGHUP, SIG_IGN);
1287 	if (t->t_dflg & F_NICE)
1288 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
1289     }
1290     else {
1291 	if (wanttty >= 0)
1292 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
1293 	palloc(pid, t);
1294 	sigprocmask(SIG_SETMASK, &osigset, NULL);
1295     }
1296 
1297     return (pid);
1298 }
1299 
1300 static void
1301 okpcntl()
1302 {
1303     if (tpgrp == -1)
1304 	stderror(ERR_JOBCONTROL);
1305     if (tpgrp == 0)
1306 	stderror(ERR_JOBCTRLSUB);
1307 }
1308 
1309 /*
1310  * if we don't have vfork(), things can still go in the wrong order
1311  * resulting in the famous 'Stopped (tty output)'. But some systems
1312  * don't permit the setpgid() call, (these are more recent secure
1313  * systems such as ibm's aix). Then we'd rather print an error message
1314  * than hang the shell!
1315  * I am open to suggestions how to fix that.
1316  */
1317 void
1318 pgetty(wanttty, pgrp)
1319     int     wanttty, pgrp;
1320 {
1321     sigset_t sigset, osigset;
1322 
1323     /*
1324      * christos: I am blocking the tty signals till I've set things
1325      * correctly....
1326      */
1327     if (wanttty > 0) {
1328 	sigemptyset(&sigset);
1329 	sigaddset(&sigset, SIGTSTP);
1330 	sigaddset(&sigset, SIGTTIN);
1331 	sigaddset(&sigset, SIGTTOU);
1332 	sigprocmask(SIG_BLOCK, &sigset, &osigset);
1333     }
1334     /*
1335      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
1336      * Don't check for tpgrp >= 0 so even non-interactive shells give
1337      * background jobs process groups Same for the comparison in the other part
1338      * of the #ifdef
1339      */
1340     if (wanttty >= 0)
1341 	if (setpgid(0, pgrp) == -1) {
1342 	    (void) fprintf(csherr, "csh: setpgid error.\n");
1343 	    xexit(0);
1344 	}
1345 
1346     if (wanttty > 0) {
1347 	(void) tcsetpgrp(FSHTTY, pgrp);
1348 	sigprocmask(SIG_SETMASK, &osigset, NULL);
1349     }
1350 
1351     if (tpgrp > 0)
1352 	tpgrp = 0;		/* gave tty away */
1353 }
1354