xref: /csrg-svn/bin/csh/proc.c (revision 21940)
1*21940Sdist /*
2*21940Sdist  * Copyright (c) 1980 Regents of the University of California.
3*21940Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21940Sdist  * specifies the terms and conditions for redistribution.
5*21940Sdist  */
6*21940Sdist 
717509Sedward #ifndef lint
8*21940Sdist static char sccsid[] = "@(#)proc.c	5.1 (Berkeley) 06/04/85";
9*21940Sdist #endif not lint
101302Sbill 
111302Sbill #include "sh.h"
121302Sbill #include "sh.dir.h"
131302Sbill #include "sh.proc.h"
1413590Swnj #include <sys/wait.h>
151302Sbill #include <sys/ioctl.h>
161302Sbill 
171302Sbill /*
181302Sbill  * C Shell - functions that manage processes, handling hanging, termination
191302Sbill  */
201302Sbill 
211302Sbill #define BIGINDEX	9	/* largest desirable job index */
221302Sbill 
231302Sbill /*
241302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
251302Sbill  *	indicating that at least one child has terminated or stopped
261302Sbill  *	thus at least one wait system call will definitely return a
271302Sbill  *	childs status.  Top level routines (like pwait) must be sure
281302Sbill  *	to mask interrupts when playing with the proclist data structures!
291302Sbill  */
301302Sbill pchild()
311302Sbill {
321302Sbill 	register struct process *pp;
331302Sbill 	register struct process	*fp;
341302Sbill 	register int pid;
351302Sbill 	union wait w;
361302Sbill 	int jobflags;
3710035Ssam 	struct rusage ru;
381302Sbill 
391302Sbill loop:
4017509Sedward 	pid = wait3(&w, (setintr ? WNOHANG|WUNTRACED:WNOHANG), &ru);
411302Sbill 	if (pid <= 0) {
421302Sbill 		if (errno == EINTR) {
431302Sbill 			errno = 0;
441302Sbill 			goto loop;
451302Sbill 		}
461302Sbill 		pnoprocesses = pid == -1;
471302Sbill 		return;
481302Sbill 	}
491302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
501302Sbill 		if (pid == pp->p_pid)
511302Sbill 			goto found;
521302Sbill 	goto loop;
531302Sbill found:
541302Sbill 	if (pid == atoi(value("child")))
551302Sbill 		unsetv("child");
561302Sbill 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
571302Sbill 	if (WIFSTOPPED(w)) {
581302Sbill 		pp->p_flags |= PSTOPPED;
591302Sbill 		pp->p_reason = w.w_stopsig;
601302Sbill 	} else {
6117509Sedward 		if (pp->p_flags & (PTIME|PPTIME) || adrof("time"))
6217509Sedward 			(void) gettimeofday(&pp->p_etime, (struct timezone *)0);
6310035Ssam 		pp->p_rusage = ru;
641302Sbill 		if (WIFSIGNALED(w)) {
651302Sbill 			if (w.w_termsig == SIGINT)
661302Sbill 				pp->p_flags |= PINTERRUPTED;
671302Sbill 			else
681302Sbill 				pp->p_flags |= PSIGNALED;
691302Sbill 			if (w.w_coredump)
701302Sbill 				pp->p_flags |= PDUMPED;
711302Sbill 			pp->p_reason = w.w_termsig;
721302Sbill 		} else {
731302Sbill 			pp->p_reason = w.w_retcode;
741302Sbill 			if (pp->p_reason != 0)
751302Sbill 				pp->p_flags |= PAEXITED;
761302Sbill 			else
771302Sbill 				pp->p_flags |= PNEXITED;
781302Sbill 		}
791302Sbill 	}
801302Sbill 	jobflags = 0;
811302Sbill 	fp = pp;
821302Sbill 	do {
831302Sbill 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
841302Sbill 		    !child && adrof("time") &&
8517509Sedward 		    fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
861302Sbill 		     atoi(value("time")))
871302Sbill 			fp->p_flags |= PTIME;
881302Sbill 		jobflags |= fp->p_flags;
891302Sbill 	} while ((fp = fp->p_friends) != pp);
901302Sbill 	pp->p_flags &= ~PFOREGND;
911302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
921302Sbill 		pp->p_flags &= ~PPTIME;
931302Sbill 		pp->p_flags |= PTIME;
941302Sbill 	}
951302Sbill 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
961302Sbill 		fp = pp;
971302Sbill 		do {
981302Sbill 			if (fp->p_flags&PSTOPPED)
991302Sbill 				fp->p_flags |= PREPORTED;
1001302Sbill 		} while((fp = fp->p_friends) != pp);
1011302Sbill 		while(fp->p_pid != fp->p_jobid)
1021302Sbill 			fp = fp->p_friends;
1032357Swnj 		if (jobflags&PSTOPPED) {
1042357Swnj 			if (pcurrent && pcurrent != fp)
1052357Swnj 				pprevious = pcurrent;
1062357Swnj 			pcurrent = fp;
1072357Swnj 		} else
1082357Swnj 			pclrcurr(fp);
1091302Sbill 		if (jobflags&PFOREGND) {
1101302Sbill 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
1111302Sbill #ifdef IIASA
1121302Sbill 			    jobflags & PAEXITED ||
1131302Sbill #endif
1141302Sbill 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
1153213Swnj 				;	/* print in pjwait */
1163646Sroot 			}
1173646Sroot /*
1183646Sroot 		else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
1191302Sbill 				ptprint(fp);
1203646Sroot */
1211302Sbill 		} else {
1221302Sbill 			if (jobflags&PNOTIFY || adrof("notify")) {
1231302Sbill 				printf("\215\n");
12417509Sedward 				(void) pprint(pp, NUMBER|NAME|REASON);
1251302Sbill 				if ((jobflags&PSTOPPED) == 0)
1261302Sbill 					pflush(pp);
1271302Sbill 			} else {
1281302Sbill 				fp->p_flags |= PNEEDNOTE;
1291302Sbill 				neednote++;
1301302Sbill 			}
1311302Sbill 		}
1321302Sbill 	}
1331302Sbill 	goto loop;
1341302Sbill }
1351302Sbill 
1361302Sbill pnote()
1371302Sbill {
1381302Sbill 	register struct process *pp;
13917136Sralph 	int flags, omask;
1401302Sbill 
1411302Sbill 	neednote = 0;
1421302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
1431302Sbill 		if (pp->p_flags & PNEEDNOTE) {
14417136Sralph 			omask = sigblock(sigmask(SIGCHLD));
1451302Sbill 			pp->p_flags &= ~PNEEDNOTE;
1461302Sbill 			flags = pprint(pp, NUMBER|NAME|REASON);
1471302Sbill 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
1481302Sbill 				pflush(pp);
14917509Sedward 			(void) sigsetmask(omask);
1501302Sbill 		}
1511302Sbill 	}
1521302Sbill }
1531302Sbill 
1541302Sbill /*
1551302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1561302Sbill  *	of current and previous job indicators.
1571302Sbill  */
1581302Sbill pwait()
1591302Sbill {
1601302Sbill 	register struct process *fp, *pp;
16117136Sralph 	int omask;
1621302Sbill 
1631302Sbill 	/*
1641302Sbill 	 * Here's where dead procs get flushed.
1651302Sbill 	 */
16617136Sralph 	omask = sigblock(sigmask(SIGCHLD));
1671302Sbill 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
1681302Sbill 		if (pp->p_pid == 0) {
1691302Sbill 			fp->p_next = pp->p_next;
1701302Sbill 			xfree(pp->p_command);
1711302Sbill 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
1721302Sbill 				if (pp->p_cwd->di_next == 0)
1731302Sbill 					dfree(pp->p_cwd);
1741302Sbill 			xfree((char *)pp);
1751302Sbill 			pp = fp;
1761302Sbill 		}
17717509Sedward 	(void) sigsetmask(omask);
1781302Sbill 	pjwait(pcurrjob);
1791302Sbill }
1801302Sbill 
1811302Sbill /*
1821302Sbill  * pjwait - wait for a job to finish or become stopped
1831302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
1841302Sbill  */
1851302Sbill pjwait(pp)
1861302Sbill 	register struct process *pp;
1871302Sbill {
1881302Sbill 	register struct process *fp;
18917136Sralph 	int jobflags, reason, omask;
1901302Sbill 
19113561Ssam 	while (pp->p_pid != pp->p_jobid)
19213561Ssam 		pp = pp->p_friends;
1931302Sbill 	fp = pp;
1941302Sbill 	do {
1951302Sbill 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
1961302Sbill 			printf("BUG: waiting for background job!\n");
1971302Sbill 	} while ((fp = fp->p_friends) != pp);
1981302Sbill 	/*
1991302Sbill 	 * Now keep pausing as long as we are not interrupted (SIGINT),
2001302Sbill 	 * and the target process, or any of its friends, are running
2011302Sbill 	 */
2021302Sbill 	fp = pp;
20317136Sralph 	omask = sigblock(sigmask(SIGCHLD));
2041302Sbill 	for (;;) {
2051302Sbill 		jobflags = 0;
2061302Sbill 		do
2071302Sbill 			jobflags |= fp->p_flags;
20817136Sralph 		while ((fp = (fp->p_friends)) != pp);
2091302Sbill 		if ((jobflags & PRUNNING) == 0)
2101302Sbill 			break;
21117136Sralph 		sigpause(0);
2121302Sbill 	}
21317509Sedward 	(void) sigsetmask(omask);
21417509Sedward 	if (tpgrp > 0)			/* get tty back */
21517509Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
2163487Sroot 	if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
2173487Sroot 	     !eq(dcwd->di_name, fp->p_cwd->di_name)) {
2183487Sroot 		if (jobflags&PSTOPPED)
2193487Sroot 			printf("\n");
22017509Sedward 		(void) pprint(pp, AREASON|SHELLDIR);
2213487Sroot 	}
2223213Swnj 	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2231302Sbill 	    (!gointr || !eq(gointr, "-"))) {
2243213Swnj 		if ((jobflags & PSTOPPED) == 0)
2253213Swnj 			pflush(pp);
2263213Swnj 		pintr1(0);
2271302Sbill 		/*NOTREACHED*/
2281302Sbill 	}
2291302Sbill 	reason = 0;
2301302Sbill 	fp = pp;
2311302Sbill 	do {
2321302Sbill 		if (fp->p_reason)
2331302Sbill 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
2341302Sbill 				fp->p_reason | QUOTE : fp->p_reason;
2351302Sbill 	} while ((fp = fp->p_friends) != pp);
2361302Sbill 	set("status", putn(reason));
2371302Sbill 	if (reason && exiterr)
2381302Sbill 		exitstat();
2391302Sbill 	pflush(pp);
2401302Sbill }
2411302Sbill 
2421302Sbill /*
2431302Sbill  * dowait - wait for all processes to finish
2441302Sbill  */
2451302Sbill dowait()
2461302Sbill {
2471302Sbill 	register struct process *pp;
24817136Sralph 	int omask;
2491302Sbill 
2501302Sbill 	pjobs++;
25117136Sralph 	omask = sigblock(sigmask(SIGCHLD));
2521302Sbill loop:
2531302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
25413561Ssam 		if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
2551302Sbill 		    pp->p_flags&PRUNNING) {
25617136Sralph 			sigpause(0);
2571302Sbill 			goto loop;
2581302Sbill 		}
25917509Sedward 	(void) sigsetmask(omask);
2601302Sbill 	pjobs = 0;
2611302Sbill }
2621302Sbill 
2631302Sbill /*
2641302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
2651302Sbill  */
2661302Sbill pflushall()
2671302Sbill {
2681302Sbill 	register struct process	*pp;
2691302Sbill 
2701302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
2711302Sbill 		if (pp->p_pid)
2721302Sbill 			pflush(pp);
2731302Sbill }
2741302Sbill 
2751302Sbill /*
2761302Sbill  * pflush - flag all process structures in the same job as the
2771302Sbill  *	the argument process for deletion.  The actual free of the
2781302Sbill  *	space is not done here since pflush is called at interrupt level.
2791302Sbill  */
2801302Sbill pflush(pp)
2811302Sbill 	register struct process	*pp;
2821302Sbill {
2831302Sbill 	register struct process *np;
2841302Sbill 	register int index;
2851302Sbill 
2861302Sbill 	if (pp->p_pid == 0) {
2871302Sbill 		printf("BUG: process flushed twice");
2881302Sbill 		return;
2891302Sbill 	}
2901302Sbill 	while (pp->p_pid != pp->p_jobid)
2911302Sbill 		pp = pp->p_friends;
2921302Sbill 	pclrcurr(pp);
2931302Sbill 	if (pp == pcurrjob)
2941302Sbill 		pcurrjob = 0;
2951302Sbill 	index = pp->p_index;
2961302Sbill 	np = pp;
2971302Sbill 	do {
2981302Sbill 		np->p_index = np->p_pid = 0;
2991302Sbill 		np->p_flags &= ~PNEEDNOTE;
3001302Sbill 	} while ((np = np->p_friends) != pp);
3011302Sbill 	if (index == pmaxindex) {
3021302Sbill 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
3031302Sbill 			if (np->p_index > index)
3041302Sbill 				index = np->p_index;
3051302Sbill 		pmaxindex = index;
3061302Sbill 	}
3071302Sbill }
3081302Sbill 
3091302Sbill /*
3101302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3111302Sbill  *	pp MUST be the job leader
3121302Sbill  */
3131302Sbill pclrcurr(pp)
3141302Sbill 	register struct process *pp;
3151302Sbill {
3161302Sbill 
3171302Sbill 	if (pp == pcurrent)
3181302Sbill 		if (pprevious != PNULL) {
3191302Sbill 			pcurrent = pprevious;
3201302Sbill 			pprevious = pgetcurr(pp);
3211302Sbill 		} else {
3221302Sbill 			pcurrent = pgetcurr(pp);
3231302Sbill 			pprevious = pgetcurr(pp);
3241302Sbill 		}
3251302Sbill 	else if (pp == pprevious)
3261302Sbill 		pprevious = pgetcurr(pp);
3271302Sbill }
3281302Sbill 
3291302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
3301302Sbill char	command[PMAXLEN+4];
3311302Sbill int	cmdlen;
3321302Sbill char	*cmdp;
3331302Sbill /*
3341302Sbill  * palloc - allocate a process structure and fill it up.
3351302Sbill  *	an important assumption is made that the process is running.
3361302Sbill  */
3371302Sbill palloc(pid, t)
3381302Sbill 	int pid;
3391302Sbill 	register struct command *t;
3401302Sbill {
3411302Sbill 	register struct process	*pp;
3421302Sbill 	int i;
3431302Sbill 
3441302Sbill 	pp = (struct process *)calloc(1, sizeof(struct process));
3451302Sbill 	pp->p_pid = pid;
3461302Sbill 	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
3471302Sbill 	if (t->t_dflg & FTIME)
3481302Sbill 		pp->p_flags |= PPTIME;
3491302Sbill 	cmdp = command;
3501302Sbill 	cmdlen = 0;
3511302Sbill 	padd(t);
3521302Sbill 	*cmdp++ = 0;
3531302Sbill 	if (t->t_dflg & FPOU) {
3541302Sbill 		pp->p_flags |= PPOU;
3551302Sbill 		if (t->t_dflg & FDIAG)
3561302Sbill 			pp->p_flags |= PDIAG;
3571302Sbill 	}
3581302Sbill 	pp->p_command = savestr(command);
3591302Sbill 	if (pcurrjob) {
3601302Sbill 		struct process *fp;
3611302Sbill 		/* careful here with interrupt level */
3621302Sbill 		pp->p_cwd = 0;
3631302Sbill 		pp->p_index = pcurrjob->p_index;
3641302Sbill 		pp->p_friends = pcurrjob;
3651302Sbill 		pp->p_jobid = pcurrjob->p_pid;
3661302Sbill 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
3671302Sbill 			;
3681302Sbill 		fp->p_friends = pp;
3691302Sbill 	} else {
3701302Sbill 		pcurrjob = pp;
3711302Sbill 		pp->p_jobid = pid;
3721302Sbill 		pp->p_friends = pp;
3731302Sbill 		pp->p_cwd = dcwd;
3741302Sbill 		dcwd->di_count++;
3751302Sbill 		if (pmaxindex < BIGINDEX)
3761302Sbill 			pp->p_index = ++pmaxindex;
3771302Sbill 		else {
3781302Sbill 			struct process *np;
3791302Sbill 
3801302Sbill 			for (i = 1; ; i++) {
3811302Sbill 				for (np = proclist.p_next; np; np = np->p_next)
3821302Sbill 					if (np->p_index == i)
3831302Sbill 						goto tryagain;
3842357Swnj 				pp->p_index = i;
3852357Swnj 				if (i > pmaxindex)
3862357Swnj 					pmaxindex = i;
3871302Sbill 				break;
3881302Sbill 			tryagain:;
3891302Sbill 			}
3901302Sbill 		}
3911302Sbill 		if (pcurrent == PNULL)
3921302Sbill 			pcurrent = pp;
3931302Sbill 		else if (pprevious == PNULL)
3941302Sbill 			pprevious = pp;
3951302Sbill 	}
3961302Sbill 	pp->p_next = proclist.p_next;
3971302Sbill 	proclist.p_next = pp;
39817509Sedward 	(void) gettimeofday(&pp->p_btime, (struct timezone *)0);
3991302Sbill }
4001302Sbill 
4011302Sbill padd(t)
4021302Sbill 	register struct command *t;
4031302Sbill {
4041302Sbill 	char **argp;
4051302Sbill 
4061302Sbill 	if (t == 0)
4071302Sbill 		return;
4081302Sbill 	switch (t->t_dtyp) {
4091302Sbill 
4101302Sbill 	case TPAR:
4111302Sbill 		pads("( ");
4121302Sbill 		padd(t->t_dspr);
4131302Sbill 		pads(" )");
4141302Sbill 		break;
4151302Sbill 
4161302Sbill 	case TCOM:
4171302Sbill 		for (argp = t->t_dcom; *argp; argp++) {
4181302Sbill 			pads(*argp);
4191302Sbill 			if (argp[1])
4201302Sbill 				pads(" ");
4211302Sbill 		}
4221302Sbill 		break;
4231302Sbill 
42417903Sedward 	case TOR:
42517903Sedward 	case TAND:
4261302Sbill 	case TFIL:
4271302Sbill 	case TLST:
4281302Sbill 		padd(t->t_dcar);
42917903Sedward 		switch (t->t_dtyp) {
43017903Sedward 		case TOR:
43117903Sedward 			pads(" || ");
43217903Sedward 			break;
43317903Sedward 		case TAND:
43417903Sedward 			pads(" && ");
43517903Sedward 			break;
43617903Sedward 		case TFIL:
43717903Sedward 			pads(" | ");
43817903Sedward 			break;
43917903Sedward 		case TLST:
44017903Sedward 			pads("; ");
44117903Sedward 			break;
44217903Sedward 		}
4431302Sbill 		padd(t->t_dcdr);
4441302Sbill 		return;
4451302Sbill 	}
4461302Sbill 	if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
4471302Sbill 		pads((t->t_dflg & FHERE) ? " << " : " < ");
4481302Sbill 		pads(t->t_dlef);
4491302Sbill 	}
4501302Sbill 	if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
4511302Sbill 		pads((t->t_dflg & FCAT) ? " >>" : " >");
4521302Sbill 		if (t->t_dflg & FDIAG)
4531302Sbill 			pads("&");
4541302Sbill 		pads(" ");
4551302Sbill 		pads(t->t_drit);
4561302Sbill 	}
4571302Sbill }
4581302Sbill 
4591302Sbill pads(cp)
4601302Sbill 	char *cp;
4611302Sbill {
4621302Sbill 	register int i = strlen(cp);
4631302Sbill 
4641302Sbill 	if (cmdlen >= PMAXLEN)
4651302Sbill 		return;
4661302Sbill 	if (cmdlen + i >= PMAXLEN) {
46717509Sedward 		(void) strcpy(cmdp, " ...");
4681302Sbill 		cmdlen = PMAXLEN;
4691302Sbill 		cmdp += 4;
4701302Sbill 		return;
4711302Sbill 	}
47217509Sedward 	(void) strcpy(cmdp, cp);
4731302Sbill 	cmdp += i;
4741302Sbill 	cmdlen += i;
4751302Sbill }
4761302Sbill 
4771302Sbill /*
4781302Sbill  * psavejob - temporarily save the current job on a one level stack
4791302Sbill  *	so another job can be created.  Used for { } in exp6
4801302Sbill  *	and `` in globbing.
4811302Sbill  */
4821302Sbill psavejob()
4831302Sbill {
4841302Sbill 
4851302Sbill 	pholdjob = pcurrjob;
4861302Sbill 	pcurrjob = PNULL;
4871302Sbill }
4881302Sbill 
4891302Sbill /*
4901302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
4911302Sbill  *	somewhere, but pendjob cleans up anyway.
4921302Sbill  */
4931302Sbill prestjob()
4941302Sbill {
4951302Sbill 
4961302Sbill 	pcurrjob = pholdjob;
4971302Sbill 	pholdjob = PNULL;
4981302Sbill }
4991302Sbill 
5001302Sbill /*
5011302Sbill  * pendjob - indicate that a job (set of commands) has been completed
5021302Sbill  *	or is about to begin.
5031302Sbill  */
5041302Sbill pendjob()
5051302Sbill {
5061302Sbill 	register struct process *pp, *tp;
5071302Sbill 
5081302Sbill 	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
5091302Sbill 		pp = pcurrjob;
5101302Sbill 		while (pp->p_pid != pp->p_jobid)
5111302Sbill 			pp = pp->p_friends;
5121302Sbill 		printf("[%d]", pp->p_index);
5131302Sbill 		tp = pp;
5141302Sbill 		do {
5151302Sbill 			printf(" %d", pp->p_pid);
5161302Sbill 			pp = pp->p_friends;
5171302Sbill 		} while (pp != tp);
5181302Sbill 		printf("\n");
5191302Sbill 	}
5201302Sbill 	pholdjob = pcurrjob = 0;
5211302Sbill }
5221302Sbill 
5231302Sbill /*
5241302Sbill  * pprint - print a job
5251302Sbill  */
5261302Sbill pprint(pp, flag)
5271302Sbill 	register struct process	*pp;
5281302Sbill {
5291302Sbill 	register status, reason;
5301302Sbill 	struct process *tp;
5311302Sbill 	extern char *linp, linbuf[];
5321302Sbill 	int jobflags, pstatus;
5331302Sbill 	char *format;
5341302Sbill 
5351302Sbill 	while (pp->p_pid != pp->p_jobid)
5361302Sbill 		pp = pp->p_friends;
5371302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
5381302Sbill 		pp->p_flags &= ~PPTIME;
5391302Sbill 		pp->p_flags |= PTIME;
5401302Sbill 	}
5411302Sbill 	tp = pp;
5421302Sbill 	status = reason = -1;
5431302Sbill 	jobflags = 0;
5441302Sbill 	do {
5451302Sbill 		jobflags |= pp->p_flags;
5461302Sbill 		pstatus = pp->p_flags & PALLSTATES;
5471302Sbill 		if (tp != pp && linp != linbuf && !(flag&FANCY) &&
5481302Sbill 		    (pstatus == status && pp->p_reason == reason ||
5491302Sbill 		     !(flag&REASON)))
5501302Sbill 			printf(" ");
5511302Sbill 		else {
5521302Sbill 			if (tp != pp && linp != linbuf)
5531302Sbill 				printf("\n");
5541302Sbill 			if(flag&NUMBER)
5551302Sbill 				if (pp == tp)
5561302Sbill 					printf("[%d]%s %c ", pp->p_index,
5571302Sbill 					    pp->p_index < 10 ? " " : "",
5581302Sbill 					    pp==pcurrent ? '+' :
5591302Sbill 						(pp == pprevious ? '-' : ' '));
5601302Sbill 				else
5611302Sbill 					printf("       ");
5621302Sbill 			if (flag&FANCY)
5631302Sbill 				printf("%5d ", pp->p_pid);
5641302Sbill 			if (flag&(REASON|AREASON)) {
5651302Sbill 				if (flag&NAME)
5661302Sbill 					format = "%-21s";
5671302Sbill 				else
5681302Sbill 					format = "%s";
5691302Sbill 				if (pstatus == status)
5701302Sbill 					if (pp->p_reason == reason) {
5711302Sbill 						printf(format, "");
5721302Sbill 						goto prcomd;
5731302Sbill 					} else
5741302Sbill 						reason = pp->p_reason;
5751302Sbill 				else {
5761302Sbill 					status = pstatus;
5771302Sbill 					reason = pp->p_reason;
5781302Sbill 				}
5791302Sbill 				switch (status) {
5801302Sbill 
5811302Sbill 				case PRUNNING:
5821302Sbill 					printf(format, "Running ");
5831302Sbill 					break;
5841302Sbill 
5851302Sbill 				case PINTERRUPTED:
5861302Sbill 				case PSTOPPED:
5871302Sbill 				case PSIGNALED:
5881302Sbill 					if (flag&REASON || reason != SIGINT ||
5891302Sbill 					    reason != SIGPIPE)
5901302Sbill 						printf(format, mesg[pp->p_reason].pname);
5911302Sbill 					break;
5921302Sbill 
5931302Sbill 				case PNEXITED:
5941302Sbill 				case PAEXITED:
5951302Sbill 					if (flag & REASON)
5961302Sbill 						if (pp->p_reason)
5971302Sbill 							printf("Exit %-16d", pp->p_reason);
5981302Sbill 						else
5991302Sbill 							printf(format, "Done");
6001302Sbill 					break;
6011302Sbill 
6021302Sbill 				default:
6031302Sbill 					printf("BUG: status=%-9o", status);
6041302Sbill 				}
6051302Sbill 			}
6061302Sbill 		}
6071302Sbill prcomd:
6081302Sbill 		if (flag&NAME) {
6091302Sbill 			printf("%s", pp->p_command);
6101302Sbill 			if (pp->p_flags & PPOU)
6111302Sbill 				printf(" |");
6121302Sbill 			if (pp->p_flags & PDIAG)
6131302Sbill 				printf("&");
6141302Sbill 		}
6151302Sbill 		if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
6161302Sbill 			printf(" (core dumped)");
6171302Sbill 		if (tp == pp->p_friends) {
6181302Sbill 			if (flag&AMPERSAND)
6191302Sbill 				printf(" &");
6201302Sbill 			if (flag&JOBDIR &&
6211302Sbill 			    !eq(tp->p_cwd->di_name, dcwd->di_name)) {
6221302Sbill 				printf(" (wd: ");
6231302Sbill 				dtildepr(value("home"), tp->p_cwd->di_name);
6241302Sbill 				printf(")");
6251302Sbill 			}
6261302Sbill 		}
6271302Sbill 		if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
6281302Sbill 			if (linp != linbuf)
6291302Sbill 				printf("\n\t");
63010035Ssam 			{ static struct rusage zru;
63110704Ssam 			  prusage(&zru, &pp->p_rusage, &pp->p_etime,
63210704Ssam 			    &pp->p_btime);
63310035Ssam 			}
6341302Sbill 		}
6351302Sbill 		if (tp == pp->p_friends) {
6361302Sbill 			if (linp != linbuf)
6371302Sbill 				printf("\n");
6381302Sbill 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
6391302Sbill 				printf("(wd now: ");
6401302Sbill 				dtildepr(value("home"), dcwd->di_name);
6411302Sbill 				printf(")\n");
6421302Sbill 			}
6431302Sbill 		}
6441302Sbill 	} while ((pp = pp->p_friends) != tp);
6451302Sbill 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
6461302Sbill 		if (jobflags & NUMBER)
6471302Sbill 			printf("       ");
6481302Sbill 		ptprint(tp);
6491302Sbill 	}
6501302Sbill 	return (jobflags);
6511302Sbill }
6521302Sbill 
6531302Sbill ptprint(tp)
6541302Sbill 	register struct process *tp;
6551302Sbill {
65610704Ssam 	struct timeval tetime, diff;
65710704Ssam 	static struct timeval ztime;
65810035Ssam 	struct rusage ru;
65910035Ssam 	static struct rusage zru;
6601302Sbill 	register struct process *pp = tp;
6611302Sbill 
66210035Ssam 	ru = zru;
66310704Ssam 	tetime = ztime;
6641302Sbill 	do {
66510035Ssam 		ruadd(&ru, &pp->p_rusage);
66610704Ssam 		tvsub(&diff, &pp->p_etime, &pp->p_btime);
66710704Ssam 		if (timercmp(&diff, &tetime, >))
66810704Ssam 			tetime = diff;
6691302Sbill 	} while ((pp = pp->p_friends) != tp);
67010704Ssam 	prusage(&zru, &ru, &tetime, &ztime);
6711302Sbill }
6721302Sbill 
6731302Sbill /*
6741302Sbill  * dojobs - print all jobs
6751302Sbill  */
6761302Sbill dojobs(v)
6771302Sbill 	char **v;
6781302Sbill {
6791302Sbill 	register struct process *pp;
6801302Sbill 	register int flag = NUMBER|NAME|REASON;
6811302Sbill 	int i;
6821302Sbill 
6831302Sbill 	if (chkstop)
6841302Sbill 		chkstop = 2;
6851302Sbill 	if (*++v) {
6861302Sbill 		if (v[1] || !eq(*v, "-l"))
6871302Sbill 			error("Usage: jobs [ -l ]");
6881302Sbill 		flag |= FANCY|JOBDIR;
6891302Sbill 	}
6901302Sbill 	for (i = 1; i <= pmaxindex; i++)
6911302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
6921302Sbill 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
6931302Sbill 				pp->p_flags &= ~PNEEDNOTE;
6941302Sbill 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
6951302Sbill 					pflush(pp);
6961302Sbill 				break;
6971302Sbill 			}
6981302Sbill }
6991302Sbill 
7001302Sbill /*
7011302Sbill  * dofg - builtin - put the job into the foreground
7021302Sbill  */
7031302Sbill dofg(v)
7041302Sbill 	char **v;
7051302Sbill {
7061302Sbill 	register struct process *pp;
7071302Sbill 
7081302Sbill 	okpcntl();
7091302Sbill 	++v;
7101302Sbill 	do {
7111302Sbill 		pp = pfind(*v);
7121302Sbill 		pstart(pp, 1);
7131302Sbill 		pjwait(pp);
7141302Sbill 	} while (*v && *++v);
7151302Sbill }
7161302Sbill 
7171302Sbill /*
7181302Sbill  * %... - builtin - put the job into the foreground
7191302Sbill  */
7201302Sbill dofg1(v)
7211302Sbill 	char **v;
7221302Sbill {
7231302Sbill 	register struct process *pp;
7241302Sbill 
7251302Sbill 	okpcntl();
7261302Sbill 	pp = pfind(v[0]);
7271302Sbill 	pstart(pp, 1);
7281302Sbill 	pjwait(pp);
7291302Sbill }
7301302Sbill 
7311302Sbill /*
7321302Sbill  * dobg - builtin - put the job into the background
7331302Sbill  */
7341302Sbill dobg(v)
7351302Sbill 	char **v;
7361302Sbill {
7371302Sbill 	register struct process *pp;
7381302Sbill 
7391302Sbill 	okpcntl();
7401302Sbill 	++v;
7411302Sbill 	do {
7421302Sbill 		pp = pfind(*v);
7431302Sbill 		pstart(pp, 0);
7441302Sbill 	} while (*v && *++v);
7451302Sbill }
7461302Sbill 
7471302Sbill /*
7481302Sbill  * %... & - builtin - put the job into the background
7491302Sbill  */
7501302Sbill dobg1(v)
7511302Sbill 	char **v;
7521302Sbill {
7531302Sbill 	register struct process *pp;
7541302Sbill 
7551302Sbill 	pp = pfind(v[0]);
7561302Sbill 	pstart(pp, 0);
7571302Sbill }
7581302Sbill 
7591302Sbill /*
7601302Sbill  * dostop - builtin - stop the job
7611302Sbill  */
7621302Sbill dostop(v)
7631302Sbill 	char **v;
7641302Sbill {
7651302Sbill 
7661302Sbill 	pkill(++v, SIGSTOP);
7671302Sbill }
7681302Sbill 
7691302Sbill /*
7701302Sbill  * dokill - builtin - superset of kill (1)
7711302Sbill  */
7721302Sbill dokill(v)
7731302Sbill 	char **v;
7741302Sbill {
7751302Sbill 	register int signum;
7761302Sbill 	register char *name;
7771302Sbill 
7781302Sbill 	v++;
7791302Sbill 	if (v[0] && v[0][0] == '-') {
7801302Sbill 		if (v[0][1] == 'l') {
7811302Sbill 			for (signum = 1; signum <= NSIG; signum++) {
7821302Sbill 				if (name = mesg[signum].iname)
7831302Sbill 					printf("%s ", name);
7841302Sbill 				if (signum == 16)
78517509Sedward 					putchar('\n');
7861302Sbill 			}
78717509Sedward 			putchar('\n');
7881302Sbill 			return;
7891302Sbill 		}
7901302Sbill 		if (digit(v[0][1])) {
7911302Sbill 			signum = atoi(v[0]+1);
7921302Sbill 			if (signum < 1 || signum > NSIG)
7931302Sbill 				bferr("Bad signal number");
7941302Sbill 		} else {
7951302Sbill 			name = &v[0][1];
7961302Sbill 			for (signum = 1; signum <= NSIG; signum++)
7971302Sbill 			if (mesg[signum].iname &&
7981302Sbill 			    eq(name, mesg[signum].iname))
7991302Sbill 				goto gotsig;
8001302Sbill 			setname(name);
8011302Sbill 			bferr("Unknown signal; kill -l lists signals");
8021302Sbill 		}
8031302Sbill gotsig:
8041302Sbill 		v++;
8051302Sbill 	} else
8061302Sbill 		signum = SIGTERM;
8071302Sbill 	pkill(v, signum);
8081302Sbill }
8091302Sbill 
8101302Sbill pkill(v, signum)
8111302Sbill 	char **v;
8121302Sbill 	int signum;
8131302Sbill {
8141302Sbill 	register struct process *pp, *np;
8151302Sbill 	register int jobflags = 0;
81617136Sralph 	int omask, pid, err = 0;
81713561Ssam 	char *cp;
8181302Sbill 	extern char *sys_errlist[];
8191302Sbill 
82017136Sralph 	omask = sigmask(SIGCHLD);
8211302Sbill 	if (setintr)
82217136Sralph 		omask |= sigmask(SIGINT);
82317136Sralph 	omask = sigblock(omask) & ~omask;
8241302Sbill 	while (*v) {
82513561Ssam 		cp = globone(*v);
82613561Ssam 		if (*cp == '%') {
82713561Ssam 			np = pp = pfind(cp);
8281302Sbill 			do
8291302Sbill 				jobflags |= np->p_flags;
8301302Sbill 			while ((np = np->p_friends) != pp);
8311302Sbill 			switch (signum) {
8321302Sbill 
8331302Sbill 			case SIGSTOP:
8341302Sbill 			case SIGTSTP:
8351302Sbill 			case SIGTTIN:
8361302Sbill 			case SIGTTOU:
8371302Sbill 				if ((jobflags & PRUNNING) == 0) {
83813561Ssam 					printf("%s: Already stopped\n", cp);
8391302Sbill 					err++;
8401302Sbill 					goto cont;
8411302Sbill 				}
8421302Sbill 			}
84318424Smckusick 			if (killpg(pp->p_jobid, signum) < 0) {
84418424Smckusick 				printf("%s: ", cp);
84518424Smckusick 				printf("%s\n", sys_errlist[errno]);
84618424Smckusick 				err++;
84718424Smckusick 			}
8481302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
84917509Sedward 				(void) killpg(pp->p_jobid, SIGCONT);
85013561Ssam 		} else if (!digit(*cp))
8511302Sbill 			bferr("Arguments should be jobs or process id's");
8521302Sbill 		else {
85313561Ssam 			pid = atoi(cp);
8541302Sbill 			if (kill(pid, signum) < 0) {
8551302Sbill 				printf("%d: ", pid);
8561302Sbill 				printf("%s\n", sys_errlist[errno]);
8571302Sbill 				err++;
8581302Sbill 				goto cont;
8591302Sbill 			}
8601302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
86117509Sedward 				(void) kill(pid, SIGCONT);
8621302Sbill 		}
8631302Sbill cont:
86413561Ssam 		xfree(cp);
8651302Sbill 		v++;
8661302Sbill 	}
86717509Sedward 	(void) sigsetmask(omask);
8681302Sbill 	if (err)
8691302Sbill 		error(NOSTR);
8701302Sbill }
8711302Sbill 
8721302Sbill /*
8731302Sbill  * pstart - start the job in foreground/background
8741302Sbill  */
8751302Sbill pstart(pp, foregnd)
8761302Sbill 	register struct process *pp;
8771302Sbill 	int foregnd;
8781302Sbill {
8791302Sbill 	register struct process *np;
88017136Sralph 	int omask, jobflags = 0;
8811302Sbill 
88217136Sralph 	omask = sigblock(sigmask(SIGCHLD));
8831302Sbill 	np = pp;
8841302Sbill 	do {
8851302Sbill 		jobflags |= np->p_flags;
8861302Sbill 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
8871302Sbill 			np->p_flags |= PRUNNING;
8881302Sbill 			np->p_flags &= ~PSTOPPED;
8891302Sbill 			if (foregnd)
8901302Sbill 				np->p_flags |= PFOREGND;
8911302Sbill 			else
8921302Sbill 				np->p_flags &= ~PFOREGND;
8931302Sbill 		}
8941302Sbill 	} while((np = np->p_friends) != pp);
8952357Swnj 	if (!foregnd)
8962357Swnj 		pclrcurr(pp);
89717509Sedward 	(void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
8981302Sbill 	if (foregnd)
89917509Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid);
9001302Sbill 	if (jobflags&PSTOPPED)
90117509Sedward 		(void) killpg(pp->p_jobid, SIGCONT);
90217509Sedward 	(void) sigsetmask(omask);
9031302Sbill }
9041302Sbill 
9051302Sbill panystop(neednl)
9061302Sbill {
9071302Sbill 	register struct process *pp;
9081302Sbill 
9091302Sbill 	chkstop = 2;
9101302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9111302Sbill 		if (pp->p_flags & PSTOPPED)
9121302Sbill 			error("\nThere are stopped jobs" + 1 - neednl);
9131302Sbill }
9141302Sbill 
9151302Sbill struct process *
9161302Sbill pfind(cp)
9171302Sbill 	char *cp;
9181302Sbill {
9191302Sbill 	register struct process *pp, *np;
9201302Sbill 
9211302Sbill 	if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
9221302Sbill 		if (pcurrent == PNULL)
9231302Sbill 			bferr("No current job");
9241302Sbill 		return (pcurrent);
9251302Sbill 	}
9261302Sbill 	if (eq(cp, "%-") || eq(cp, "%#")) {
9271302Sbill 		if (pprevious == PNULL)
9281302Sbill 			bferr("No previous job");
9291302Sbill 		return (pprevious);
9301302Sbill 	}
9311302Sbill 	if (digit(cp[1])) {
9321302Sbill 		int index = atoi(cp+1);
9331302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
9341302Sbill 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
9351302Sbill 				return (pp);
9361302Sbill 		bferr("No such job");
9371302Sbill 	}
9381302Sbill 	np = PNULL;
9391302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9401302Sbill 		if (pp->p_pid == pp->p_jobid) {
9411302Sbill 			if (cp[1] == '?') {
9421302Sbill 				register char *dp;
9431302Sbill 				for (dp = pp->p_command; *dp; dp++) {
9441302Sbill 					if (*dp != cp[2])
9451302Sbill 						continue;
9461302Sbill 					if (prefix(cp+2, dp))
9471302Sbill 						goto match;
9481302Sbill 				}
9491302Sbill 			} else if (prefix(cp+1, pp->p_command)) {
9501302Sbill match:
9511302Sbill 				if (np)
9521302Sbill 					bferr("Ambiguous");
9531302Sbill 				np = pp;
9541302Sbill 			}
9551302Sbill 		}
9561302Sbill 	if (np)
9571302Sbill 		return (np);
9581302Sbill 	if (cp[1] == '?')
9591302Sbill 		bferr("No job matches pattern");
9601302Sbill 	else
9611302Sbill 		bferr("No such job");
96217509Sedward 	/*NOTREACHED*/
9631302Sbill }
9641302Sbill 
9651302Sbill /*
9662357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
9671302Sbill  */
9681302Sbill struct process *
9691302Sbill pgetcurr(pp)
9701302Sbill 	register struct process *pp;
9711302Sbill {
9721302Sbill 	register struct process *np;
9732357Swnj 	register struct process *xp = PNULL;
9741302Sbill 
9751302Sbill 	for (np = proclist.p_next; np; np = np->p_next)
9761302Sbill 		if (np != pcurrent && np != pp && np->p_pid &&
9771302Sbill 		    np->p_pid == np->p_jobid) {
9782357Swnj 			if (np->p_flags & PSTOPPED)
9792357Swnj 				return (np);
9802357Swnj 			if (xp == PNULL)
9812357Swnj 				xp = np;
9821302Sbill 		}
9832357Swnj 	return (xp);
9841302Sbill }
9851302Sbill 
9861302Sbill /*
9871302Sbill  * donotify - flag the job so as to report termination asynchronously
9881302Sbill  */
9891302Sbill donotify(v)
9901302Sbill 	char **v;
9911302Sbill {
9921302Sbill 	register struct process *pp;
9931302Sbill 
9941302Sbill 	pp = pfind(*++v);
9951302Sbill 	pp->p_flags |= PNOTIFY;
9961302Sbill }
9971302Sbill 
9981302Sbill /*
9991302Sbill  * Do the fork and whatever should be done in the child side that
10001302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
10011302Sbill  * Also do everything that needs any signals fiddled with in the parent side
10021302Sbill  *
10031302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
10041302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
10051302Sbill  *	 0:	already have tty; manipulate process pgrps only
10061302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
10071302Sbill  * It is usually just the value of tpgrp.
10081302Sbill  */
10091302Sbill pfork(t, wanttty)
10101302Sbill 	struct command *t;	/* command we are forking for */
10111302Sbill 	int wanttty;
10121302Sbill {
10131302Sbill 	register int pid;
10141302Sbill 	bool ignint = 0;
101517136Sralph 	int pgrp, omask;
10161302Sbill 
10171302Sbill 	/*
10181302Sbill 	 * A child will be uninterruptible only under very special
10191302Sbill 	 * conditions. Remember that the semantics of '&' is
10201302Sbill 	 * implemented by disconnecting the process from the tty so
10211302Sbill 	 * signals do not need to ignored just for '&'.
10221302Sbill 	 * Thus signals are set to default action for children unless:
10231302Sbill 	 *	we have had an "onintr -" (then specifically ignored)
10241302Sbill 	 *	we are not playing with signals (inherit action)
10251302Sbill 	 */
10261302Sbill 	if (setintr)
10271302Sbill 		ignint = (tpgrp == -1 && (t->t_dflg&FINT))
10281302Sbill 		    || (gointr && eq(gointr, "-"));
10291302Sbill 	/*
10301302Sbill 	 * Hold SIGCHLD until we have the process installed in our table.
10311302Sbill 	 */
103217136Sralph 	omask = sigblock(sigmask(SIGCHLD));
10331302Sbill 	while ((pid = fork()) < 0)
10341302Sbill 		if (setintr == 0)
10351302Sbill 			sleep(FORKSLEEP);
10361302Sbill 		else {
103717509Sedward 			(void) sigsetmask(omask);
10381302Sbill 			error("No more processes");
10391302Sbill 		}
10401302Sbill 	if (pid == 0) {
10411302Sbill 		settimes();
10421302Sbill 		pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
10431302Sbill 		pflushall();
10441302Sbill 		pcurrjob = PNULL;
10451302Sbill 		child++;
10461302Sbill 		if (setintr) {
10471302Sbill 			setintr = 0;		/* until I think otherwise */
10481302Sbill 			/*
10491302Sbill 			 * Children just get blown away on SIGINT, SIGQUIT
10501302Sbill 			 * unless "onintr -" seen.
10511302Sbill 			 */
105217509Sedward 			(void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
105317509Sedward 			(void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
10541302Sbill 			if (wanttty >= 0) {
10551302Sbill 				/* make stoppable */
105617509Sedward 				(void) signal(SIGTSTP, SIG_DFL);
105717509Sedward 				(void) signal(SIGTTIN, SIG_DFL);
105817509Sedward 				(void) signal(SIGTTOU, SIG_DFL);
10591302Sbill 			}
106017509Sedward 			(void) signal(SIGTERM, parterm);
10611302Sbill 		} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
106217509Sedward 			(void) signal(SIGINT, SIG_IGN);
106317509Sedward 			(void) signal(SIGQUIT, SIG_IGN);
10641302Sbill 		}
10651302Sbill 		if (wanttty > 0)
106617509Sedward 			(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp);
10671302Sbill 		if (wanttty >= 0 && tpgrp >= 0)
106817509Sedward 			(void) setpgrp(0, pgrp);
10691302Sbill 		if (tpgrp > 0)
10701302Sbill 			tpgrp = 0;		/* gave tty away */
10711302Sbill 		/*
10721302Sbill 		 * Nohup and nice apply only to TCOM's but it would be
10731302Sbill 		 * nice (?!?) if you could say "nohup (foo;bar)"
10741302Sbill 		 * Then the parser would have to know about nice/nohup/time
10751302Sbill 		 */
10761302Sbill 		if (t->t_dflg & FNOHUP)
107717509Sedward 			(void) signal(SIGHUP, SIG_IGN);
107817136Sralph 		if (t->t_dflg & FNICE)
107917509Sedward 			(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
10801302Sbill 	} else {
10811302Sbill 		palloc(pid, t);
108217509Sedward 		(void) sigsetmask(omask);
10831302Sbill 	}
10841302Sbill 
10851302Sbill 	return (pid);
10861302Sbill }
10871302Sbill 
10881302Sbill okpcntl()
10891302Sbill {
10901302Sbill 
10911302Sbill 	if (tpgrp == -1)
10921302Sbill 		error("No job control in this shell");
10931302Sbill 	if (tpgrp == 0)
10941302Sbill 		error("No job control in subshells");
10951302Sbill }
1096