xref: /csrg-svn/bin/csh/proc.c (revision 68576)
147823Sbostic /*-
260765Sbostic  * Copyright (c) 1980, 1991, 1993
360765Sbostic  *	The Regents of the University of California.  All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621940Sdist  */
721940Sdist 
817509Sedward #ifndef lint
9*68576Schristos static char sccsid[] = "@(#)proc.c	8.2 (Berkeley) 03/22/95";
1047823Sbostic #endif /* not lint */
111302Sbill 
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <sys/wait.h>
1450028Sbostic #include <errno.h>
1550028Sbostic #include <unistd.h>
1650028Sbostic #include <stdlib.h>
1750028Sbostic #include <string.h>
1850033Schristos #if __STDC__
1950033Schristos # include <stdarg.h>
2050033Schristos #else
2150033Schristos # include <varargs.h>
2250033Schristos #endif
2350033Schristos 
2450023Sbostic #include "csh.h"
2550023Sbostic #include "dir.h"
2650023Sbostic #include "proc.h"
2750023Sbostic #include "extern.h"
281302Sbill 
291302Sbill #define BIGINDEX	9	/* largest desirable job index */
301302Sbill 
3149992Sbostic static struct rusage zru;
3249992Sbostic 
3350024Schristos static void	 pflushall __P((void));
3450024Schristos static void	 pflush __P((struct process *));
3550024Schristos static void	 pclrcurr __P((struct process *));
3650024Schristos static void	 padd __P((struct command *));
3750024Schristos static int	 pprint __P((struct process *, int));
3850024Schristos static void	 ptprint __P((struct process *));
3950024Schristos static void	 pads __P((Char *));
4050024Schristos static void	 pkill __P((Char **v, int));
4151437Sleres static struct	process
4250024Schristos 		*pgetcurr __P((struct process *));
4350024Schristos static void	 okpcntl __P((void));
4449992Sbostic 
451302Sbill /*
461302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
471302Sbill  *	indicating that at least one child has terminated or stopped
481302Sbill  *	thus at least one wait system call will definitely return a
491302Sbill  *	childs status.  Top level routines (like pwait) must be sure
501302Sbill  *	to mask interrupts when playing with the proclist data structures!
511302Sbill  */
5250023Sbostic /* ARGUSED */
5346657Sbostic void
pchild(notused)5450023Sbostic pchild(notused)
5550023Sbostic 	int notused;
561302Sbill {
5749992Sbostic     register struct process *pp;
5849992Sbostic     register struct process *fp;
5949992Sbostic     register int pid;
6049992Sbostic     extern int insource;
6149992Sbostic     union wait w;
6249992Sbostic     int     jobflags;
6349992Sbostic     struct rusage ru;
641302Sbill 
651302Sbill loop:
6649992Sbostic     errno = 0;			/* reset, just in case */
6749992Sbostic     pid = wait3(&w.w_status,
6849992Sbostic        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
6949992Sbostic 
7049992Sbostic     if (pid <= 0) {
7149992Sbostic 	if (errno == EINTR) {
7249992Sbostic 	    errno = 0;
7349992Sbostic 	    goto loop;
741302Sbill 	}
7549992Sbostic 	pnoprocesses = pid == -1;
7649992Sbostic 	return;
7749992Sbostic     }
7850040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
7949992Sbostic 	if (pid == pp->p_pid)
8049992Sbostic 	    goto found;
8149992Sbostic     goto loop;
821302Sbill found:
8349992Sbostic     if (pid == atoi(short2str(value(STRchild))))
8449992Sbostic 	unsetv(STRchild);
8549992Sbostic     pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
8649992Sbostic     if (WIFSTOPPED(w)) {
8749992Sbostic 	pp->p_flags |= PSTOPPED;
8849992Sbostic 	pp->p_reason = w.w_stopsig;
8949992Sbostic     }
9049992Sbostic     else {
9149992Sbostic 	if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
9250028Sbostic 	    (void) gettimeofday(&pp->p_etime, NULL);
9349992Sbostic 
9449992Sbostic 	pp->p_rusage = ru;
9549992Sbostic 	if (WIFSIGNALED(w)) {
9649992Sbostic 	    if (w.w_termsig == SIGINT)
9749992Sbostic 		pp->p_flags |= PINTERRUPTED;
9849992Sbostic 	    else
9949992Sbostic 		pp->p_flags |= PSIGNALED;
10049992Sbostic 	    if (w.w_coredump)
10149992Sbostic 		pp->p_flags |= PDUMPED;
10249992Sbostic 	    pp->p_reason = w.w_termsig;
1031302Sbill 	}
10449992Sbostic 	else {
10549992Sbostic 	    pp->p_reason = w.w_retcode;
10649992Sbostic 	    if (pp->p_reason != 0)
10749992Sbostic 		pp->p_flags |= PAEXITED;
10849992Sbostic 	    else
10949992Sbostic 		pp->p_flags |= PNEXITED;
11049992Sbostic 	}
11149992Sbostic     }
11249992Sbostic     jobflags = 0;
11349992Sbostic     fp = pp;
11449992Sbostic     do {
11549992Sbostic 	if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
11649992Sbostic 	    !child && adrof(STRtime) &&
11749992Sbostic 	    fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
11849992Sbostic 	    >= atoi(short2str(value(STRtime))))
11949992Sbostic 	    fp->p_flags |= PTIME;
12049992Sbostic 	jobflags |= fp->p_flags;
12149992Sbostic     } while ((fp = fp->p_friends) != pp);
12249992Sbostic     pp->p_flags &= ~PFOREGND;
12349992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
12449992Sbostic 	pp->p_flags &= ~PPTIME;
12549992Sbostic 	pp->p_flags |= PTIME;
12649992Sbostic     }
12749992Sbostic     if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
1281302Sbill 	fp = pp;
1291302Sbill 	do {
13049992Sbostic 	    if (fp->p_flags & PSTOPPED)
13149992Sbostic 		fp->p_flags |= PREPORTED;
1321302Sbill 	} while ((fp = fp->p_friends) != pp);
13349992Sbostic 	while (fp->p_pid != fp->p_jobid)
13449992Sbostic 	    fp = fp->p_friends;
13549992Sbostic 	if (jobflags & PSTOPPED) {
13649992Sbostic 	    if (pcurrent && pcurrent != fp)
13749992Sbostic 		pprevious = pcurrent;
13849992Sbostic 	    pcurrent = fp;
1391302Sbill 	}
14049992Sbostic 	else
14149992Sbostic 	    pclrcurr(fp);
14249992Sbostic 	if (jobflags & PFOREGND) {
14349992Sbostic 	    if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
14449992Sbostic #ifdef IIASA
14549992Sbostic 		jobflags & PAEXITED ||
14649992Sbostic #endif
14749992Sbostic 		!eq(dcwd->di_name, fp->p_cwd->di_name)) {
14849992Sbostic 		;		/* print in pjwait */
14949992Sbostic 	    }
15049992Sbostic 	    /* PWP: print a newline after ^C */
15150445Schristos 	    else if (jobflags & PINTERRUPTED) {
15251589Schristos 		(void) vis_fputc('\r' | QUOTE, cshout);
15350445Schristos 		(void) fputc('\n', cshout);
15450445Schristos 	    }
1551302Sbill 	}
15649992Sbostic 	else {
15749992Sbostic 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
15851589Schristos 		(void) vis_fputc('\r' | QUOTE, cshout);
15950445Schristos 		(void) fputc('\n', cshout);
16049992Sbostic 		(void) pprint(pp, NUMBER | NAME | REASON);
16149992Sbostic 		if ((jobflags & PSTOPPED) == 0)
16249992Sbostic 		    pflush(pp);
16349992Sbostic 	    }
16449992Sbostic 	    else {
16549992Sbostic 		fp->p_flags |= PNEEDNOTE;
16649992Sbostic 		neednote++;
16749992Sbostic 	    }
16849992Sbostic 	}
16949992Sbostic     }
17049992Sbostic     goto loop;
1711302Sbill }
1721302Sbill 
17349992Sbostic void
pnote()1741302Sbill pnote()
1751302Sbill {
17649992Sbostic     register struct process *pp;
17749992Sbostic     int     flags;
178*68576Schristos     sigset_t sigset, osigset;
1791302Sbill 
18049992Sbostic     neednote = 0;
181*68576Schristos     sigemptyset(&sigset);
182*68576Schristos     sigaddset(&sigset, SIGCHLD);
18350040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
18449992Sbostic 	if (pp->p_flags & PNEEDNOTE) {
185*68576Schristos 	    sigprocmask(SIG_BLOCK, &sigset, &osigset);
18649992Sbostic 	    pp->p_flags &= ~PNEEDNOTE;
18749992Sbostic 	    flags = pprint(pp, NUMBER | NAME | REASON);
18849992Sbostic 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
18949992Sbostic 		pflush(pp);
190*68576Schristos 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
1911302Sbill 	}
19249992Sbostic     }
1931302Sbill }
1941302Sbill 
1951302Sbill /*
1961302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1971302Sbill  *	of current and previous job indicators.
1981302Sbill  */
19949992Sbostic void
pwait()2001302Sbill pwait()
2011302Sbill {
20249992Sbostic     register struct process *fp, *pp;
203*68576Schristos     sigset_t sigset, osigset;
2041302Sbill 
20549992Sbostic     /*
20649992Sbostic      * Here's where dead procs get flushed.
20749992Sbostic      */
208*68576Schristos     sigemptyset(&sigset);
209*68576Schristos     sigaddset(&sigset, SIGCHLD);
210*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, &osigset);
21150040Schristos     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
21249992Sbostic 	if (pp->p_pid == 0) {
21349992Sbostic 	    fp->p_next = pp->p_next;
21449992Sbostic 	    xfree((ptr_t) pp->p_command);
21549992Sbostic 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
21649992Sbostic 		if (pp->p_cwd->di_next == 0)
21749992Sbostic 		    dfree(pp->p_cwd);
21849992Sbostic 	    xfree((ptr_t) pp);
21949992Sbostic 	    pp = fp;
22049992Sbostic 	}
221*68576Schristos     sigprocmask(SIG_SETMASK, &osigset, NULL);
22249992Sbostic     pjwait(pcurrjob);
2231302Sbill }
2241302Sbill 
22549992Sbostic 
2261302Sbill /*
2271302Sbill  * pjwait - wait for a job to finish or become stopped
2281302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
2291302Sbill  */
23049992Sbostic void
pjwait(pp)2311302Sbill pjwait(pp)
23249992Sbostic     register struct process *pp;
2331302Sbill {
23449992Sbostic     register struct process *fp;
23549992Sbostic     int     jobflags, reason;
236*68576Schristos     sigset_t sigset, osigset;
2371302Sbill 
23849992Sbostic     while (pp->p_pid != pp->p_jobid)
23949992Sbostic 	pp = pp->p_friends;
24049992Sbostic     fp = pp;
24149992Sbostic 
24249992Sbostic     do {
24349992Sbostic 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
24450439Schristos 	    (void) fprintf(csherr, "BUG: waiting for background job!\n");
24549992Sbostic     } while ((fp = fp->p_friends) != pp);
24649992Sbostic     /*
24749992Sbostic      * Now keep pausing as long as we are not interrupted (SIGINT), and the
24849992Sbostic      * target process, or any of its friends, are running
24949992Sbostic      */
25049992Sbostic     fp = pp;
251*68576Schristos     sigemptyset(&sigset);
252*68576Schristos     sigaddset(&sigset, SIGCHLD);
253*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, &osigset);
25449992Sbostic     for (;;) {
255*68576Schristos 	sigemptyset(&sigset);
256*68576Schristos 	sigaddset(&sigset, SIGCHLD);
257*68576Schristos 	sigprocmask(SIG_BLOCK, &sigset, NULL);
25849992Sbostic 	jobflags = 0;
25949992Sbostic 	do
26049992Sbostic 	    jobflags |= fp->p_flags;
26149992Sbostic 	while ((fp = (fp->p_friends)) != pp);
26249992Sbostic 	if ((jobflags & PRUNNING) == 0)
26349992Sbostic 	    break;
26449992Sbostic #ifdef JOBDEBUG
265*68576Schristos 	(void) fprintf(csherr, "starting to sigsuspend for  SIGCHLD on %d\n",
26650439Schristos 		       fp->p_pid);
26749992Sbostic #endif				/* JOBDEBUG */
268*68576Schristos 	sigset = osigset;
269*68576Schristos 	sigdelset(&sigset, SIGCHLD);
270*68576Schristos 	sigsuspend(&sigset);
27149992Sbostic     }
272*68576Schristos     sigprocmask(SIG_SETMASK, &osigset, NULL);
27349992Sbostic     if (tpgrp > 0)		/* get tty back */
27449992Sbostic 	(void) tcsetpgrp(FSHTTY, tpgrp);
27549992Sbostic     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
27649992Sbostic 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
27749992Sbostic 	if (jobflags & PSTOPPED) {
27850445Schristos 	    (void) fputc('\n', cshout);
27949992Sbostic 	    if (adrof(STRlistjobs)) {
28049992Sbostic 		Char   *jobcommand[3];
28149992Sbostic 
28249992Sbostic 		jobcommand[0] = STRjobs;
28349992Sbostic 		if (eq(value(STRlistjobs), STRlong))
28449992Sbostic 		    jobcommand[1] = STRml;
28549992Sbostic 		else
28649992Sbostic 		    jobcommand[1] = NULL;
28749992Sbostic 		jobcommand[2] = NULL;
28849992Sbostic 
28950439Schristos 		dojobs(jobcommand, NULL);
29049992Sbostic 		(void) pprint(pp, SHELLDIR);
29149992Sbostic 	    }
29249992Sbostic 	    else
29349992Sbostic 		(void) pprint(pp, AREASON | SHELLDIR);
2941302Sbill 	}
29549992Sbostic 	else
29649992Sbostic 	    (void) pprint(pp, AREASON | SHELLDIR);
29749992Sbostic     }
29849992Sbostic     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
29949992Sbostic 	(!gointr || !eq(gointr, STRminus))) {
30049992Sbostic 	if ((jobflags & PSTOPPED) == 0)
30149992Sbostic 	    pflush(pp);
30249992Sbostic 	pintr1(0);
30349992Sbostic 	/* NOTREACHED */
30449992Sbostic     }
30549992Sbostic     reason = 0;
30649992Sbostic     fp = pp;
30749992Sbostic     do {
30849992Sbostic 	if (fp->p_reason)
30949992Sbostic 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
31049992Sbostic 		fp->p_reason | META : fp->p_reason;
31149992Sbostic     } while ((fp = fp->p_friends) != pp);
31250445Schristos     if ((reason != 0) && (adrof(STRprintexitvalue))) {
31350439Schristos 	(void) fprintf(cshout, "Exit %d\n", reason);
31450445Schristos     }
31549992Sbostic     set(STRstatus, putn(reason));
31649992Sbostic     if (reason && exiterr)
31749992Sbostic 	exitstat();
31849992Sbostic     pflush(pp);
3191302Sbill }
3201302Sbill 
3211302Sbill /*
3221302Sbill  * dowait - wait for all processes to finish
3231302Sbill  */
32449992Sbostic void
32550439Schristos /*ARGSUSED*/
dowait(v,t)32650439Schristos dowait(v, t)
32750439Schristos     Char **v;
32850439Schristos     struct command *t;
3291302Sbill {
33049992Sbostic     register struct process *pp;
331*68576Schristos     sigset_t sigset, osigset;
3321302Sbill 
33349992Sbostic     pjobs++;
334*68576Schristos     sigemptyset(&sigset);
335*68576Schristos     sigaddset(&sigset, SIGCHLD);
336*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, &osigset);
3371302Sbill loop:
33849992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
33949992Sbostic 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
34049992Sbostic 	    pp->p_flags & PRUNNING) {
341*68576Schristos 	    sigemptyset(&sigset);
342*68576Schristos 	    sigsuspend(&sigset);
34349992Sbostic 	    goto loop;
34449992Sbostic 	}
345*68576Schristos     sigprocmask(SIG_SETMASK, &osigset, NULL);
34649992Sbostic     pjobs = 0;
3471302Sbill }
3481302Sbill 
3491302Sbill /*
3501302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
3511302Sbill  */
35249992Sbostic static void
pflushall()3531302Sbill pflushall()
3541302Sbill {
35549992Sbostic     register struct process *pp;
3561302Sbill 
35750040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
35849992Sbostic 	if (pp->p_pid)
35949992Sbostic 	    pflush(pp);
3601302Sbill }
3611302Sbill 
3621302Sbill /*
3631302Sbill  * pflush - flag all process structures in the same job as the
3641302Sbill  *	the argument process for deletion.  The actual free of the
3651302Sbill  *	space is not done here since pflush is called at interrupt level.
3661302Sbill  */
36749992Sbostic static void
pflush(pp)3681302Sbill pflush(pp)
36949992Sbostic     register struct process *pp;
3701302Sbill {
37149992Sbostic     register struct process *np;
37249992Sbostic     register int idx;
3731302Sbill 
37449992Sbostic     if (pp->p_pid == 0) {
37550439Schristos 	(void) fprintf(csherr, "BUG: process flushed twice");
37649992Sbostic 	return;
37749992Sbostic     }
37849992Sbostic     while (pp->p_pid != pp->p_jobid)
37949992Sbostic 	pp = pp->p_friends;
38049992Sbostic     pclrcurr(pp);
38149992Sbostic     if (pp == pcurrjob)
38249992Sbostic 	pcurrjob = 0;
38349992Sbostic     idx = pp->p_index;
38449992Sbostic     np = pp;
38549992Sbostic     do {
38649992Sbostic 	np->p_index = np->p_pid = 0;
38749992Sbostic 	np->p_flags &= ~PNEEDNOTE;
38849992Sbostic     } while ((np = np->p_friends) != pp);
38949992Sbostic     if (idx == pmaxindex) {
39049992Sbostic 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
39149992Sbostic 	    if (np->p_index > idx)
39249992Sbostic 		idx = np->p_index;
39349992Sbostic 	pmaxindex = idx;
39449992Sbostic     }
3951302Sbill }
3961302Sbill 
3971302Sbill /*
3981302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3991302Sbill  *	pp MUST be the job leader
4001302Sbill  */
40149992Sbostic static void
pclrcurr(pp)4021302Sbill pclrcurr(pp)
40349992Sbostic     register struct process *pp;
4041302Sbill {
4051302Sbill 
40649992Sbostic     if (pp == pcurrent)
40750040Schristos 	if (pprevious != NULL) {
40849992Sbostic 	    pcurrent = pprevious;
40949992Sbostic 	    pprevious = pgetcurr(pp);
41049992Sbostic 	}
41149992Sbostic 	else {
41249992Sbostic 	    pcurrent = pgetcurr(pp);
41349992Sbostic 	    pprevious = pgetcurr(pp);
41449992Sbostic 	}
41549992Sbostic     else if (pp == pprevious)
41649992Sbostic 	pprevious = pgetcurr(pp);
4171302Sbill }
4181302Sbill 
4191302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
42049992Sbostic static Char command[PMAXLEN + 4];
42149992Sbostic static int cmdlen;
42249992Sbostic static Char *cmdp;
42349992Sbostic 
4241302Sbill /*
4251302Sbill  * palloc - allocate a process structure and fill it up.
4261302Sbill  *	an important assumption is made that the process is running.
4271302Sbill  */
42849992Sbostic void
palloc(pid,t)4291302Sbill palloc(pid, t)
43049992Sbostic     int     pid;
43149992Sbostic     register struct command *t;
4321302Sbill {
43349992Sbostic     register struct process *pp;
43449992Sbostic     int     i;
4351302Sbill 
43649992Sbostic     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
43749992Sbostic     pp->p_pid = pid;
43849992Sbostic     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
43949992Sbostic     if (t->t_dflg & F_TIME)
44049992Sbostic 	pp->p_flags |= PPTIME;
44149992Sbostic     cmdp = command;
44249992Sbostic     cmdlen = 0;
44349992Sbostic     padd(t);
44449992Sbostic     *cmdp++ = 0;
44549992Sbostic     if (t->t_dflg & F_PIPEOUT) {
44649992Sbostic 	pp->p_flags |= PPOU;
44749992Sbostic 	if (t->t_dflg & F_STDERR)
44850439Schristos 	    pp->p_flags |= PERR;
44949992Sbostic     }
45049992Sbostic     pp->p_command = Strsave(command);
45149992Sbostic     if (pcurrjob) {
45249992Sbostic 	struct process *fp;
4531302Sbill 
45449992Sbostic 	/* careful here with interrupt level */
45549992Sbostic 	pp->p_cwd = 0;
45649992Sbostic 	pp->p_index = pcurrjob->p_index;
45749992Sbostic 	pp->p_friends = pcurrjob;
45849992Sbostic 	pp->p_jobid = pcurrjob->p_pid;
45951437Sleres 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
46051437Sleres 	    continue;
46149992Sbostic 	fp->p_friends = pp;
46249992Sbostic     }
46349992Sbostic     else {
46449992Sbostic 	pcurrjob = pp;
46549992Sbostic 	pp->p_jobid = pid;
46649992Sbostic 	pp->p_friends = pp;
46749992Sbostic 	pp->p_cwd = dcwd;
46849992Sbostic 	dcwd->di_count++;
46949992Sbostic 	if (pmaxindex < BIGINDEX)
47049992Sbostic 	    pp->p_index = ++pmaxindex;
47149992Sbostic 	else {
47249992Sbostic 	    struct process *np;
47349992Sbostic 
47449992Sbostic 	    for (i = 1;; i++) {
47549992Sbostic 		for (np = proclist.p_next; np; np = np->p_next)
47649992Sbostic 		    if (np->p_index == i)
47749992Sbostic 			goto tryagain;
47849992Sbostic 		pp->p_index = i;
47949992Sbostic 		if (i > pmaxindex)
48049992Sbostic 		    pmaxindex = i;
48149992Sbostic 		break;
48249992Sbostic 	tryagain:;
48349992Sbostic 	    }
4841302Sbill 	}
48550040Schristos 	if (pcurrent == NULL)
48649992Sbostic 	    pcurrent = pp;
48750040Schristos 	else if (pprevious == NULL)
48849992Sbostic 	    pprevious = pp;
48949992Sbostic     }
49049992Sbostic     pp->p_next = proclist.p_next;
49149992Sbostic     proclist.p_next = pp;
49250028Sbostic     (void) gettimeofday(&pp->p_btime, NULL);
4931302Sbill }
4941302Sbill 
49549992Sbostic static void
padd(t)4961302Sbill padd(t)
49749992Sbostic     register struct command *t;
4981302Sbill {
49949992Sbostic     Char  **argp;
5001302Sbill 
50149992Sbostic     if (t == 0)
50249992Sbostic 	return;
50349992Sbostic     switch (t->t_dtyp) {
5041302Sbill 
50549992Sbostic     case NODE_PAREN:
50649992Sbostic 	pads(STRLparensp);
50749992Sbostic 	padd(t->t_dspr);
50849992Sbostic 	pads(STRspRparen);
50949992Sbostic 	break;
5101302Sbill 
51149992Sbostic     case NODE_COMMAND:
51249992Sbostic 	for (argp = t->t_dcom; *argp; argp++) {
51349992Sbostic 	    pads(*argp);
51449992Sbostic 	    if (argp[1])
51549992Sbostic 		pads(STRspace);
51649992Sbostic 	}
51749992Sbostic 	break;
5181302Sbill 
51949992Sbostic     case NODE_OR:
52049992Sbostic     case NODE_AND:
52149992Sbostic     case NODE_PIPE:
52249992Sbostic     case NODE_LIST:
52349992Sbostic 	padd(t->t_dcar);
52449992Sbostic 	switch (t->t_dtyp) {
52547724Sbostic 	case NODE_OR:
52649992Sbostic 	    pads(STRspor2sp);
52749992Sbostic 	    break;
52847724Sbostic 	case NODE_AND:
52949992Sbostic 	    pads(STRspand2sp);
53049992Sbostic 	    break;
53147724Sbostic 	case NODE_PIPE:
53249992Sbostic 	    pads(STRsporsp);
53349992Sbostic 	    break;
53447724Sbostic 	case NODE_LIST:
53549992Sbostic 	    pads(STRsemisp);
53649992Sbostic 	    break;
5371302Sbill 	}
53849992Sbostic 	padd(t->t_dcdr);
53949992Sbostic 	return;
54049992Sbostic     }
54149992Sbostic     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
54249992Sbostic 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
54349992Sbostic 	pads(t->t_dlef);
54449992Sbostic     }
54549992Sbostic     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
54649992Sbostic 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
54749992Sbostic 	if (t->t_dflg & F_STDERR)
54849992Sbostic 	    pads(STRand);
54949992Sbostic 	pads(STRspace);
55049992Sbostic 	pads(t->t_drit);
55149992Sbostic     }
5521302Sbill }
5531302Sbill 
55449992Sbostic static void
pads(cp)5551302Sbill pads(cp)
55649992Sbostic     Char   *cp;
5571302Sbill {
55849992Sbostic     register int i;
5591302Sbill 
56049992Sbostic     /*
56149992Sbostic      * Avoid the Quoted Space alias hack! Reported by:
56249992Sbostic      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
56349992Sbostic      */
56449992Sbostic     if (cp[0] == STRQNULL[0])
56549992Sbostic 	cp++;
56649992Sbostic 
56749992Sbostic     i = Strlen(cp);
56849992Sbostic 
56949992Sbostic     if (cmdlen >= PMAXLEN)
57049992Sbostic 	return;
57149992Sbostic     if (cmdlen + i >= PMAXLEN) {
57249992Sbostic 	(void) Strcpy(cmdp, STRsp3dots);
57349992Sbostic 	cmdlen = PMAXLEN;
57449992Sbostic 	cmdp += 4;
57549992Sbostic 	return;
57649992Sbostic     }
57749992Sbostic     (void) Strcpy(cmdp, cp);
57849992Sbostic     cmdp += i;
57949992Sbostic     cmdlen += i;
5801302Sbill }
5811302Sbill 
5821302Sbill /*
5831302Sbill  * psavejob - temporarily save the current job on a one level stack
5841302Sbill  *	so another job can be created.  Used for { } in exp6
5851302Sbill  *	and `` in globbing.
5861302Sbill  */
58749992Sbostic void
psavejob()5881302Sbill psavejob()
5891302Sbill {
5901302Sbill 
59149992Sbostic     pholdjob = pcurrjob;
59250040Schristos     pcurrjob = NULL;
5931302Sbill }
5941302Sbill 
5951302Sbill /*
5961302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
5971302Sbill  *	somewhere, but pendjob cleans up anyway.
5981302Sbill  */
59949992Sbostic void
prestjob()6001302Sbill prestjob()
6011302Sbill {
6021302Sbill 
60349992Sbostic     pcurrjob = pholdjob;
60450040Schristos     pholdjob = NULL;
6051302Sbill }
6061302Sbill 
6071302Sbill /*
6081302Sbill  * pendjob - indicate that a job (set of commands) has been completed
6091302Sbill  *	or is about to begin.
6101302Sbill  */
61149992Sbostic void
pendjob()6121302Sbill pendjob()
6131302Sbill {
61449992Sbostic     register struct process *pp, *tp;
6151302Sbill 
61649992Sbostic     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
61749992Sbostic 	pp = pcurrjob;
61849992Sbostic 	while (pp->p_pid != pp->p_jobid)
61949992Sbostic 	    pp = pp->p_friends;
62050439Schristos 	(void) fprintf(cshout, "[%d]", pp->p_index);
62149992Sbostic 	tp = pp;
62249992Sbostic 	do {
62350439Schristos 	    (void) fprintf(cshout, " %d", pp->p_pid);
62449992Sbostic 	    pp = pp->p_friends;
62549992Sbostic 	} while (pp != tp);
62650439Schristos 	(void) fputc('\n', cshout);
62749992Sbostic     }
62849992Sbostic     pholdjob = pcurrjob = 0;
6291302Sbill }
6301302Sbill 
6311302Sbill /*
6321302Sbill  * pprint - print a job
6331302Sbill  */
63449992Sbostic static int
pprint(pp,flag)6351302Sbill pprint(pp, flag)
63649992Sbostic     register struct process *pp;
63749992Sbostic     bool    flag;
6381302Sbill {
63949992Sbostic     register status, reason;
64049992Sbostic     struct process *tp;
64149992Sbostic     int     jobflags, pstatus;
64250445Schristos     bool hadnl = 1;	/* did we just have a newline */
64349992Sbostic     char   *format;
6441302Sbill 
64550439Schristos     (void) fpurge(cshout);
64650439Schristos 
64749992Sbostic     while (pp->p_pid != pp->p_jobid)
64849992Sbostic 	pp = pp->p_friends;
64949992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
65049992Sbostic 	pp->p_flags &= ~PPTIME;
65149992Sbostic 	pp->p_flags |= PTIME;
65249992Sbostic     }
65349992Sbostic     tp = pp;
65449992Sbostic     status = reason = -1;
65549992Sbostic     jobflags = 0;
65649992Sbostic     do {
65749992Sbostic 	jobflags |= pp->p_flags;
65849992Sbostic 	pstatus = pp->p_flags & PALLSTATES;
65951437Sleres 	if (tp != pp && !hadnl && !(flag & FANCY) &&
66050445Schristos 	    ((pstatus == status && pp->p_reason == reason) ||
66150445Schristos 	     !(flag & REASON))) {
66250439Schristos 	    (void) fputc(' ', cshout);
66350445Schristos 	    hadnl = 0;
66450445Schristos 	}
66549992Sbostic 	else {
66650445Schristos 	    if (tp != pp && !hadnl) {
66750439Schristos 		(void) fputc('\n', cshout);
66850445Schristos 		hadnl = 1;
66950445Schristos 	    }
67050445Schristos 	    if (flag & NUMBER) {
67149992Sbostic 		if (pp == tp)
67250439Schristos 		    (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
67349992Sbostic 			    pp->p_index < 10 ? " " : "",
67449992Sbostic 			    pp == pcurrent ? '+' :
67549992Sbostic 			    (pp == pprevious ? '-' : ' '));
67649992Sbostic 		else
67750439Schristos 		    (void) fprintf(cshout, "       ");
67850445Schristos 		hadnl = 0;
67950445Schristos 	    }
68049992Sbostic 	    if (flag & FANCY) {
68150439Schristos 		(void) fprintf(cshout, "%5d ", pp->p_pid);
68250445Schristos 		hadnl = 0;
68349992Sbostic 	    }
68449992Sbostic 	    if (flag & (REASON | AREASON)) {
68549992Sbostic 		if (flag & NAME)
68649992Sbostic 		    format = "%-23s";
68749992Sbostic 		else
68849992Sbostic 		    format = "%s";
68949992Sbostic 		if (pstatus == status)
69049992Sbostic 		    if (pp->p_reason == reason) {
69150439Schristos 			(void) fprintf(cshout, format, "");
69250445Schristos 			hadnl = 0;
69349992Sbostic 			goto prcomd;
69449992Sbostic 		    }
69549992Sbostic 		    else
69649992Sbostic 			reason = pp->p_reason;
6971302Sbill 		else {
69849992Sbostic 		    status = pstatus;
69949992Sbostic 		    reason = pp->p_reason;
70049992Sbostic 		}
70149992Sbostic 		switch (status) {
7021302Sbill 
70349992Sbostic 		case PRUNNING:
70450439Schristos 		    (void) fprintf(cshout, format, "Running ");
70550445Schristos 		    hadnl = 0;
70649992Sbostic 		    break;
7071302Sbill 
70849992Sbostic 		case PINTERRUPTED:
70949992Sbostic 		case PSTOPPED:
71049992Sbostic 		case PSIGNALED:
71150445Schristos                     /*
71250445Schristos                      * tell what happened to the background job
71350445Schristos                      * From: Michael Schroeder
71450445Schristos                      * <mlschroe@immd4.informatik.uni-erlangen.de>
71550445Schristos                      */
71650445Schristos                     if ((flag & REASON)
71750445Schristos                         || ((flag & AREASON)
71850445Schristos                             && reason != SIGINT
71950445Schristos                             && (reason != SIGPIPE
72050445Schristos                                 || (pp->p_flags & PPOU) == 0))) {
72151437Sleres 			(void) fprintf(cshout, format,
72260237Schristos 				       sys_siglist[(unsigned char)
72360237Schristos 						   pp->p_reason]);
72450445Schristos 			hadnl = 0;
72550445Schristos 		    }
72649992Sbostic 		    break;
7271302Sbill 
72849992Sbostic 		case PNEXITED:
72949992Sbostic 		case PAEXITED:
73050445Schristos 		    if (flag & REASON) {
73149992Sbostic 			if (pp->p_reason)
73250439Schristos 			    (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
73349992Sbostic 			else
73450439Schristos 			    (void) fprintf(cshout, format, "Done");
73550445Schristos 			hadnl = 0;
73650445Schristos 		    }
73749992Sbostic 		    break;
7381302Sbill 
73949992Sbostic 		default:
74050439Schristos 		    (void) fprintf(csherr, "BUG: status=%-9o", status);
7411302Sbill 		}
74249992Sbostic 	    }
74349992Sbostic 	}
7441302Sbill prcomd:
74549992Sbostic 	if (flag & NAME) {
74651589Schristos 	    (void) fprintf(cshout, "%s", vis_str(pp->p_command));
74749992Sbostic 	    if (pp->p_flags & PPOU)
74850439Schristos 		(void) fprintf(cshout, " |");
74950439Schristos 	    if (pp->p_flags & PERR)
75050439Schristos 		(void) fputc('&', cshout);
75150445Schristos 	    hadnl = 0;
7521302Sbill 	}
75350445Schristos 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
75450439Schristos 	    (void) fprintf(cshout, " (core dumped)");
75550445Schristos 	    hadnl = 0;
75650445Schristos 	}
75749992Sbostic 	if (tp == pp->p_friends) {
75850445Schristos 	    if (flag & AMPERSAND) {
75950439Schristos 		(void) fprintf(cshout, " &");
76050445Schristos 		hadnl = 0;
76150445Schristos 	    }
76249992Sbostic 	    if (flag & JOBDIR &&
76349992Sbostic 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
76450439Schristos 		(void) fprintf(cshout, " (wd: ");
76549992Sbostic 		dtildepr(value(STRhome), tp->p_cwd->di_name);
76650439Schristos 		(void) fputc(')', cshout);
76750445Schristos 		hadnl = 0;
76849992Sbostic 	    }
76949992Sbostic 	}
77049992Sbostic 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
77150445Schristos 	    if (!hadnl)
77250445Schristos 		(void) fprintf(cshout, "\n\t");
77349992Sbostic 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
77449992Sbostic 		    &pp->p_btime);
77550445Schristos 	    hadnl = 1;
77649992Sbostic 	}
77749992Sbostic 	if (tp == pp->p_friends) {
77850445Schristos 	    if (!hadnl) {
77950439Schristos 		(void) fputc('\n', cshout);
78050445Schristos 		hadnl = 1;
78150445Schristos 	    }
78249992Sbostic 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
78350439Schristos 		(void) fprintf(cshout, "(wd now: ");
78449992Sbostic 		dtildepr(value(STRhome), dcwd->di_name);
78550439Schristos 		(void) fprintf(cshout, ")\n");
78650445Schristos 		hadnl = 1;
78749992Sbostic 	    }
78849992Sbostic 	}
78949992Sbostic     } while ((pp = pp->p_friends) != tp);
79049992Sbostic     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
79149992Sbostic 	if (jobflags & NUMBER)
79250439Schristos 	    (void) fprintf(cshout, "       ");
79349992Sbostic 	ptprint(tp);
79450445Schristos 	hadnl = 1;
79549992Sbostic     }
79650439Schristos     (void) fflush(cshout);
79749992Sbostic     return (jobflags);
7981302Sbill }
7991302Sbill 
80049992Sbostic static void
ptprint(tp)8011302Sbill ptprint(tp)
80249992Sbostic     register struct process *tp;
8031302Sbill {
80449992Sbostic     struct timeval tetime, diff;
80549992Sbostic     static struct timeval ztime;
80649992Sbostic     struct rusage ru;
80749992Sbostic     static struct rusage zru;
80849992Sbostic     register struct process *pp = tp;
8091302Sbill 
81049992Sbostic     ru = zru;
81149992Sbostic     tetime = ztime;
81249992Sbostic     do {
81349992Sbostic 	ruadd(&ru, &pp->p_rusage);
81449992Sbostic 	tvsub(&diff, &pp->p_etime, &pp->p_btime);
81549992Sbostic 	if (timercmp(&diff, &tetime, >))
81649992Sbostic 	    tetime = diff;
81749992Sbostic     } while ((pp = pp->p_friends) != tp);
81849992Sbostic     prusage(&zru, &ru, &tetime, &ztime);
8191302Sbill }
8201302Sbill 
8211302Sbill /*
8221302Sbill  * dojobs - print all jobs
8231302Sbill  */
82449992Sbostic void
82550439Schristos /*ARGSUSED*/
dojobs(v,t)82650439Schristos dojobs(v, t)
82750439Schristos     Char **v;
82850439Schristos     struct command *t;
8291302Sbill {
83049992Sbostic     register struct process *pp;
83149992Sbostic     register int flag = NUMBER | NAME | REASON;
83249992Sbostic     int     i;
8331302Sbill 
83449992Sbostic     if (chkstop)
83549992Sbostic 	chkstop = 2;
83649992Sbostic     if (*++v) {
83749992Sbostic 	if (v[1] || !eq(*v, STRml))
83849992Sbostic 	    stderror(ERR_JOBS);
83949992Sbostic 	flag |= FANCY | JOBDIR;
84049992Sbostic     }
84149992Sbostic     for (i = 1; i <= pmaxindex; i++)
84249992Sbostic 	for (pp = proclist.p_next; pp; pp = pp->p_next)
84349992Sbostic 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
84449992Sbostic 		pp->p_flags &= ~PNEEDNOTE;
84549992Sbostic 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
84649992Sbostic 		    pflush(pp);
84749992Sbostic 		break;
84849992Sbostic 	    }
8491302Sbill }
8501302Sbill 
8511302Sbill /*
8521302Sbill  * dofg - builtin - put the job into the foreground
8531302Sbill  */
85449992Sbostic void
85550439Schristos /*ARGSUSED*/
dofg(v,t)85650439Schristos dofg(v, t)
85750439Schristos     Char **v;
85850439Schristos     struct command *t;
8591302Sbill {
86049992Sbostic     register struct process *pp;
8611302Sbill 
86249992Sbostic     okpcntl();
86349992Sbostic     ++v;
86449992Sbostic     do {
86549992Sbostic 	pp = pfind(*v);
86649992Sbostic 	pstart(pp, 1);
86749992Sbostic 	pjwait(pp);
86849992Sbostic     } while (*v && *++v);
8691302Sbill }
8701302Sbill 
8711302Sbill /*
8721302Sbill  * %... - builtin - put the job into the foreground
8731302Sbill  */
87449992Sbostic void
87550439Schristos /*ARGSUSED*/
dofg1(v,t)87650439Schristos dofg1(v, t)
87750439Schristos     Char **v;
87850439Schristos     struct command *t;
8791302Sbill {
88049992Sbostic     register struct process *pp;
8811302Sbill 
88249992Sbostic     okpcntl();
88349992Sbostic     pp = pfind(v[0]);
88449992Sbostic     pstart(pp, 1);
88549992Sbostic     pjwait(pp);
8861302Sbill }
8871302Sbill 
8881302Sbill /*
8891302Sbill  * dobg - builtin - put the job into the background
8901302Sbill  */
89149992Sbostic void
89250439Schristos /*ARGSUSED*/
dobg(v,t)89350439Schristos dobg(v, t)
89450439Schristos     Char **v;
89550439Schristos     struct command *t;
8961302Sbill {
89749992Sbostic     register struct process *pp;
8981302Sbill 
89949992Sbostic     okpcntl();
90049992Sbostic     ++v;
90149992Sbostic     do {
90249992Sbostic 	pp = pfind(*v);
90349992Sbostic 	pstart(pp, 0);
90449992Sbostic     } while (*v && *++v);
9051302Sbill }
9061302Sbill 
9071302Sbill /*
9081302Sbill  * %... & - builtin - put the job into the background
9091302Sbill  */
91049992Sbostic void
91150439Schristos /*ARGSUSED*/
dobg1(v,t)91250439Schristos dobg1(v, t)
91350439Schristos     Char **v;
91450439Schristos     struct command *t;
9151302Sbill {
91649992Sbostic     register struct process *pp;
9171302Sbill 
91849992Sbostic     pp = pfind(v[0]);
91949992Sbostic     pstart(pp, 0);
9201302Sbill }
9211302Sbill 
9221302Sbill /*
9231302Sbill  * dostop - builtin - stop the job
9241302Sbill  */
92549992Sbostic void
92650439Schristos /*ARGSUSED*/
dostop(v,t)92750439Schristos dostop(v, t)
92850439Schristos     Char **v;
92950439Schristos     struct command *t;
9301302Sbill {
93149992Sbostic     pkill(++v, SIGSTOP);
9321302Sbill }
9331302Sbill 
9341302Sbill /*
9351302Sbill  * dokill - builtin - superset of kill (1)
9361302Sbill  */
93749992Sbostic void
93850439Schristos /*ARGSUSED*/
dokill(v,t)93950439Schristos dokill(v, t)
94050439Schristos     Char **v;
94150439Schristos     struct command *t;
9421302Sbill {
94350761Schristos     register int signum = SIGTERM;
94449992Sbostic     register char *name;
9451302Sbill 
94649992Sbostic     v++;
94749992Sbostic     if (v[0] && v[0][0] == '-') {
94849992Sbostic 	if (v[0][1] == 'l') {
94950761Schristos 	    for (signum = 1; signum < NSIG; signum++) {
95050761Schristos 		(void) fprintf(cshout, "%s ", sys_signame[signum]);
95150761Schristos 		if (signum == NSIG / 2)
95250761Schristos 		    (void) fputc('\n', cshout);
95349992Sbostic 	    }
95450439Schristos 	    (void) fputc('\n', cshout);
95549992Sbostic 	    return;
95649992Sbostic 	}
95749992Sbostic 	if (Isdigit(v[0][1])) {
95849992Sbostic 	    signum = atoi(short2str(v[0] + 1));
95949992Sbostic 	    if (signum < 0 || signum > NSIG)
96049992Sbostic 		stderror(ERR_NAME | ERR_BADSIG);
96149992Sbostic 	}
96249992Sbostic 	else {
96350761Schristos 	    name = short2str(&v[0][1]);
96450761Schristos 	    if (!strncasecmp(name, "sig", 3))
96550761Schristos 		name += 3;
96650761Schristos 
96751437Sleres 	    for (signum = 1; signum < NSIG; signum++)
96850761Schristos 		if (!strcasecmp(sys_signame[signum], name))
96950761Schristos 		    break;
97050761Schristos 
97150761Schristos 	    if (signum == NSIG) {
97251589Schristos 		setname(vis_str(&v[0][1]));
97350761Schristos 		stderror(ERR_NAME | ERR_UNKSIG);
97450761Schristos 	    }
97549992Sbostic 	}
97649992Sbostic 	v++;
97749992Sbostic     }
97849992Sbostic     pkill(v, signum);
9791302Sbill }
9801302Sbill 
98149992Sbostic static void
pkill(v,signum)9821302Sbill pkill(v, signum)
98349992Sbostic     Char  **v;
98449992Sbostic     int     signum;
9851302Sbill {
98649992Sbostic     register struct process *pp, *np;
98749992Sbostic     register int jobflags = 0;
98849992Sbostic     int     pid, err1 = 0;
989*68576Schristos     sigset_t sigset;
99049992Sbostic     Char   *cp;
9911302Sbill 
992*68576Schristos     sigemptyset(&sigset);
993*68576Schristos     sigaddset(&sigset, SIGCHLD);
99449992Sbostic     if (setintr)
995*68576Schristos 	sigaddset(&sigset, SIGINT);
996*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, NULL);
99749992Sbostic     gflag = 0, tglob(v);
99849992Sbostic     if (gflag) {
99949992Sbostic 	v = globall(v);
100049992Sbostic 	if (v == 0)
100149992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
100249992Sbostic     }
100349992Sbostic     else {
100449992Sbostic 	v = gargv = saveblk(v);
100549992Sbostic 	trim(v);
100649992Sbostic     }
10071302Sbill 
100849992Sbostic     while (v && (cp = *v)) {
100949992Sbostic 	if (*cp == '%') {
101049992Sbostic 	    np = pp = pfind(cp);
101149992Sbostic 	    do
101249992Sbostic 		jobflags |= np->p_flags;
101349992Sbostic 	    while ((np = np->p_friends) != pp);
101449992Sbostic 	    switch (signum) {
101549992Sbostic 
101649992Sbostic 	    case SIGSTOP:
101749992Sbostic 	    case SIGTSTP:
101849992Sbostic 	    case SIGTTIN:
101949992Sbostic 	    case SIGTTOU:
102049992Sbostic 		if ((jobflags & PRUNNING) == 0) {
102151437Sleres 		    (void) fprintf(csherr, "%s: Already suspended\n",
102251589Schristos 				   vis_str(cp));
102349992Sbostic 		    err1++;
102449992Sbostic 		    goto cont;
10251302Sbill 		}
102649992Sbostic 		break;
102749992Sbostic 		/*
102849992Sbostic 		 * suspend a process, kill -CONT %, then type jobs; the shell
102949992Sbostic 		 * says it is suspended, but it is running; thanks jaap..
103049992Sbostic 		 */
103149992Sbostic 	    case SIGCONT:
103249992Sbostic 		pstart(pp, 0);
103349992Sbostic 		goto cont;
103449992Sbostic 	    }
103549992Sbostic 	    if (killpg((pid_t) pp->p_jobid, signum) < 0) {
103651589Schristos 		(void) fprintf(csherr, "%s: %s\n", vis_str(cp),
103750439Schristos 			       strerror(errno));
103849992Sbostic 		err1++;
103949992Sbostic 	    }
104049992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
104149992Sbostic 		(void) killpg((pid_t) pp->p_jobid, SIGCONT);
104249992Sbostic 	}
104349992Sbostic 	else if (!(Isdigit(*cp) || *cp == '-'))
104449992Sbostic 	    stderror(ERR_NAME | ERR_JOBARGS);
104549992Sbostic 	else {
104649992Sbostic 	    pid = atoi(short2str(cp));
104749992Sbostic 	    if (kill((pid_t) pid, signum) < 0) {
104850439Schristos 		(void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
104949992Sbostic 		err1++;
105049992Sbostic 		goto cont;
105149992Sbostic 	    }
105249992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
105349992Sbostic 		(void) kill((pid_t) pid, SIGCONT);
105449992Sbostic 	}
10551302Sbill cont:
105649992Sbostic 	v++;
105749992Sbostic     }
105849992Sbostic     if (gargv)
105949992Sbostic 	blkfree(gargv), gargv = 0;
1060*68576Schristos     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
106149992Sbostic     if (err1)
106249992Sbostic 	stderror(ERR_SILENT);
10631302Sbill }
10641302Sbill 
10651302Sbill /*
10661302Sbill  * pstart - start the job in foreground/background
10671302Sbill  */
106849992Sbostic void
pstart(pp,foregnd)10691302Sbill pstart(pp, foregnd)
107049992Sbostic     register struct process *pp;
107149992Sbostic     int     foregnd;
10721302Sbill {
107349992Sbostic     register struct process *np;
1074*68576Schristos     sigset_t sigset, osigset;
107549992Sbostic     long    jobflags = 0;
10761302Sbill 
1077*68576Schristos     sigemptyset(&sigset);
1078*68576Schristos     sigaddset(&sigset, SIGCHLD);
1079*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, &osigset);
108049992Sbostic     np = pp;
108149992Sbostic     do {
108249992Sbostic 	jobflags |= np->p_flags;
108349992Sbostic 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
108449992Sbostic 	    np->p_flags |= PRUNNING;
108549992Sbostic 	    np->p_flags &= ~PSTOPPED;
108649992Sbostic 	    if (foregnd)
108749992Sbostic 		np->p_flags |= PFOREGND;
108849992Sbostic 	    else
108949992Sbostic 		np->p_flags &= ~PFOREGND;
109049992Sbostic 	}
109149992Sbostic     } while ((np = np->p_friends) != pp);
109249992Sbostic     if (!foregnd)
109349992Sbostic 	pclrcurr(pp);
109449992Sbostic     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
109549992Sbostic     if (foregnd)
109649992Sbostic 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
109749992Sbostic     if (jobflags & PSTOPPED)
109849992Sbostic 	(void) killpg((pid_t) pp->p_jobid, SIGCONT);
1099*68576Schristos     sigprocmask(SIG_SETMASK, &osigset, NULL);
11001302Sbill }
11011302Sbill 
110249992Sbostic void
panystop(neednl)11031302Sbill panystop(neednl)
110449992Sbostic     bool    neednl;
11051302Sbill {
110649992Sbostic     register struct process *pp;
11071302Sbill 
110849992Sbostic     chkstop = 2;
110949992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
111049992Sbostic 	if (pp->p_flags & PSTOPPED)
111149992Sbostic 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
11121302Sbill }
11131302Sbill 
11141302Sbill struct process *
pfind(cp)11151302Sbill pfind(cp)
111649992Sbostic     Char   *cp;
11171302Sbill {
111849992Sbostic     register struct process *pp, *np;
11191302Sbill 
112049992Sbostic     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
112150040Schristos 	if (pcurrent == NULL)
112249992Sbostic 	    stderror(ERR_NAME | ERR_JOBCUR);
112349992Sbostic 	return (pcurrent);
112449992Sbostic     }
112549992Sbostic     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
112650040Schristos 	if (pprevious == NULL)
112749992Sbostic 	    stderror(ERR_NAME | ERR_JOBPREV);
112849992Sbostic 	return (pprevious);
112949992Sbostic     }
113049992Sbostic     if (Isdigit(cp[1])) {
113149992Sbostic 	int     idx = atoi(short2str(cp + 1));
113249992Sbostic 
11331302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
113449992Sbostic 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
113549992Sbostic 		return (pp);
113649992Sbostic 	stderror(ERR_NAME | ERR_NOSUCHJOB);
113749992Sbostic     }
113850040Schristos     np = NULL;
113949992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
114049992Sbostic 	if (pp->p_pid == pp->p_jobid) {
114149992Sbostic 	    if (cp[1] == '?') {
114249992Sbostic 		register Char *dp;
114349992Sbostic 
114449992Sbostic 		for (dp = pp->p_command; *dp; dp++) {
114549992Sbostic 		    if (*dp != cp[2])
114649992Sbostic 			continue;
114749992Sbostic 		    if (prefix(cp + 2, dp))
114849992Sbostic 			goto match;
11491302Sbill 		}
115049992Sbostic 	    }
115149992Sbostic 	    else if (prefix(cp + 1, pp->p_command)) {
115249992Sbostic 	match:
115349992Sbostic 		if (np)
115449992Sbostic 		    stderror(ERR_NAME | ERR_AMBIG);
115549992Sbostic 		np = pp;
115649992Sbostic 	    }
115749992Sbostic 	}
115849992Sbostic     if (np)
115949992Sbostic 	return (np);
116049992Sbostic     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
116149992Sbostic     /* NOTREACHED */
116249992Sbostic     return (0);
11631302Sbill }
11641302Sbill 
116549992Sbostic 
11661302Sbill /*
11672357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
11681302Sbill  */
116949992Sbostic static struct process *
pgetcurr(pp)11701302Sbill pgetcurr(pp)
117149992Sbostic     register struct process *pp;
11721302Sbill {
117349992Sbostic     register struct process *np;
117450040Schristos     register struct process *xp = NULL;
11751302Sbill 
117649992Sbostic     for (np = proclist.p_next; np; np = np->p_next)
117749992Sbostic 	if (np != pcurrent && np != pp && np->p_pid &&
117849992Sbostic 	    np->p_pid == np->p_jobid) {
117949992Sbostic 	    if (np->p_flags & PSTOPPED)
118049992Sbostic 		return (np);
118150040Schristos 	    if (xp == NULL)
118249992Sbostic 		xp = np;
118349992Sbostic 	}
118449992Sbostic     return (xp);
11851302Sbill }
11861302Sbill 
11871302Sbill /*
11881302Sbill  * donotify - flag the job so as to report termination asynchronously
11891302Sbill  */
119049992Sbostic void
119150439Schristos /*ARGSUSED*/
donotify(v,t)119250439Schristos donotify(v, t)
119350439Schristos     Char **v;
119450439Schristos     struct command *t;
11951302Sbill {
119649992Sbostic     register struct process *pp;
11971302Sbill 
119849992Sbostic     pp = pfind(*++v);
119949992Sbostic     pp->p_flags |= PNOTIFY;
12001302Sbill }
12011302Sbill 
12021302Sbill /*
12031302Sbill  * Do the fork and whatever should be done in the child side that
12041302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
12051302Sbill  * Also do everything that needs any signals fiddled with in the parent side
12061302Sbill  *
12071302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
12081302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
12091302Sbill  *	 0:	already have tty; manipulate process pgrps only
12101302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
12111302Sbill  * It is usually just the value of tpgrp.
12121302Sbill  */
121349992Sbostic 
121449992Sbostic int
pfork(t,wanttty)12151302Sbill pfork(t, wanttty)
121649992Sbostic     struct command *t;		/* command we are forking for */
121749992Sbostic     int     wanttty;
12181302Sbill {
121949992Sbostic     register int pid;
122049992Sbostic     bool    ignint = 0;
122149992Sbostic     int     pgrp;
1222*68576Schristos     sigset_t sigset, osigset;
12231302Sbill 
122449992Sbostic     /*
122549992Sbostic      * A child will be uninterruptible only under very special conditions.
122649992Sbostic      * Remember that the semantics of '&' is implemented by disconnecting the
122749992Sbostic      * process from the tty so signals do not need to ignored just for '&'.
122849992Sbostic      * Thus signals are set to default action for children unless: we have had
122949992Sbostic      * an "onintr -" (then specifically ignored) we are not playing with
123049992Sbostic      * signals (inherit action)
123149992Sbostic      */
123249992Sbostic     if (setintr)
123349992Sbostic 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
123449992Sbostic 	    || (gointr && eq(gointr, STRminus));
123549992Sbostic     /*
123649992Sbostic      * Check for maximum nesting of 16 processes to avoid Forking loops
123749992Sbostic      */
123849992Sbostic     if (child == 16)
123949992Sbostic 	stderror(ERR_NESTING, 16);
124049992Sbostic     /*
124149992Sbostic      * Hold SIGCHLD until we have the process installed in our table.
124249992Sbostic      */
1243*68576Schristos     sigemptyset(&sigset);
1244*68576Schristos     sigaddset(&sigset, SIGCHLD);
1245*68576Schristos     sigprocmask(SIG_BLOCK, &sigset, &osigset);
124649992Sbostic     while ((pid = fork()) < 0)
124749992Sbostic 	if (setintr == 0)
124849992Sbostic 	    (void) sleep(FORKSLEEP);
124949992Sbostic 	else {
1250*68576Schristos 	    sigprocmask(SIG_SETMASK, &osigset, NULL);
125149992Sbostic 	    stderror(ERR_NOPROC);
125249992Sbostic 	}
125349992Sbostic     if (pid == 0) {
125449992Sbostic 	settimes();
125549992Sbostic 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
125649992Sbostic 	pflushall();
125750040Schristos 	pcurrjob = NULL;
125849992Sbostic 	child++;
125949992Sbostic 	if (setintr) {
126049992Sbostic 	    setintr = 0;	/* until I think otherwise */
126149992Sbostic 	    /*
126249992Sbostic 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
126349992Sbostic 	     * -" seen.
126449992Sbostic 	     */
126549992Sbostic 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
126649992Sbostic 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
126749992Sbostic 	    if (wanttty >= 0) {
126849992Sbostic 		/* make stoppable */
126949992Sbostic 		(void) signal(SIGTSTP, SIG_DFL);
127049992Sbostic 		(void) signal(SIGTTIN, SIG_DFL);
127149992Sbostic 		(void) signal(SIGTTOU, SIG_DFL);
127249992Sbostic 	    }
127349992Sbostic 	    (void) signal(SIGTERM, parterm);
127449992Sbostic 	}
127549992Sbostic 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
127649992Sbostic 	    (void) signal(SIGINT, SIG_IGN);
127749992Sbostic 	    (void) signal(SIGQUIT, SIG_IGN);
127849992Sbostic 	}
127949992Sbostic 	pgetty(wanttty, pgrp);
12801302Sbill 	/*
128149992Sbostic 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
128249992Sbostic 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
128349992Sbostic 	 * to know about nice/nohup/time
12841302Sbill 	 */
128549992Sbostic 	if (t->t_dflg & F_NOHUP)
128649992Sbostic 	    (void) signal(SIGHUP, SIG_IGN);
128749992Sbostic 	if (t->t_dflg & F_NICE)
128849992Sbostic 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
128949992Sbostic     }
129049992Sbostic     else {
129149992Sbostic 	if (wanttty >= 0)
129249992Sbostic 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
129349992Sbostic 	palloc(pid, t);
1294*68576Schristos 	sigprocmask(SIG_SETMASK, &osigset, NULL);
129549992Sbostic     }
12961302Sbill 
129749992Sbostic     return (pid);
12981302Sbill }
12991302Sbill 
130049992Sbostic static void
okpcntl()13011302Sbill okpcntl()
13021302Sbill {
130349992Sbostic     if (tpgrp == -1)
130449992Sbostic 	stderror(ERR_JOBCONTROL);
130549992Sbostic     if (tpgrp == 0)
130649992Sbostic 	stderror(ERR_JOBCTRLSUB);
130749992Sbostic }
13081302Sbill 
130949992Sbostic /*
131049992Sbostic  * if we don't have vfork(), things can still go in the wrong order
131149992Sbostic  * resulting in the famous 'Stopped (tty output)'. But some systems
131249992Sbostic  * don't permit the setpgid() call, (these are more recent secure
131349992Sbostic  * systems such as ibm's aix). Then we'd rather print an error message
131449992Sbostic  * than hang the shell!
131549992Sbostic  * I am open to suggestions how to fix that.
131649992Sbostic  */
131749992Sbostic void
pgetty(wanttty,pgrp)131849992Sbostic pgetty(wanttty, pgrp)
131949992Sbostic     int     wanttty, pgrp;
132049992Sbostic {
1321*68576Schristos     sigset_t sigset, osigset;
132249992Sbostic 
132349992Sbostic     /*
132449992Sbostic      * christos: I am blocking the tty signals till I've set things
132549992Sbostic      * correctly....
132649992Sbostic      */
1327*68576Schristos     if (wanttty > 0) {
1328*68576Schristos 	sigemptyset(&sigset);
1329*68576Schristos 	sigaddset(&sigset, SIGTSTP);
1330*68576Schristos 	sigaddset(&sigset, SIGTTIN);
1331*68576Schristos 	sigaddset(&sigset, SIGTTOU);
1332*68576Schristos 	sigprocmask(SIG_BLOCK, &sigset, &osigset);
1333*68576Schristos     }
133449992Sbostic     /*
133549992Sbostic      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
133649992Sbostic      * Don't check for tpgrp >= 0 so even non-interactive shells give
133749992Sbostic      * background jobs process groups Same for the comparison in the other part
133849992Sbostic      * of the #ifdef
133949992Sbostic      */
134049992Sbostic     if (wanttty >= 0)
134149992Sbostic 	if (setpgid(0, pgrp) == -1) {
134250439Schristos 	    (void) fprintf(csherr, "csh: setpgid error.\n");
134349992Sbostic 	    xexit(0);
134449992Sbostic 	}
134549992Sbostic 
134649992Sbostic     if (wanttty > 0) {
134749992Sbostic 	(void) tcsetpgrp(FSHTTY, pgrp);
1348*68576Schristos 	sigprocmask(SIG_SETMASK, &osigset, NULL);
134949992Sbostic     }
135049992Sbostic 
135149992Sbostic     if (tpgrp > 0)
135249992Sbostic 	tpgrp = 0;		/* gave tty away */
13531302Sbill }
1354