xref: /csrg-svn/bin/csh/proc.c (revision 51589)
147823Sbostic /*-
247823Sbostic  * Copyright (c) 1980, 1991 The Regents of the University of California.
347823Sbostic  * All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621940Sdist  */
721940Sdist 
817509Sedward #ifndef lint
9*51589Schristos static char sccsid[] = "@(#)proc.c	5.28 (Berkeley) 11/06/91";
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
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) {
152*51589Schristos 		(void) vis_fputc('\r' | QUOTE, cshout);
15350445Schristos 		(void) fputc('\n', cshout);
15450445Schristos 	    }
1551302Sbill 	}
15649992Sbostic 	else {
15749992Sbostic 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
158*51589Schristos 		(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
1741302Sbill pnote()
1751302Sbill {
17649992Sbostic     register struct process *pp;
17749992Sbostic     int     flags;
17850028Sbostic     sigset_t omask;
1791302Sbill 
18049992Sbostic     neednote = 0;
18150040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
18249992Sbostic 	if (pp->p_flags & PNEEDNOTE) {
18349992Sbostic 	    omask = sigblock(sigmask(SIGCHLD));
18449992Sbostic 	    pp->p_flags &= ~PNEEDNOTE;
18549992Sbostic 	    flags = pprint(pp, NUMBER | NAME | REASON);
18649992Sbostic 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
18749992Sbostic 		pflush(pp);
18849992Sbostic 	    (void) sigsetmask(omask);
1891302Sbill 	}
19049992Sbostic     }
1911302Sbill }
1921302Sbill 
1931302Sbill /*
1941302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1951302Sbill  *	of current and previous job indicators.
1961302Sbill  */
19749992Sbostic void
1981302Sbill pwait()
1991302Sbill {
20049992Sbostic     register struct process *fp, *pp;
20150028Sbostic     sigset_t omask;
2021302Sbill 
20349992Sbostic     /*
20449992Sbostic      * Here's where dead procs get flushed.
20549992Sbostic      */
20649992Sbostic     omask = sigblock(sigmask(SIGCHLD));
20750040Schristos     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
20849992Sbostic 	if (pp->p_pid == 0) {
20949992Sbostic 	    fp->p_next = pp->p_next;
21049992Sbostic 	    xfree((ptr_t) pp->p_command);
21149992Sbostic 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
21249992Sbostic 		if (pp->p_cwd->di_next == 0)
21349992Sbostic 		    dfree(pp->p_cwd);
21449992Sbostic 	    xfree((ptr_t) pp);
21549992Sbostic 	    pp = fp;
21649992Sbostic 	}
21749992Sbostic     (void) sigsetmask(omask);
21849992Sbostic     pjwait(pcurrjob);
2191302Sbill }
2201302Sbill 
22149992Sbostic 
2221302Sbill /*
2231302Sbill  * pjwait - wait for a job to finish or become stopped
2241302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
2251302Sbill  */
22649992Sbostic void
2271302Sbill pjwait(pp)
22849992Sbostic     register struct process *pp;
2291302Sbill {
23049992Sbostic     register struct process *fp;
23149992Sbostic     int     jobflags, reason;
23250028Sbostic     sigset_t omask;
2331302Sbill 
23449992Sbostic     while (pp->p_pid != pp->p_jobid)
23549992Sbostic 	pp = pp->p_friends;
23649992Sbostic     fp = pp;
23749992Sbostic 
23849992Sbostic     do {
23949992Sbostic 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
24050439Schristos 	    (void) fprintf(csherr, "BUG: waiting for background job!\n");
24149992Sbostic     } while ((fp = fp->p_friends) != pp);
24249992Sbostic     /*
24349992Sbostic      * Now keep pausing as long as we are not interrupted (SIGINT), and the
24449992Sbostic      * target process, or any of its friends, are running
24549992Sbostic      */
24649992Sbostic     fp = pp;
24749992Sbostic     omask = sigblock(sigmask(SIGCHLD));
24849992Sbostic     for (;;) {
24949992Sbostic 	(void) sigblock(sigmask(SIGCHLD));
25049992Sbostic 	jobflags = 0;
25149992Sbostic 	do
25249992Sbostic 	    jobflags |= fp->p_flags;
25349992Sbostic 	while ((fp = (fp->p_friends)) != pp);
25449992Sbostic 	if ((jobflags & PRUNNING) == 0)
25549992Sbostic 	    break;
25649992Sbostic #ifdef JOBDEBUG
25751437Sleres 	(void) fprintf(csherr, "starting to sigpause for  SIGCHLD on %d\n",
25850439Schristos 		       fp->p_pid);
25949992Sbostic #endif				/* JOBDEBUG */
26049992Sbostic 	(void) sigpause(omask & ~sigmask(SIGCHLD));
26149992Sbostic     }
26249992Sbostic     (void) sigsetmask(omask);
26349992Sbostic     if (tpgrp > 0)		/* get tty back */
26449992Sbostic 	(void) tcsetpgrp(FSHTTY, tpgrp);
26549992Sbostic     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
26649992Sbostic 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
26749992Sbostic 	if (jobflags & PSTOPPED) {
26850445Schristos 	    (void) fputc('\n', cshout);
26949992Sbostic 	    if (adrof(STRlistjobs)) {
27049992Sbostic 		Char   *jobcommand[3];
27149992Sbostic 
27249992Sbostic 		jobcommand[0] = STRjobs;
27349992Sbostic 		if (eq(value(STRlistjobs), STRlong))
27449992Sbostic 		    jobcommand[1] = STRml;
27549992Sbostic 		else
27649992Sbostic 		    jobcommand[1] = NULL;
27749992Sbostic 		jobcommand[2] = NULL;
27849992Sbostic 
27950439Schristos 		dojobs(jobcommand, NULL);
28049992Sbostic 		(void) pprint(pp, SHELLDIR);
28149992Sbostic 	    }
28249992Sbostic 	    else
28349992Sbostic 		(void) pprint(pp, AREASON | SHELLDIR);
2841302Sbill 	}
28549992Sbostic 	else
28649992Sbostic 	    (void) pprint(pp, AREASON | SHELLDIR);
28749992Sbostic     }
28849992Sbostic     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
28949992Sbostic 	(!gointr || !eq(gointr, STRminus))) {
29049992Sbostic 	if ((jobflags & PSTOPPED) == 0)
29149992Sbostic 	    pflush(pp);
29249992Sbostic 	pintr1(0);
29349992Sbostic 	/* NOTREACHED */
29449992Sbostic     }
29549992Sbostic     reason = 0;
29649992Sbostic     fp = pp;
29749992Sbostic     do {
29849992Sbostic 	if (fp->p_reason)
29949992Sbostic 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
30049992Sbostic 		fp->p_reason | META : fp->p_reason;
30149992Sbostic     } while ((fp = fp->p_friends) != pp);
30250445Schristos     if ((reason != 0) && (adrof(STRprintexitvalue))) {
30350439Schristos 	(void) fprintf(cshout, "Exit %d\n", reason);
30450445Schristos     }
30549992Sbostic     set(STRstatus, putn(reason));
30649992Sbostic     if (reason && exiterr)
30749992Sbostic 	exitstat();
30849992Sbostic     pflush(pp);
3091302Sbill }
3101302Sbill 
3111302Sbill /*
3121302Sbill  * dowait - wait for all processes to finish
3131302Sbill  */
31449992Sbostic void
31550439Schristos /*ARGSUSED*/
31650439Schristos dowait(v, t)
31750439Schristos     Char **v;
31850439Schristos     struct command *t;
3191302Sbill {
32049992Sbostic     register struct process *pp;
32150028Sbostic     sigset_t omask;
3221302Sbill 
32349992Sbostic     pjobs++;
32449992Sbostic     omask = sigblock(sigmask(SIGCHLD));
3251302Sbill loop:
32649992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
32749992Sbostic 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
32849992Sbostic 	    pp->p_flags & PRUNNING) {
32950028Sbostic 	    (void) sigpause((sigset_t) 0);
33049992Sbostic 	    goto loop;
33149992Sbostic 	}
33249992Sbostic     (void) sigsetmask(omask);
33349992Sbostic     pjobs = 0;
3341302Sbill }
3351302Sbill 
3361302Sbill /*
3371302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
3381302Sbill  */
33949992Sbostic static void
3401302Sbill pflushall()
3411302Sbill {
34249992Sbostic     register struct process *pp;
3431302Sbill 
34450040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
34549992Sbostic 	if (pp->p_pid)
34649992Sbostic 	    pflush(pp);
3471302Sbill }
3481302Sbill 
3491302Sbill /*
3501302Sbill  * pflush - flag all process structures in the same job as the
3511302Sbill  *	the argument process for deletion.  The actual free of the
3521302Sbill  *	space is not done here since pflush is called at interrupt level.
3531302Sbill  */
35449992Sbostic static void
3551302Sbill pflush(pp)
35649992Sbostic     register struct process *pp;
3571302Sbill {
35849992Sbostic     register struct process *np;
35949992Sbostic     register int idx;
3601302Sbill 
36149992Sbostic     if (pp->p_pid == 0) {
36250439Schristos 	(void) fprintf(csherr, "BUG: process flushed twice");
36349992Sbostic 	return;
36449992Sbostic     }
36549992Sbostic     while (pp->p_pid != pp->p_jobid)
36649992Sbostic 	pp = pp->p_friends;
36749992Sbostic     pclrcurr(pp);
36849992Sbostic     if (pp == pcurrjob)
36949992Sbostic 	pcurrjob = 0;
37049992Sbostic     idx = pp->p_index;
37149992Sbostic     np = pp;
37249992Sbostic     do {
37349992Sbostic 	np->p_index = np->p_pid = 0;
37449992Sbostic 	np->p_flags &= ~PNEEDNOTE;
37549992Sbostic     } while ((np = np->p_friends) != pp);
37649992Sbostic     if (idx == pmaxindex) {
37749992Sbostic 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
37849992Sbostic 	    if (np->p_index > idx)
37949992Sbostic 		idx = np->p_index;
38049992Sbostic 	pmaxindex = idx;
38149992Sbostic     }
3821302Sbill }
3831302Sbill 
3841302Sbill /*
3851302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3861302Sbill  *	pp MUST be the job leader
3871302Sbill  */
38849992Sbostic static void
3891302Sbill pclrcurr(pp)
39049992Sbostic     register struct process *pp;
3911302Sbill {
3921302Sbill 
39349992Sbostic     if (pp == pcurrent)
39450040Schristos 	if (pprevious != NULL) {
39549992Sbostic 	    pcurrent = pprevious;
39649992Sbostic 	    pprevious = pgetcurr(pp);
39749992Sbostic 	}
39849992Sbostic 	else {
39949992Sbostic 	    pcurrent = pgetcurr(pp);
40049992Sbostic 	    pprevious = pgetcurr(pp);
40149992Sbostic 	}
40249992Sbostic     else if (pp == pprevious)
40349992Sbostic 	pprevious = pgetcurr(pp);
4041302Sbill }
4051302Sbill 
4061302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
40749992Sbostic static Char command[PMAXLEN + 4];
40849992Sbostic static int cmdlen;
40949992Sbostic static Char *cmdp;
41049992Sbostic 
4111302Sbill /*
4121302Sbill  * palloc - allocate a process structure and fill it up.
4131302Sbill  *	an important assumption is made that the process is running.
4141302Sbill  */
41549992Sbostic void
4161302Sbill palloc(pid, t)
41749992Sbostic     int     pid;
41849992Sbostic     register struct command *t;
4191302Sbill {
42049992Sbostic     register struct process *pp;
42149992Sbostic     int     i;
4221302Sbill 
42349992Sbostic     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
42449992Sbostic     pp->p_pid = pid;
42549992Sbostic     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
42649992Sbostic     if (t->t_dflg & F_TIME)
42749992Sbostic 	pp->p_flags |= PPTIME;
42849992Sbostic     cmdp = command;
42949992Sbostic     cmdlen = 0;
43049992Sbostic     padd(t);
43149992Sbostic     *cmdp++ = 0;
43249992Sbostic     if (t->t_dflg & F_PIPEOUT) {
43349992Sbostic 	pp->p_flags |= PPOU;
43449992Sbostic 	if (t->t_dflg & F_STDERR)
43550439Schristos 	    pp->p_flags |= PERR;
43649992Sbostic     }
43749992Sbostic     pp->p_command = Strsave(command);
43849992Sbostic     if (pcurrjob) {
43949992Sbostic 	struct process *fp;
4401302Sbill 
44149992Sbostic 	/* careful here with interrupt level */
44249992Sbostic 	pp->p_cwd = 0;
44349992Sbostic 	pp->p_index = pcurrjob->p_index;
44449992Sbostic 	pp->p_friends = pcurrjob;
44549992Sbostic 	pp->p_jobid = pcurrjob->p_pid;
44651437Sleres 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
44751437Sleres 	    continue;
44849992Sbostic 	fp->p_friends = pp;
44949992Sbostic     }
45049992Sbostic     else {
45149992Sbostic 	pcurrjob = pp;
45249992Sbostic 	pp->p_jobid = pid;
45349992Sbostic 	pp->p_friends = pp;
45449992Sbostic 	pp->p_cwd = dcwd;
45549992Sbostic 	dcwd->di_count++;
45649992Sbostic 	if (pmaxindex < BIGINDEX)
45749992Sbostic 	    pp->p_index = ++pmaxindex;
45849992Sbostic 	else {
45949992Sbostic 	    struct process *np;
46049992Sbostic 
46149992Sbostic 	    for (i = 1;; i++) {
46249992Sbostic 		for (np = proclist.p_next; np; np = np->p_next)
46349992Sbostic 		    if (np->p_index == i)
46449992Sbostic 			goto tryagain;
46549992Sbostic 		pp->p_index = i;
46649992Sbostic 		if (i > pmaxindex)
46749992Sbostic 		    pmaxindex = i;
46849992Sbostic 		break;
46949992Sbostic 	tryagain:;
47049992Sbostic 	    }
4711302Sbill 	}
47250040Schristos 	if (pcurrent == NULL)
47349992Sbostic 	    pcurrent = pp;
47450040Schristos 	else if (pprevious == NULL)
47549992Sbostic 	    pprevious = pp;
47649992Sbostic     }
47749992Sbostic     pp->p_next = proclist.p_next;
47849992Sbostic     proclist.p_next = pp;
47950028Sbostic     (void) gettimeofday(&pp->p_btime, NULL);
4801302Sbill }
4811302Sbill 
48249992Sbostic static void
4831302Sbill padd(t)
48449992Sbostic     register struct command *t;
4851302Sbill {
48649992Sbostic     Char  **argp;
4871302Sbill 
48849992Sbostic     if (t == 0)
48949992Sbostic 	return;
49049992Sbostic     switch (t->t_dtyp) {
4911302Sbill 
49249992Sbostic     case NODE_PAREN:
49349992Sbostic 	pads(STRLparensp);
49449992Sbostic 	padd(t->t_dspr);
49549992Sbostic 	pads(STRspRparen);
49649992Sbostic 	break;
4971302Sbill 
49849992Sbostic     case NODE_COMMAND:
49949992Sbostic 	for (argp = t->t_dcom; *argp; argp++) {
50049992Sbostic 	    pads(*argp);
50149992Sbostic 	    if (argp[1])
50249992Sbostic 		pads(STRspace);
50349992Sbostic 	}
50449992Sbostic 	break;
5051302Sbill 
50649992Sbostic     case NODE_OR:
50749992Sbostic     case NODE_AND:
50849992Sbostic     case NODE_PIPE:
50949992Sbostic     case NODE_LIST:
51049992Sbostic 	padd(t->t_dcar);
51149992Sbostic 	switch (t->t_dtyp) {
51247724Sbostic 	case NODE_OR:
51349992Sbostic 	    pads(STRspor2sp);
51449992Sbostic 	    break;
51547724Sbostic 	case NODE_AND:
51649992Sbostic 	    pads(STRspand2sp);
51749992Sbostic 	    break;
51847724Sbostic 	case NODE_PIPE:
51949992Sbostic 	    pads(STRsporsp);
52049992Sbostic 	    break;
52147724Sbostic 	case NODE_LIST:
52249992Sbostic 	    pads(STRsemisp);
52349992Sbostic 	    break;
5241302Sbill 	}
52549992Sbostic 	padd(t->t_dcdr);
52649992Sbostic 	return;
52749992Sbostic     }
52849992Sbostic     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
52949992Sbostic 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
53049992Sbostic 	pads(t->t_dlef);
53149992Sbostic     }
53249992Sbostic     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
53349992Sbostic 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
53449992Sbostic 	if (t->t_dflg & F_STDERR)
53549992Sbostic 	    pads(STRand);
53649992Sbostic 	pads(STRspace);
53749992Sbostic 	pads(t->t_drit);
53849992Sbostic     }
5391302Sbill }
5401302Sbill 
54149992Sbostic static void
5421302Sbill pads(cp)
54349992Sbostic     Char   *cp;
5441302Sbill {
54549992Sbostic     register int i;
5461302Sbill 
54749992Sbostic     /*
54849992Sbostic      * Avoid the Quoted Space alias hack! Reported by:
54949992Sbostic      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
55049992Sbostic      */
55149992Sbostic     if (cp[0] == STRQNULL[0])
55249992Sbostic 	cp++;
55349992Sbostic 
55449992Sbostic     i = Strlen(cp);
55549992Sbostic 
55649992Sbostic     if (cmdlen >= PMAXLEN)
55749992Sbostic 	return;
55849992Sbostic     if (cmdlen + i >= PMAXLEN) {
55949992Sbostic 	(void) Strcpy(cmdp, STRsp3dots);
56049992Sbostic 	cmdlen = PMAXLEN;
56149992Sbostic 	cmdp += 4;
56249992Sbostic 	return;
56349992Sbostic     }
56449992Sbostic     (void) Strcpy(cmdp, cp);
56549992Sbostic     cmdp += i;
56649992Sbostic     cmdlen += i;
5671302Sbill }
5681302Sbill 
5691302Sbill /*
5701302Sbill  * psavejob - temporarily save the current job on a one level stack
5711302Sbill  *	so another job can be created.  Used for { } in exp6
5721302Sbill  *	and `` in globbing.
5731302Sbill  */
57449992Sbostic void
5751302Sbill psavejob()
5761302Sbill {
5771302Sbill 
57849992Sbostic     pholdjob = pcurrjob;
57950040Schristos     pcurrjob = NULL;
5801302Sbill }
5811302Sbill 
5821302Sbill /*
5831302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
5841302Sbill  *	somewhere, but pendjob cleans up anyway.
5851302Sbill  */
58649992Sbostic void
5871302Sbill prestjob()
5881302Sbill {
5891302Sbill 
59049992Sbostic     pcurrjob = pholdjob;
59150040Schristos     pholdjob = NULL;
5921302Sbill }
5931302Sbill 
5941302Sbill /*
5951302Sbill  * pendjob - indicate that a job (set of commands) has been completed
5961302Sbill  *	or is about to begin.
5971302Sbill  */
59849992Sbostic void
5991302Sbill pendjob()
6001302Sbill {
60149992Sbostic     register struct process *pp, *tp;
6021302Sbill 
60349992Sbostic     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
60449992Sbostic 	pp = pcurrjob;
60549992Sbostic 	while (pp->p_pid != pp->p_jobid)
60649992Sbostic 	    pp = pp->p_friends;
60750439Schristos 	(void) fprintf(cshout, "[%d]", pp->p_index);
60849992Sbostic 	tp = pp;
60949992Sbostic 	do {
61050439Schristos 	    (void) fprintf(cshout, " %d", pp->p_pid);
61149992Sbostic 	    pp = pp->p_friends;
61249992Sbostic 	} while (pp != tp);
61350439Schristos 	(void) fputc('\n', cshout);
61449992Sbostic     }
61549992Sbostic     pholdjob = pcurrjob = 0;
6161302Sbill }
6171302Sbill 
6181302Sbill /*
6191302Sbill  * pprint - print a job
6201302Sbill  */
62149992Sbostic static int
6221302Sbill pprint(pp, flag)
62349992Sbostic     register struct process *pp;
62449992Sbostic     bool    flag;
6251302Sbill {
62649992Sbostic     register status, reason;
62749992Sbostic     struct process *tp;
62849992Sbostic     int     jobflags, pstatus;
62950445Schristos     bool hadnl = 1;	/* did we just have a newline */
63049992Sbostic     char   *format;
6311302Sbill 
63250439Schristos     (void) fpurge(cshout);
63350439Schristos 
63449992Sbostic     while (pp->p_pid != pp->p_jobid)
63549992Sbostic 	pp = pp->p_friends;
63649992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
63749992Sbostic 	pp->p_flags &= ~PPTIME;
63849992Sbostic 	pp->p_flags |= PTIME;
63949992Sbostic     }
64049992Sbostic     tp = pp;
64149992Sbostic     status = reason = -1;
64249992Sbostic     jobflags = 0;
64349992Sbostic     do {
64449992Sbostic 	jobflags |= pp->p_flags;
64549992Sbostic 	pstatus = pp->p_flags & PALLSTATES;
64651437Sleres 	if (tp != pp && !hadnl && !(flag & FANCY) &&
64750445Schristos 	    ((pstatus == status && pp->p_reason == reason) ||
64850445Schristos 	     !(flag & REASON))) {
64950439Schristos 	    (void) fputc(' ', cshout);
65050445Schristos 	    hadnl = 0;
65150445Schristos 	}
65249992Sbostic 	else {
65350445Schristos 	    if (tp != pp && !hadnl) {
65450439Schristos 		(void) fputc('\n', cshout);
65550445Schristos 		hadnl = 1;
65650445Schristos 	    }
65750445Schristos 	    if (flag & NUMBER) {
65849992Sbostic 		if (pp == tp)
65950439Schristos 		    (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
66049992Sbostic 			    pp->p_index < 10 ? " " : "",
66149992Sbostic 			    pp == pcurrent ? '+' :
66249992Sbostic 			    (pp == pprevious ? '-' : ' '));
66349992Sbostic 		else
66450439Schristos 		    (void) fprintf(cshout, "       ");
66550445Schristos 		hadnl = 0;
66650445Schristos 	    }
66749992Sbostic 	    if (flag & FANCY) {
66850439Schristos 		(void) fprintf(cshout, "%5d ", pp->p_pid);
66950445Schristos 		hadnl = 0;
67049992Sbostic 	    }
67149992Sbostic 	    if (flag & (REASON | AREASON)) {
67249992Sbostic 		if (flag & NAME)
67349992Sbostic 		    format = "%-23s";
67449992Sbostic 		else
67549992Sbostic 		    format = "%s";
67649992Sbostic 		if (pstatus == status)
67749992Sbostic 		    if (pp->p_reason == reason) {
67850439Schristos 			(void) fprintf(cshout, format, "");
67950445Schristos 			hadnl = 0;
68049992Sbostic 			goto prcomd;
68149992Sbostic 		    }
68249992Sbostic 		    else
68349992Sbostic 			reason = pp->p_reason;
6841302Sbill 		else {
68549992Sbostic 		    status = pstatus;
68649992Sbostic 		    reason = pp->p_reason;
68749992Sbostic 		}
68849992Sbostic 		switch (status) {
6891302Sbill 
69049992Sbostic 		case PRUNNING:
69150439Schristos 		    (void) fprintf(cshout, format, "Running ");
69250445Schristos 		    hadnl = 0;
69349992Sbostic 		    break;
6941302Sbill 
69549992Sbostic 		case PINTERRUPTED:
69649992Sbostic 		case PSTOPPED:
69749992Sbostic 		case PSIGNALED:
69850445Schristos                     /*
69950445Schristos                      * tell what happened to the background job
70050445Schristos                      * From: Michael Schroeder
70150445Schristos                      * <mlschroe@immd4.informatik.uni-erlangen.de>
70250445Schristos                      */
70350445Schristos                     if ((flag & REASON)
70450445Schristos                         || ((flag & AREASON)
70550445Schristos                             && reason != SIGINT
70650445Schristos                             && (reason != SIGPIPE
70750445Schristos                                 || (pp->p_flags & PPOU) == 0))) {
70851437Sleres 			(void) fprintf(cshout, format,
70950947Schristos 				       sys_siglist[pp->p_reason]);
71050445Schristos 			hadnl = 0;
71150445Schristos 		    }
71249992Sbostic 		    break;
7131302Sbill 
71449992Sbostic 		case PNEXITED:
71549992Sbostic 		case PAEXITED:
71650445Schristos 		    if (flag & REASON) {
71749992Sbostic 			if (pp->p_reason)
71850439Schristos 			    (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
71949992Sbostic 			else
72050439Schristos 			    (void) fprintf(cshout, format, "Done");
72150445Schristos 			hadnl = 0;
72250445Schristos 		    }
72349992Sbostic 		    break;
7241302Sbill 
72549992Sbostic 		default:
72650439Schristos 		    (void) fprintf(csherr, "BUG: status=%-9o", status);
7271302Sbill 		}
72849992Sbostic 	    }
72949992Sbostic 	}
7301302Sbill prcomd:
73149992Sbostic 	if (flag & NAME) {
732*51589Schristos 	    (void) fprintf(cshout, "%s", vis_str(pp->p_command));
73349992Sbostic 	    if (pp->p_flags & PPOU)
73450439Schristos 		(void) fprintf(cshout, " |");
73550439Schristos 	    if (pp->p_flags & PERR)
73650439Schristos 		(void) fputc('&', cshout);
73750445Schristos 	    hadnl = 0;
7381302Sbill 	}
73950445Schristos 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
74050439Schristos 	    (void) fprintf(cshout, " (core dumped)");
74150445Schristos 	    hadnl = 0;
74250445Schristos 	}
74349992Sbostic 	if (tp == pp->p_friends) {
74450445Schristos 	    if (flag & AMPERSAND) {
74550439Schristos 		(void) fprintf(cshout, " &");
74650445Schristos 		hadnl = 0;
74750445Schristos 	    }
74849992Sbostic 	    if (flag & JOBDIR &&
74949992Sbostic 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
75050439Schristos 		(void) fprintf(cshout, " (wd: ");
75149992Sbostic 		dtildepr(value(STRhome), tp->p_cwd->di_name);
75250439Schristos 		(void) fputc(')', cshout);
75350445Schristos 		hadnl = 0;
75449992Sbostic 	    }
75549992Sbostic 	}
75649992Sbostic 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
75750445Schristos 	    if (!hadnl)
75850445Schristos 		(void) fprintf(cshout, "\n\t");
75949992Sbostic 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
76049992Sbostic 		    &pp->p_btime);
76150445Schristos 	    hadnl = 1;
76249992Sbostic 	}
76349992Sbostic 	if (tp == pp->p_friends) {
76450445Schristos 	    if (!hadnl) {
76550439Schristos 		(void) fputc('\n', cshout);
76650445Schristos 		hadnl = 1;
76750445Schristos 	    }
76849992Sbostic 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
76950439Schristos 		(void) fprintf(cshout, "(wd now: ");
77049992Sbostic 		dtildepr(value(STRhome), dcwd->di_name);
77150439Schristos 		(void) fprintf(cshout, ")\n");
77250445Schristos 		hadnl = 1;
77349992Sbostic 	    }
77449992Sbostic 	}
77549992Sbostic     } while ((pp = pp->p_friends) != tp);
77649992Sbostic     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
77749992Sbostic 	if (jobflags & NUMBER)
77850439Schristos 	    (void) fprintf(cshout, "       ");
77949992Sbostic 	ptprint(tp);
78050445Schristos 	hadnl = 1;
78149992Sbostic     }
78250439Schristos     (void) fflush(cshout);
78349992Sbostic     return (jobflags);
7841302Sbill }
7851302Sbill 
78649992Sbostic static void
7871302Sbill ptprint(tp)
78849992Sbostic     register struct process *tp;
7891302Sbill {
79049992Sbostic     struct timeval tetime, diff;
79149992Sbostic     static struct timeval ztime;
79249992Sbostic     struct rusage ru;
79349992Sbostic     static struct rusage zru;
79449992Sbostic     register struct process *pp = tp;
7951302Sbill 
79649992Sbostic     ru = zru;
79749992Sbostic     tetime = ztime;
79849992Sbostic     do {
79949992Sbostic 	ruadd(&ru, &pp->p_rusage);
80049992Sbostic 	tvsub(&diff, &pp->p_etime, &pp->p_btime);
80149992Sbostic 	if (timercmp(&diff, &tetime, >))
80249992Sbostic 	    tetime = diff;
80349992Sbostic     } while ((pp = pp->p_friends) != tp);
80449992Sbostic     prusage(&zru, &ru, &tetime, &ztime);
8051302Sbill }
8061302Sbill 
8071302Sbill /*
8081302Sbill  * dojobs - print all jobs
8091302Sbill  */
81049992Sbostic void
81150439Schristos /*ARGSUSED*/
81250439Schristos dojobs(v, t)
81350439Schristos     Char **v;
81450439Schristos     struct command *t;
8151302Sbill {
81649992Sbostic     register struct process *pp;
81749992Sbostic     register int flag = NUMBER | NAME | REASON;
81849992Sbostic     int     i;
8191302Sbill 
82049992Sbostic     if (chkstop)
82149992Sbostic 	chkstop = 2;
82249992Sbostic     if (*++v) {
82349992Sbostic 	if (v[1] || !eq(*v, STRml))
82449992Sbostic 	    stderror(ERR_JOBS);
82549992Sbostic 	flag |= FANCY | JOBDIR;
82649992Sbostic     }
82749992Sbostic     for (i = 1; i <= pmaxindex; i++)
82849992Sbostic 	for (pp = proclist.p_next; pp; pp = pp->p_next)
82949992Sbostic 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
83049992Sbostic 		pp->p_flags &= ~PNEEDNOTE;
83149992Sbostic 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
83249992Sbostic 		    pflush(pp);
83349992Sbostic 		break;
83449992Sbostic 	    }
8351302Sbill }
8361302Sbill 
8371302Sbill /*
8381302Sbill  * dofg - builtin - put the job into the foreground
8391302Sbill  */
84049992Sbostic void
84150439Schristos /*ARGSUSED*/
84250439Schristos dofg(v, t)
84350439Schristos     Char **v;
84450439Schristos     struct command *t;
8451302Sbill {
84649992Sbostic     register struct process *pp;
8471302Sbill 
84849992Sbostic     okpcntl();
84949992Sbostic     ++v;
85049992Sbostic     do {
85149992Sbostic 	pp = pfind(*v);
85249992Sbostic 	pstart(pp, 1);
85349992Sbostic 	pjwait(pp);
85449992Sbostic     } while (*v && *++v);
8551302Sbill }
8561302Sbill 
8571302Sbill /*
8581302Sbill  * %... - builtin - put the job into the foreground
8591302Sbill  */
86049992Sbostic void
86150439Schristos /*ARGSUSED*/
86250439Schristos dofg1(v, t)
86350439Schristos     Char **v;
86450439Schristos     struct command *t;
8651302Sbill {
86649992Sbostic     register struct process *pp;
8671302Sbill 
86849992Sbostic     okpcntl();
86949992Sbostic     pp = pfind(v[0]);
87049992Sbostic     pstart(pp, 1);
87149992Sbostic     pjwait(pp);
8721302Sbill }
8731302Sbill 
8741302Sbill /*
8751302Sbill  * dobg - builtin - put the job into the background
8761302Sbill  */
87749992Sbostic void
87850439Schristos /*ARGSUSED*/
87950439Schristos dobg(v, t)
88050439Schristos     Char **v;
88150439Schristos     struct command *t;
8821302Sbill {
88349992Sbostic     register struct process *pp;
8841302Sbill 
88549992Sbostic     okpcntl();
88649992Sbostic     ++v;
88749992Sbostic     do {
88849992Sbostic 	pp = pfind(*v);
88949992Sbostic 	pstart(pp, 0);
89049992Sbostic     } while (*v && *++v);
8911302Sbill }
8921302Sbill 
8931302Sbill /*
8941302Sbill  * %... & - builtin - put the job into the background
8951302Sbill  */
89649992Sbostic void
89750439Schristos /*ARGSUSED*/
89850439Schristos dobg1(v, t)
89950439Schristos     Char **v;
90050439Schristos     struct command *t;
9011302Sbill {
90249992Sbostic     register struct process *pp;
9031302Sbill 
90449992Sbostic     pp = pfind(v[0]);
90549992Sbostic     pstart(pp, 0);
9061302Sbill }
9071302Sbill 
9081302Sbill /*
9091302Sbill  * dostop - builtin - stop the job
9101302Sbill  */
91149992Sbostic void
91250439Schristos /*ARGSUSED*/
91350439Schristos dostop(v, t)
91450439Schristos     Char **v;
91550439Schristos     struct command *t;
9161302Sbill {
91749992Sbostic     pkill(++v, SIGSTOP);
9181302Sbill }
9191302Sbill 
9201302Sbill /*
9211302Sbill  * dokill - builtin - superset of kill (1)
9221302Sbill  */
92349992Sbostic void
92450439Schristos /*ARGSUSED*/
92550439Schristos dokill(v, t)
92650439Schristos     Char **v;
92750439Schristos     struct command *t;
9281302Sbill {
92950761Schristos     register int signum = SIGTERM;
93049992Sbostic     register char *name;
9311302Sbill 
93249992Sbostic     v++;
93349992Sbostic     if (v[0] && v[0][0] == '-') {
93449992Sbostic 	if (v[0][1] == 'l') {
93550761Schristos 	    for (signum = 1; signum < NSIG; signum++) {
93650761Schristos 		(void) fprintf(cshout, "%s ", sys_signame[signum]);
93750761Schristos 		if (signum == NSIG / 2)
93850761Schristos 		    (void) fputc('\n', cshout);
93949992Sbostic 	    }
94050439Schristos 	    (void) fputc('\n', cshout);
94149992Sbostic 	    return;
94249992Sbostic 	}
94349992Sbostic 	if (Isdigit(v[0][1])) {
94449992Sbostic 	    signum = atoi(short2str(v[0] + 1));
94549992Sbostic 	    if (signum < 0 || signum > NSIG)
94649992Sbostic 		stderror(ERR_NAME | ERR_BADSIG);
94749992Sbostic 	}
94849992Sbostic 	else {
94950761Schristos 	    name = short2str(&v[0][1]);
95050761Schristos 	    if (!strncasecmp(name, "sig", 3))
95150761Schristos 		name += 3;
95250761Schristos 
95351437Sleres 	    for (signum = 1; signum < NSIG; signum++)
95450761Schristos 		if (!strcasecmp(sys_signame[signum], name))
95550761Schristos 		    break;
95650761Schristos 
95750761Schristos 	    if (signum == NSIG) {
958*51589Schristos 		setname(vis_str(&v[0][1]));
95950761Schristos 		stderror(ERR_NAME | ERR_UNKSIG);
96050761Schristos 	    }
96149992Sbostic 	}
96249992Sbostic 	v++;
96349992Sbostic     }
96449992Sbostic     pkill(v, signum);
9651302Sbill }
9661302Sbill 
96749992Sbostic static void
9681302Sbill pkill(v, signum)
96949992Sbostic     Char  **v;
97049992Sbostic     int     signum;
9711302Sbill {
97249992Sbostic     register struct process *pp, *np;
97349992Sbostic     register int jobflags = 0;
97449992Sbostic     int     pid, err1 = 0;
97550028Sbostic     sigset_t omask;
97649992Sbostic     Char   *cp;
9771302Sbill 
97849992Sbostic     omask = sigmask(SIGCHLD);
97949992Sbostic     if (setintr)
98049992Sbostic 	omask |= sigmask(SIGINT);
98149992Sbostic     omask = sigblock(omask) & ~omask;
98249992Sbostic     gflag = 0, tglob(v);
98349992Sbostic     if (gflag) {
98449992Sbostic 	v = globall(v);
98549992Sbostic 	if (v == 0)
98649992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
98749992Sbostic     }
98849992Sbostic     else {
98949992Sbostic 	v = gargv = saveblk(v);
99049992Sbostic 	trim(v);
99149992Sbostic     }
9921302Sbill 
99349992Sbostic     while (v && (cp = *v)) {
99449992Sbostic 	if (*cp == '%') {
99549992Sbostic 	    np = pp = pfind(cp);
99649992Sbostic 	    do
99749992Sbostic 		jobflags |= np->p_flags;
99849992Sbostic 	    while ((np = np->p_friends) != pp);
99949992Sbostic 	    switch (signum) {
100049992Sbostic 
100149992Sbostic 	    case SIGSTOP:
100249992Sbostic 	    case SIGTSTP:
100349992Sbostic 	    case SIGTTIN:
100449992Sbostic 	    case SIGTTOU:
100549992Sbostic 		if ((jobflags & PRUNNING) == 0) {
100651437Sleres 		    (void) fprintf(csherr, "%s: Already suspended\n",
1007*51589Schristos 				   vis_str(cp));
100849992Sbostic 		    err1++;
100949992Sbostic 		    goto cont;
10101302Sbill 		}
101149992Sbostic 		break;
101249992Sbostic 		/*
101349992Sbostic 		 * suspend a process, kill -CONT %, then type jobs; the shell
101449992Sbostic 		 * says it is suspended, but it is running; thanks jaap..
101549992Sbostic 		 */
101649992Sbostic 	    case SIGCONT:
101749992Sbostic 		pstart(pp, 0);
101849992Sbostic 		goto cont;
101949992Sbostic 	    }
102049992Sbostic 	    if (killpg((pid_t) pp->p_jobid, signum) < 0) {
1021*51589Schristos 		(void) fprintf(csherr, "%s: %s\n", vis_str(cp),
102250439Schristos 			       strerror(errno));
102349992Sbostic 		err1++;
102449992Sbostic 	    }
102549992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
102649992Sbostic 		(void) killpg((pid_t) pp->p_jobid, SIGCONT);
102749992Sbostic 	}
102849992Sbostic 	else if (!(Isdigit(*cp) || *cp == '-'))
102949992Sbostic 	    stderror(ERR_NAME | ERR_JOBARGS);
103049992Sbostic 	else {
103149992Sbostic 	    pid = atoi(short2str(cp));
103249992Sbostic 	    if (kill((pid_t) pid, signum) < 0) {
103350439Schristos 		(void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
103449992Sbostic 		err1++;
103549992Sbostic 		goto cont;
103649992Sbostic 	    }
103749992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
103849992Sbostic 		(void) kill((pid_t) pid, SIGCONT);
103949992Sbostic 	}
10401302Sbill cont:
104149992Sbostic 	v++;
104249992Sbostic     }
104349992Sbostic     if (gargv)
104449992Sbostic 	blkfree(gargv), gargv = 0;
104549992Sbostic     (void) sigsetmask(omask);
104649992Sbostic     if (err1)
104749992Sbostic 	stderror(ERR_SILENT);
10481302Sbill }
10491302Sbill 
10501302Sbill /*
10511302Sbill  * pstart - start the job in foreground/background
10521302Sbill  */
105349992Sbostic void
10541302Sbill pstart(pp, foregnd)
105549992Sbostic     register struct process *pp;
105649992Sbostic     int     foregnd;
10571302Sbill {
105849992Sbostic     register struct process *np;
105950028Sbostic     sigset_t omask;
106049992Sbostic     long    jobflags = 0;
10611302Sbill 
106249992Sbostic     omask = sigblock(sigmask(SIGCHLD));
106349992Sbostic     np = pp;
106449992Sbostic     do {
106549992Sbostic 	jobflags |= np->p_flags;
106649992Sbostic 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
106749992Sbostic 	    np->p_flags |= PRUNNING;
106849992Sbostic 	    np->p_flags &= ~PSTOPPED;
106949992Sbostic 	    if (foregnd)
107049992Sbostic 		np->p_flags |= PFOREGND;
107149992Sbostic 	    else
107249992Sbostic 		np->p_flags &= ~PFOREGND;
107349992Sbostic 	}
107449992Sbostic     } while ((np = np->p_friends) != pp);
107549992Sbostic     if (!foregnd)
107649992Sbostic 	pclrcurr(pp);
107749992Sbostic     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
107849992Sbostic     if (foregnd)
107949992Sbostic 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
108049992Sbostic     if (jobflags & PSTOPPED)
108149992Sbostic 	(void) killpg((pid_t) pp->p_jobid, SIGCONT);
108249992Sbostic     (void) sigsetmask(omask);
10831302Sbill }
10841302Sbill 
108549992Sbostic void
10861302Sbill panystop(neednl)
108749992Sbostic     bool    neednl;
10881302Sbill {
108949992Sbostic     register struct process *pp;
10901302Sbill 
109149992Sbostic     chkstop = 2;
109249992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
109349992Sbostic 	if (pp->p_flags & PSTOPPED)
109449992Sbostic 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
10951302Sbill }
10961302Sbill 
10971302Sbill struct process *
10981302Sbill pfind(cp)
109949992Sbostic     Char   *cp;
11001302Sbill {
110149992Sbostic     register struct process *pp, *np;
11021302Sbill 
110349992Sbostic     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
110450040Schristos 	if (pcurrent == NULL)
110549992Sbostic 	    stderror(ERR_NAME | ERR_JOBCUR);
110649992Sbostic 	return (pcurrent);
110749992Sbostic     }
110849992Sbostic     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
110950040Schristos 	if (pprevious == NULL)
111049992Sbostic 	    stderror(ERR_NAME | ERR_JOBPREV);
111149992Sbostic 	return (pprevious);
111249992Sbostic     }
111349992Sbostic     if (Isdigit(cp[1])) {
111449992Sbostic 	int     idx = atoi(short2str(cp + 1));
111549992Sbostic 
11161302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
111749992Sbostic 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
111849992Sbostic 		return (pp);
111949992Sbostic 	stderror(ERR_NAME | ERR_NOSUCHJOB);
112049992Sbostic     }
112150040Schristos     np = NULL;
112249992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
112349992Sbostic 	if (pp->p_pid == pp->p_jobid) {
112449992Sbostic 	    if (cp[1] == '?') {
112549992Sbostic 		register Char *dp;
112649992Sbostic 
112749992Sbostic 		for (dp = pp->p_command; *dp; dp++) {
112849992Sbostic 		    if (*dp != cp[2])
112949992Sbostic 			continue;
113049992Sbostic 		    if (prefix(cp + 2, dp))
113149992Sbostic 			goto match;
11321302Sbill 		}
113349992Sbostic 	    }
113449992Sbostic 	    else if (prefix(cp + 1, pp->p_command)) {
113549992Sbostic 	match:
113649992Sbostic 		if (np)
113749992Sbostic 		    stderror(ERR_NAME | ERR_AMBIG);
113849992Sbostic 		np = pp;
113949992Sbostic 	    }
114049992Sbostic 	}
114149992Sbostic     if (np)
114249992Sbostic 	return (np);
114349992Sbostic     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
114449992Sbostic     /* NOTREACHED */
114549992Sbostic     return (0);
11461302Sbill }
11471302Sbill 
114849992Sbostic 
11491302Sbill /*
11502357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
11511302Sbill  */
115249992Sbostic static struct process *
11531302Sbill pgetcurr(pp)
115449992Sbostic     register struct process *pp;
11551302Sbill {
115649992Sbostic     register struct process *np;
115750040Schristos     register struct process *xp = NULL;
11581302Sbill 
115949992Sbostic     for (np = proclist.p_next; np; np = np->p_next)
116049992Sbostic 	if (np != pcurrent && np != pp && np->p_pid &&
116149992Sbostic 	    np->p_pid == np->p_jobid) {
116249992Sbostic 	    if (np->p_flags & PSTOPPED)
116349992Sbostic 		return (np);
116450040Schristos 	    if (xp == NULL)
116549992Sbostic 		xp = np;
116649992Sbostic 	}
116749992Sbostic     return (xp);
11681302Sbill }
11691302Sbill 
11701302Sbill /*
11711302Sbill  * donotify - flag the job so as to report termination asynchronously
11721302Sbill  */
117349992Sbostic void
117450439Schristos /*ARGSUSED*/
117550439Schristos donotify(v, t)
117650439Schristos     Char **v;
117750439Schristos     struct command *t;
11781302Sbill {
117949992Sbostic     register struct process *pp;
11801302Sbill 
118149992Sbostic     pp = pfind(*++v);
118249992Sbostic     pp->p_flags |= PNOTIFY;
11831302Sbill }
11841302Sbill 
11851302Sbill /*
11861302Sbill  * Do the fork and whatever should be done in the child side that
11871302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
11881302Sbill  * Also do everything that needs any signals fiddled with in the parent side
11891302Sbill  *
11901302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
11911302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
11921302Sbill  *	 0:	already have tty; manipulate process pgrps only
11931302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
11941302Sbill  * It is usually just the value of tpgrp.
11951302Sbill  */
119649992Sbostic 
119749992Sbostic int
11981302Sbill pfork(t, wanttty)
119949992Sbostic     struct command *t;		/* command we are forking for */
120049992Sbostic     int     wanttty;
12011302Sbill {
120249992Sbostic     register int pid;
120349992Sbostic     bool    ignint = 0;
120449992Sbostic     int     pgrp;
120550028Sbostic     sigset_t omask;
12061302Sbill 
120749992Sbostic     /*
120849992Sbostic      * A child will be uninterruptible only under very special conditions.
120949992Sbostic      * Remember that the semantics of '&' is implemented by disconnecting the
121049992Sbostic      * process from the tty so signals do not need to ignored just for '&'.
121149992Sbostic      * Thus signals are set to default action for children unless: we have had
121249992Sbostic      * an "onintr -" (then specifically ignored) we are not playing with
121349992Sbostic      * signals (inherit action)
121449992Sbostic      */
121549992Sbostic     if (setintr)
121649992Sbostic 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
121749992Sbostic 	    || (gointr && eq(gointr, STRminus));
121849992Sbostic     /*
121949992Sbostic      * Check for maximum nesting of 16 processes to avoid Forking loops
122049992Sbostic      */
122149992Sbostic     if (child == 16)
122249992Sbostic 	stderror(ERR_NESTING, 16);
122349992Sbostic     /*
122449992Sbostic      * Hold SIGCHLD until we have the process installed in our table.
122549992Sbostic      */
122649992Sbostic     omask = sigblock(sigmask(SIGCHLD));
122749992Sbostic     while ((pid = fork()) < 0)
122849992Sbostic 	if (setintr == 0)
122949992Sbostic 	    (void) sleep(FORKSLEEP);
123049992Sbostic 	else {
123149992Sbostic 	    (void) sigsetmask(omask);
123249992Sbostic 	    stderror(ERR_NOPROC);
123349992Sbostic 	}
123449992Sbostic     if (pid == 0) {
123549992Sbostic 	settimes();
123649992Sbostic 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
123749992Sbostic 	pflushall();
123850040Schristos 	pcurrjob = NULL;
123949992Sbostic 	child++;
124049992Sbostic 	if (setintr) {
124149992Sbostic 	    setintr = 0;	/* until I think otherwise */
124249992Sbostic 	    /*
124349992Sbostic 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
124449992Sbostic 	     * -" seen.
124549992Sbostic 	     */
124649992Sbostic 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
124749992Sbostic 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
124849992Sbostic 	    if (wanttty >= 0) {
124949992Sbostic 		/* make stoppable */
125049992Sbostic 		(void) signal(SIGTSTP, SIG_DFL);
125149992Sbostic 		(void) signal(SIGTTIN, SIG_DFL);
125249992Sbostic 		(void) signal(SIGTTOU, SIG_DFL);
125349992Sbostic 	    }
125449992Sbostic 	    (void) signal(SIGTERM, parterm);
125549992Sbostic 	}
125649992Sbostic 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
125749992Sbostic 	    (void) signal(SIGINT, SIG_IGN);
125849992Sbostic 	    (void) signal(SIGQUIT, SIG_IGN);
125949992Sbostic 	}
126049992Sbostic 	pgetty(wanttty, pgrp);
12611302Sbill 	/*
126249992Sbostic 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
126349992Sbostic 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
126449992Sbostic 	 * to know about nice/nohup/time
12651302Sbill 	 */
126649992Sbostic 	if (t->t_dflg & F_NOHUP)
126749992Sbostic 	    (void) signal(SIGHUP, SIG_IGN);
126849992Sbostic 	if (t->t_dflg & F_NICE)
126949992Sbostic 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
127049992Sbostic     }
127149992Sbostic     else {
127249992Sbostic 	if (wanttty >= 0)
127349992Sbostic 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
127449992Sbostic 	palloc(pid, t);
127549992Sbostic 	(void) sigsetmask(omask);
127649992Sbostic     }
12771302Sbill 
127849992Sbostic     return (pid);
12791302Sbill }
12801302Sbill 
128149992Sbostic static void
12821302Sbill okpcntl()
12831302Sbill {
128449992Sbostic     if (tpgrp == -1)
128549992Sbostic 	stderror(ERR_JOBCONTROL);
128649992Sbostic     if (tpgrp == 0)
128749992Sbostic 	stderror(ERR_JOBCTRLSUB);
128849992Sbostic }
12891302Sbill 
129049992Sbostic /*
129149992Sbostic  * if we don't have vfork(), things can still go in the wrong order
129249992Sbostic  * resulting in the famous 'Stopped (tty output)'. But some systems
129349992Sbostic  * don't permit the setpgid() call, (these are more recent secure
129449992Sbostic  * systems such as ibm's aix). Then we'd rather print an error message
129549992Sbostic  * than hang the shell!
129649992Sbostic  * I am open to suggestions how to fix that.
129749992Sbostic  */
129849992Sbostic void
129949992Sbostic pgetty(wanttty, pgrp)
130049992Sbostic     int     wanttty, pgrp;
130149992Sbostic {
130250028Sbostic     sigset_t omask = 0;
130349992Sbostic 
130449992Sbostic     /*
130549992Sbostic      * christos: I am blocking the tty signals till I've set things
130649992Sbostic      * correctly....
130749992Sbostic      */
130849992Sbostic     if (wanttty > 0)
130949992Sbostic 	omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
131049992Sbostic     /*
131149992Sbostic      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
131249992Sbostic      * Don't check for tpgrp >= 0 so even non-interactive shells give
131349992Sbostic      * background jobs process groups Same for the comparison in the other part
131449992Sbostic      * of the #ifdef
131549992Sbostic      */
131649992Sbostic     if (wanttty >= 0)
131749992Sbostic 	if (setpgid(0, pgrp) == -1) {
131850439Schristos 	    (void) fprintf(csherr, "csh: setpgid error.\n");
131949992Sbostic 	    xexit(0);
132049992Sbostic 	}
132149992Sbostic 
132249992Sbostic     if (wanttty > 0) {
132349992Sbostic 	(void) tcsetpgrp(FSHTTY, pgrp);
132449992Sbostic 	(void) sigsetmask(omask);
132549992Sbostic     }
132649992Sbostic 
132749992Sbostic     if (tpgrp > 0)
132849992Sbostic 	tpgrp = 0;		/* gave tty away */
13291302Sbill }
1330