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