xref: /csrg-svn/bin/csh/proc.c (revision 50040)
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*50040Schristos static char sccsid[] = "@(#)proc.c	5.21 (Berkeley) 06/09/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));
4150024Schristos 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     }
78*50040Schristos     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 */
15149992Sbostic 	    else if (jobflags & PINTERRUPTED)
15249992Sbostic 		xputchar('\r' | QUOTE), xputchar('\n');
1531302Sbill 	}
15449992Sbostic 	else {
15549992Sbostic 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
15649992Sbostic 		xputchar('\r' | QUOTE), xputchar('\n');
15749992Sbostic 		(void) pprint(pp, NUMBER | NAME | REASON);
15849992Sbostic 		if ((jobflags & PSTOPPED) == 0)
15949992Sbostic 		    pflush(pp);
16049992Sbostic 	    }
16149992Sbostic 	    else {
16249992Sbostic 		fp->p_flags |= PNEEDNOTE;
16349992Sbostic 		neednote++;
16449992Sbostic 	    }
16549992Sbostic 	}
16649992Sbostic     }
16749992Sbostic     goto loop;
1681302Sbill }
1691302Sbill 
17049992Sbostic void
1711302Sbill pnote()
1721302Sbill {
17349992Sbostic     register struct process *pp;
17449992Sbostic     int     flags;
17550028Sbostic     sigset_t omask;
1761302Sbill 
17749992Sbostic     neednote = 0;
178*50040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
17949992Sbostic 	if (pp->p_flags & PNEEDNOTE) {
18049992Sbostic 	    omask = sigblock(sigmask(SIGCHLD));
18149992Sbostic 	    pp->p_flags &= ~PNEEDNOTE;
18249992Sbostic 	    flags = pprint(pp, NUMBER | NAME | REASON);
18349992Sbostic 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
18449992Sbostic 		pflush(pp);
18549992Sbostic 	    (void) sigsetmask(omask);
1861302Sbill 	}
18749992Sbostic     }
1881302Sbill }
1891302Sbill 
1901302Sbill /*
1911302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1921302Sbill  *	of current and previous job indicators.
1931302Sbill  */
19449992Sbostic void
1951302Sbill pwait()
1961302Sbill {
19749992Sbostic     register struct process *fp, *pp;
19850028Sbostic     sigset_t omask;
1991302Sbill 
20049992Sbostic     /*
20149992Sbostic      * Here's where dead procs get flushed.
20249992Sbostic      */
20349992Sbostic     omask = sigblock(sigmask(SIGCHLD));
204*50040Schristos     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
20549992Sbostic 	if (pp->p_pid == 0) {
20649992Sbostic 	    fp->p_next = pp->p_next;
20749992Sbostic 	    xfree((ptr_t) pp->p_command);
20849992Sbostic 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
20949992Sbostic 		if (pp->p_cwd->di_next == 0)
21049992Sbostic 		    dfree(pp->p_cwd);
21149992Sbostic 	    xfree((ptr_t) pp);
21249992Sbostic 	    pp = fp;
21349992Sbostic 	}
21449992Sbostic     (void) sigsetmask(omask);
21549992Sbostic     pjwait(pcurrjob);
2161302Sbill }
2171302Sbill 
21849992Sbostic 
2191302Sbill /*
2201302Sbill  * pjwait - wait for a job to finish or become stopped
2211302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
2221302Sbill  */
22349992Sbostic void
2241302Sbill pjwait(pp)
22549992Sbostic     register struct process *pp;
2261302Sbill {
22749992Sbostic     register struct process *fp;
22849992Sbostic     int     jobflags, reason;
22950028Sbostic     sigset_t omask;
2301302Sbill 
23149992Sbostic     while (pp->p_pid != pp->p_jobid)
23249992Sbostic 	pp = pp->p_friends;
23349992Sbostic     fp = pp;
23449992Sbostic 
23549992Sbostic     do {
23649992Sbostic 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
23749992Sbostic 	    xprintf("BUG: waiting for background job!\n");
23849992Sbostic     } while ((fp = fp->p_friends) != pp);
23949992Sbostic     /*
24049992Sbostic      * Now keep pausing as long as we are not interrupted (SIGINT), and the
24149992Sbostic      * target process, or any of its friends, are running
24249992Sbostic      */
24349992Sbostic     fp = pp;
24449992Sbostic     omask = sigblock(sigmask(SIGCHLD));
24549992Sbostic     for (;;) {
24649992Sbostic 	(void) sigblock(sigmask(SIGCHLD));
24749992Sbostic 	jobflags = 0;
24849992Sbostic 	do
24949992Sbostic 	    jobflags |= fp->p_flags;
25049992Sbostic 	while ((fp = (fp->p_friends)) != pp);
25149992Sbostic 	if ((jobflags & PRUNNING) == 0)
25249992Sbostic 	    break;
25349992Sbostic #ifdef JOBDEBUG
25449992Sbostic 	xprintf("starting to sigpause for  SIGCHLD on %d\n", fp->p_pid);
25549992Sbostic #endif				/* JOBDEBUG */
25649992Sbostic 	(void) sigpause(omask & ~sigmask(SIGCHLD));
25749992Sbostic     }
25849992Sbostic     (void) sigsetmask(omask);
25949992Sbostic     if (tpgrp > 0)		/* get tty back */
26049992Sbostic 	(void) tcsetpgrp(FSHTTY, tpgrp);
26149992Sbostic     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
26249992Sbostic 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
26349992Sbostic 	if (jobflags & PSTOPPED) {
26449992Sbostic 	    xprintf("\n");
26549992Sbostic 	    if (adrof(STRlistjobs)) {
26649992Sbostic 		Char   *jobcommand[3];
26749992Sbostic 
26849992Sbostic 		jobcommand[0] = STRjobs;
26949992Sbostic 		if (eq(value(STRlistjobs), STRlong))
27049992Sbostic 		    jobcommand[1] = STRml;
27149992Sbostic 		else
27249992Sbostic 		    jobcommand[1] = NULL;
27349992Sbostic 		jobcommand[2] = NULL;
27449992Sbostic 
27549992Sbostic 		dojobs(jobcommand);
27649992Sbostic 		(void) pprint(pp, SHELLDIR);
27749992Sbostic 	    }
27849992Sbostic 	    else
27949992Sbostic 		(void) pprint(pp, AREASON | SHELLDIR);
2801302Sbill 	}
28149992Sbostic 	else
28249992Sbostic 	    (void) pprint(pp, AREASON | SHELLDIR);
28349992Sbostic     }
28449992Sbostic     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
28549992Sbostic 	(!gointr || !eq(gointr, STRminus))) {
28649992Sbostic 	if ((jobflags & PSTOPPED) == 0)
28749992Sbostic 	    pflush(pp);
28849992Sbostic 	pintr1(0);
28949992Sbostic 	/* NOTREACHED */
29049992Sbostic     }
29149992Sbostic     reason = 0;
29249992Sbostic     fp = pp;
29349992Sbostic     do {
29449992Sbostic 	if (fp->p_reason)
29549992Sbostic 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
29649992Sbostic 		fp->p_reason | META : fp->p_reason;
29749992Sbostic     } while ((fp = fp->p_friends) != pp);
29849992Sbostic     if ((reason != 0) && (adrof(STRprintexitvalue)))
29949992Sbostic 	xprintf("Exit %d\n", reason);
30049992Sbostic     set(STRstatus, putn(reason));
30149992Sbostic     if (reason && exiterr)
30249992Sbostic 	exitstat();
30349992Sbostic     pflush(pp);
3041302Sbill }
3051302Sbill 
3061302Sbill /*
3071302Sbill  * dowait - wait for all processes to finish
3081302Sbill  */
30949992Sbostic void
3101302Sbill dowait()
3111302Sbill {
31249992Sbostic     register struct process *pp;
31350028Sbostic     sigset_t omask;
3141302Sbill 
31549992Sbostic     pjobs++;
31649992Sbostic     omask = sigblock(sigmask(SIGCHLD));
3171302Sbill loop:
31849992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
31949992Sbostic 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
32049992Sbostic 	    pp->p_flags & PRUNNING) {
32150028Sbostic 	    (void) sigpause((sigset_t) 0);
32249992Sbostic 	    goto loop;
32349992Sbostic 	}
32449992Sbostic     (void) sigsetmask(omask);
32549992Sbostic     pjobs = 0;
3261302Sbill }
3271302Sbill 
3281302Sbill /*
3291302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
3301302Sbill  */
33149992Sbostic static void
3321302Sbill pflushall()
3331302Sbill {
33449992Sbostic     register struct process *pp;
3351302Sbill 
336*50040Schristos     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
33749992Sbostic 	if (pp->p_pid)
33849992Sbostic 	    pflush(pp);
3391302Sbill }
3401302Sbill 
3411302Sbill /*
3421302Sbill  * pflush - flag all process structures in the same job as the
3431302Sbill  *	the argument process for deletion.  The actual free of the
3441302Sbill  *	space is not done here since pflush is called at interrupt level.
3451302Sbill  */
34649992Sbostic static void
3471302Sbill pflush(pp)
34849992Sbostic     register struct process *pp;
3491302Sbill {
35049992Sbostic     register struct process *np;
35149992Sbostic     register int idx;
3521302Sbill 
35349992Sbostic     if (pp->p_pid == 0) {
35449992Sbostic 	xprintf("BUG: process flushed twice");
35549992Sbostic 	return;
35649992Sbostic     }
35749992Sbostic     while (pp->p_pid != pp->p_jobid)
35849992Sbostic 	pp = pp->p_friends;
35949992Sbostic     pclrcurr(pp);
36049992Sbostic     if (pp == pcurrjob)
36149992Sbostic 	pcurrjob = 0;
36249992Sbostic     idx = pp->p_index;
36349992Sbostic     np = pp;
36449992Sbostic     do {
36549992Sbostic 	np->p_index = np->p_pid = 0;
36649992Sbostic 	np->p_flags &= ~PNEEDNOTE;
36749992Sbostic     } while ((np = np->p_friends) != pp);
36849992Sbostic     if (idx == pmaxindex) {
36949992Sbostic 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
37049992Sbostic 	    if (np->p_index > idx)
37149992Sbostic 		idx = np->p_index;
37249992Sbostic 	pmaxindex = idx;
37349992Sbostic     }
3741302Sbill }
3751302Sbill 
3761302Sbill /*
3771302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3781302Sbill  *	pp MUST be the job leader
3791302Sbill  */
38049992Sbostic static void
3811302Sbill pclrcurr(pp)
38249992Sbostic     register struct process *pp;
3831302Sbill {
3841302Sbill 
38549992Sbostic     if (pp == pcurrent)
386*50040Schristos 	if (pprevious != NULL) {
38749992Sbostic 	    pcurrent = pprevious;
38849992Sbostic 	    pprevious = pgetcurr(pp);
38949992Sbostic 	}
39049992Sbostic 	else {
39149992Sbostic 	    pcurrent = pgetcurr(pp);
39249992Sbostic 	    pprevious = pgetcurr(pp);
39349992Sbostic 	}
39449992Sbostic     else if (pp == pprevious)
39549992Sbostic 	pprevious = pgetcurr(pp);
3961302Sbill }
3971302Sbill 
3981302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
39949992Sbostic static Char command[PMAXLEN + 4];
40049992Sbostic static int cmdlen;
40149992Sbostic static Char *cmdp;
40249992Sbostic 
4031302Sbill /*
4041302Sbill  * palloc - allocate a process structure and fill it up.
4051302Sbill  *	an important assumption is made that the process is running.
4061302Sbill  */
40749992Sbostic void
4081302Sbill palloc(pid, t)
40949992Sbostic     int     pid;
41049992Sbostic     register struct command *t;
4111302Sbill {
41249992Sbostic     register struct process *pp;
41349992Sbostic     int     i;
4141302Sbill 
41549992Sbostic     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
41649992Sbostic     pp->p_pid = pid;
41749992Sbostic     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
41849992Sbostic     if (t->t_dflg & F_TIME)
41949992Sbostic 	pp->p_flags |= PPTIME;
42049992Sbostic     cmdp = command;
42149992Sbostic     cmdlen = 0;
42249992Sbostic     padd(t);
42349992Sbostic     *cmdp++ = 0;
42449992Sbostic     if (t->t_dflg & F_PIPEOUT) {
42549992Sbostic 	pp->p_flags |= PPOU;
42649992Sbostic 	if (t->t_dflg & F_STDERR)
42749992Sbostic 	    pp->p_flags |= PDIAG;
42849992Sbostic     }
42949992Sbostic     pp->p_command = Strsave(command);
43049992Sbostic     if (pcurrjob) {
43149992Sbostic 	struct process *fp;
4321302Sbill 
43349992Sbostic 	/* careful here with interrupt level */
43449992Sbostic 	pp->p_cwd = 0;
43549992Sbostic 	pp->p_index = pcurrjob->p_index;
43649992Sbostic 	pp->p_friends = pcurrjob;
43749992Sbostic 	pp->p_jobid = pcurrjob->p_pid;
43849992Sbostic 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends);
43949992Sbostic 	fp->p_friends = pp;
44049992Sbostic     }
44149992Sbostic     else {
44249992Sbostic 	pcurrjob = pp;
44349992Sbostic 	pp->p_jobid = pid;
44449992Sbostic 	pp->p_friends = pp;
44549992Sbostic 	pp->p_cwd = dcwd;
44649992Sbostic 	dcwd->di_count++;
44749992Sbostic 	if (pmaxindex < BIGINDEX)
44849992Sbostic 	    pp->p_index = ++pmaxindex;
44949992Sbostic 	else {
45049992Sbostic 	    struct process *np;
45149992Sbostic 
45249992Sbostic 	    for (i = 1;; i++) {
45349992Sbostic 		for (np = proclist.p_next; np; np = np->p_next)
45449992Sbostic 		    if (np->p_index == i)
45549992Sbostic 			goto tryagain;
45649992Sbostic 		pp->p_index = i;
45749992Sbostic 		if (i > pmaxindex)
45849992Sbostic 		    pmaxindex = i;
45949992Sbostic 		break;
46049992Sbostic 	tryagain:;
46149992Sbostic 	    }
4621302Sbill 	}
463*50040Schristos 	if (pcurrent == NULL)
46449992Sbostic 	    pcurrent = pp;
465*50040Schristos 	else if (pprevious == NULL)
46649992Sbostic 	    pprevious = pp;
46749992Sbostic     }
46849992Sbostic     pp->p_next = proclist.p_next;
46949992Sbostic     proclist.p_next = pp;
47050028Sbostic     (void) gettimeofday(&pp->p_btime, NULL);
4711302Sbill }
4721302Sbill 
47349992Sbostic static void
4741302Sbill padd(t)
47549992Sbostic     register struct command *t;
4761302Sbill {
47749992Sbostic     Char  **argp;
4781302Sbill 
47949992Sbostic     if (t == 0)
48049992Sbostic 	return;
48149992Sbostic     switch (t->t_dtyp) {
4821302Sbill 
48349992Sbostic     case NODE_PAREN:
48449992Sbostic 	pads(STRLparensp);
48549992Sbostic 	padd(t->t_dspr);
48649992Sbostic 	pads(STRspRparen);
48749992Sbostic 	break;
4881302Sbill 
48949992Sbostic     case NODE_COMMAND:
49049992Sbostic 	for (argp = t->t_dcom; *argp; argp++) {
49149992Sbostic 	    pads(*argp);
49249992Sbostic 	    if (argp[1])
49349992Sbostic 		pads(STRspace);
49449992Sbostic 	}
49549992Sbostic 	break;
4961302Sbill 
49749992Sbostic     case NODE_OR:
49849992Sbostic     case NODE_AND:
49949992Sbostic     case NODE_PIPE:
50049992Sbostic     case NODE_LIST:
50149992Sbostic 	padd(t->t_dcar);
50249992Sbostic 	switch (t->t_dtyp) {
50347724Sbostic 	case NODE_OR:
50449992Sbostic 	    pads(STRspor2sp);
50549992Sbostic 	    break;
50647724Sbostic 	case NODE_AND:
50749992Sbostic 	    pads(STRspand2sp);
50849992Sbostic 	    break;
50947724Sbostic 	case NODE_PIPE:
51049992Sbostic 	    pads(STRsporsp);
51149992Sbostic 	    break;
51247724Sbostic 	case NODE_LIST:
51349992Sbostic 	    pads(STRsemisp);
51449992Sbostic 	    break;
5151302Sbill 	}
51649992Sbostic 	padd(t->t_dcdr);
51749992Sbostic 	return;
51849992Sbostic     }
51949992Sbostic     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
52049992Sbostic 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
52149992Sbostic 	pads(t->t_dlef);
52249992Sbostic     }
52349992Sbostic     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
52449992Sbostic 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
52549992Sbostic 	if (t->t_dflg & F_STDERR)
52649992Sbostic 	    pads(STRand);
52749992Sbostic 	pads(STRspace);
52849992Sbostic 	pads(t->t_drit);
52949992Sbostic     }
5301302Sbill }
5311302Sbill 
53249992Sbostic static void
5331302Sbill pads(cp)
53449992Sbostic     Char   *cp;
5351302Sbill {
53649992Sbostic     register int i;
5371302Sbill 
53849992Sbostic     /*
53949992Sbostic      * Avoid the Quoted Space alias hack! Reported by:
54049992Sbostic      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
54149992Sbostic      */
54249992Sbostic     if (cp[0] == STRQNULL[0])
54349992Sbostic 	cp++;
54449992Sbostic 
54549992Sbostic     i = Strlen(cp);
54649992Sbostic 
54749992Sbostic     if (cmdlen >= PMAXLEN)
54849992Sbostic 	return;
54949992Sbostic     if (cmdlen + i >= PMAXLEN) {
55049992Sbostic 	(void) Strcpy(cmdp, STRsp3dots);
55149992Sbostic 	cmdlen = PMAXLEN;
55249992Sbostic 	cmdp += 4;
55349992Sbostic 	return;
55449992Sbostic     }
55549992Sbostic     (void) Strcpy(cmdp, cp);
55649992Sbostic     cmdp += i;
55749992Sbostic     cmdlen += i;
5581302Sbill }
5591302Sbill 
5601302Sbill /*
5611302Sbill  * psavejob - temporarily save the current job on a one level stack
5621302Sbill  *	so another job can be created.  Used for { } in exp6
5631302Sbill  *	and `` in globbing.
5641302Sbill  */
56549992Sbostic void
5661302Sbill psavejob()
5671302Sbill {
5681302Sbill 
56949992Sbostic     pholdjob = pcurrjob;
570*50040Schristos     pcurrjob = NULL;
5711302Sbill }
5721302Sbill 
5731302Sbill /*
5741302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
5751302Sbill  *	somewhere, but pendjob cleans up anyway.
5761302Sbill  */
57749992Sbostic void
5781302Sbill prestjob()
5791302Sbill {
5801302Sbill 
58149992Sbostic     pcurrjob = pholdjob;
582*50040Schristos     pholdjob = NULL;
5831302Sbill }
5841302Sbill 
5851302Sbill /*
5861302Sbill  * pendjob - indicate that a job (set of commands) has been completed
5871302Sbill  *	or is about to begin.
5881302Sbill  */
58949992Sbostic void
5901302Sbill pendjob()
5911302Sbill {
59249992Sbostic     register struct process *pp, *tp;
5931302Sbill 
59449992Sbostic     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
59549992Sbostic 	pp = pcurrjob;
59649992Sbostic 	while (pp->p_pid != pp->p_jobid)
59749992Sbostic 	    pp = pp->p_friends;
59849992Sbostic 	xprintf("[%d]", pp->p_index);
59949992Sbostic 	tp = pp;
60049992Sbostic 	do {
60149992Sbostic 	    xprintf(" %d", pp->p_pid);
60249992Sbostic 	    pp = pp->p_friends;
60349992Sbostic 	} while (pp != tp);
60449992Sbostic 	xprintf("\n");
60549992Sbostic     }
60649992Sbostic     pholdjob = pcurrjob = 0;
6071302Sbill }
6081302Sbill 
6091302Sbill /*
6101302Sbill  * pprint - print a job
6111302Sbill  */
61249992Sbostic static int
6131302Sbill pprint(pp, flag)
61449992Sbostic     register struct process *pp;
61549992Sbostic     bool    flag;
6161302Sbill {
61749992Sbostic     register status, reason;
61849992Sbostic     struct process *tp;
61949992Sbostic     extern char *linp, linbuf[];
62049992Sbostic     int     jobflags, pstatus;
62149992Sbostic     char   *format;
6221302Sbill 
62349992Sbostic     while (pp->p_pid != pp->p_jobid)
62449992Sbostic 	pp = pp->p_friends;
62549992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
62649992Sbostic 	pp->p_flags &= ~PPTIME;
62749992Sbostic 	pp->p_flags |= PTIME;
62849992Sbostic     }
62949992Sbostic     tp = pp;
63049992Sbostic     status = reason = -1;
63149992Sbostic     jobflags = 0;
63249992Sbostic     do {
63349992Sbostic 	jobflags |= pp->p_flags;
63449992Sbostic 	pstatus = pp->p_flags & PALLSTATES;
63549992Sbostic 	if (tp != pp && linp != linbuf && !(flag & FANCY) &&
63649992Sbostic 	    (pstatus == status && pp->p_reason == reason ||
63749992Sbostic 	     !(flag & REASON)))
63849992Sbostic 	    xprintf(" ");
63949992Sbostic 	else {
64049992Sbostic 	    if (tp != pp && linp != linbuf)
64149992Sbostic 		xprintf("\n");
64249992Sbostic 	    if (flag & NUMBER)
64349992Sbostic 		if (pp == tp)
64449992Sbostic 		    xprintf("[%d]%s %c ", pp->p_index,
64549992Sbostic 			    pp->p_index < 10 ? " " : "",
64649992Sbostic 			    pp == pcurrent ? '+' :
64749992Sbostic 			    (pp == pprevious ? '-' : ' '));
64849992Sbostic 		else
64949992Sbostic 		    xprintf("       ");
65049992Sbostic 	    if (flag & FANCY) {
65149992Sbostic 		xprintf("%5d ", pp->p_pid);
65249992Sbostic 	    }
65349992Sbostic 	    if (flag & (REASON | AREASON)) {
65449992Sbostic 		if (flag & NAME)
65549992Sbostic 		    format = "%-23s";
65649992Sbostic 		else
65749992Sbostic 		    format = "%s";
65849992Sbostic 		if (pstatus == status)
65949992Sbostic 		    if (pp->p_reason == reason) {
66049992Sbostic 			xprintf(format, "");
66149992Sbostic 			goto prcomd;
66249992Sbostic 		    }
66349992Sbostic 		    else
66449992Sbostic 			reason = pp->p_reason;
6651302Sbill 		else {
66649992Sbostic 		    status = pstatus;
66749992Sbostic 		    reason = pp->p_reason;
66849992Sbostic 		}
66949992Sbostic 		switch (status) {
6701302Sbill 
67149992Sbostic 		case PRUNNING:
67249992Sbostic 		    xprintf(format, "Running ");
67349992Sbostic 		    break;
6741302Sbill 
67549992Sbostic 		case PINTERRUPTED:
67649992Sbostic 		case PSTOPPED:
67749992Sbostic 		case PSIGNALED:
67849992Sbostic 		    if ((flag & (REASON | AREASON)) && reason != SIGINT
67949992Sbostic 			&& reason != SIGPIPE)
68049992Sbostic 			xprintf(format, mesg[pp->p_reason].pname);
68149992Sbostic 		    break;
6821302Sbill 
68349992Sbostic 		case PNEXITED:
68449992Sbostic 		case PAEXITED:
68549992Sbostic 		    if (flag & REASON)
68649992Sbostic 			if (pp->p_reason)
68749992Sbostic 			    xprintf("Exit %-16d", pp->p_reason);
68849992Sbostic 			else
68949992Sbostic 			    xprintf(format, "Done");
69049992Sbostic 		    break;
6911302Sbill 
69249992Sbostic 		default:
69349992Sbostic 		    xprintf("BUG: status=%-9o", status);
6941302Sbill 		}
69549992Sbostic 	    }
69649992Sbostic 	}
6971302Sbill prcomd:
69849992Sbostic 	if (flag & NAME) {
69949992Sbostic 	    xprintf("%s", short2str(pp->p_command));
70049992Sbostic 	    if (pp->p_flags & PPOU)
70149992Sbostic 		xprintf(" |");
70249992Sbostic 	    if (pp->p_flags & PDIAG)
70349992Sbostic 		xprintf("&");
7041302Sbill 	}
70549992Sbostic 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED)
70649992Sbostic 	    xprintf(" (core dumped)");
70749992Sbostic 	if (tp == pp->p_friends) {
70849992Sbostic 	    if (flag & AMPERSAND)
70949992Sbostic 		xprintf(" &");
71049992Sbostic 	    if (flag & JOBDIR &&
71149992Sbostic 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
71249992Sbostic 		xprintf(" (wd: ");
71349992Sbostic 		dtildepr(value(STRhome), tp->p_cwd->di_name);
71449992Sbostic 		xprintf(")");
71549992Sbostic 	    }
71649992Sbostic 	}
71749992Sbostic 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
71849992Sbostic 	    if (linp != linbuf)
71949992Sbostic 		xprintf("\n\t");
72049992Sbostic 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
72149992Sbostic 		    &pp->p_btime);
72249992Sbostic 	}
72349992Sbostic 	if (tp == pp->p_friends) {
72449992Sbostic 	    if (linp != linbuf)
72549992Sbostic 		xprintf("\n");
72649992Sbostic 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
72749992Sbostic 		xprintf("(wd now: ");
72849992Sbostic 		dtildepr(value(STRhome), dcwd->di_name);
72949992Sbostic 		xprintf(")\n");
73049992Sbostic 	    }
73149992Sbostic 	}
73249992Sbostic     } while ((pp = pp->p_friends) != tp);
73349992Sbostic     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
73449992Sbostic 	if (jobflags & NUMBER)
73549992Sbostic 	    xprintf("       ");
73649992Sbostic 	ptprint(tp);
73749992Sbostic     }
73849992Sbostic     return (jobflags);
7391302Sbill }
7401302Sbill 
74149992Sbostic static void
7421302Sbill ptprint(tp)
74349992Sbostic     register struct process *tp;
7441302Sbill {
74549992Sbostic     struct timeval tetime, diff;
74649992Sbostic     static struct timeval ztime;
74749992Sbostic     struct rusage ru;
74849992Sbostic     static struct rusage zru;
74949992Sbostic     register struct process *pp = tp;
7501302Sbill 
75149992Sbostic     ru = zru;
75249992Sbostic     tetime = ztime;
75349992Sbostic     do {
75449992Sbostic 	ruadd(&ru, &pp->p_rusage);
75549992Sbostic 	tvsub(&diff, &pp->p_etime, &pp->p_btime);
75649992Sbostic 	if (timercmp(&diff, &tetime, >))
75749992Sbostic 	    tetime = diff;
75849992Sbostic     } while ((pp = pp->p_friends) != tp);
75949992Sbostic     prusage(&zru, &ru, &tetime, &ztime);
7601302Sbill }
7611302Sbill 
7621302Sbill /*
7631302Sbill  * dojobs - print all jobs
7641302Sbill  */
76549992Sbostic void
7661302Sbill dojobs(v)
76749992Sbostic     Char  **v;
7681302Sbill {
76949992Sbostic     register struct process *pp;
77049992Sbostic     register int flag = NUMBER | NAME | REASON;
77149992Sbostic     int     i;
7721302Sbill 
77349992Sbostic     if (chkstop)
77449992Sbostic 	chkstop = 2;
77549992Sbostic     if (*++v) {
77649992Sbostic 	if (v[1] || !eq(*v, STRml))
77749992Sbostic 	    stderror(ERR_JOBS);
77849992Sbostic 	flag |= FANCY | JOBDIR;
77949992Sbostic     }
78049992Sbostic     for (i = 1; i <= pmaxindex; i++)
78149992Sbostic 	for (pp = proclist.p_next; pp; pp = pp->p_next)
78249992Sbostic 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
78349992Sbostic 		pp->p_flags &= ~PNEEDNOTE;
78449992Sbostic 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
78549992Sbostic 		    pflush(pp);
78649992Sbostic 		break;
78749992Sbostic 	    }
7881302Sbill }
7891302Sbill 
7901302Sbill /*
7911302Sbill  * dofg - builtin - put the job into the foreground
7921302Sbill  */
79349992Sbostic void
7941302Sbill dofg(v)
79549992Sbostic     Char  **v;
7961302Sbill {
79749992Sbostic     register struct process *pp;
7981302Sbill 
79949992Sbostic     okpcntl();
80049992Sbostic     ++v;
80149992Sbostic     do {
80249992Sbostic 	pp = pfind(*v);
80349992Sbostic 	pstart(pp, 1);
80449992Sbostic 	pjwait(pp);
80549992Sbostic     } while (*v && *++v);
8061302Sbill }
8071302Sbill 
8081302Sbill /*
8091302Sbill  * %... - builtin - put the job into the foreground
8101302Sbill  */
81149992Sbostic void
8121302Sbill dofg1(v)
81349992Sbostic     Char  **v;
8141302Sbill {
81549992Sbostic     register struct process *pp;
8161302Sbill 
81749992Sbostic     okpcntl();
81849992Sbostic     pp = pfind(v[0]);
81949992Sbostic     pstart(pp, 1);
82049992Sbostic     pjwait(pp);
8211302Sbill }
8221302Sbill 
8231302Sbill /*
8241302Sbill  * dobg - builtin - put the job into the background
8251302Sbill  */
82649992Sbostic void
8271302Sbill dobg(v)
82849992Sbostic     Char  **v;
8291302Sbill {
83049992Sbostic     register struct process *pp;
8311302Sbill 
83249992Sbostic     okpcntl();
83349992Sbostic     ++v;
83449992Sbostic     do {
83549992Sbostic 	pp = pfind(*v);
83649992Sbostic 	pstart(pp, 0);
83749992Sbostic     } while (*v && *++v);
8381302Sbill }
8391302Sbill 
8401302Sbill /*
8411302Sbill  * %... & - builtin - put the job into the background
8421302Sbill  */
84349992Sbostic void
8441302Sbill dobg1(v)
84549992Sbostic     Char  **v;
8461302Sbill {
84749992Sbostic     register struct process *pp;
8481302Sbill 
84949992Sbostic     pp = pfind(v[0]);
85049992Sbostic     pstart(pp, 0);
8511302Sbill }
8521302Sbill 
8531302Sbill /*
8541302Sbill  * dostop - builtin - stop the job
8551302Sbill  */
85649992Sbostic void
8571302Sbill dostop(v)
85849992Sbostic     Char  **v;
8591302Sbill {
86049992Sbostic     pkill(++v, SIGSTOP);
8611302Sbill }
8621302Sbill 
8631302Sbill /*
8641302Sbill  * dokill - builtin - superset of kill (1)
8651302Sbill  */
86649992Sbostic void
8671302Sbill dokill(v)
86849992Sbostic     Char  **v;
8691302Sbill {
87049992Sbostic     register int signum, len = 0;
87149992Sbostic     register char *name;
8721302Sbill 
87349992Sbostic     v++;
87449992Sbostic     if (v[0] && v[0][0] == '-') {
87549992Sbostic 	if (v[0][1] == 'l') {
87649992Sbostic 	    for (signum = 1; signum <= NSIG; signum++) {
87749992Sbostic 		if ((name = mesg[signum].iname) != NULL) {
87849992Sbostic 		    len += strlen(name) + 1;
87949992Sbostic 		    if (len >= 80 - 1) {
88049992Sbostic 			xprintf("\n");
88149992Sbostic 			len = strlen(name) + 1;
88249992Sbostic 		    }
88349992Sbostic 		    xprintf("%s ", name);
8841302Sbill 		}
88549992Sbostic 	    }
88649992Sbostic 	    xprintf("\n");
88749992Sbostic 	    return;
88849992Sbostic 	}
88949992Sbostic 	if (Isdigit(v[0][1])) {
89049992Sbostic 	    signum = atoi(short2str(v[0] + 1));
89149992Sbostic 	    if (signum < 0 || signum > NSIG)
89249992Sbostic 		stderror(ERR_NAME | ERR_BADSIG);
89349992Sbostic 	}
89449992Sbostic 	else {
89549992Sbostic 	    for (signum = 1; signum <= NSIG; signum++)
89649992Sbostic 		if (mesg[signum].iname &&
89749992Sbostic 		    eq(&v[0][1], str2short(mesg[signum].iname)))
89849992Sbostic 		    goto gotsig;
89949992Sbostic 	    setname(short2str(&v[0][1]));
90049992Sbostic 	    stderror(ERR_NAME | ERR_UNKSIG);
90149992Sbostic 	}
9021302Sbill gotsig:
90349992Sbostic 	v++;
90449992Sbostic     }
90549992Sbostic     else
90649992Sbostic 	signum = SIGTERM;
90749992Sbostic     pkill(v, signum);
9081302Sbill }
9091302Sbill 
91049992Sbostic static void
9111302Sbill pkill(v, signum)
91249992Sbostic     Char  **v;
91349992Sbostic     int     signum;
9141302Sbill {
91549992Sbostic     register struct process *pp, *np;
91649992Sbostic     register int jobflags = 0;
91749992Sbostic     int     pid, err1 = 0;
91850028Sbostic     sigset_t omask;
91949992Sbostic     Char   *cp;
9201302Sbill 
92149992Sbostic     omask = sigmask(SIGCHLD);
92249992Sbostic     if (setintr)
92349992Sbostic 	omask |= sigmask(SIGINT);
92449992Sbostic     omask = sigblock(omask) & ~omask;
92549992Sbostic     gflag = 0, tglob(v);
92649992Sbostic     if (gflag) {
92749992Sbostic 	v = globall(v);
92849992Sbostic 	if (v == 0)
92949992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
93049992Sbostic     }
93149992Sbostic     else {
93249992Sbostic 	v = gargv = saveblk(v);
93349992Sbostic 	trim(v);
93449992Sbostic     }
9351302Sbill 
93649992Sbostic     while (v && (cp = *v)) {
93749992Sbostic 	if (*cp == '%') {
93849992Sbostic 	    np = pp = pfind(cp);
93949992Sbostic 	    do
94049992Sbostic 		jobflags |= np->p_flags;
94149992Sbostic 	    while ((np = np->p_friends) != pp);
94249992Sbostic 	    switch (signum) {
94349992Sbostic 
94449992Sbostic 	    case SIGSTOP:
94549992Sbostic 	    case SIGTSTP:
94649992Sbostic 	    case SIGTTIN:
94749992Sbostic 	    case SIGTTOU:
94849992Sbostic 		if ((jobflags & PRUNNING) == 0) {
94949992Sbostic 		    xprintf("%s: Already suspended\n", short2str(cp));
95049992Sbostic 		    err1++;
95149992Sbostic 		    goto cont;
9521302Sbill 		}
95349992Sbostic 		break;
95449992Sbostic 		/*
95549992Sbostic 		 * suspend a process, kill -CONT %, then type jobs; the shell
95649992Sbostic 		 * says it is suspended, but it is running; thanks jaap..
95749992Sbostic 		 */
95849992Sbostic 	    case SIGCONT:
95949992Sbostic 		pstart(pp, 0);
96049992Sbostic 		goto cont;
96149992Sbostic 	    }
96249992Sbostic 	    if (killpg((pid_t) pp->p_jobid, signum) < 0) {
96349992Sbostic 		xprintf("%s: %s\n", short2str(cp), strerror(errno));
96449992Sbostic 		err1++;
96549992Sbostic 	    }
96649992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
96749992Sbostic 		(void) killpg((pid_t) pp->p_jobid, SIGCONT);
96849992Sbostic 	}
96949992Sbostic 	else if (!(Isdigit(*cp) || *cp == '-'))
97049992Sbostic 	    stderror(ERR_NAME | ERR_JOBARGS);
97149992Sbostic 	else {
97249992Sbostic 	    pid = atoi(short2str(cp));
97349992Sbostic 	    if (kill((pid_t) pid, signum) < 0) {
97449992Sbostic 		xprintf("%d: %s\n", pid, strerror(errno));
97549992Sbostic 		err1++;
97649992Sbostic 		goto cont;
97749992Sbostic 	    }
97849992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
97949992Sbostic 		(void) kill((pid_t) pid, SIGCONT);
98049992Sbostic 	}
9811302Sbill cont:
98249992Sbostic 	v++;
98349992Sbostic     }
98449992Sbostic     if (gargv)
98549992Sbostic 	blkfree(gargv), gargv = 0;
98649992Sbostic     (void) sigsetmask(omask);
98749992Sbostic     if (err1)
98849992Sbostic 	stderror(ERR_SILENT);
9891302Sbill }
9901302Sbill 
9911302Sbill /*
9921302Sbill  * pstart - start the job in foreground/background
9931302Sbill  */
99449992Sbostic void
9951302Sbill pstart(pp, foregnd)
99649992Sbostic     register struct process *pp;
99749992Sbostic     int     foregnd;
9981302Sbill {
99949992Sbostic     register struct process *np;
100050028Sbostic     sigset_t omask;
100149992Sbostic     long    jobflags = 0;
10021302Sbill 
100349992Sbostic     omask = sigblock(sigmask(SIGCHLD));
100449992Sbostic     np = pp;
100549992Sbostic     do {
100649992Sbostic 	jobflags |= np->p_flags;
100749992Sbostic 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
100849992Sbostic 	    np->p_flags |= PRUNNING;
100949992Sbostic 	    np->p_flags &= ~PSTOPPED;
101049992Sbostic 	    if (foregnd)
101149992Sbostic 		np->p_flags |= PFOREGND;
101249992Sbostic 	    else
101349992Sbostic 		np->p_flags &= ~PFOREGND;
101449992Sbostic 	}
101549992Sbostic     } while ((np = np->p_friends) != pp);
101649992Sbostic     if (!foregnd)
101749992Sbostic 	pclrcurr(pp);
101849992Sbostic     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
101949992Sbostic     if (foregnd)
102049992Sbostic 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
102149992Sbostic     if (jobflags & PSTOPPED)
102249992Sbostic 	(void) killpg((pid_t) pp->p_jobid, SIGCONT);
102349992Sbostic     (void) sigsetmask(omask);
10241302Sbill }
10251302Sbill 
102649992Sbostic void
10271302Sbill panystop(neednl)
102849992Sbostic     bool    neednl;
10291302Sbill {
103049992Sbostic     register struct process *pp;
10311302Sbill 
103249992Sbostic     chkstop = 2;
103349992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
103449992Sbostic 	if (pp->p_flags & PSTOPPED)
103549992Sbostic 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
10361302Sbill }
10371302Sbill 
10381302Sbill struct process *
10391302Sbill pfind(cp)
104049992Sbostic     Char   *cp;
10411302Sbill {
104249992Sbostic     register struct process *pp, *np;
10431302Sbill 
104449992Sbostic     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1045*50040Schristos 	if (pcurrent == NULL)
104649992Sbostic 	    stderror(ERR_NAME | ERR_JOBCUR);
104749992Sbostic 	return (pcurrent);
104849992Sbostic     }
104949992Sbostic     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1050*50040Schristos 	if (pprevious == NULL)
105149992Sbostic 	    stderror(ERR_NAME | ERR_JOBPREV);
105249992Sbostic 	return (pprevious);
105349992Sbostic     }
105449992Sbostic     if (Isdigit(cp[1])) {
105549992Sbostic 	int     idx = atoi(short2str(cp + 1));
105649992Sbostic 
10571302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
105849992Sbostic 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
105949992Sbostic 		return (pp);
106049992Sbostic 	stderror(ERR_NAME | ERR_NOSUCHJOB);
106149992Sbostic     }
1062*50040Schristos     np = NULL;
106349992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
106449992Sbostic 	if (pp->p_pid == pp->p_jobid) {
106549992Sbostic 	    if (cp[1] == '?') {
106649992Sbostic 		register Char *dp;
106749992Sbostic 
106849992Sbostic 		for (dp = pp->p_command; *dp; dp++) {
106949992Sbostic 		    if (*dp != cp[2])
107049992Sbostic 			continue;
107149992Sbostic 		    if (prefix(cp + 2, dp))
107249992Sbostic 			goto match;
10731302Sbill 		}
107449992Sbostic 	    }
107549992Sbostic 	    else if (prefix(cp + 1, pp->p_command)) {
107649992Sbostic 	match:
107749992Sbostic 		if (np)
107849992Sbostic 		    stderror(ERR_NAME | ERR_AMBIG);
107949992Sbostic 		np = pp;
108049992Sbostic 	    }
108149992Sbostic 	}
108249992Sbostic     if (np)
108349992Sbostic 	return (np);
108449992Sbostic     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
108549992Sbostic     /* NOTREACHED */
108649992Sbostic     return (0);
10871302Sbill }
10881302Sbill 
108949992Sbostic 
10901302Sbill /*
10912357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
10921302Sbill  */
109349992Sbostic static struct process *
10941302Sbill pgetcurr(pp)
109549992Sbostic     register struct process *pp;
10961302Sbill {
109749992Sbostic     register struct process *np;
1098*50040Schristos     register struct process *xp = NULL;
10991302Sbill 
110049992Sbostic     for (np = proclist.p_next; np; np = np->p_next)
110149992Sbostic 	if (np != pcurrent && np != pp && np->p_pid &&
110249992Sbostic 	    np->p_pid == np->p_jobid) {
110349992Sbostic 	    if (np->p_flags & PSTOPPED)
110449992Sbostic 		return (np);
1105*50040Schristos 	    if (xp == NULL)
110649992Sbostic 		xp = np;
110749992Sbostic 	}
110849992Sbostic     return (xp);
11091302Sbill }
11101302Sbill 
11111302Sbill /*
11121302Sbill  * donotify - flag the job so as to report termination asynchronously
11131302Sbill  */
111449992Sbostic void
11151302Sbill donotify(v)
111649992Sbostic     Char  **v;
11171302Sbill {
111849992Sbostic     register struct process *pp;
11191302Sbill 
112049992Sbostic     pp = pfind(*++v);
112149992Sbostic     pp->p_flags |= PNOTIFY;
11221302Sbill }
11231302Sbill 
11241302Sbill /*
11251302Sbill  * Do the fork and whatever should be done in the child side that
11261302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
11271302Sbill  * Also do everything that needs any signals fiddled with in the parent side
11281302Sbill  *
11291302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
11301302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
11311302Sbill  *	 0:	already have tty; manipulate process pgrps only
11321302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
11331302Sbill  * It is usually just the value of tpgrp.
11341302Sbill  */
113549992Sbostic 
113649992Sbostic int
11371302Sbill pfork(t, wanttty)
113849992Sbostic     struct command *t;		/* command we are forking for */
113949992Sbostic     int     wanttty;
11401302Sbill {
114149992Sbostic     register int pid;
114249992Sbostic     bool    ignint = 0;
114349992Sbostic     int     pgrp;
114450028Sbostic     sigset_t omask;
11451302Sbill 
114649992Sbostic     /*
114749992Sbostic      * A child will be uninterruptible only under very special conditions.
114849992Sbostic      * Remember that the semantics of '&' is implemented by disconnecting the
114949992Sbostic      * process from the tty so signals do not need to ignored just for '&'.
115049992Sbostic      * Thus signals are set to default action for children unless: we have had
115149992Sbostic      * an "onintr -" (then specifically ignored) we are not playing with
115249992Sbostic      * signals (inherit action)
115349992Sbostic      */
115449992Sbostic     if (setintr)
115549992Sbostic 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
115649992Sbostic 	    || (gointr && eq(gointr, STRminus));
115749992Sbostic     /*
115849992Sbostic      * Check for maximum nesting of 16 processes to avoid Forking loops
115949992Sbostic      */
116049992Sbostic     if (child == 16)
116149992Sbostic 	stderror(ERR_NESTING, 16);
116249992Sbostic     /*
116349992Sbostic      * Hold SIGCHLD until we have the process installed in our table.
116449992Sbostic      */
116549992Sbostic     omask = sigblock(sigmask(SIGCHLD));
116649992Sbostic     while ((pid = fork()) < 0)
116749992Sbostic 	if (setintr == 0)
116849992Sbostic 	    (void) sleep(FORKSLEEP);
116949992Sbostic 	else {
117049992Sbostic 	    (void) sigsetmask(omask);
117149992Sbostic 	    stderror(ERR_NOPROC);
117249992Sbostic 	}
117349992Sbostic     if (pid == 0) {
117449992Sbostic 	settimes();
117549992Sbostic 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
117649992Sbostic 	pflushall();
1177*50040Schristos 	pcurrjob = NULL;
117849992Sbostic 	child++;
117949992Sbostic 	if (setintr) {
118049992Sbostic 	    setintr = 0;	/* until I think otherwise */
118149992Sbostic 	    /*
118249992Sbostic 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
118349992Sbostic 	     * -" seen.
118449992Sbostic 	     */
118549992Sbostic 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
118649992Sbostic 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
118749992Sbostic 	    if (wanttty >= 0) {
118849992Sbostic 		/* make stoppable */
118949992Sbostic 		(void) signal(SIGTSTP, SIG_DFL);
119049992Sbostic 		(void) signal(SIGTTIN, SIG_DFL);
119149992Sbostic 		(void) signal(SIGTTOU, SIG_DFL);
119249992Sbostic 	    }
119349992Sbostic 	    (void) signal(SIGTERM, parterm);
119449992Sbostic 	}
119549992Sbostic 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
119649992Sbostic 	    (void) signal(SIGINT, SIG_IGN);
119749992Sbostic 	    (void) signal(SIGQUIT, SIG_IGN);
119849992Sbostic 	}
119949992Sbostic 	pgetty(wanttty, pgrp);
12001302Sbill 	/*
120149992Sbostic 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
120249992Sbostic 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
120349992Sbostic 	 * to know about nice/nohup/time
12041302Sbill 	 */
120549992Sbostic 	if (t->t_dflg & F_NOHUP)
120649992Sbostic 	    (void) signal(SIGHUP, SIG_IGN);
120749992Sbostic 	if (t->t_dflg & F_NICE)
120849992Sbostic 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
120949992Sbostic     }
121049992Sbostic     else {
121149992Sbostic 	if (wanttty >= 0)
121249992Sbostic 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
121349992Sbostic 	palloc(pid, t);
121449992Sbostic 	(void) sigsetmask(omask);
121549992Sbostic     }
12161302Sbill 
121749992Sbostic     return (pid);
12181302Sbill }
12191302Sbill 
122049992Sbostic static void
12211302Sbill okpcntl()
12221302Sbill {
122349992Sbostic     if (tpgrp == -1)
122449992Sbostic 	stderror(ERR_JOBCONTROL);
122549992Sbostic     if (tpgrp == 0)
122649992Sbostic 	stderror(ERR_JOBCTRLSUB);
122749992Sbostic }
12281302Sbill 
122949992Sbostic /*
123049992Sbostic  * if we don't have vfork(), things can still go in the wrong order
123149992Sbostic  * resulting in the famous 'Stopped (tty output)'. But some systems
123249992Sbostic  * don't permit the setpgid() call, (these are more recent secure
123349992Sbostic  * systems such as ibm's aix). Then we'd rather print an error message
123449992Sbostic  * than hang the shell!
123549992Sbostic  * I am open to suggestions how to fix that.
123649992Sbostic  */
123749992Sbostic void
123849992Sbostic pgetty(wanttty, pgrp)
123949992Sbostic     int     wanttty, pgrp;
124049992Sbostic {
124150028Sbostic     sigset_t omask = 0;
124249992Sbostic 
124349992Sbostic     /*
124449992Sbostic      * christos: I am blocking the tty signals till I've set things
124549992Sbostic      * correctly....
124649992Sbostic      */
124749992Sbostic     if (wanttty > 0)
124849992Sbostic 	omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
124949992Sbostic     /*
125049992Sbostic      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
125149992Sbostic      * Don't check for tpgrp >= 0 so even non-interactive shells give
125249992Sbostic      * background jobs process groups Same for the comparison in the other part
125349992Sbostic      * of the #ifdef
125449992Sbostic      */
125549992Sbostic     if (wanttty >= 0)
125649992Sbostic 	if (setpgid(0, pgrp) == -1) {
125749992Sbostic 	    xprintf("csh: setpgid error.\n");
125849992Sbostic 	    xexit(0);
125949992Sbostic 	}
126049992Sbostic 
126149992Sbostic     if (wanttty > 0) {
126249992Sbostic 	(void) tcsetpgrp(FSHTTY, pgrp);
126349992Sbostic 	(void) sigsetmask(omask);
126449992Sbostic     }
126549992Sbostic 
126649992Sbostic     if (tpgrp > 0)
126749992Sbostic 	tpgrp = 0;		/* gave tty away */
12681302Sbill }
1269