xref: /csrg-svn/bin/csh/proc.c (revision 47823)
1*47823Sbostic /*-
2*47823Sbostic  * Copyright (c) 1980, 1991 The Regents of the University of California.
3*47823Sbostic  * All rights reserved.
4*47823Sbostic  *
5*47823Sbostic  * %sccs.include.redist.c%
621940Sdist  */
721940Sdist 
817509Sedward #ifndef lint
9*47823Sbostic static char sccsid[] = "@(#)proc.c	5.15 (Berkeley) 04/04/91";
10*47823Sbostic #endif /* not lint */
111302Sbill 
121302Sbill #include "sh.h"
131302Sbill #include "sh.dir.h"
141302Sbill #include "sh.proc.h"
1544759Smarc #include <string.h>
1613590Swnj #include <sys/wait.h>
171302Sbill #include <sys/ioctl.h>
181302Sbill 
191302Sbill /*
201302Sbill  * C Shell - functions that manage processes, handling hanging, termination
211302Sbill  */
221302Sbill 
231302Sbill #define BIGINDEX	9	/* largest desirable job index */
241302Sbill 
251302Sbill /*
261302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
271302Sbill  *	indicating that at least one child has terminated or stopped
281302Sbill  *	thus at least one wait system call will definitely return a
291302Sbill  *	childs status.  Top level routines (like pwait) must be sure
301302Sbill  *	to mask interrupts when playing with the proclist data structures!
311302Sbill  */
3246657Sbostic void
331302Sbill pchild()
341302Sbill {
351302Sbill 	register struct process *pp;
361302Sbill 	register struct process	*fp;
371302Sbill 	register int pid;
381302Sbill 	union wait w;
391302Sbill 	int jobflags;
4010035Ssam 	struct rusage ru;
4133369Sbostic 	extern int insource;
421302Sbill 
431302Sbill loop:
4446657Sbostic 	pid = wait3((int *)&w,
4546657Sbostic 	    (setintr && (intty || insource) ? WNOHANG|WUNTRACED:WNOHANG), &ru);
461302Sbill 	if (pid <= 0) {
471302Sbill 		if (errno == EINTR) {
481302Sbill 			errno = 0;
491302Sbill 			goto loop;
501302Sbill 		}
511302Sbill 		pnoprocesses = pid == -1;
521302Sbill 		return;
531302Sbill 	}
541302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
551302Sbill 		if (pid == pp->p_pid)
561302Sbill 			goto found;
571302Sbill 	goto loop;
581302Sbill found:
591302Sbill 	if (pid == atoi(value("child")))
601302Sbill 		unsetv("child");
611302Sbill 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
621302Sbill 	if (WIFSTOPPED(w)) {
631302Sbill 		pp->p_flags |= PSTOPPED;
641302Sbill 		pp->p_reason = w.w_stopsig;
651302Sbill 	} else {
6617509Sedward 		if (pp->p_flags & (PTIME|PPTIME) || adrof("time"))
6717509Sedward 			(void) gettimeofday(&pp->p_etime, (struct timezone *)0);
6810035Ssam 		pp->p_rusage = ru;
691302Sbill 		if (WIFSIGNALED(w)) {
701302Sbill 			if (w.w_termsig == SIGINT)
711302Sbill 				pp->p_flags |= PINTERRUPTED;
721302Sbill 			else
731302Sbill 				pp->p_flags |= PSIGNALED;
741302Sbill 			if (w.w_coredump)
751302Sbill 				pp->p_flags |= PDUMPED;
761302Sbill 			pp->p_reason = w.w_termsig;
771302Sbill 		} else {
781302Sbill 			pp->p_reason = w.w_retcode;
791302Sbill 			if (pp->p_reason != 0)
801302Sbill 				pp->p_flags |= PAEXITED;
811302Sbill 			else
821302Sbill 				pp->p_flags |= PNEXITED;
831302Sbill 		}
841302Sbill 	}
851302Sbill 	jobflags = 0;
861302Sbill 	fp = pp;
871302Sbill 	do {
881302Sbill 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
891302Sbill 		    !child && adrof("time") &&
9017509Sedward 		    fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
911302Sbill 		     atoi(value("time")))
921302Sbill 			fp->p_flags |= PTIME;
931302Sbill 		jobflags |= fp->p_flags;
941302Sbill 	} while ((fp = fp->p_friends) != pp);
951302Sbill 	pp->p_flags &= ~PFOREGND;
961302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
971302Sbill 		pp->p_flags &= ~PPTIME;
981302Sbill 		pp->p_flags |= PTIME;
991302Sbill 	}
1001302Sbill 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
1011302Sbill 		fp = pp;
1021302Sbill 		do {
1031302Sbill 			if (fp->p_flags&PSTOPPED)
1041302Sbill 				fp->p_flags |= PREPORTED;
1051302Sbill 		} while((fp = fp->p_friends) != pp);
1061302Sbill 		while(fp->p_pid != fp->p_jobid)
1071302Sbill 			fp = fp->p_friends;
1082357Swnj 		if (jobflags&PSTOPPED) {
1092357Swnj 			if (pcurrent && pcurrent != fp)
1102357Swnj 				pprevious = pcurrent;
1112357Swnj 			pcurrent = fp;
1122357Swnj 		} else
1132357Swnj 			pclrcurr(fp);
1141302Sbill 		if (jobflags&PFOREGND) {
1151302Sbill 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
1161302Sbill 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
1173213Swnj 				;	/* print in pjwait */
1183646Sroot 			}
1193646Sroot /*
1203646Sroot 		else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
1211302Sbill 				ptprint(fp);
1223646Sroot */
1231302Sbill 		} else {
1241302Sbill 			if (jobflags&PNOTIFY || adrof("notify")) {
1251302Sbill 				printf("\215\n");
12617509Sedward 				(void) pprint(pp, NUMBER|NAME|REASON);
1271302Sbill 				if ((jobflags&PSTOPPED) == 0)
1281302Sbill 					pflush(pp);
1291302Sbill 			} else {
1301302Sbill 				fp->p_flags |= PNEEDNOTE;
1311302Sbill 				neednote++;
1321302Sbill 			}
1331302Sbill 		}
1341302Sbill 	}
1351302Sbill 	goto loop;
1361302Sbill }
1371302Sbill 
1381302Sbill pnote()
1391302Sbill {
1401302Sbill 	register struct process *pp;
14131685Sbostic 	int flags;
14231685Sbostic 	long omask;
1431302Sbill 
1441302Sbill 	neednote = 0;
1451302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
1461302Sbill 		if (pp->p_flags & PNEEDNOTE) {
14717136Sralph 			omask = sigblock(sigmask(SIGCHLD));
1481302Sbill 			pp->p_flags &= ~PNEEDNOTE;
1491302Sbill 			flags = pprint(pp, NUMBER|NAME|REASON);
1501302Sbill 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
1511302Sbill 				pflush(pp);
15217509Sedward 			(void) sigsetmask(omask);
1531302Sbill 		}
1541302Sbill 	}
1551302Sbill }
1561302Sbill 
1571302Sbill /*
1581302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1591302Sbill  *	of current and previous job indicators.
1601302Sbill  */
1611302Sbill pwait()
1621302Sbill {
1631302Sbill 	register struct process *fp, *pp;
16431685Sbostic 	long omask;
1651302Sbill 
1661302Sbill 	/*
1671302Sbill 	 * Here's where dead procs get flushed.
1681302Sbill 	 */
16917136Sralph 	omask = sigblock(sigmask(SIGCHLD));
1701302Sbill 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
1711302Sbill 		if (pp->p_pid == 0) {
1721302Sbill 			fp->p_next = pp->p_next;
1731302Sbill 			xfree(pp->p_command);
1741302Sbill 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
1751302Sbill 				if (pp->p_cwd->di_next == 0)
1761302Sbill 					dfree(pp->p_cwd);
1771302Sbill 			xfree((char *)pp);
1781302Sbill 			pp = fp;
1791302Sbill 		}
18017509Sedward 	(void) sigsetmask(omask);
1811302Sbill 	pjwait(pcurrjob);
1821302Sbill }
1831302Sbill 
1841302Sbill /*
1851302Sbill  * pjwait - wait for a job to finish or become stopped
1861302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
1871302Sbill  */
1881302Sbill pjwait(pp)
1891302Sbill 	register struct process *pp;
1901302Sbill {
1911302Sbill 	register struct process *fp;
19231685Sbostic 	int jobflags, reason;
19331685Sbostic 	long omask;
1941302Sbill 
19513561Ssam 	while (pp->p_pid != pp->p_jobid)
19613561Ssam 		pp = pp->p_friends;
1971302Sbill 	fp = pp;
1981302Sbill 	do {
1991302Sbill 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
2001302Sbill 			printf("BUG: waiting for background job!\n");
2011302Sbill 	} while ((fp = fp->p_friends) != pp);
2021302Sbill 	/*
2031302Sbill 	 * Now keep pausing as long as we are not interrupted (SIGINT),
2041302Sbill 	 * and the target process, or any of its friends, are running
2051302Sbill 	 */
2061302Sbill 	fp = pp;
20717136Sralph 	omask = sigblock(sigmask(SIGCHLD));
2081302Sbill 	for (;;) {
2091302Sbill 		jobflags = 0;
2101302Sbill 		do
2111302Sbill 			jobflags |= fp->p_flags;
21217136Sralph 		while ((fp = (fp->p_friends)) != pp);
2131302Sbill 		if ((jobflags & PRUNNING) == 0)
2141302Sbill 			break;
21531685Sbostic 		sigpause(sigblock(0L) &~ sigmask(SIGCHLD));
2161302Sbill 	}
21717509Sedward 	(void) sigsetmask(omask);
21817509Sedward 	if (tpgrp > 0)			/* get tty back */
21917509Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
2203487Sroot 	if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
2213487Sroot 	     !eq(dcwd->di_name, fp->p_cwd->di_name)) {
2223487Sroot 		if (jobflags&PSTOPPED)
2233487Sroot 			printf("\n");
22417509Sedward 		(void) pprint(pp, AREASON|SHELLDIR);
2253487Sroot 	}
2263213Swnj 	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2271302Sbill 	    (!gointr || !eq(gointr, "-"))) {
2283213Swnj 		if ((jobflags & PSTOPPED) == 0)
2293213Swnj 			pflush(pp);
2303213Swnj 		pintr1(0);
2311302Sbill 		/*NOTREACHED*/
2321302Sbill 	}
2331302Sbill 	reason = 0;
2341302Sbill 	fp = pp;
2351302Sbill 	do {
2361302Sbill 		if (fp->p_reason)
2371302Sbill 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
2381302Sbill 				fp->p_reason | QUOTE : fp->p_reason;
2391302Sbill 	} while ((fp = fp->p_friends) != pp);
2401302Sbill 	set("status", putn(reason));
2411302Sbill 	if (reason && exiterr)
2421302Sbill 		exitstat();
2431302Sbill 	pflush(pp);
2441302Sbill }
2451302Sbill 
2461302Sbill /*
2471302Sbill  * dowait - wait for all processes to finish
2481302Sbill  */
2491302Sbill dowait()
2501302Sbill {
2511302Sbill 	register struct process *pp;
25231685Sbostic 	long omask;
2531302Sbill 
2541302Sbill 	pjobs++;
25517136Sralph 	omask = sigblock(sigmask(SIGCHLD));
2561302Sbill loop:
2571302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
25813561Ssam 		if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
2591302Sbill 		    pp->p_flags&PRUNNING) {
26031685Sbostic 			sigpause(0L);
2611302Sbill 			goto loop;
2621302Sbill 		}
26317509Sedward 	(void) sigsetmask(omask);
2641302Sbill 	pjobs = 0;
2651302Sbill }
2661302Sbill 
2671302Sbill /*
2681302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
2691302Sbill  */
2701302Sbill pflushall()
2711302Sbill {
2721302Sbill 	register struct process	*pp;
2731302Sbill 
2741302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
2751302Sbill 		if (pp->p_pid)
2761302Sbill 			pflush(pp);
2771302Sbill }
2781302Sbill 
2791302Sbill /*
2801302Sbill  * pflush - flag all process structures in the same job as the
2811302Sbill  *	the argument process for deletion.  The actual free of the
2821302Sbill  *	space is not done here since pflush is called at interrupt level.
2831302Sbill  */
2841302Sbill pflush(pp)
2851302Sbill 	register struct process	*pp;
2861302Sbill {
2871302Sbill 	register struct process *np;
2881302Sbill 	register int index;
2891302Sbill 
2901302Sbill 	if (pp->p_pid == 0) {
2911302Sbill 		printf("BUG: process flushed twice");
2921302Sbill 		return;
2931302Sbill 	}
2941302Sbill 	while (pp->p_pid != pp->p_jobid)
2951302Sbill 		pp = pp->p_friends;
2961302Sbill 	pclrcurr(pp);
2971302Sbill 	if (pp == pcurrjob)
2981302Sbill 		pcurrjob = 0;
2991302Sbill 	index = pp->p_index;
3001302Sbill 	np = pp;
3011302Sbill 	do {
3021302Sbill 		np->p_index = np->p_pid = 0;
3031302Sbill 		np->p_flags &= ~PNEEDNOTE;
3041302Sbill 	} while ((np = np->p_friends) != pp);
3051302Sbill 	if (index == pmaxindex) {
3061302Sbill 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
3071302Sbill 			if (np->p_index > index)
3081302Sbill 				index = np->p_index;
3091302Sbill 		pmaxindex = index;
3101302Sbill 	}
3111302Sbill }
3121302Sbill 
3131302Sbill /*
3141302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3151302Sbill  *	pp MUST be the job leader
3161302Sbill  */
3171302Sbill pclrcurr(pp)
3181302Sbill 	register struct process *pp;
3191302Sbill {
3201302Sbill 
3211302Sbill 	if (pp == pcurrent)
3221302Sbill 		if (pprevious != PNULL) {
3231302Sbill 			pcurrent = pprevious;
3241302Sbill 			pprevious = pgetcurr(pp);
3251302Sbill 		} else {
3261302Sbill 			pcurrent = pgetcurr(pp);
3271302Sbill 			pprevious = pgetcurr(pp);
3281302Sbill 		}
3291302Sbill 	else if (pp == pprevious)
3301302Sbill 		pprevious = pgetcurr(pp);
3311302Sbill }
3321302Sbill 
3331302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
3341302Sbill char	command[PMAXLEN+4];
3351302Sbill int	cmdlen;
3361302Sbill char	*cmdp;
3371302Sbill /*
3381302Sbill  * palloc - allocate a process structure and fill it up.
3391302Sbill  *	an important assumption is made that the process is running.
3401302Sbill  */
3411302Sbill palloc(pid, t)
3421302Sbill 	int pid;
3431302Sbill 	register struct command *t;
3441302Sbill {
3451302Sbill 	register struct process	*pp;
3461302Sbill 	int i;
3471302Sbill 
3481302Sbill 	pp = (struct process *)calloc(1, sizeof(struct process));
3491302Sbill 	pp->p_pid = pid;
35047724Sbostic 	pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING|PFOREGND;
35147724Sbostic 	if (t->t_dflg & F_TIME)
3521302Sbill 		pp->p_flags |= PPTIME;
3531302Sbill 	cmdp = command;
3541302Sbill 	cmdlen = 0;
3551302Sbill 	padd(t);
3561302Sbill 	*cmdp++ = 0;
35747724Sbostic 	if (t->t_dflg & F_PIPEOUT) {
3581302Sbill 		pp->p_flags |= PPOU;
35947724Sbostic 		if (t->t_dflg & F_STDERR)
3601302Sbill 			pp->p_flags |= PDIAG;
3611302Sbill 	}
3621302Sbill 	pp->p_command = savestr(command);
3631302Sbill 	if (pcurrjob) {
3641302Sbill 		struct process *fp;
3651302Sbill 		/* careful here with interrupt level */
3661302Sbill 		pp->p_cwd = 0;
3671302Sbill 		pp->p_index = pcurrjob->p_index;
3681302Sbill 		pp->p_friends = pcurrjob;
3691302Sbill 		pp->p_jobid = pcurrjob->p_pid;
3701302Sbill 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
3711302Sbill 			;
3721302Sbill 		fp->p_friends = pp;
3731302Sbill 	} else {
3741302Sbill 		pcurrjob = pp;
3751302Sbill 		pp->p_jobid = pid;
3761302Sbill 		pp->p_friends = pp;
3771302Sbill 		pp->p_cwd = dcwd;
3781302Sbill 		dcwd->di_count++;
3791302Sbill 		if (pmaxindex < BIGINDEX)
3801302Sbill 			pp->p_index = ++pmaxindex;
3811302Sbill 		else {
3821302Sbill 			struct process *np;
3831302Sbill 
3841302Sbill 			for (i = 1; ; i++) {
3851302Sbill 				for (np = proclist.p_next; np; np = np->p_next)
3861302Sbill 					if (np->p_index == i)
3871302Sbill 						goto tryagain;
3882357Swnj 				pp->p_index = i;
3892357Swnj 				if (i > pmaxindex)
3902357Swnj 					pmaxindex = i;
3911302Sbill 				break;
3921302Sbill 			tryagain:;
3931302Sbill 			}
3941302Sbill 		}
3951302Sbill 		if (pcurrent == PNULL)
3961302Sbill 			pcurrent = pp;
3971302Sbill 		else if (pprevious == PNULL)
3981302Sbill 			pprevious = pp;
3991302Sbill 	}
4001302Sbill 	pp->p_next = proclist.p_next;
4011302Sbill 	proclist.p_next = pp;
40217509Sedward 	(void) gettimeofday(&pp->p_btime, (struct timezone *)0);
4031302Sbill }
4041302Sbill 
4051302Sbill padd(t)
4061302Sbill 	register struct command *t;
4071302Sbill {
4081302Sbill 	char **argp;
4091302Sbill 
4101302Sbill 	if (t == 0)
4111302Sbill 		return;
4121302Sbill 	switch (t->t_dtyp) {
4131302Sbill 
41447724Sbostic 	case NODE_PAREN:
4151302Sbill 		pads("( ");
4161302Sbill 		padd(t->t_dspr);
4171302Sbill 		pads(" )");
4181302Sbill 		break;
4191302Sbill 
42047724Sbostic 	case NODE_COMMAND:
4211302Sbill 		for (argp = t->t_dcom; *argp; argp++) {
4221302Sbill 			pads(*argp);
4231302Sbill 			if (argp[1])
4241302Sbill 				pads(" ");
4251302Sbill 		}
4261302Sbill 		break;
4271302Sbill 
42847724Sbostic 	case NODE_OR:
42947724Sbostic 	case NODE_AND:
43047724Sbostic 	case NODE_PIPE:
43147724Sbostic 	case NODE_LIST:
4321302Sbill 		padd(t->t_dcar);
43317903Sedward 		switch (t->t_dtyp) {
43447724Sbostic 		case NODE_OR:
43517903Sedward 			pads(" || ");
43617903Sedward 			break;
43747724Sbostic 		case NODE_AND:
43817903Sedward 			pads(" && ");
43917903Sedward 			break;
44047724Sbostic 		case NODE_PIPE:
44117903Sedward 			pads(" | ");
44217903Sedward 			break;
44347724Sbostic 		case NODE_LIST:
44417903Sedward 			pads("; ");
44517903Sedward 			break;
44617903Sedward 		}
4471302Sbill 		padd(t->t_dcdr);
4481302Sbill 		return;
4491302Sbill 	}
45047724Sbostic 	if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
45147724Sbostic 		pads((t->t_dflg & F_READ) ? " << " : " < ");
4521302Sbill 		pads(t->t_dlef);
4531302Sbill 	}
45447724Sbostic 	if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
45547724Sbostic 		pads((t->t_dflg & F_APPEND) ? " >>" : " >");
45647724Sbostic 		if (t->t_dflg & F_STDERR)
4571302Sbill 			pads("&");
4581302Sbill 		pads(" ");
4591302Sbill 		pads(t->t_drit);
4601302Sbill 	}
4611302Sbill }
4621302Sbill 
4631302Sbill pads(cp)
4641302Sbill 	char *cp;
4651302Sbill {
4661302Sbill 	register int i = strlen(cp);
4671302Sbill 
4681302Sbill 	if (cmdlen >= PMAXLEN)
4691302Sbill 		return;
4701302Sbill 	if (cmdlen + i >= PMAXLEN) {
47117509Sedward 		(void) strcpy(cmdp, " ...");
4721302Sbill 		cmdlen = PMAXLEN;
4731302Sbill 		cmdp += 4;
4741302Sbill 		return;
4751302Sbill 	}
47617509Sedward 	(void) strcpy(cmdp, cp);
4771302Sbill 	cmdp += i;
4781302Sbill 	cmdlen += i;
4791302Sbill }
4801302Sbill 
4811302Sbill /*
4821302Sbill  * psavejob - temporarily save the current job on a one level stack
4831302Sbill  *	so another job can be created.  Used for { } in exp6
4841302Sbill  *	and `` in globbing.
4851302Sbill  */
4861302Sbill psavejob()
4871302Sbill {
4881302Sbill 
4891302Sbill 	pholdjob = pcurrjob;
4901302Sbill 	pcurrjob = PNULL;
4911302Sbill }
4921302Sbill 
4931302Sbill /*
4941302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
4951302Sbill  *	somewhere, but pendjob cleans up anyway.
4961302Sbill  */
4971302Sbill prestjob()
4981302Sbill {
4991302Sbill 
5001302Sbill 	pcurrjob = pholdjob;
5011302Sbill 	pholdjob = PNULL;
5021302Sbill }
5031302Sbill 
5041302Sbill /*
5051302Sbill  * pendjob - indicate that a job (set of commands) has been completed
5061302Sbill  *	or is about to begin.
5071302Sbill  */
5081302Sbill pendjob()
5091302Sbill {
5101302Sbill 	register struct process *pp, *tp;
5111302Sbill 
5121302Sbill 	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
5131302Sbill 		pp = pcurrjob;
5141302Sbill 		while (pp->p_pid != pp->p_jobid)
5151302Sbill 			pp = pp->p_friends;
5161302Sbill 		printf("[%d]", pp->p_index);
5171302Sbill 		tp = pp;
5181302Sbill 		do {
5191302Sbill 			printf(" %d", pp->p_pid);
5201302Sbill 			pp = pp->p_friends;
5211302Sbill 		} while (pp != tp);
5221302Sbill 		printf("\n");
5231302Sbill 	}
5241302Sbill 	pholdjob = pcurrjob = 0;
5251302Sbill }
5261302Sbill 
5271302Sbill /*
5281302Sbill  * pprint - print a job
5291302Sbill  */
5301302Sbill pprint(pp, flag)
5311302Sbill 	register struct process	*pp;
5321302Sbill {
5331302Sbill 	register status, reason;
5341302Sbill 	struct process *tp;
5351302Sbill 	extern char *linp, linbuf[];
5361302Sbill 	int jobflags, pstatus;
5371302Sbill 	char *format;
5381302Sbill 
5391302Sbill 	while (pp->p_pid != pp->p_jobid)
5401302Sbill 		pp = pp->p_friends;
5411302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
5421302Sbill 		pp->p_flags &= ~PPTIME;
5431302Sbill 		pp->p_flags |= PTIME;
5441302Sbill 	}
5451302Sbill 	tp = pp;
5461302Sbill 	status = reason = -1;
5471302Sbill 	jobflags = 0;
5481302Sbill 	do {
5491302Sbill 		jobflags |= pp->p_flags;
5501302Sbill 		pstatus = pp->p_flags & PALLSTATES;
5511302Sbill 		if (tp != pp && linp != linbuf && !(flag&FANCY) &&
5521302Sbill 		    (pstatus == status && pp->p_reason == reason ||
5531302Sbill 		     !(flag&REASON)))
5541302Sbill 			printf(" ");
5551302Sbill 		else {
5561302Sbill 			if (tp != pp && linp != linbuf)
5571302Sbill 				printf("\n");
5581302Sbill 			if(flag&NUMBER)
5591302Sbill 				if (pp == tp)
5601302Sbill 					printf("[%d]%s %c ", pp->p_index,
5611302Sbill 					    pp->p_index < 10 ? " " : "",
5621302Sbill 					    pp==pcurrent ? '+' :
5631302Sbill 						(pp == pprevious ? '-' : ' '));
5641302Sbill 				else
5651302Sbill 					printf("       ");
5661302Sbill 			if (flag&FANCY)
5671302Sbill 				printf("%5d ", pp->p_pid);
5681302Sbill 			if (flag&(REASON|AREASON)) {
5691302Sbill 				if (flag&NAME)
57032205Sbostic 					format = "%-23s";
5711302Sbill 				else
5721302Sbill 					format = "%s";
5731302Sbill 				if (pstatus == status)
5741302Sbill 					if (pp->p_reason == reason) {
5751302Sbill 						printf(format, "");
5761302Sbill 						goto prcomd;
5771302Sbill 					} else
5781302Sbill 						reason = pp->p_reason;
5791302Sbill 				else {
5801302Sbill 					status = pstatus;
5811302Sbill 					reason = pp->p_reason;
5821302Sbill 				}
5831302Sbill 				switch (status) {
5841302Sbill 
5851302Sbill 				case PRUNNING:
5861302Sbill 					printf(format, "Running ");
5871302Sbill 					break;
5881302Sbill 
5891302Sbill 				case PINTERRUPTED:
5901302Sbill 				case PSTOPPED:
5911302Sbill 				case PSIGNALED:
59228054Slepreau 					if ((flag&(REASON|AREASON))
59328054Slepreau 					    && reason != SIGINT
59428054Slepreau 					    && reason != SIGPIPE)
5951302Sbill 						printf(format, mesg[pp->p_reason].pname);
5961302Sbill 					break;
5971302Sbill 
5981302Sbill 				case PNEXITED:
5991302Sbill 				case PAEXITED:
6001302Sbill 					if (flag & REASON)
6011302Sbill 						if (pp->p_reason)
6021302Sbill 							printf("Exit %-16d", pp->p_reason);
6031302Sbill 						else
6041302Sbill 							printf(format, "Done");
6051302Sbill 					break;
6061302Sbill 
6071302Sbill 				default:
6081302Sbill 					printf("BUG: status=%-9o", status);
6091302Sbill 				}
6101302Sbill 			}
6111302Sbill 		}
6121302Sbill prcomd:
6131302Sbill 		if (flag&NAME) {
6141302Sbill 			printf("%s", pp->p_command);
6151302Sbill 			if (pp->p_flags & PPOU)
6161302Sbill 				printf(" |");
6171302Sbill 			if (pp->p_flags & PDIAG)
6181302Sbill 				printf("&");
6191302Sbill 		}
6201302Sbill 		if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
6211302Sbill 			printf(" (core dumped)");
6221302Sbill 		if (tp == pp->p_friends) {
6231302Sbill 			if (flag&AMPERSAND)
6241302Sbill 				printf(" &");
6251302Sbill 			if (flag&JOBDIR &&
6261302Sbill 			    !eq(tp->p_cwd->di_name, dcwd->di_name)) {
6271302Sbill 				printf(" (wd: ");
6281302Sbill 				dtildepr(value("home"), tp->p_cwd->di_name);
6291302Sbill 				printf(")");
6301302Sbill 			}
6311302Sbill 		}
6321302Sbill 		if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
6331302Sbill 			if (linp != linbuf)
6341302Sbill 				printf("\n\t");
63510035Ssam 			{ static struct rusage zru;
63610704Ssam 			  prusage(&zru, &pp->p_rusage, &pp->p_etime,
63710704Ssam 			    &pp->p_btime);
63810035Ssam 			}
6391302Sbill 		}
6401302Sbill 		if (tp == pp->p_friends) {
6411302Sbill 			if (linp != linbuf)
6421302Sbill 				printf("\n");
6431302Sbill 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
6441302Sbill 				printf("(wd now: ");
6451302Sbill 				dtildepr(value("home"), dcwd->di_name);
6461302Sbill 				printf(")\n");
6471302Sbill 			}
6481302Sbill 		}
6491302Sbill 	} while ((pp = pp->p_friends) != tp);
6501302Sbill 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
6511302Sbill 		if (jobflags & NUMBER)
6521302Sbill 			printf("       ");
6531302Sbill 		ptprint(tp);
6541302Sbill 	}
6551302Sbill 	return (jobflags);
6561302Sbill }
6571302Sbill 
6581302Sbill ptprint(tp)
6591302Sbill 	register struct process *tp;
6601302Sbill {
66110704Ssam 	struct timeval tetime, diff;
66210704Ssam 	static struct timeval ztime;
66310035Ssam 	struct rusage ru;
66410035Ssam 	static struct rusage zru;
6651302Sbill 	register struct process *pp = tp;
6661302Sbill 
66710035Ssam 	ru = zru;
66810704Ssam 	tetime = ztime;
6691302Sbill 	do {
67010035Ssam 		ruadd(&ru, &pp->p_rusage);
67110704Ssam 		tvsub(&diff, &pp->p_etime, &pp->p_btime);
67210704Ssam 		if (timercmp(&diff, &tetime, >))
67310704Ssam 			tetime = diff;
6741302Sbill 	} while ((pp = pp->p_friends) != tp);
67510704Ssam 	prusage(&zru, &ru, &tetime, &ztime);
6761302Sbill }
6771302Sbill 
6781302Sbill /*
6791302Sbill  * dojobs - print all jobs
6801302Sbill  */
6811302Sbill dojobs(v)
6821302Sbill 	char **v;
6831302Sbill {
6841302Sbill 	register struct process *pp;
6851302Sbill 	register int flag = NUMBER|NAME|REASON;
6861302Sbill 	int i;
6871302Sbill 
6881302Sbill 	if (chkstop)
6891302Sbill 		chkstop = 2;
6901302Sbill 	if (*++v) {
6911302Sbill 		if (v[1] || !eq(*v, "-l"))
6921302Sbill 			error("Usage: jobs [ -l ]");
6931302Sbill 		flag |= FANCY|JOBDIR;
6941302Sbill 	}
6951302Sbill 	for (i = 1; i <= pmaxindex; i++)
6961302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
6971302Sbill 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
6981302Sbill 				pp->p_flags &= ~PNEEDNOTE;
6991302Sbill 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
7001302Sbill 					pflush(pp);
7011302Sbill 				break;
7021302Sbill 			}
7031302Sbill }
7041302Sbill 
7051302Sbill /*
7061302Sbill  * dofg - builtin - put the job into the foreground
7071302Sbill  */
7081302Sbill dofg(v)
7091302Sbill 	char **v;
7101302Sbill {
7111302Sbill 	register struct process *pp;
7121302Sbill 
7131302Sbill 	okpcntl();
7141302Sbill 	++v;
7151302Sbill 	do {
7161302Sbill 		pp = pfind(*v);
7171302Sbill 		pstart(pp, 1);
7181302Sbill 		pjwait(pp);
7191302Sbill 	} while (*v && *++v);
7201302Sbill }
7211302Sbill 
7221302Sbill /*
7231302Sbill  * %... - builtin - put the job into the foreground
7241302Sbill  */
7251302Sbill dofg1(v)
7261302Sbill 	char **v;
7271302Sbill {
7281302Sbill 	register struct process *pp;
7291302Sbill 
7301302Sbill 	okpcntl();
7311302Sbill 	pp = pfind(v[0]);
7321302Sbill 	pstart(pp, 1);
7331302Sbill 	pjwait(pp);
7341302Sbill }
7351302Sbill 
7361302Sbill /*
7371302Sbill  * dobg - builtin - put the job into the background
7381302Sbill  */
7391302Sbill dobg(v)
7401302Sbill 	char **v;
7411302Sbill {
7421302Sbill 	register struct process *pp;
7431302Sbill 
7441302Sbill 	okpcntl();
7451302Sbill 	++v;
7461302Sbill 	do {
7471302Sbill 		pp = pfind(*v);
7481302Sbill 		pstart(pp, 0);
7491302Sbill 	} while (*v && *++v);
7501302Sbill }
7511302Sbill 
7521302Sbill /*
7531302Sbill  * %... & - builtin - put the job into the background
7541302Sbill  */
7551302Sbill dobg1(v)
7561302Sbill 	char **v;
7571302Sbill {
7581302Sbill 	register struct process *pp;
7591302Sbill 
7601302Sbill 	pp = pfind(v[0]);
7611302Sbill 	pstart(pp, 0);
7621302Sbill }
7631302Sbill 
7641302Sbill /*
7651302Sbill  * dostop - builtin - stop the job
7661302Sbill  */
7671302Sbill dostop(v)
7681302Sbill 	char **v;
7691302Sbill {
7701302Sbill 
7711302Sbill 	pkill(++v, SIGSTOP);
7721302Sbill }
7731302Sbill 
7741302Sbill /*
7751302Sbill  * dokill - builtin - superset of kill (1)
7761302Sbill  */
7771302Sbill dokill(v)
7781302Sbill 	char **v;
7791302Sbill {
7801302Sbill 	register int signum;
7811302Sbill 	register char *name;
7821302Sbill 
7831302Sbill 	v++;
7841302Sbill 	if (v[0] && v[0][0] == '-') {
7851302Sbill 		if (v[0][1] == 'l') {
7861302Sbill 			for (signum = 1; signum <= NSIG; signum++) {
7871302Sbill 				if (name = mesg[signum].iname)
7881302Sbill 					printf("%s ", name);
7891302Sbill 				if (signum == 16)
79034340Sbostic 					cshputchar('\n');
7911302Sbill 			}
79234340Sbostic 			cshputchar('\n');
7931302Sbill 			return;
7941302Sbill 		}
7951302Sbill 		if (digit(v[0][1])) {
7961302Sbill 			signum = atoi(v[0]+1);
79728054Slepreau 			if (signum < 0 || signum > NSIG)
7981302Sbill 				bferr("Bad signal number");
7991302Sbill 		} else {
8001302Sbill 			name = &v[0][1];
8011302Sbill 			for (signum = 1; signum <= NSIG; signum++)
8021302Sbill 			if (mesg[signum].iname &&
8031302Sbill 			    eq(name, mesg[signum].iname))
8041302Sbill 				goto gotsig;
8051302Sbill 			setname(name);
8061302Sbill 			bferr("Unknown signal; kill -l lists signals");
8071302Sbill 		}
8081302Sbill gotsig:
8091302Sbill 		v++;
8101302Sbill 	} else
8111302Sbill 		signum = SIGTERM;
8121302Sbill 	pkill(v, signum);
8131302Sbill }
8141302Sbill 
8151302Sbill pkill(v, signum)
8161302Sbill 	char **v;
8171302Sbill 	int signum;
8181302Sbill {
8191302Sbill 	register struct process *pp, *np;
8201302Sbill 	register int jobflags = 0;
82131685Sbostic 	int pid, err = 0;
82231685Sbostic 	long omask;
82313561Ssam 	char *cp;
8241302Sbill 
82517136Sralph 	omask = sigmask(SIGCHLD);
8261302Sbill 	if (setintr)
82717136Sralph 		omask |= sigmask(SIGINT);
82817136Sralph 	omask = sigblock(omask) & ~omask;
8291302Sbill 	while (*v) {
83013561Ssam 		cp = globone(*v);
83113561Ssam 		if (*cp == '%') {
83213561Ssam 			np = pp = pfind(cp);
8331302Sbill 			do
8341302Sbill 				jobflags |= np->p_flags;
8351302Sbill 			while ((np = np->p_friends) != pp);
8361302Sbill 			switch (signum) {
8371302Sbill 
8381302Sbill 			case SIGSTOP:
8391302Sbill 			case SIGTSTP:
8401302Sbill 			case SIGTTIN:
8411302Sbill 			case SIGTTOU:
8421302Sbill 				if ((jobflags & PRUNNING) == 0) {
84332205Sbostic 					printf("%s: Already suspended\n", cp);
8441302Sbill 					err++;
8451302Sbill 					goto cont;
8461302Sbill 				}
8471302Sbill 			}
84818424Smckusick 			if (killpg(pp->p_jobid, signum) < 0) {
84944759Smarc 				printf("%s: %s\n", cp, strerror(errno));
85018424Smckusick 				err++;
85118424Smckusick 			}
8521302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
85317509Sedward 				(void) killpg(pp->p_jobid, SIGCONT);
85428054Slepreau 		} else if (!(digit(*cp) || *cp == '-'))
8551302Sbill 			bferr("Arguments should be jobs or process id's");
8561302Sbill 		else {
85713561Ssam 			pid = atoi(cp);
8581302Sbill 			if (kill(pid, signum) < 0) {
85944759Smarc 				printf("%d: %s\n", pid, strerror(errno));
8601302Sbill 				err++;
8611302Sbill 				goto cont;
8621302Sbill 			}
8631302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
86417509Sedward 				(void) kill(pid, SIGCONT);
8651302Sbill 		}
8661302Sbill cont:
86713561Ssam 		xfree(cp);
8681302Sbill 		v++;
8691302Sbill 	}
87017509Sedward 	(void) sigsetmask(omask);
8711302Sbill 	if (err)
8721302Sbill 		error(NOSTR);
8731302Sbill }
8741302Sbill 
8751302Sbill /*
8761302Sbill  * pstart - start the job in foreground/background
8771302Sbill  */
8781302Sbill pstart(pp, foregnd)
8791302Sbill 	register struct process *pp;
8801302Sbill 	int foregnd;
8811302Sbill {
8821302Sbill 	register struct process *np;
88331685Sbostic 	int jobflags = 0;
88431685Sbostic 	long omask;
8851302Sbill 
88617136Sralph 	omask = sigblock(sigmask(SIGCHLD));
8871302Sbill 	np = pp;
8881302Sbill 	do {
8891302Sbill 		jobflags |= np->p_flags;
8901302Sbill 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
8911302Sbill 			np->p_flags |= PRUNNING;
8921302Sbill 			np->p_flags &= ~PSTOPPED;
8931302Sbill 			if (foregnd)
8941302Sbill 				np->p_flags |= PFOREGND;
8951302Sbill 			else
8961302Sbill 				np->p_flags &= ~PFOREGND;
8971302Sbill 		}
8981302Sbill 	} while((np = np->p_friends) != pp);
8992357Swnj 	if (!foregnd)
9002357Swnj 		pclrcurr(pp);
90117509Sedward 	(void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
9021302Sbill 	if (foregnd)
90317509Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid);
9041302Sbill 	if (jobflags&PSTOPPED)
90517509Sedward 		(void) killpg(pp->p_jobid, SIGCONT);
90617509Sedward 	(void) sigsetmask(omask);
9071302Sbill }
9081302Sbill 
9091302Sbill panystop(neednl)
9101302Sbill {
9111302Sbill 	register struct process *pp;
9121302Sbill 
9131302Sbill 	chkstop = 2;
9141302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9151302Sbill 		if (pp->p_flags & PSTOPPED)
91632205Sbostic 			error("\nThere are suspended jobs" + 1 - neednl);
9171302Sbill }
9181302Sbill 
9191302Sbill struct process *
9201302Sbill pfind(cp)
9211302Sbill 	char *cp;
9221302Sbill {
9231302Sbill 	register struct process *pp, *np;
9241302Sbill 
9251302Sbill 	if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
9261302Sbill 		if (pcurrent == PNULL)
9271302Sbill 			bferr("No current job");
9281302Sbill 		return (pcurrent);
9291302Sbill 	}
9301302Sbill 	if (eq(cp, "%-") || eq(cp, "%#")) {
9311302Sbill 		if (pprevious == PNULL)
9321302Sbill 			bferr("No previous job");
9331302Sbill 		return (pprevious);
9341302Sbill 	}
9351302Sbill 	if (digit(cp[1])) {
9361302Sbill 		int index = atoi(cp+1);
9371302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
9381302Sbill 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
9391302Sbill 				return (pp);
9401302Sbill 		bferr("No such job");
9411302Sbill 	}
9421302Sbill 	np = PNULL;
9431302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9441302Sbill 		if (pp->p_pid == pp->p_jobid) {
9451302Sbill 			if (cp[1] == '?') {
9461302Sbill 				register char *dp;
9471302Sbill 				for (dp = pp->p_command; *dp; dp++) {
9481302Sbill 					if (*dp != cp[2])
9491302Sbill 						continue;
9501302Sbill 					if (prefix(cp+2, dp))
9511302Sbill 						goto match;
9521302Sbill 				}
9531302Sbill 			} else if (prefix(cp+1, pp->p_command)) {
9541302Sbill match:
9551302Sbill 				if (np)
9561302Sbill 					bferr("Ambiguous");
9571302Sbill 				np = pp;
9581302Sbill 			}
9591302Sbill 		}
9601302Sbill 	if (np)
9611302Sbill 		return (np);
9621302Sbill 	if (cp[1] == '?')
9631302Sbill 		bferr("No job matches pattern");
9641302Sbill 	else
9651302Sbill 		bferr("No such job");
96617509Sedward 	/*NOTREACHED*/
9671302Sbill }
9681302Sbill 
9691302Sbill /*
9702357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
9711302Sbill  */
9721302Sbill struct process *
9731302Sbill pgetcurr(pp)
9741302Sbill 	register struct process *pp;
9751302Sbill {
9761302Sbill 	register struct process *np;
9772357Swnj 	register struct process *xp = PNULL;
9781302Sbill 
9791302Sbill 	for (np = proclist.p_next; np; np = np->p_next)
9801302Sbill 		if (np != pcurrent && np != pp && np->p_pid &&
9811302Sbill 		    np->p_pid == np->p_jobid) {
9822357Swnj 			if (np->p_flags & PSTOPPED)
9832357Swnj 				return (np);
9842357Swnj 			if (xp == PNULL)
9852357Swnj 				xp = np;
9861302Sbill 		}
9872357Swnj 	return (xp);
9881302Sbill }
9891302Sbill 
9901302Sbill /*
9911302Sbill  * donotify - flag the job so as to report termination asynchronously
9921302Sbill  */
9931302Sbill donotify(v)
9941302Sbill 	char **v;
9951302Sbill {
9961302Sbill 	register struct process *pp;
9971302Sbill 
9981302Sbill 	pp = pfind(*++v);
9991302Sbill 	pp->p_flags |= PNOTIFY;
10001302Sbill }
10011302Sbill 
10021302Sbill /*
10031302Sbill  * Do the fork and whatever should be done in the child side that
10041302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
10051302Sbill  * Also do everything that needs any signals fiddled with in the parent side
10061302Sbill  *
10071302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
10081302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
10091302Sbill  *	 0:	already have tty; manipulate process pgrps only
10101302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
10111302Sbill  * It is usually just the value of tpgrp.
10121302Sbill  */
10131302Sbill pfork(t, wanttty)
10141302Sbill 	struct command *t;	/* command we are forking for */
10151302Sbill 	int wanttty;
10161302Sbill {
10171302Sbill 	register int pid;
10181302Sbill 	bool ignint = 0;
101931685Sbostic 	int pgrp;
102031685Sbostic 	long omask;
10211302Sbill 
10221302Sbill 	/*
10231302Sbill 	 * A child will be uninterruptible only under very special
10241302Sbill 	 * conditions. Remember that the semantics of '&' is
10251302Sbill 	 * implemented by disconnecting the process from the tty so
10261302Sbill 	 * signals do not need to ignored just for '&'.
10271302Sbill 	 * Thus signals are set to default action for children unless:
10281302Sbill 	 *	we have had an "onintr -" (then specifically ignored)
10291302Sbill 	 *	we are not playing with signals (inherit action)
10301302Sbill 	 */
10311302Sbill 	if (setintr)
103247724Sbostic 		ignint = (tpgrp == -1 && (t->t_dflg&F_NOINTERRUPT))
10331302Sbill 		    || (gointr && eq(gointr, "-"));
10341302Sbill 	/*
10351302Sbill 	 * Hold SIGCHLD until we have the process installed in our table.
10361302Sbill 	 */
103717136Sralph 	omask = sigblock(sigmask(SIGCHLD));
10381302Sbill 	while ((pid = fork()) < 0)
10391302Sbill 		if (setintr == 0)
10401302Sbill 			sleep(FORKSLEEP);
10411302Sbill 		else {
104217509Sedward 			(void) sigsetmask(omask);
10431302Sbill 			error("No more processes");
10441302Sbill 		}
10451302Sbill 	if (pid == 0) {
10461302Sbill 		settimes();
10471302Sbill 		pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
10481302Sbill 		pflushall();
10491302Sbill 		pcurrjob = PNULL;
10501302Sbill 		child++;
10511302Sbill 		if (setintr) {
10521302Sbill 			setintr = 0;		/* until I think otherwise */
10531302Sbill 			/*
10541302Sbill 			 * Children just get blown away on SIGINT, SIGQUIT
10551302Sbill 			 * unless "onintr -" seen.
10561302Sbill 			 */
105717509Sedward 			(void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
105817509Sedward 			(void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
10591302Sbill 			if (wanttty >= 0) {
10601302Sbill 				/* make stoppable */
106117509Sedward 				(void) signal(SIGTSTP, SIG_DFL);
106217509Sedward 				(void) signal(SIGTTIN, SIG_DFL);
106317509Sedward 				(void) signal(SIGTTOU, SIG_DFL);
10641302Sbill 			}
106517509Sedward 			(void) signal(SIGTERM, parterm);
106647724Sbostic 		} else if (tpgrp == -1 && (t->t_dflg&F_NOINTERRUPT)) {
106717509Sedward 			(void) signal(SIGINT, SIG_IGN);
106817509Sedward 			(void) signal(SIGQUIT, SIG_IGN);
10691302Sbill 		}
107044759Smarc 		if (wanttty >= 0 && tpgrp >= 0)
107144759Smarc 			(void) setpgrp(0, pgrp);
10721302Sbill 		if (wanttty > 0)
107317509Sedward 			(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp);
10741302Sbill 		if (tpgrp > 0)
10751302Sbill 			tpgrp = 0;		/* gave tty away */
10761302Sbill 		/*
107747724Sbostic 		 * Nohup and nice apply only to NODE_COMMAND's but it would be
107847724Sbostic 		 * nice (?!?) if you could say "nohup (foo;bar)".  Then the
107947724Sbostic 		 * parser would have to know about nice/nohup/time.
10801302Sbill 		 */
108147724Sbostic 		if (t->t_dflg & F_NOHUP)
108217509Sedward 			(void) signal(SIGHUP, SIG_IGN);
108347724Sbostic 		if (t->t_dflg & F_NICE)
108428054Slepreau 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
10851302Sbill 	} else {
108639545Smarc 		if (wanttty >= 0 && tpgrp >= 0)
108739545Smarc 			(void) setpgrp(pid, pcurrjob ? pcurrjob->p_jobid : pid);
10881302Sbill 		palloc(pid, t);
108917509Sedward 		(void) sigsetmask(omask);
10901302Sbill 	}
10911302Sbill 
10921302Sbill 	return (pid);
10931302Sbill }
10941302Sbill 
10951302Sbill okpcntl()
10961302Sbill {
10971302Sbill 
10981302Sbill 	if (tpgrp == -1)
10991302Sbill 		error("No job control in this shell");
11001302Sbill 	if (tpgrp == 0)
11011302Sbill 		error("No job control in subshells");
11021302Sbill }
1103