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