xref: /csrg-svn/bin/csh/proc.c (revision 50023)
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*50023Sbostic static char sccsid[] = "@(#)proc.c	5.17 (Berkeley) 06/07/91";
1047823Sbostic #endif /* not lint */
111302Sbill 
12*50023Sbostic #include "csh.h"
13*50023Sbostic #include "dir.h"
14*50023Sbostic #include "proc.h"
15*50023Sbostic #include "extern.h"
1613590Swnj #include <sys/wait.h>
171302Sbill 
181302Sbill #define BIGINDEX	9	/* largest desirable job index */
191302Sbill 
2049992Sbostic static struct rusage zru;
2149992Sbostic 
2249992Sbostic static void pflushall();
2349992Sbostic static void pflush();
2449992Sbostic static void pclrcurr();
2549992Sbostic static void padd();
2649992Sbostic static int pprint();
2749992Sbostic static void ptprint();
2849992Sbostic static void pads();
2949992Sbostic static void pkill();
3049992Sbostic static struct process *pgetcurr();
3149992Sbostic static void okpcntl();
3249992Sbostic 
331302Sbill /*
341302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
351302Sbill  *	indicating that at least one child has terminated or stopped
361302Sbill  *	thus at least one wait system call will definitely return a
371302Sbill  *	childs status.  Top level routines (like pwait) must be sure
381302Sbill  *	to mask interrupts when playing with the proclist data structures!
391302Sbill  */
40*50023Sbostic /* ARGUSED */
4146657Sbostic void
42*50023Sbostic pchild(notused)
43*50023Sbostic 	int notused;
441302Sbill {
4549992Sbostic     register struct process *pp;
4649992Sbostic     register struct process *fp;
4749992Sbostic     register int pid;
4849992Sbostic     extern int insource;
4949992Sbostic     union wait w;
5049992Sbostic     int     jobflags;
5149992Sbostic     struct rusage ru;
521302Sbill 
531302Sbill loop:
5449992Sbostic     errno = 0;			/* reset, just in case */
5549992Sbostic     pid = wait3(&w.w_status,
5649992Sbostic        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
5749992Sbostic 
5849992Sbostic     if (pid <= 0) {
5949992Sbostic 	if (errno == EINTR) {
6049992Sbostic 	    errno = 0;
6149992Sbostic 	    goto loop;
621302Sbill 	}
6349992Sbostic 	pnoprocesses = pid == -1;
6449992Sbostic 	return;
6549992Sbostic     }
6649992Sbostic     for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
6749992Sbostic 	if (pid == pp->p_pid)
6849992Sbostic 	    goto found;
6949992Sbostic     goto loop;
701302Sbill found:
7149992Sbostic     if (pid == atoi(short2str(value(STRchild))))
7249992Sbostic 	unsetv(STRchild);
7349992Sbostic     pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
7449992Sbostic     if (WIFSTOPPED(w)) {
7549992Sbostic 	pp->p_flags |= PSTOPPED;
7649992Sbostic 	pp->p_reason = w.w_stopsig;
7749992Sbostic     }
7849992Sbostic     else {
7949992Sbostic 	if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
8049992Sbostic 	    (void) gettimeofday(&pp->p_etime, (struct timezone *) 0);
8149992Sbostic 
8249992Sbostic 	pp->p_rusage = ru;
8349992Sbostic 	if (WIFSIGNALED(w)) {
8449992Sbostic 	    if (w.w_termsig == SIGINT)
8549992Sbostic 		pp->p_flags |= PINTERRUPTED;
8649992Sbostic 	    else
8749992Sbostic 		pp->p_flags |= PSIGNALED;
8849992Sbostic 	    if (w.w_coredump)
8949992Sbostic 		pp->p_flags |= PDUMPED;
9049992Sbostic 	    pp->p_reason = w.w_termsig;
911302Sbill 	}
9249992Sbostic 	else {
9349992Sbostic 	    pp->p_reason = w.w_retcode;
9449992Sbostic 	    if (pp->p_reason != 0)
9549992Sbostic 		pp->p_flags |= PAEXITED;
9649992Sbostic 	    else
9749992Sbostic 		pp->p_flags |= PNEXITED;
9849992Sbostic 	}
9949992Sbostic     }
10049992Sbostic     jobflags = 0;
10149992Sbostic     fp = pp;
10249992Sbostic     do {
10349992Sbostic 	if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
10449992Sbostic 	    !child && adrof(STRtime) &&
10549992Sbostic 	    fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
10649992Sbostic 	    >= atoi(short2str(value(STRtime))))
10749992Sbostic 	    fp->p_flags |= PTIME;
10849992Sbostic 	jobflags |= fp->p_flags;
10949992Sbostic     } while ((fp = fp->p_friends) != pp);
11049992Sbostic     pp->p_flags &= ~PFOREGND;
11149992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
11249992Sbostic 	pp->p_flags &= ~PPTIME;
11349992Sbostic 	pp->p_flags |= PTIME;
11449992Sbostic     }
11549992Sbostic     if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
1161302Sbill 	fp = pp;
1171302Sbill 	do {
11849992Sbostic 	    if (fp->p_flags & PSTOPPED)
11949992Sbostic 		fp->p_flags |= PREPORTED;
1201302Sbill 	} while ((fp = fp->p_friends) != pp);
12149992Sbostic 	while (fp->p_pid != fp->p_jobid)
12249992Sbostic 	    fp = fp->p_friends;
12349992Sbostic 	if (jobflags & PSTOPPED) {
12449992Sbostic 	    if (pcurrent && pcurrent != fp)
12549992Sbostic 		pprevious = pcurrent;
12649992Sbostic 	    pcurrent = fp;
1271302Sbill 	}
12849992Sbostic 	else
12949992Sbostic 	    pclrcurr(fp);
13049992Sbostic 	if (jobflags & PFOREGND) {
13149992Sbostic 	    if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
13249992Sbostic #ifdef IIASA
13349992Sbostic 		jobflags & PAEXITED ||
13449992Sbostic #endif
13549992Sbostic 		!eq(dcwd->di_name, fp->p_cwd->di_name)) {
13649992Sbostic 		;		/* print in pjwait */
13749992Sbostic 	    }
13849992Sbostic 	    /* PWP: print a newline after ^C */
13949992Sbostic 	    else if (jobflags & PINTERRUPTED)
14049992Sbostic 		xputchar('\r' | QUOTE), xputchar('\n');
1411302Sbill 	}
14249992Sbostic 	else {
14349992Sbostic 	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
14449992Sbostic 		xputchar('\r' | QUOTE), xputchar('\n');
14549992Sbostic 		(void) pprint(pp, NUMBER | NAME | REASON);
14649992Sbostic 		if ((jobflags & PSTOPPED) == 0)
14749992Sbostic 		    pflush(pp);
14849992Sbostic 	    }
14949992Sbostic 	    else {
15049992Sbostic 		fp->p_flags |= PNEEDNOTE;
15149992Sbostic 		neednote++;
15249992Sbostic 	    }
15349992Sbostic 	}
15449992Sbostic     }
15549992Sbostic     goto loop;
1561302Sbill }
1571302Sbill 
15849992Sbostic void
1591302Sbill pnote()
1601302Sbill {
16149992Sbostic     register struct process *pp;
16249992Sbostic     int     flags;
16349992Sbostic     sigmask_t omask;
1641302Sbill 
16549992Sbostic     neednote = 0;
16649992Sbostic     for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
16749992Sbostic 	if (pp->p_flags & PNEEDNOTE) {
16849992Sbostic 	    omask = sigblock(sigmask(SIGCHLD));
16949992Sbostic 	    pp->p_flags &= ~PNEEDNOTE;
17049992Sbostic 	    flags = pprint(pp, NUMBER | NAME | REASON);
17149992Sbostic 	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
17249992Sbostic 		pflush(pp);
17349992Sbostic 	    (void) sigsetmask(omask);
1741302Sbill 	}
17549992Sbostic     }
1761302Sbill }
1771302Sbill 
1781302Sbill /*
1791302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1801302Sbill  *	of current and previous job indicators.
1811302Sbill  */
18249992Sbostic void
1831302Sbill pwait()
1841302Sbill {
18549992Sbostic     register struct process *fp, *pp;
18649992Sbostic     sigmask_t omask;
1871302Sbill 
18849992Sbostic     /*
18949992Sbostic      * Here's where dead procs get flushed.
19049992Sbostic      */
19149992Sbostic     omask = sigblock(sigmask(SIGCHLD));
19249992Sbostic     for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
19349992Sbostic 	if (pp->p_pid == 0) {
19449992Sbostic 	    fp->p_next = pp->p_next;
19549992Sbostic 	    xfree((ptr_t) pp->p_command);
19649992Sbostic 	    if (pp->p_cwd && --pp->p_cwd->di_count == 0)
19749992Sbostic 		if (pp->p_cwd->di_next == 0)
19849992Sbostic 		    dfree(pp->p_cwd);
19949992Sbostic 	    xfree((ptr_t) pp);
20049992Sbostic 	    pp = fp;
20149992Sbostic 	}
20249992Sbostic     (void) sigsetmask(omask);
20349992Sbostic     pjwait(pcurrjob);
2041302Sbill }
2051302Sbill 
20649992Sbostic 
2071302Sbill /*
2081302Sbill  * pjwait - wait for a job to finish or become stopped
2091302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
2101302Sbill  */
21149992Sbostic void
2121302Sbill pjwait(pp)
21349992Sbostic     register struct process *pp;
2141302Sbill {
21549992Sbostic     register struct process *fp;
21649992Sbostic     int     jobflags, reason;
21749992Sbostic     sigmask_t omask;
2181302Sbill 
21949992Sbostic     while (pp->p_pid != pp->p_jobid)
22049992Sbostic 	pp = pp->p_friends;
22149992Sbostic     fp = pp;
22249992Sbostic 
22349992Sbostic     do {
22449992Sbostic 	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
22549992Sbostic 	    xprintf("BUG: waiting for background job!\n");
22649992Sbostic     } while ((fp = fp->p_friends) != pp);
22749992Sbostic     /*
22849992Sbostic      * Now keep pausing as long as we are not interrupted (SIGINT), and the
22949992Sbostic      * target process, or any of its friends, are running
23049992Sbostic      */
23149992Sbostic     fp = pp;
23249992Sbostic     omask = sigblock(sigmask(SIGCHLD));
23349992Sbostic     for (;;) {
23449992Sbostic 	(void) sigblock(sigmask(SIGCHLD));
23549992Sbostic 	jobflags = 0;
23649992Sbostic 	do
23749992Sbostic 	    jobflags |= fp->p_flags;
23849992Sbostic 	while ((fp = (fp->p_friends)) != pp);
23949992Sbostic 	if ((jobflags & PRUNNING) == 0)
24049992Sbostic 	    break;
24149992Sbostic #ifdef JOBDEBUG
24249992Sbostic 	xprintf("starting to sigpause for  SIGCHLD on %d\n", fp->p_pid);
24349992Sbostic #endif				/* JOBDEBUG */
24449992Sbostic 	(void) sigpause(omask & ~sigmask(SIGCHLD));
24549992Sbostic     }
24649992Sbostic     (void) sigsetmask(omask);
24749992Sbostic     if (tpgrp > 0)		/* get tty back */
24849992Sbostic 	(void) tcsetpgrp(FSHTTY, tpgrp);
24949992Sbostic     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
25049992Sbostic 	!eq(dcwd->di_name, fp->p_cwd->di_name)) {
25149992Sbostic 	if (jobflags & PSTOPPED) {
25249992Sbostic 	    xprintf("\n");
25349992Sbostic 	    if (adrof(STRlistjobs)) {
25449992Sbostic 		Char   *jobcommand[3];
25549992Sbostic 
25649992Sbostic 		jobcommand[0] = STRjobs;
25749992Sbostic 		if (eq(value(STRlistjobs), STRlong))
25849992Sbostic 		    jobcommand[1] = STRml;
25949992Sbostic 		else
26049992Sbostic 		    jobcommand[1] = NULL;
26149992Sbostic 		jobcommand[2] = NULL;
26249992Sbostic 
26349992Sbostic 		dojobs(jobcommand);
26449992Sbostic 		(void) pprint(pp, SHELLDIR);
26549992Sbostic 	    }
26649992Sbostic 	    else
26749992Sbostic 		(void) pprint(pp, AREASON | SHELLDIR);
2681302Sbill 	}
26949992Sbostic 	else
27049992Sbostic 	    (void) pprint(pp, AREASON | SHELLDIR);
27149992Sbostic     }
27249992Sbostic     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
27349992Sbostic 	(!gointr || !eq(gointr, STRminus))) {
27449992Sbostic 	if ((jobflags & PSTOPPED) == 0)
27549992Sbostic 	    pflush(pp);
27649992Sbostic 	pintr1(0);
27749992Sbostic 	/* NOTREACHED */
27849992Sbostic     }
27949992Sbostic     reason = 0;
28049992Sbostic     fp = pp;
28149992Sbostic     do {
28249992Sbostic 	if (fp->p_reason)
28349992Sbostic 	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
28449992Sbostic 		fp->p_reason | META : fp->p_reason;
28549992Sbostic     } while ((fp = fp->p_friends) != pp);
28649992Sbostic     if ((reason != 0) && (adrof(STRprintexitvalue)))
28749992Sbostic 	xprintf("Exit %d\n", reason);
28849992Sbostic     set(STRstatus, putn(reason));
28949992Sbostic     if (reason && exiterr)
29049992Sbostic 	exitstat();
29149992Sbostic     pflush(pp);
2921302Sbill }
2931302Sbill 
2941302Sbill /*
2951302Sbill  * dowait - wait for all processes to finish
2961302Sbill  */
29749992Sbostic void
2981302Sbill dowait()
2991302Sbill {
30049992Sbostic     register struct process *pp;
30149992Sbostic     sigmask_t omask;
3021302Sbill 
30349992Sbostic     pjobs++;
30449992Sbostic     omask = sigblock(sigmask(SIGCHLD));
3051302Sbill loop:
30649992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
30749992Sbostic 	if (pp->p_pid &&	/* pp->p_pid == pp->p_jobid && */
30849992Sbostic 	    pp->p_flags & PRUNNING) {
30949992Sbostic 	    (void) sigpause((sigmask_t) 0);
31049992Sbostic 	    goto loop;
31149992Sbostic 	}
31249992Sbostic     (void) sigsetmask(omask);
31349992Sbostic     pjobs = 0;
3141302Sbill }
3151302Sbill 
3161302Sbill /*
3171302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
3181302Sbill  */
31949992Sbostic static void
3201302Sbill pflushall()
3211302Sbill {
32249992Sbostic     register struct process *pp;
3231302Sbill 
32449992Sbostic     for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
32549992Sbostic 	if (pp->p_pid)
32649992Sbostic 	    pflush(pp);
3271302Sbill }
3281302Sbill 
3291302Sbill /*
3301302Sbill  * pflush - flag all process structures in the same job as the
3311302Sbill  *	the argument process for deletion.  The actual free of the
3321302Sbill  *	space is not done here since pflush is called at interrupt level.
3331302Sbill  */
33449992Sbostic static void
3351302Sbill pflush(pp)
33649992Sbostic     register struct process *pp;
3371302Sbill {
33849992Sbostic     register struct process *np;
33949992Sbostic     register int idx;
3401302Sbill 
34149992Sbostic     if (pp->p_pid == 0) {
34249992Sbostic 	xprintf("BUG: process flushed twice");
34349992Sbostic 	return;
34449992Sbostic     }
34549992Sbostic     while (pp->p_pid != pp->p_jobid)
34649992Sbostic 	pp = pp->p_friends;
34749992Sbostic     pclrcurr(pp);
34849992Sbostic     if (pp == pcurrjob)
34949992Sbostic 	pcurrjob = 0;
35049992Sbostic     idx = pp->p_index;
35149992Sbostic     np = pp;
35249992Sbostic     do {
35349992Sbostic 	np->p_index = np->p_pid = 0;
35449992Sbostic 	np->p_flags &= ~PNEEDNOTE;
35549992Sbostic     } while ((np = np->p_friends) != pp);
35649992Sbostic     if (idx == pmaxindex) {
35749992Sbostic 	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
35849992Sbostic 	    if (np->p_index > idx)
35949992Sbostic 		idx = np->p_index;
36049992Sbostic 	pmaxindex = idx;
36149992Sbostic     }
3621302Sbill }
3631302Sbill 
3641302Sbill /*
3651302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3661302Sbill  *	pp MUST be the job leader
3671302Sbill  */
36849992Sbostic static void
3691302Sbill pclrcurr(pp)
37049992Sbostic     register struct process *pp;
3711302Sbill {
3721302Sbill 
37349992Sbostic     if (pp == pcurrent)
37449992Sbostic 	if (pprevious != PNULL) {
37549992Sbostic 	    pcurrent = pprevious;
37649992Sbostic 	    pprevious = pgetcurr(pp);
37749992Sbostic 	}
37849992Sbostic 	else {
37949992Sbostic 	    pcurrent = pgetcurr(pp);
38049992Sbostic 	    pprevious = pgetcurr(pp);
38149992Sbostic 	}
38249992Sbostic     else if (pp == pprevious)
38349992Sbostic 	pprevious = pgetcurr(pp);
3841302Sbill }
3851302Sbill 
3861302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
38749992Sbostic static Char command[PMAXLEN + 4];
38849992Sbostic static int cmdlen;
38949992Sbostic static Char *cmdp;
39049992Sbostic 
3911302Sbill /*
3921302Sbill  * palloc - allocate a process structure and fill it up.
3931302Sbill  *	an important assumption is made that the process is running.
3941302Sbill  */
39549992Sbostic void
3961302Sbill palloc(pid, t)
39749992Sbostic     int     pid;
39849992Sbostic     register struct command *t;
3991302Sbill {
40049992Sbostic     register struct process *pp;
40149992Sbostic     int     i;
4021302Sbill 
40349992Sbostic     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
40449992Sbostic     pp->p_pid = pid;
40549992Sbostic     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
40649992Sbostic     if (t->t_dflg & F_TIME)
40749992Sbostic 	pp->p_flags |= PPTIME;
40849992Sbostic     cmdp = command;
40949992Sbostic     cmdlen = 0;
41049992Sbostic     padd(t);
41149992Sbostic     *cmdp++ = 0;
41249992Sbostic     if (t->t_dflg & F_PIPEOUT) {
41349992Sbostic 	pp->p_flags |= PPOU;
41449992Sbostic 	if (t->t_dflg & F_STDERR)
41549992Sbostic 	    pp->p_flags |= PDIAG;
41649992Sbostic     }
41749992Sbostic     pp->p_command = Strsave(command);
41849992Sbostic     if (pcurrjob) {
41949992Sbostic 	struct process *fp;
4201302Sbill 
42149992Sbostic 	/* careful here with interrupt level */
42249992Sbostic 	pp->p_cwd = 0;
42349992Sbostic 	pp->p_index = pcurrjob->p_index;
42449992Sbostic 	pp->p_friends = pcurrjob;
42549992Sbostic 	pp->p_jobid = pcurrjob->p_pid;
42649992Sbostic 	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends);
42749992Sbostic 	fp->p_friends = pp;
42849992Sbostic     }
42949992Sbostic     else {
43049992Sbostic 	pcurrjob = pp;
43149992Sbostic 	pp->p_jobid = pid;
43249992Sbostic 	pp->p_friends = pp;
43349992Sbostic 	pp->p_cwd = dcwd;
43449992Sbostic 	dcwd->di_count++;
43549992Sbostic 	if (pmaxindex < BIGINDEX)
43649992Sbostic 	    pp->p_index = ++pmaxindex;
43749992Sbostic 	else {
43849992Sbostic 	    struct process *np;
43949992Sbostic 
44049992Sbostic 	    for (i = 1;; i++) {
44149992Sbostic 		for (np = proclist.p_next; np; np = np->p_next)
44249992Sbostic 		    if (np->p_index == i)
44349992Sbostic 			goto tryagain;
44449992Sbostic 		pp->p_index = i;
44549992Sbostic 		if (i > pmaxindex)
44649992Sbostic 		    pmaxindex = i;
44749992Sbostic 		break;
44849992Sbostic 	tryagain:;
44949992Sbostic 	    }
4501302Sbill 	}
45149992Sbostic 	if (pcurrent == PNULL)
45249992Sbostic 	    pcurrent = pp;
45349992Sbostic 	else if (pprevious == PNULL)
45449992Sbostic 	    pprevious = pp;
45549992Sbostic     }
45649992Sbostic     pp->p_next = proclist.p_next;
45749992Sbostic     proclist.p_next = pp;
45849992Sbostic     (void) gettimeofday(&pp->p_btime, (struct timezone *) 0);
4591302Sbill }
4601302Sbill 
46149992Sbostic static void
4621302Sbill padd(t)
46349992Sbostic     register struct command *t;
4641302Sbill {
46549992Sbostic     Char  **argp;
4661302Sbill 
46749992Sbostic     if (t == 0)
46849992Sbostic 	return;
46949992Sbostic     switch (t->t_dtyp) {
4701302Sbill 
47149992Sbostic     case NODE_PAREN:
47249992Sbostic 	pads(STRLparensp);
47349992Sbostic 	padd(t->t_dspr);
47449992Sbostic 	pads(STRspRparen);
47549992Sbostic 	break;
4761302Sbill 
47749992Sbostic     case NODE_COMMAND:
47849992Sbostic 	for (argp = t->t_dcom; *argp; argp++) {
47949992Sbostic 	    pads(*argp);
48049992Sbostic 	    if (argp[1])
48149992Sbostic 		pads(STRspace);
48249992Sbostic 	}
48349992Sbostic 	break;
4841302Sbill 
48549992Sbostic     case NODE_OR:
48649992Sbostic     case NODE_AND:
48749992Sbostic     case NODE_PIPE:
48849992Sbostic     case NODE_LIST:
48949992Sbostic 	padd(t->t_dcar);
49049992Sbostic 	switch (t->t_dtyp) {
49147724Sbostic 	case NODE_OR:
49249992Sbostic 	    pads(STRspor2sp);
49349992Sbostic 	    break;
49447724Sbostic 	case NODE_AND:
49549992Sbostic 	    pads(STRspand2sp);
49649992Sbostic 	    break;
49747724Sbostic 	case NODE_PIPE:
49849992Sbostic 	    pads(STRsporsp);
49949992Sbostic 	    break;
50047724Sbostic 	case NODE_LIST:
50149992Sbostic 	    pads(STRsemisp);
50249992Sbostic 	    break;
5031302Sbill 	}
50449992Sbostic 	padd(t->t_dcdr);
50549992Sbostic 	return;
50649992Sbostic     }
50749992Sbostic     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
50849992Sbostic 	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
50949992Sbostic 	pads(t->t_dlef);
51049992Sbostic     }
51149992Sbostic     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
51249992Sbostic 	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
51349992Sbostic 	if (t->t_dflg & F_STDERR)
51449992Sbostic 	    pads(STRand);
51549992Sbostic 	pads(STRspace);
51649992Sbostic 	pads(t->t_drit);
51749992Sbostic     }
5181302Sbill }
5191302Sbill 
52049992Sbostic static void
5211302Sbill pads(cp)
52249992Sbostic     Char   *cp;
5231302Sbill {
52449992Sbostic     register int i;
5251302Sbill 
52649992Sbostic     /*
52749992Sbostic      * Avoid the Quoted Space alias hack! Reported by:
52849992Sbostic      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
52949992Sbostic      */
53049992Sbostic     if (cp[0] == STRQNULL[0])
53149992Sbostic 	cp++;
53249992Sbostic 
53349992Sbostic     i = Strlen(cp);
53449992Sbostic 
53549992Sbostic     if (cmdlen >= PMAXLEN)
53649992Sbostic 	return;
53749992Sbostic     if (cmdlen + i >= PMAXLEN) {
53849992Sbostic 	(void) Strcpy(cmdp, STRsp3dots);
53949992Sbostic 	cmdlen = PMAXLEN;
54049992Sbostic 	cmdp += 4;
54149992Sbostic 	return;
54249992Sbostic     }
54349992Sbostic     (void) Strcpy(cmdp, cp);
54449992Sbostic     cmdp += i;
54549992Sbostic     cmdlen += i;
5461302Sbill }
5471302Sbill 
5481302Sbill /*
5491302Sbill  * psavejob - temporarily save the current job on a one level stack
5501302Sbill  *	so another job can be created.  Used for { } in exp6
5511302Sbill  *	and `` in globbing.
5521302Sbill  */
55349992Sbostic void
5541302Sbill psavejob()
5551302Sbill {
5561302Sbill 
55749992Sbostic     pholdjob = pcurrjob;
55849992Sbostic     pcurrjob = PNULL;
5591302Sbill }
5601302Sbill 
5611302Sbill /*
5621302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
5631302Sbill  *	somewhere, but pendjob cleans up anyway.
5641302Sbill  */
56549992Sbostic void
5661302Sbill prestjob()
5671302Sbill {
5681302Sbill 
56949992Sbostic     pcurrjob = pholdjob;
57049992Sbostic     pholdjob = PNULL;
5711302Sbill }
5721302Sbill 
5731302Sbill /*
5741302Sbill  * pendjob - indicate that a job (set of commands) has been completed
5751302Sbill  *	or is about to begin.
5761302Sbill  */
57749992Sbostic void
5781302Sbill pendjob()
5791302Sbill {
58049992Sbostic     register struct process *pp, *tp;
5811302Sbill 
58249992Sbostic     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
58349992Sbostic 	pp = pcurrjob;
58449992Sbostic 	while (pp->p_pid != pp->p_jobid)
58549992Sbostic 	    pp = pp->p_friends;
58649992Sbostic 	xprintf("[%d]", pp->p_index);
58749992Sbostic 	tp = pp;
58849992Sbostic 	do {
58949992Sbostic 	    xprintf(" %d", pp->p_pid);
59049992Sbostic 	    pp = pp->p_friends;
59149992Sbostic 	} while (pp != tp);
59249992Sbostic 	xprintf("\n");
59349992Sbostic     }
59449992Sbostic     pholdjob = pcurrjob = 0;
5951302Sbill }
5961302Sbill 
5971302Sbill /*
5981302Sbill  * pprint - print a job
5991302Sbill  */
60049992Sbostic static int
6011302Sbill pprint(pp, flag)
60249992Sbostic     register struct process *pp;
60349992Sbostic     bool    flag;
6041302Sbill {
60549992Sbostic     register status, reason;
60649992Sbostic     struct process *tp;
60749992Sbostic     extern char *linp, linbuf[];
60849992Sbostic     int     jobflags, pstatus;
60949992Sbostic     char   *format;
6101302Sbill 
61149992Sbostic     while (pp->p_pid != pp->p_jobid)
61249992Sbostic 	pp = pp->p_friends;
61349992Sbostic     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
61449992Sbostic 	pp->p_flags &= ~PPTIME;
61549992Sbostic 	pp->p_flags |= PTIME;
61649992Sbostic     }
61749992Sbostic     tp = pp;
61849992Sbostic     status = reason = -1;
61949992Sbostic     jobflags = 0;
62049992Sbostic     do {
62149992Sbostic 	jobflags |= pp->p_flags;
62249992Sbostic 	pstatus = pp->p_flags & PALLSTATES;
62349992Sbostic 	if (tp != pp && linp != linbuf && !(flag & FANCY) &&
62449992Sbostic 	    (pstatus == status && pp->p_reason == reason ||
62549992Sbostic 	     !(flag & REASON)))
62649992Sbostic 	    xprintf(" ");
62749992Sbostic 	else {
62849992Sbostic 	    if (tp != pp && linp != linbuf)
62949992Sbostic 		xprintf("\n");
63049992Sbostic 	    if (flag & NUMBER)
63149992Sbostic 		if (pp == tp)
63249992Sbostic 		    xprintf("[%d]%s %c ", pp->p_index,
63349992Sbostic 			    pp->p_index < 10 ? " " : "",
63449992Sbostic 			    pp == pcurrent ? '+' :
63549992Sbostic 			    (pp == pprevious ? '-' : ' '));
63649992Sbostic 		else
63749992Sbostic 		    xprintf("       ");
63849992Sbostic 	    if (flag & FANCY) {
63949992Sbostic 		xprintf("%5d ", pp->p_pid);
64049992Sbostic 	    }
64149992Sbostic 	    if (flag & (REASON | AREASON)) {
64249992Sbostic 		if (flag & NAME)
64349992Sbostic 		    format = "%-23s";
64449992Sbostic 		else
64549992Sbostic 		    format = "%s";
64649992Sbostic 		if (pstatus == status)
64749992Sbostic 		    if (pp->p_reason == reason) {
64849992Sbostic 			xprintf(format, "");
64949992Sbostic 			goto prcomd;
65049992Sbostic 		    }
65149992Sbostic 		    else
65249992Sbostic 			reason = pp->p_reason;
6531302Sbill 		else {
65449992Sbostic 		    status = pstatus;
65549992Sbostic 		    reason = pp->p_reason;
65649992Sbostic 		}
65749992Sbostic 		switch (status) {
6581302Sbill 
65949992Sbostic 		case PRUNNING:
66049992Sbostic 		    xprintf(format, "Running ");
66149992Sbostic 		    break;
6621302Sbill 
66349992Sbostic 		case PINTERRUPTED:
66449992Sbostic 		case PSTOPPED:
66549992Sbostic 		case PSIGNALED:
66649992Sbostic 		    if ((flag & (REASON | AREASON)) && reason != SIGINT
66749992Sbostic 			&& reason != SIGPIPE)
66849992Sbostic 			xprintf(format, mesg[pp->p_reason].pname);
66949992Sbostic 		    break;
6701302Sbill 
67149992Sbostic 		case PNEXITED:
67249992Sbostic 		case PAEXITED:
67349992Sbostic 		    if (flag & REASON)
67449992Sbostic 			if (pp->p_reason)
67549992Sbostic 			    xprintf("Exit %-16d", pp->p_reason);
67649992Sbostic 			else
67749992Sbostic 			    xprintf(format, "Done");
67849992Sbostic 		    break;
6791302Sbill 
68049992Sbostic 		default:
68149992Sbostic 		    xprintf("BUG: status=%-9o", status);
6821302Sbill 		}
68349992Sbostic 	    }
68449992Sbostic 	}
6851302Sbill prcomd:
68649992Sbostic 	if (flag & NAME) {
68749992Sbostic 	    xprintf("%s", short2str(pp->p_command));
68849992Sbostic 	    if (pp->p_flags & PPOU)
68949992Sbostic 		xprintf(" |");
69049992Sbostic 	    if (pp->p_flags & PDIAG)
69149992Sbostic 		xprintf("&");
6921302Sbill 	}
69349992Sbostic 	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED)
69449992Sbostic 	    xprintf(" (core dumped)");
69549992Sbostic 	if (tp == pp->p_friends) {
69649992Sbostic 	    if (flag & AMPERSAND)
69749992Sbostic 		xprintf(" &");
69849992Sbostic 	    if (flag & JOBDIR &&
69949992Sbostic 		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
70049992Sbostic 		xprintf(" (wd: ");
70149992Sbostic 		dtildepr(value(STRhome), tp->p_cwd->di_name);
70249992Sbostic 		xprintf(")");
70349992Sbostic 	    }
70449992Sbostic 	}
70549992Sbostic 	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
70649992Sbostic 	    if (linp != linbuf)
70749992Sbostic 		xprintf("\n\t");
70849992Sbostic 	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
70949992Sbostic 		    &pp->p_btime);
71049992Sbostic 	}
71149992Sbostic 	if (tp == pp->p_friends) {
71249992Sbostic 	    if (linp != linbuf)
71349992Sbostic 		xprintf("\n");
71449992Sbostic 	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
71549992Sbostic 		xprintf("(wd now: ");
71649992Sbostic 		dtildepr(value(STRhome), dcwd->di_name);
71749992Sbostic 		xprintf(")\n");
71849992Sbostic 	    }
71949992Sbostic 	}
72049992Sbostic     } while ((pp = pp->p_friends) != tp);
72149992Sbostic     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
72249992Sbostic 	if (jobflags & NUMBER)
72349992Sbostic 	    xprintf("       ");
72449992Sbostic 	ptprint(tp);
72549992Sbostic     }
72649992Sbostic     return (jobflags);
7271302Sbill }
7281302Sbill 
72949992Sbostic static void
7301302Sbill ptprint(tp)
73149992Sbostic     register struct process *tp;
7321302Sbill {
73349992Sbostic     struct timeval tetime, diff;
73449992Sbostic     static struct timeval ztime;
73549992Sbostic     struct rusage ru;
73649992Sbostic     static struct rusage zru;
73749992Sbostic     register struct process *pp = tp;
7381302Sbill 
73949992Sbostic     ru = zru;
74049992Sbostic     tetime = ztime;
74149992Sbostic     do {
74249992Sbostic 	ruadd(&ru, &pp->p_rusage);
74349992Sbostic 	tvsub(&diff, &pp->p_etime, &pp->p_btime);
74449992Sbostic 	if (timercmp(&diff, &tetime, >))
74549992Sbostic 	    tetime = diff;
74649992Sbostic     } while ((pp = pp->p_friends) != tp);
74749992Sbostic     prusage(&zru, &ru, &tetime, &ztime);
7481302Sbill }
7491302Sbill 
7501302Sbill /*
7511302Sbill  * dojobs - print all jobs
7521302Sbill  */
75349992Sbostic void
7541302Sbill dojobs(v)
75549992Sbostic     Char  **v;
7561302Sbill {
75749992Sbostic     register struct process *pp;
75849992Sbostic     register int flag = NUMBER | NAME | REASON;
75949992Sbostic     int     i;
7601302Sbill 
76149992Sbostic     if (chkstop)
76249992Sbostic 	chkstop = 2;
76349992Sbostic     if (*++v) {
76449992Sbostic 	if (v[1] || !eq(*v, STRml))
76549992Sbostic 	    stderror(ERR_JOBS);
76649992Sbostic 	flag |= FANCY | JOBDIR;
76749992Sbostic     }
76849992Sbostic     for (i = 1; i <= pmaxindex; i++)
76949992Sbostic 	for (pp = proclist.p_next; pp; pp = pp->p_next)
77049992Sbostic 	    if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
77149992Sbostic 		pp->p_flags &= ~PNEEDNOTE;
77249992Sbostic 		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
77349992Sbostic 		    pflush(pp);
77449992Sbostic 		break;
77549992Sbostic 	    }
7761302Sbill }
7771302Sbill 
7781302Sbill /*
7791302Sbill  * dofg - builtin - put the job into the foreground
7801302Sbill  */
78149992Sbostic void
7821302Sbill dofg(v)
78349992Sbostic     Char  **v;
7841302Sbill {
78549992Sbostic     register struct process *pp;
7861302Sbill 
78749992Sbostic     okpcntl();
78849992Sbostic     ++v;
78949992Sbostic     do {
79049992Sbostic 	pp = pfind(*v);
79149992Sbostic 	pstart(pp, 1);
79249992Sbostic 	pjwait(pp);
79349992Sbostic     } while (*v && *++v);
7941302Sbill }
7951302Sbill 
7961302Sbill /*
7971302Sbill  * %... - builtin - put the job into the foreground
7981302Sbill  */
79949992Sbostic void
8001302Sbill dofg1(v)
80149992Sbostic     Char  **v;
8021302Sbill {
80349992Sbostic     register struct process *pp;
8041302Sbill 
80549992Sbostic     okpcntl();
80649992Sbostic     pp = pfind(v[0]);
80749992Sbostic     pstart(pp, 1);
80849992Sbostic     pjwait(pp);
8091302Sbill }
8101302Sbill 
8111302Sbill /*
8121302Sbill  * dobg - builtin - put the job into the background
8131302Sbill  */
81449992Sbostic void
8151302Sbill dobg(v)
81649992Sbostic     Char  **v;
8171302Sbill {
81849992Sbostic     register struct process *pp;
8191302Sbill 
82049992Sbostic     okpcntl();
82149992Sbostic     ++v;
82249992Sbostic     do {
82349992Sbostic 	pp = pfind(*v);
82449992Sbostic 	pstart(pp, 0);
82549992Sbostic     } while (*v && *++v);
8261302Sbill }
8271302Sbill 
8281302Sbill /*
8291302Sbill  * %... & - builtin - put the job into the background
8301302Sbill  */
83149992Sbostic void
8321302Sbill dobg1(v)
83349992Sbostic     Char  **v;
8341302Sbill {
83549992Sbostic     register struct process *pp;
8361302Sbill 
83749992Sbostic     pp = pfind(v[0]);
83849992Sbostic     pstart(pp, 0);
8391302Sbill }
8401302Sbill 
8411302Sbill /*
8421302Sbill  * dostop - builtin - stop the job
8431302Sbill  */
84449992Sbostic void
8451302Sbill dostop(v)
84649992Sbostic     Char  **v;
8471302Sbill {
84849992Sbostic     pkill(++v, SIGSTOP);
8491302Sbill }
8501302Sbill 
8511302Sbill /*
8521302Sbill  * dokill - builtin - superset of kill (1)
8531302Sbill  */
85449992Sbostic void
8551302Sbill dokill(v)
85649992Sbostic     Char  **v;
8571302Sbill {
85849992Sbostic     register int signum, len = 0;
85949992Sbostic     register char *name;
8601302Sbill 
86149992Sbostic     v++;
86249992Sbostic     if (v[0] && v[0][0] == '-') {
86349992Sbostic 	if (v[0][1] == 'l') {
86449992Sbostic 	    for (signum = 1; signum <= NSIG; signum++) {
86549992Sbostic 		if ((name = mesg[signum].iname) != NULL) {
86649992Sbostic 		    len += strlen(name) + 1;
86749992Sbostic 		    if (len >= 80 - 1) {
86849992Sbostic 			xprintf("\n");
86949992Sbostic 			len = strlen(name) + 1;
87049992Sbostic 		    }
87149992Sbostic 		    xprintf("%s ", name);
8721302Sbill 		}
87349992Sbostic 	    }
87449992Sbostic 	    xprintf("\n");
87549992Sbostic 	    return;
87649992Sbostic 	}
87749992Sbostic 	if (Isdigit(v[0][1])) {
87849992Sbostic 	    signum = atoi(short2str(v[0] + 1));
87949992Sbostic 	    if (signum < 0 || signum > NSIG)
88049992Sbostic 		stderror(ERR_NAME | ERR_BADSIG);
88149992Sbostic 	}
88249992Sbostic 	else {
88349992Sbostic 	    for (signum = 1; signum <= NSIG; signum++)
88449992Sbostic 		if (mesg[signum].iname &&
88549992Sbostic 		    eq(&v[0][1], str2short(mesg[signum].iname)))
88649992Sbostic 		    goto gotsig;
88749992Sbostic 	    setname(short2str(&v[0][1]));
88849992Sbostic 	    stderror(ERR_NAME | ERR_UNKSIG);
88949992Sbostic 	}
8901302Sbill gotsig:
89149992Sbostic 	v++;
89249992Sbostic     }
89349992Sbostic     else
89449992Sbostic 	signum = SIGTERM;
89549992Sbostic     pkill(v, signum);
8961302Sbill }
8971302Sbill 
89849992Sbostic static void
8991302Sbill pkill(v, signum)
90049992Sbostic     Char  **v;
90149992Sbostic     int     signum;
9021302Sbill {
90349992Sbostic     register struct process *pp, *np;
90449992Sbostic     register int jobflags = 0;
90549992Sbostic     int     pid, err1 = 0;
90649992Sbostic     sigmask_t omask;
90749992Sbostic     Char   *cp;
9081302Sbill 
90949992Sbostic     omask = sigmask(SIGCHLD);
91049992Sbostic     if (setintr)
91149992Sbostic 	omask |= sigmask(SIGINT);
91249992Sbostic     omask = sigblock(omask) & ~omask;
91349992Sbostic     gflag = 0, tglob(v);
91449992Sbostic     if (gflag) {
91549992Sbostic 	v = globall(v);
91649992Sbostic 	if (v == 0)
91749992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
91849992Sbostic     }
91949992Sbostic     else {
92049992Sbostic 	v = gargv = saveblk(v);
92149992Sbostic 	trim(v);
92249992Sbostic     }
9231302Sbill 
92449992Sbostic     while (v && (cp = *v)) {
92549992Sbostic 	if (*cp == '%') {
92649992Sbostic 	    np = pp = pfind(cp);
92749992Sbostic 	    do
92849992Sbostic 		jobflags |= np->p_flags;
92949992Sbostic 	    while ((np = np->p_friends) != pp);
93049992Sbostic 	    switch (signum) {
93149992Sbostic 
93249992Sbostic 	    case SIGSTOP:
93349992Sbostic 	    case SIGTSTP:
93449992Sbostic 	    case SIGTTIN:
93549992Sbostic 	    case SIGTTOU:
93649992Sbostic 		if ((jobflags & PRUNNING) == 0) {
93749992Sbostic 		    xprintf("%s: Already suspended\n", short2str(cp));
93849992Sbostic 		    err1++;
93949992Sbostic 		    goto cont;
9401302Sbill 		}
94149992Sbostic 		break;
94249992Sbostic 		/*
94349992Sbostic 		 * suspend a process, kill -CONT %, then type jobs; the shell
94449992Sbostic 		 * says it is suspended, but it is running; thanks jaap..
94549992Sbostic 		 */
94649992Sbostic 	    case SIGCONT:
94749992Sbostic 		pstart(pp, 0);
94849992Sbostic 		goto cont;
94949992Sbostic 	    }
95049992Sbostic 	    if (killpg((pid_t) pp->p_jobid, signum) < 0) {
95149992Sbostic 		xprintf("%s: %s\n", short2str(cp), strerror(errno));
95249992Sbostic 		err1++;
95349992Sbostic 	    }
95449992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
95549992Sbostic 		(void) killpg((pid_t) pp->p_jobid, SIGCONT);
95649992Sbostic 	}
95749992Sbostic 	else if (!(Isdigit(*cp) || *cp == '-'))
95849992Sbostic 	    stderror(ERR_NAME | ERR_JOBARGS);
95949992Sbostic 	else {
96049992Sbostic 	    pid = atoi(short2str(cp));
96149992Sbostic 	    if (kill((pid_t) pid, signum) < 0) {
96249992Sbostic 		xprintf("%d: %s\n", pid, strerror(errno));
96349992Sbostic 		err1++;
96449992Sbostic 		goto cont;
96549992Sbostic 	    }
96649992Sbostic 	    if (signum == SIGTERM || signum == SIGHUP)
96749992Sbostic 		(void) kill((pid_t) pid, SIGCONT);
96849992Sbostic 	}
9691302Sbill cont:
97049992Sbostic 	v++;
97149992Sbostic     }
97249992Sbostic     if (gargv)
97349992Sbostic 	blkfree(gargv), gargv = 0;
97449992Sbostic     (void) sigsetmask(omask);
97549992Sbostic     if (err1)
97649992Sbostic 	stderror(ERR_SILENT);
9771302Sbill }
9781302Sbill 
9791302Sbill /*
9801302Sbill  * pstart - start the job in foreground/background
9811302Sbill  */
98249992Sbostic void
9831302Sbill pstart(pp, foregnd)
98449992Sbostic     register struct process *pp;
98549992Sbostic     int     foregnd;
9861302Sbill {
98749992Sbostic     register struct process *np;
98849992Sbostic     sigmask_t omask;
98949992Sbostic     long    jobflags = 0;
9901302Sbill 
99149992Sbostic     omask = sigblock(sigmask(SIGCHLD));
99249992Sbostic     np = pp;
99349992Sbostic     do {
99449992Sbostic 	jobflags |= np->p_flags;
99549992Sbostic 	if (np->p_flags & (PRUNNING | PSTOPPED)) {
99649992Sbostic 	    np->p_flags |= PRUNNING;
99749992Sbostic 	    np->p_flags &= ~PSTOPPED;
99849992Sbostic 	    if (foregnd)
99949992Sbostic 		np->p_flags |= PFOREGND;
100049992Sbostic 	    else
100149992Sbostic 		np->p_flags &= ~PFOREGND;
100249992Sbostic 	}
100349992Sbostic     } while ((np = np->p_friends) != pp);
100449992Sbostic     if (!foregnd)
100549992Sbostic 	pclrcurr(pp);
100649992Sbostic     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
100749992Sbostic     if (foregnd)
100849992Sbostic 	(void) tcsetpgrp(FSHTTY, pp->p_jobid);
100949992Sbostic     if (jobflags & PSTOPPED)
101049992Sbostic 	(void) killpg((pid_t) pp->p_jobid, SIGCONT);
101149992Sbostic     (void) sigsetmask(omask);
10121302Sbill }
10131302Sbill 
101449992Sbostic void
10151302Sbill panystop(neednl)
101649992Sbostic     bool    neednl;
10171302Sbill {
101849992Sbostic     register struct process *pp;
10191302Sbill 
102049992Sbostic     chkstop = 2;
102149992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
102249992Sbostic 	if (pp->p_flags & PSTOPPED)
102349992Sbostic 	    stderror(ERR_STOPPED, neednl ? "\n" : "");
10241302Sbill }
10251302Sbill 
10261302Sbill struct process *
10271302Sbill pfind(cp)
102849992Sbostic     Char   *cp;
10291302Sbill {
103049992Sbostic     register struct process *pp, *np;
10311302Sbill 
103249992Sbostic     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
103349992Sbostic 	if (pcurrent == PNULL)
103449992Sbostic 	    stderror(ERR_NAME | ERR_JOBCUR);
103549992Sbostic 	return (pcurrent);
103649992Sbostic     }
103749992Sbostic     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
103849992Sbostic 	if (pprevious == PNULL)
103949992Sbostic 	    stderror(ERR_NAME | ERR_JOBPREV);
104049992Sbostic 	return (pprevious);
104149992Sbostic     }
104249992Sbostic     if (Isdigit(cp[1])) {
104349992Sbostic 	int     idx = atoi(short2str(cp + 1));
104449992Sbostic 
10451302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
104649992Sbostic 	    if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
104749992Sbostic 		return (pp);
104849992Sbostic 	stderror(ERR_NAME | ERR_NOSUCHJOB);
104949992Sbostic     }
105049992Sbostic     np = PNULL;
105149992Sbostic     for (pp = proclist.p_next; pp; pp = pp->p_next)
105249992Sbostic 	if (pp->p_pid == pp->p_jobid) {
105349992Sbostic 	    if (cp[1] == '?') {
105449992Sbostic 		register Char *dp;
105549992Sbostic 
105649992Sbostic 		for (dp = pp->p_command; *dp; dp++) {
105749992Sbostic 		    if (*dp != cp[2])
105849992Sbostic 			continue;
105949992Sbostic 		    if (prefix(cp + 2, dp))
106049992Sbostic 			goto match;
10611302Sbill 		}
106249992Sbostic 	    }
106349992Sbostic 	    else if (prefix(cp + 1, pp->p_command)) {
106449992Sbostic 	match:
106549992Sbostic 		if (np)
106649992Sbostic 		    stderror(ERR_NAME | ERR_AMBIG);
106749992Sbostic 		np = pp;
106849992Sbostic 	    }
106949992Sbostic 	}
107049992Sbostic     if (np)
107149992Sbostic 	return (np);
107249992Sbostic     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
107349992Sbostic     /* NOTREACHED */
107449992Sbostic     return (0);
10751302Sbill }
10761302Sbill 
107749992Sbostic 
10781302Sbill /*
10792357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
10801302Sbill  */
108149992Sbostic static struct process *
10821302Sbill pgetcurr(pp)
108349992Sbostic     register struct process *pp;
10841302Sbill {
108549992Sbostic     register struct process *np;
108649992Sbostic     register struct process *xp = PNULL;
10871302Sbill 
108849992Sbostic     for (np = proclist.p_next; np; np = np->p_next)
108949992Sbostic 	if (np != pcurrent && np != pp && np->p_pid &&
109049992Sbostic 	    np->p_pid == np->p_jobid) {
109149992Sbostic 	    if (np->p_flags & PSTOPPED)
109249992Sbostic 		return (np);
109349992Sbostic 	    if (xp == PNULL)
109449992Sbostic 		xp = np;
109549992Sbostic 	}
109649992Sbostic     return (xp);
10971302Sbill }
10981302Sbill 
10991302Sbill /*
11001302Sbill  * donotify - flag the job so as to report termination asynchronously
11011302Sbill  */
110249992Sbostic void
11031302Sbill donotify(v)
110449992Sbostic     Char  **v;
11051302Sbill {
110649992Sbostic     register struct process *pp;
11071302Sbill 
110849992Sbostic     pp = pfind(*++v);
110949992Sbostic     pp->p_flags |= PNOTIFY;
11101302Sbill }
11111302Sbill 
11121302Sbill /*
11131302Sbill  * Do the fork and whatever should be done in the child side that
11141302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
11151302Sbill  * Also do everything that needs any signals fiddled with in the parent side
11161302Sbill  *
11171302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
11181302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
11191302Sbill  *	 0:	already have tty; manipulate process pgrps only
11201302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
11211302Sbill  * It is usually just the value of tpgrp.
11221302Sbill  */
112349992Sbostic 
112449992Sbostic int
11251302Sbill pfork(t, wanttty)
112649992Sbostic     struct command *t;		/* command we are forking for */
112749992Sbostic     int     wanttty;
11281302Sbill {
112949992Sbostic     register int pid;
113049992Sbostic     bool    ignint = 0;
113149992Sbostic     int     pgrp;
113249992Sbostic     sigmask_t omask;
11331302Sbill 
113449992Sbostic     /*
113549992Sbostic      * A child will be uninterruptible only under very special conditions.
113649992Sbostic      * Remember that the semantics of '&' is implemented by disconnecting the
113749992Sbostic      * process from the tty so signals do not need to ignored just for '&'.
113849992Sbostic      * Thus signals are set to default action for children unless: we have had
113949992Sbostic      * an "onintr -" (then specifically ignored) we are not playing with
114049992Sbostic      * signals (inherit action)
114149992Sbostic      */
114249992Sbostic     if (setintr)
114349992Sbostic 	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
114449992Sbostic 	    || (gointr && eq(gointr, STRminus));
114549992Sbostic     /*
114649992Sbostic      * Check for maximum nesting of 16 processes to avoid Forking loops
114749992Sbostic      */
114849992Sbostic     if (child == 16)
114949992Sbostic 	stderror(ERR_NESTING, 16);
115049992Sbostic     /*
115149992Sbostic      * Hold SIGCHLD until we have the process installed in our table.
115249992Sbostic      */
115349992Sbostic     omask = sigblock(sigmask(SIGCHLD));
115449992Sbostic     while ((pid = fork()) < 0)
115549992Sbostic 	if (setintr == 0)
115649992Sbostic 	    (void) sleep(FORKSLEEP);
115749992Sbostic 	else {
115849992Sbostic 	    (void) sigsetmask(omask);
115949992Sbostic 	    stderror(ERR_NOPROC);
116049992Sbostic 	}
116149992Sbostic     if (pid == 0) {
116249992Sbostic 	settimes();
116349992Sbostic 	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
116449992Sbostic 	pflushall();
116549992Sbostic 	pcurrjob = PNULL;
116649992Sbostic 	child++;
116749992Sbostic 	if (setintr) {
116849992Sbostic 	    setintr = 0;	/* until I think otherwise */
116949992Sbostic 	    /*
117049992Sbostic 	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
117149992Sbostic 	     * -" seen.
117249992Sbostic 	     */
117349992Sbostic 	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
117449992Sbostic 	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
117549992Sbostic 	    if (wanttty >= 0) {
117649992Sbostic 		/* make stoppable */
117749992Sbostic 		(void) signal(SIGTSTP, SIG_DFL);
117849992Sbostic 		(void) signal(SIGTTIN, SIG_DFL);
117949992Sbostic 		(void) signal(SIGTTOU, SIG_DFL);
118049992Sbostic 	    }
118149992Sbostic 	    (void) signal(SIGTERM, parterm);
118249992Sbostic 	}
118349992Sbostic 	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
118449992Sbostic 	    (void) signal(SIGINT, SIG_IGN);
118549992Sbostic 	    (void) signal(SIGQUIT, SIG_IGN);
118649992Sbostic 	}
118749992Sbostic 	pgetty(wanttty, pgrp);
11881302Sbill 	/*
118949992Sbostic 	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
119049992Sbostic 	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
119149992Sbostic 	 * to know about nice/nohup/time
11921302Sbill 	 */
119349992Sbostic 	if (t->t_dflg & F_NOHUP)
119449992Sbostic 	    (void) signal(SIGHUP, SIG_IGN);
119549992Sbostic 	if (t->t_dflg & F_NICE)
119649992Sbostic 	    (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
119749992Sbostic     }
119849992Sbostic     else {
119949992Sbostic 	if (wanttty >= 0)
120049992Sbostic 	    (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
120149992Sbostic 	palloc(pid, t);
120249992Sbostic 	(void) sigsetmask(omask);
120349992Sbostic     }
12041302Sbill 
120549992Sbostic     return (pid);
12061302Sbill }
12071302Sbill 
120849992Sbostic static void
12091302Sbill okpcntl()
12101302Sbill {
121149992Sbostic     if (tpgrp == -1)
121249992Sbostic 	stderror(ERR_JOBCONTROL);
121349992Sbostic     if (tpgrp == 0)
121449992Sbostic 	stderror(ERR_JOBCTRLSUB);
121549992Sbostic }
12161302Sbill 
121749992Sbostic /*
121849992Sbostic  * if we don't have vfork(), things can still go in the wrong order
121949992Sbostic  * resulting in the famous 'Stopped (tty output)'. But some systems
122049992Sbostic  * don't permit the setpgid() call, (these are more recent secure
122149992Sbostic  * systems such as ibm's aix). Then we'd rather print an error message
122249992Sbostic  * than hang the shell!
122349992Sbostic  * I am open to suggestions how to fix that.
122449992Sbostic  */
122549992Sbostic void
122649992Sbostic pgetty(wanttty, pgrp)
122749992Sbostic     int     wanttty, pgrp;
122849992Sbostic {
122949992Sbostic     sigmask_t omask = 0;
123049992Sbostic 
123149992Sbostic     /*
123249992Sbostic      * christos: I am blocking the tty signals till I've set things
123349992Sbostic      * correctly....
123449992Sbostic      */
123549992Sbostic     if (wanttty > 0)
123649992Sbostic 	omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
123749992Sbostic     /*
123849992Sbostic      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
123949992Sbostic      * Don't check for tpgrp >= 0 so even non-interactive shells give
124049992Sbostic      * background jobs process groups Same for the comparison in the other part
124149992Sbostic      * of the #ifdef
124249992Sbostic      */
124349992Sbostic     if (wanttty >= 0)
124449992Sbostic 	if (setpgid(0, pgrp) == -1) {
124549992Sbostic 	    xprintf("csh: setpgid error.\n");
124649992Sbostic 	    xexit(0);
124749992Sbostic 	}
124849992Sbostic 
124949992Sbostic     if (wanttty > 0) {
125049992Sbostic 	(void) tcsetpgrp(FSHTTY, pgrp);
125149992Sbostic 	(void) sigsetmask(omask);
125249992Sbostic     }
125349992Sbostic 
125449992Sbostic     if (tpgrp > 0)
125549992Sbostic 	tpgrp = 0;		/* gave tty away */
12561302Sbill }
1257