xref: /csrg-svn/bin/csh/proc.c (revision 3213)
1*3213Swnj static	char *sccsid = "@(#)proc.c 4.3 03/11/81";
21302Sbill 
31302Sbill #include "sh.h"
41302Sbill #include "sh.dir.h"
51302Sbill #include "sh.proc.h"
61302Sbill #include <wait.h>
71302Sbill #include <sys/ioctl.h>
81302Sbill 
91302Sbill /*
101302Sbill  * C Shell - functions that manage processes, handling hanging, termination
111302Sbill  */
121302Sbill 
131302Sbill #define BIGINDEX	9	/* largest desirable job index */
141302Sbill 
151302Sbill /*
161302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
171302Sbill  *	indicating that at least one child has terminated or stopped
181302Sbill  *	thus at least one wait system call will definitely return a
191302Sbill  *	childs status.  Top level routines (like pwait) must be sure
201302Sbill  *	to mask interrupts when playing with the proclist data structures!
211302Sbill  */
221302Sbill pchild()
231302Sbill {
241302Sbill 	register struct process *pp;
251302Sbill 	register struct process	*fp;
261302Sbill 	register int pid;
271302Sbill 	union wait w;
281302Sbill 	int jobflags;
291302Sbill #ifdef VMUNIX
301302Sbill 	struct vtimes vt;
311302Sbill #endif
321302Sbill 
331302Sbill 	if (!timesdone)
341302Sbill 		timesdone++, times(&shtimes);
351302Sbill loop:
361302Sbill 	pid = wait3(&w.w_status, (setintr ? WNOHANG|WUNTRACED:WNOHANG),
371302Sbill #ifndef VMUNIX
381302Sbill 	    0);
391302Sbill #else
401302Sbill 	    &vt);
411302Sbill #endif
421302Sbill 	if (pid <= 0) {
431302Sbill 		if (errno == EINTR) {
441302Sbill 			errno = 0;
451302Sbill 			goto loop;
461302Sbill 		}
471302Sbill 		pnoprocesses = pid == -1;
481302Sbill 		return;
491302Sbill 	}
501302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
511302Sbill 		if (pid == pp->p_pid)
521302Sbill 			goto found;
531302Sbill 	goto loop;
541302Sbill found:
551302Sbill 	if (pid == atoi(value("child")))
561302Sbill 		unsetv("child");
571302Sbill 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
581302Sbill 	if (WIFSTOPPED(w)) {
591302Sbill 		pp->p_flags |= PSTOPPED;
601302Sbill 		pp->p_reason = w.w_stopsig;
611302Sbill 	} else {
621302Sbill 		if (pp->p_flags & (PTIME|PPTIME) || adrof("time")) {
631302Sbill 			time_t oldcutimes, oldcstimes;
641302Sbill 			oldcutimes = shtimes.tms_cutime;
651302Sbill 			oldcstimes = shtimes.tms_cstime;
661302Sbill 			time(&pp->p_etime);
671302Sbill 			times(&shtimes);
681302Sbill 			pp->p_utime = shtimes.tms_cutime - oldcutimes;
691302Sbill 			pp->p_stime = shtimes.tms_cstime - oldcstimes;
701302Sbill 		} else
711302Sbill 			times(&shtimes);
721302Sbill #ifdef VMUNIX
731302Sbill 		pp->p_vtimes = vt;
741302Sbill #endif
751302Sbill 		if (WIFSIGNALED(w)) {
761302Sbill 			if (w.w_termsig == SIGINT)
771302Sbill 				pp->p_flags |= PINTERRUPTED;
781302Sbill 			else
791302Sbill 				pp->p_flags |= PSIGNALED;
801302Sbill 			if (w.w_coredump)
811302Sbill 				pp->p_flags |= PDUMPED;
821302Sbill 			pp->p_reason = w.w_termsig;
831302Sbill 		} else {
841302Sbill 			pp->p_reason = w.w_retcode;
851302Sbill #ifdef IIASA
861302Sbill 			if (pp->p_reason >= 3)
871302Sbill #else
881302Sbill 			if (pp->p_reason != 0)
891302Sbill #endif
901302Sbill 				pp->p_flags |= PAEXITED;
911302Sbill 			else
921302Sbill 				pp->p_flags |= PNEXITED;
931302Sbill 		}
941302Sbill 	}
951302Sbill 	jobflags = 0;
961302Sbill 	fp = pp;
971302Sbill 	do {
981302Sbill 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
991302Sbill 		    !child && adrof("time") &&
1001302Sbill 		    (fp->p_utime + fp->p_stime) / HZ >=
1011302Sbill 		     atoi(value("time")))
1021302Sbill 			fp->p_flags |= PTIME;
1031302Sbill 		jobflags |= fp->p_flags;
1041302Sbill 	} while ((fp = fp->p_friends) != pp);
1051302Sbill 	pp->p_flags &= ~PFOREGND;
1061302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
1071302Sbill 		pp->p_flags &= ~PPTIME;
1081302Sbill 		pp->p_flags |= PTIME;
1091302Sbill 	}
1101302Sbill 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
1111302Sbill 		fp = pp;
1121302Sbill 		do {
1131302Sbill 			if (fp->p_flags&PSTOPPED)
1141302Sbill 				fp->p_flags |= PREPORTED;
1151302Sbill 		} while((fp = fp->p_friends) != pp);
1161302Sbill 		while(fp->p_pid != fp->p_jobid)
1171302Sbill 			fp = fp->p_friends;
1182357Swnj 		if (jobflags&PSTOPPED) {
1192357Swnj 			if (pcurrent && pcurrent != fp)
1202357Swnj 				pprevious = pcurrent;
1212357Swnj 			pcurrent = fp;
1222357Swnj 		} else
1232357Swnj 			pclrcurr(fp);
1241302Sbill 		if (jobflags&PFOREGND) {
1251302Sbill 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
1261302Sbill #ifdef IIASA
1271302Sbill 			    jobflags & PAEXITED ||
1281302Sbill #endif
1291302Sbill 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
130*3213Swnj 				;	/* print in pjwait */
1311302Sbill 			} else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
1321302Sbill 				ptprint(fp);
1331302Sbill 		} else {
1341302Sbill 			if (jobflags&PNOTIFY || adrof("notify")) {
1351302Sbill 				printf("\215\n");
1361302Sbill 				pprint(pp, NUMBER|NAME|REASON);
1371302Sbill 				if ((jobflags&PSTOPPED) == 0)
1381302Sbill 					pflush(pp);
1391302Sbill 			} else {
1401302Sbill 				fp->p_flags |= PNEEDNOTE;
1411302Sbill 				neednote++;
1421302Sbill 			}
1431302Sbill 		}
1441302Sbill 	}
1451302Sbill 	goto loop;
1461302Sbill }
1471302Sbill 
1481302Sbill pnote()
1491302Sbill {
1501302Sbill 	register struct process *pp;
1511302Sbill 	int flags;
1521302Sbill 
1531302Sbill 	neednote = 0;
1541302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
1551302Sbill 		if (pp->p_flags & PNEEDNOTE) {
1561302Sbill 			sighold(SIGCHLD);
1571302Sbill 			pp->p_flags &= ~PNEEDNOTE;
1581302Sbill 			flags = pprint(pp, NUMBER|NAME|REASON);
1591302Sbill 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
1601302Sbill 				pflush(pp);
1611302Sbill 			sigrelse(SIGCHLD);
1621302Sbill 		}
1631302Sbill 	}
1641302Sbill }
1651302Sbill 
1661302Sbill /*
1671302Sbill  * pwait - wait for current job to terminate, maintaining integrity
1681302Sbill  *	of current and previous job indicators.
1691302Sbill  */
1701302Sbill pwait()
1711302Sbill {
1721302Sbill 	register struct process *fp, *pp;
1731302Sbill 
1741302Sbill 	/*
1751302Sbill 	 * Here's where dead procs get flushed.
1761302Sbill 	 */
1771302Sbill 	sighold(SIGCHLD);
1781302Sbill 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
1791302Sbill 		if (pp->p_pid == 0) {
1801302Sbill 			fp->p_next = pp->p_next;
1811302Sbill 			xfree(pp->p_command);
1821302Sbill 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
1831302Sbill 				if (pp->p_cwd->di_next == 0)
1841302Sbill 					dfree(pp->p_cwd);
1851302Sbill 			xfree((char *)pp);
1861302Sbill 			pp = fp;
1871302Sbill 		}
1881302Sbill 	sigrelse(SIGCHLD);
1891302Sbill 	if (setintr)
1901302Sbill 		sigignore(SIGINT);
1911302Sbill 	pjwait(pcurrjob);
1921302Sbill }
1931302Sbill 
1941302Sbill /*
1951302Sbill  * pjwait - wait for a job to finish or become stopped
1961302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
1971302Sbill  */
1981302Sbill pjwait(pp)
1991302Sbill 	register struct process *pp;
2001302Sbill {
2011302Sbill 	register struct process *fp;
2021302Sbill 	int jobflags, reason;
2031302Sbill 
2041302Sbill 	fp = pp;
2051302Sbill 	do {
2061302Sbill 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
2071302Sbill 			printf("BUG: waiting for background job!\n");
2081302Sbill 	} while ((fp = fp->p_friends) != pp);
2091302Sbill 	/*
2101302Sbill 	 * Now keep pausing as long as we are not interrupted (SIGINT),
2111302Sbill 	 * and the target process, or any of its friends, are running
2121302Sbill 	 */
2131302Sbill 	fp = pp;
2141302Sbill 	for (;;) {
2151302Sbill 		sighold(SIGCHLD);
2161302Sbill 		jobflags = 0;
2171302Sbill 		do
2181302Sbill 			jobflags |= fp->p_flags;
2191302Sbill 		while((fp = (fp->p_friends)) != pp);
2201302Sbill 		if ((jobflags & PRUNNING) == 0)
2211302Sbill 			break;
2221302Sbill 		sigpause(SIGCHLD);
2231302Sbill 	}
2241302Sbill 	sigrelse(SIGCHLD);
2251302Sbill 	if (tpgrp > 0)
2261302Sbill 		ioctl(FSHTTY, TIOCSPGRP, &tpgrp);	/* get tty back */
227*3213Swnj 	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
2281302Sbill 	    (!gointr || !eq(gointr, "-"))) {
229*3213Swnj 		if ((jobflags & PSTOPPED) == 0)
230*3213Swnj 			pflush(pp);
231*3213Swnj 		else {
232*3213Swnj 			printf("\n");
233*3213Swnj 			pprint(pp, AREASON|SHELLDIR);
234*3213Swnj 		}
235*3213Swnj 		pintr1(0);
2361302Sbill 		/*NOTREACHED*/
2371302Sbill 	}
2381302Sbill 	reason = 0;
2391302Sbill 	fp = pp;
2401302Sbill 	do {
2411302Sbill 		if (fp->p_reason)
2421302Sbill 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
2431302Sbill 				fp->p_reason | QUOTE : fp->p_reason;
2441302Sbill 	} while ((fp = fp->p_friends) != pp);
2451302Sbill 	set("status", putn(reason));
2461302Sbill 	if (reason && exiterr)
2471302Sbill 		exitstat();
2481302Sbill 	pflush(pp);
2491302Sbill }
2501302Sbill 
2511302Sbill /*
2521302Sbill  * dowait - wait for all processes to finish
2531302Sbill  */
2541302Sbill dowait()
2551302Sbill {
2561302Sbill 	register struct process *pp;
2571302Sbill 
2581302Sbill 	pjobs++;
2591302Sbill 	if (setintr)
2601302Sbill 		sigrelse(SIGINT);
2611302Sbill loop:
2621302Sbill 	sighold(SIGCHLD);
2631302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
2641302Sbill 		if (pp->p_pid && pp->p_pid == pp->p_jobid &&
2651302Sbill 		    pp->p_flags&PRUNNING) {
2661302Sbill 			sigpause(SIGCHLD);
2671302Sbill 			goto loop;
2681302Sbill 		}
2691302Sbill 	sigrelse(SIGCHLD);
2701302Sbill 	pjobs = 0;
2711302Sbill }
2721302Sbill 
2731302Sbill /*
2741302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
2751302Sbill  */
2761302Sbill pflushall()
2771302Sbill {
2781302Sbill 	register struct process	*pp;
2791302Sbill 
2801302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
2811302Sbill 		if (pp->p_pid)
2821302Sbill 			pflush(pp);
2831302Sbill }
2841302Sbill 
2851302Sbill /*
2861302Sbill  * pflush - flag all process structures in the same job as the
2871302Sbill  *	the argument process for deletion.  The actual free of the
2881302Sbill  *	space is not done here since pflush is called at interrupt level.
2891302Sbill  */
2901302Sbill pflush(pp)
2911302Sbill 	register struct process	*pp;
2921302Sbill {
2931302Sbill 	register struct process *np;
2941302Sbill 	register int index;
2951302Sbill 
2961302Sbill 	if (pp->p_pid == 0) {
2971302Sbill 		printf("BUG: process flushed twice");
2981302Sbill 		return;
2991302Sbill 	}
3001302Sbill 	while (pp->p_pid != pp->p_jobid)
3011302Sbill 		pp = pp->p_friends;
3021302Sbill 	pclrcurr(pp);
3031302Sbill 	if (pp == pcurrjob)
3041302Sbill 		pcurrjob = 0;
3051302Sbill 	index = pp->p_index;
3061302Sbill 	np = pp;
3071302Sbill 	do {
3081302Sbill 		np->p_index = np->p_pid = 0;
3091302Sbill 		np->p_flags &= ~PNEEDNOTE;
3101302Sbill 	} while ((np = np->p_friends) != pp);
3111302Sbill 	if (index == pmaxindex) {
3121302Sbill 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
3131302Sbill 			if (np->p_index > index)
3141302Sbill 				index = np->p_index;
3151302Sbill 		pmaxindex = index;
3161302Sbill 	}
3171302Sbill }
3181302Sbill 
3191302Sbill /*
3201302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
3211302Sbill  *	pp MUST be the job leader
3221302Sbill  */
3231302Sbill pclrcurr(pp)
3241302Sbill 	register struct process *pp;
3251302Sbill {
3261302Sbill 
3271302Sbill 	if (pp == pcurrent)
3281302Sbill 		if (pprevious != PNULL) {
3291302Sbill 			pcurrent = pprevious;
3301302Sbill 			pprevious = pgetcurr(pp);
3311302Sbill 		} else {
3321302Sbill 			pcurrent = pgetcurr(pp);
3331302Sbill 			pprevious = pgetcurr(pp);
3341302Sbill 		}
3351302Sbill 	else if (pp == pprevious)
3361302Sbill 		pprevious = pgetcurr(pp);
3371302Sbill }
3381302Sbill 
3391302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
3401302Sbill char	command[PMAXLEN+4];
3411302Sbill int	cmdlen;
3421302Sbill char	*cmdp;
3431302Sbill /*
3441302Sbill  * palloc - allocate a process structure and fill it up.
3451302Sbill  *	an important assumption is made that the process is running.
3461302Sbill  */
3471302Sbill palloc(pid, t)
3481302Sbill 	int pid;
3491302Sbill 	register struct command *t;
3501302Sbill {
3511302Sbill 	register struct process	*pp;
3521302Sbill 	int i;
3531302Sbill 
3541302Sbill 	pp = (struct process *)calloc(1, sizeof(struct process));
3551302Sbill 	pp->p_pid = pid;
3561302Sbill 	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
3571302Sbill 	if (t->t_dflg & FTIME)
3581302Sbill 		pp->p_flags |= PPTIME;
3591302Sbill 	cmdp = command;
3601302Sbill 	cmdlen = 0;
3611302Sbill 	padd(t);
3621302Sbill 	*cmdp++ = 0;
3631302Sbill 	if (t->t_dflg & FPOU) {
3641302Sbill 		pp->p_flags |= PPOU;
3651302Sbill 		if (t->t_dflg & FDIAG)
3661302Sbill 			pp->p_flags |= PDIAG;
3671302Sbill 	}
3681302Sbill 	pp->p_command = savestr(command);
3691302Sbill 	if (pcurrjob) {
3701302Sbill 		struct process *fp;
3711302Sbill 		/* careful here with interrupt level */
3721302Sbill 		pp->p_cwd = 0;
3731302Sbill 		pp->p_index = pcurrjob->p_index;
3741302Sbill 		pp->p_friends = pcurrjob;
3751302Sbill 		pp->p_jobid = pcurrjob->p_pid;
3761302Sbill 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
3771302Sbill 			;
3781302Sbill 		fp->p_friends = pp;
3791302Sbill 	} else {
3801302Sbill 		pcurrjob = pp;
3811302Sbill 		pp->p_jobid = pid;
3821302Sbill 		pp->p_friends = pp;
3831302Sbill 		pp->p_cwd = dcwd;
3841302Sbill 		dcwd->di_count++;
3851302Sbill 		if (pmaxindex < BIGINDEX)
3861302Sbill 			pp->p_index = ++pmaxindex;
3871302Sbill 		else {
3881302Sbill 			struct process *np;
3891302Sbill 
3901302Sbill 			for (i = 1; ; i++) {
3911302Sbill 				for (np = proclist.p_next; np; np = np->p_next)
3921302Sbill 					if (np->p_index == i)
3931302Sbill 						goto tryagain;
3942357Swnj 				pp->p_index = i;
3952357Swnj 				if (i > pmaxindex)
3962357Swnj 					pmaxindex = i;
3971302Sbill 				break;
3981302Sbill 			tryagain:;
3991302Sbill 			}
4001302Sbill 		}
4011302Sbill 		if (pcurrent == PNULL)
4021302Sbill 			pcurrent = pp;
4031302Sbill 		else if (pprevious == PNULL)
4041302Sbill 			pprevious = pp;
4051302Sbill 	}
4061302Sbill 	pp->p_next = proclist.p_next;
4071302Sbill 	proclist.p_next = pp;
4081302Sbill 	time(&pp->p_btime);
4091302Sbill }
4101302Sbill 
4111302Sbill padd(t)
4121302Sbill 	register struct command *t;
4131302Sbill {
4141302Sbill 	char **argp;
4151302Sbill 
4161302Sbill 	if (t == 0)
4171302Sbill 		return;
4181302Sbill 	switch (t->t_dtyp) {
4191302Sbill 
4201302Sbill 	case TPAR:
4211302Sbill 		pads("( ");
4221302Sbill 		padd(t->t_dspr);
4231302Sbill 		pads(" )");
4241302Sbill 		break;
4251302Sbill 
4261302Sbill 	case TCOM:
4271302Sbill 		for (argp = t->t_dcom; *argp; argp++) {
4281302Sbill 			pads(*argp);
4291302Sbill 			if (argp[1])
4301302Sbill 				pads(" ");
4311302Sbill 		}
4321302Sbill 		break;
4331302Sbill 
4341302Sbill 	case TFIL:
4351302Sbill 		padd(t->t_dcar);
4361302Sbill 		pads(" | ");
4371302Sbill 		padd(t->t_dcdr);
4381302Sbill 		return;
4391302Sbill 
4401302Sbill 	case TLST:
4411302Sbill 		padd(t->t_dcar);
4421302Sbill 		pads("; ");
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) {
4671302Sbill 		strcpy(cmdp, " ...");
4681302Sbill 		cmdlen = PMAXLEN;
4691302Sbill 		cmdp += 4;
4701302Sbill 		return;
4711302Sbill 	}
4721302Sbill 	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");
6301302Sbill #ifndef VMUNIX
6311302Sbill 			ptimes(pp->p_utime, pp->p_stime, pp->p_etime-pp->p_btime);
6321302Sbill #else
6331302Sbill 			pvtimes(&zvms, &pp->p_vtimes, pp->p_etime - pp->p_btime);
6341302Sbill #endif
6351302Sbill 		}
6361302Sbill 		if (tp == pp->p_friends) {
6371302Sbill 			if (linp != linbuf)
6381302Sbill 				printf("\n");
6391302Sbill 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
6401302Sbill 				printf("(wd now: ");
6411302Sbill 				dtildepr(value("home"), dcwd->di_name);
6421302Sbill 				printf(")\n");
6431302Sbill 			}
6441302Sbill 		}
6451302Sbill 	} while ((pp = pp->p_friends) != tp);
6461302Sbill 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
6471302Sbill 		if (jobflags & NUMBER)
6481302Sbill 			printf("       ");
6491302Sbill 		ptprint(tp);
6501302Sbill 	}
6511302Sbill 	return (jobflags);
6521302Sbill }
6531302Sbill 
6541302Sbill ptprint(tp)
6551302Sbill 	register struct process *tp;
6561302Sbill {
6571302Sbill 	time_t tetime = 0;
6581302Sbill #ifdef VMUNIX
6591302Sbill 	struct vtimes vmt;
6601302Sbill #else
6611302Sbill 	time_t tutime = 0, tstime = 0;
6621302Sbill #endif
6631302Sbill 	register struct process *pp = tp;
6641302Sbill 
6651302Sbill 	vmt = zvms;
6661302Sbill 	do {
6671302Sbill #ifdef VMUNIX
6681302Sbill 		vmsadd(&vmt, &pp->p_vtimes);
6691302Sbill #else
6701302Sbill 		tutime += pp->p_utime;
6711302Sbill 		tstime += pp->p_stime;
6721302Sbill #endif
6731302Sbill 		if (pp->p_etime - pp->p_btime > tetime)
6741302Sbill 			tetime = pp->p_etime - pp->p_btime;
6751302Sbill 	} while ((pp = pp->p_friends) != tp);
6761302Sbill #ifdef VMUNIX
6771302Sbill 	pvtimes(&zvms, &vmt, tetime);
6781302Sbill #else
6791302Sbill 	ptimes(tutime, tstime, tetime);
6801302Sbill #endif
6811302Sbill }
6821302Sbill 
6831302Sbill /*
6841302Sbill  * dojobs - print all jobs
6851302Sbill  */
6861302Sbill dojobs(v)
6871302Sbill 	char **v;
6881302Sbill {
6891302Sbill 	register struct process *pp;
6901302Sbill 	register int flag = NUMBER|NAME|REASON;
6911302Sbill 	int i;
6921302Sbill 
6931302Sbill 	if (chkstop)
6941302Sbill 		chkstop = 2;
6951302Sbill 	if (*++v) {
6961302Sbill 		if (v[1] || !eq(*v, "-l"))
6971302Sbill 			error("Usage: jobs [ -l ]");
6981302Sbill 		flag |= FANCY|JOBDIR;
6991302Sbill 	}
7001302Sbill 	for (i = 1; i <= pmaxindex; i++)
7011302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
7021302Sbill 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
7031302Sbill 				pp->p_flags &= ~PNEEDNOTE;
7041302Sbill 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
7051302Sbill 					pflush(pp);
7061302Sbill 				break;
7071302Sbill 			}
7081302Sbill }
7091302Sbill 
7101302Sbill /*
7111302Sbill  * dofg - builtin - put the job into the foreground
7121302Sbill  */
7131302Sbill dofg(v)
7141302Sbill 	char **v;
7151302Sbill {
7161302Sbill 	register struct process *pp;
7171302Sbill 
7181302Sbill 	okpcntl();
7191302Sbill 	++v;
7201302Sbill 	do {
7211302Sbill 		pp = pfind(*v);
7221302Sbill 		pstart(pp, 1);
7231302Sbill 		if (setintr)
7241302Sbill 			sigignore(SIGINT);
7251302Sbill 		pjwait(pp);
7261302Sbill 	} while (*v && *++v);
7271302Sbill }
7281302Sbill 
7291302Sbill /*
7301302Sbill  * %... - builtin - put the job into the foreground
7311302Sbill  */
7321302Sbill dofg1(v)
7331302Sbill 	char **v;
7341302Sbill {
7351302Sbill 	register struct process *pp;
7361302Sbill 
7371302Sbill 	okpcntl();
7381302Sbill 	pp = pfind(v[0]);
7391302Sbill 	pstart(pp, 1);
7401302Sbill 	if (setintr)
7411302Sbill 		sigignore(SIGINT);
7421302Sbill 	pjwait(pp);
7431302Sbill }
7441302Sbill 
7451302Sbill /*
7461302Sbill  * dobg - builtin - put the job into the background
7471302Sbill  */
7481302Sbill dobg(v)
7491302Sbill 	char **v;
7501302Sbill {
7511302Sbill 	register struct process *pp;
7521302Sbill 
7531302Sbill 	okpcntl();
7541302Sbill 	++v;
7551302Sbill 	do {
7561302Sbill 		pp = pfind(*v);
7571302Sbill 		pstart(pp, 0);
7581302Sbill 	} while (*v && *++v);
7591302Sbill }
7601302Sbill 
7611302Sbill /*
7621302Sbill  * %... & - builtin - put the job into the background
7631302Sbill  */
7641302Sbill dobg1(v)
7651302Sbill 	char **v;
7661302Sbill {
7671302Sbill 	register struct process *pp;
7681302Sbill 
7691302Sbill 	pp = pfind(v[0]);
7701302Sbill 	pstart(pp, 0);
7711302Sbill }
7721302Sbill 
7731302Sbill /*
7741302Sbill  * dostop - builtin - stop the job
7751302Sbill  */
7761302Sbill dostop(v)
7771302Sbill 	char **v;
7781302Sbill {
7791302Sbill 
7801302Sbill 	pkill(++v, SIGSTOP);
7811302Sbill }
7821302Sbill 
7831302Sbill /*
7841302Sbill  * dokill - builtin - superset of kill (1)
7851302Sbill  */
7861302Sbill dokill(v)
7871302Sbill 	char **v;
7881302Sbill {
7891302Sbill 	register int signum;
7901302Sbill 	register char *name;
7911302Sbill 
7921302Sbill 	v++;
7931302Sbill 	if (v[0] && v[0][0] == '-') {
7941302Sbill 		if (v[0][1] == 'l') {
7951302Sbill 			for (signum = 1; signum <= NSIG; signum++) {
7961302Sbill 				if (name = mesg[signum].iname)
7971302Sbill 					printf("%s ", name);
7981302Sbill 				if (signum == 16)
7991302Sbill 					printf("\n");
8001302Sbill 			}
8011302Sbill 			printf("\n");
8021302Sbill 			return;
8031302Sbill 		}
8041302Sbill 		if (digit(v[0][1])) {
8051302Sbill 			signum = atoi(v[0]+1);
8061302Sbill 			if (signum < 1 || signum > NSIG)
8071302Sbill 				bferr("Bad signal number");
8081302Sbill 		} else {
8091302Sbill 			name = &v[0][1];
8101302Sbill 			for (signum = 1; signum <= NSIG; signum++)
8111302Sbill 			if (mesg[signum].iname &&
8121302Sbill 			    eq(name, mesg[signum].iname))
8131302Sbill 				goto gotsig;
8141302Sbill 			setname(name);
8151302Sbill 			bferr("Unknown signal; kill -l lists signals");
8161302Sbill 		}
8171302Sbill gotsig:
8181302Sbill 		v++;
8191302Sbill 	} else
8201302Sbill 		signum = SIGTERM;
8211302Sbill 	pkill(v, signum);
8221302Sbill }
8231302Sbill 
8241302Sbill pkill(v, signum)
8251302Sbill 	char **v;
8261302Sbill 	int signum;
8271302Sbill {
8281302Sbill 	register struct process *pp, *np;
8291302Sbill 	register int jobflags = 0;
8301302Sbill 	int pid;
8311302Sbill 	extern char *sys_errlist[];
8321302Sbill 	int err = 0;
8331302Sbill 
8341302Sbill 	if (setintr)
8351302Sbill 		sighold(SIGINT);
8361302Sbill 	sighold(SIGCHLD);
8371302Sbill 	while (*v) {
8381302Sbill 		if (**v == '%') {
8391302Sbill 			np = pp = pfind(*v);
8401302Sbill 			do
8411302Sbill 				jobflags |= np->p_flags;
8421302Sbill 			while ((np = np->p_friends) != pp);
8431302Sbill 			switch (signum) {
8441302Sbill 
8451302Sbill 			case SIGSTOP:
8461302Sbill 			case SIGTSTP:
8471302Sbill 			case SIGTTIN:
8481302Sbill 			case SIGTTOU:
8491302Sbill 				if ((jobflags & PRUNNING) == 0) {
8501302Sbill 					printf("%s: Already stopped\n", *v);
8511302Sbill 					err++;
8521302Sbill 					goto cont;
8531302Sbill 				}
8541302Sbill 			}
8551302Sbill 			killpg(pp->p_jobid, signum);
8561302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
8571302Sbill 				killpg(pp->p_jobid, SIGCONT);
8581302Sbill 		} else if (!digit(**v))
8591302Sbill 			bferr("Arguments should be jobs or process id's");
8601302Sbill 		else {
8611302Sbill 			pid = atoi(*v);
8621302Sbill 			if (kill(pid, signum) < 0) {
8631302Sbill 				printf("%d: ", pid);
8641302Sbill 				printf("%s\n", sys_errlist[errno]);
8651302Sbill 				err++;
8661302Sbill 				goto cont;
8671302Sbill 			}
8681302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
8691302Sbill 				kill(pid, SIGCONT);
8701302Sbill 		}
8711302Sbill cont:
8721302Sbill 		v++;
8731302Sbill 	}
8741302Sbill 	sigrelse(SIGCHLD);
8751302Sbill 	if (setintr)
8761302Sbill 		sigrelse(SIGINT);
8771302Sbill 	if (err)
8781302Sbill 		error(NOSTR);
8791302Sbill }
8801302Sbill 
8811302Sbill /*
8821302Sbill  * pstart - start the job in foreground/background
8831302Sbill  */
8841302Sbill pstart(pp, foregnd)
8851302Sbill 	register struct process *pp;
8861302Sbill 	int foregnd;
8871302Sbill {
8881302Sbill 	register struct process *np;
8891302Sbill 	int jobflags = 0;
8901302Sbill 
8911302Sbill 	sighold(SIGCHLD);
8921302Sbill 	np = pp;
8931302Sbill 	do {
8941302Sbill 		jobflags |= np->p_flags;
8951302Sbill 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
8961302Sbill 			np->p_flags |= PRUNNING;
8971302Sbill 			np->p_flags &= ~PSTOPPED;
8981302Sbill 			if (foregnd)
8991302Sbill 				np->p_flags |= PFOREGND;
9001302Sbill 			else
9011302Sbill 				np->p_flags &= ~PFOREGND;
9021302Sbill 		}
9031302Sbill 	} while((np = np->p_friends) != pp);
9042357Swnj 	if (!foregnd)
9052357Swnj 		pclrcurr(pp);
9061302Sbill 	pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
9071302Sbill 	if (foregnd)
9081302Sbill 		ioctl(FSHTTY, TIOCSPGRP, &pp->p_jobid);
9091302Sbill 	if (jobflags&PSTOPPED)
9101302Sbill 		killpg(pp->p_jobid, SIGCONT);
9111302Sbill 	sigrelse(SIGCHLD);
9121302Sbill }
9131302Sbill 
9141302Sbill panystop(neednl)
9151302Sbill {
9161302Sbill 	register struct process *pp;
9171302Sbill 
9181302Sbill 	chkstop = 2;
9191302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9201302Sbill 		if (pp->p_flags & PSTOPPED)
9211302Sbill 			error("\nThere are stopped jobs" + 1 - neednl);
9221302Sbill }
9231302Sbill 
9241302Sbill struct process *
9251302Sbill pfind(cp)
9261302Sbill 	char *cp;
9271302Sbill {
9281302Sbill 	register struct process *pp, *np;
9291302Sbill 
9301302Sbill 	if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
9311302Sbill 		if (pcurrent == PNULL)
9321302Sbill 			bferr("No current job");
9331302Sbill 		return (pcurrent);
9341302Sbill 	}
9351302Sbill 	if (eq(cp, "%-") || eq(cp, "%#")) {
9361302Sbill 		if (pprevious == PNULL)
9371302Sbill 			bferr("No previous job");
9381302Sbill 		return (pprevious);
9391302Sbill 	}
9401302Sbill 	if (digit(cp[1])) {
9411302Sbill 		int index = atoi(cp+1);
9421302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
9431302Sbill 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
9441302Sbill 				return (pp);
9451302Sbill 		bferr("No such job");
9461302Sbill 	}
9471302Sbill 	np = PNULL;
9481302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
9491302Sbill 		if (pp->p_pid == pp->p_jobid) {
9501302Sbill 			if (cp[1] == '?') {
9511302Sbill 				register char *dp;
9521302Sbill 				for (dp = pp->p_command; *dp; dp++) {
9531302Sbill 					if (*dp != cp[2])
9541302Sbill 						continue;
9551302Sbill 					if (prefix(cp+2, dp))
9561302Sbill 						goto match;
9571302Sbill 				}
9581302Sbill 			} else if (prefix(cp+1, pp->p_command)) {
9591302Sbill match:
9601302Sbill 				if (np)
9611302Sbill 					bferr("Ambiguous");
9621302Sbill 				np = pp;
9631302Sbill 			}
9641302Sbill 		}
9651302Sbill 	if (np)
9661302Sbill 		return (np);
9671302Sbill 	if (cp[1] == '?')
9681302Sbill 		bferr("No job matches pattern");
9691302Sbill 	else
9701302Sbill 		bferr("No such job");
9711302Sbill }
9721302Sbill 
9731302Sbill /*
9742357Swnj  * pgetcurr - find most recent job that is not pp, preferably stopped
9751302Sbill  */
9761302Sbill struct process *
9771302Sbill pgetcurr(pp)
9781302Sbill 	register struct process *pp;
9791302Sbill {
9801302Sbill 	register struct process *np;
9812357Swnj 	register struct process *xp = PNULL;
9821302Sbill 
9831302Sbill 	for (np = proclist.p_next; np; np = np->p_next)
9841302Sbill 		if (np != pcurrent && np != pp && np->p_pid &&
9851302Sbill 		    np->p_pid == np->p_jobid) {
9862357Swnj 			if (np->p_flags & PSTOPPED)
9872357Swnj 				return (np);
9882357Swnj 			if (xp == PNULL)
9892357Swnj 				xp = np;
9901302Sbill 		}
9912357Swnj 	return (xp);
9921302Sbill }
9931302Sbill 
9941302Sbill /*
9951302Sbill  * donotify - flag the job so as to report termination asynchronously
9961302Sbill  */
9971302Sbill donotify(v)
9981302Sbill 	char **v;
9991302Sbill {
10001302Sbill 	register struct process *pp;
10011302Sbill 
10021302Sbill 	pp = pfind(*++v);
10031302Sbill 	pp->p_flags |= PNOTIFY;
10041302Sbill }
10051302Sbill 
10061302Sbill /*
10071302Sbill  * Do the fork and whatever should be done in the child side that
10081302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
10091302Sbill  * Also do everything that needs any signals fiddled with in the parent side
10101302Sbill  *
10111302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
10121302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
10131302Sbill  *	 0:	already have tty; manipulate process pgrps only
10141302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
10151302Sbill  * It is usually just the value of tpgrp.
10161302Sbill  */
10171302Sbill pfork(t, wanttty)
10181302Sbill 	struct command *t;	/* command we are forking for */
10191302Sbill 	int wanttty;
10201302Sbill {
10211302Sbill 	register int pid;
10221302Sbill 	bool ignint = 0;
10231302Sbill 	int pgrp;
10241302Sbill 
10251302Sbill 	/*
10261302Sbill 	 * A child will be uninterruptible only under very special
10271302Sbill 	 * conditions. Remember that the semantics of '&' is
10281302Sbill 	 * implemented by disconnecting the process from the tty so
10291302Sbill 	 * signals do not need to ignored just for '&'.
10301302Sbill 	 * Thus signals are set to default action for children unless:
10311302Sbill 	 *	we have had an "onintr -" (then specifically ignored)
10321302Sbill 	 *	we are not playing with signals (inherit action)
10331302Sbill 	 */
10341302Sbill 	if (setintr)
10351302Sbill 		ignint = (tpgrp == -1 && (t->t_dflg&FINT))
10361302Sbill 		    || (gointr && eq(gointr, "-"));
10371302Sbill 	/*
10381302Sbill 	 * Hold SIGCHLD until we have the process installed in our table.
10391302Sbill 	 */
10401302Sbill 	sighold(SIGCHLD);
10411302Sbill 	while ((pid = fork()) < 0)
10421302Sbill 		if (setintr == 0)
10431302Sbill 			sleep(FORKSLEEP);
10441302Sbill 		else {
10451302Sbill 			sigrelse(SIGINT);
10461302Sbill 			sigrelse(SIGCHLD);
10471302Sbill 			error("No more processes");
10481302Sbill 		}
10491302Sbill 	if (pid == 0) {
10501302Sbill 		settimes();
10511302Sbill 		pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
10521302Sbill 		pflushall();
10531302Sbill 		pcurrjob = PNULL;
10541302Sbill 		timesdone = 0;
10551302Sbill 		child++;
10561302Sbill 		if (setintr) {
10571302Sbill 			setintr = 0;		/* until I think otherwise */
10581302Sbill 			sigrelse(SIGCHLD);
10591302Sbill 			/*
10601302Sbill 			 * Children just get blown away on SIGINT, SIGQUIT
10611302Sbill 			 * unless "onintr -" seen.
10621302Sbill 			 */
10631302Sbill 			signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
10641302Sbill 			signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
10651302Sbill 			if (wanttty >= 0) {
10661302Sbill 				/* make stoppable */
10671302Sbill 				signal(SIGTSTP, SIG_DFL);
10681302Sbill 				signal(SIGTTIN, SIG_DFL);
10691302Sbill 				signal(SIGTTOU, SIG_DFL);
10701302Sbill 			}
10711302Sbill 			signal(SIGTERM, parterm);
10721302Sbill 		} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
10731302Sbill 			signal(SIGINT, SIG_IGN);
10741302Sbill 			signal(SIGQUIT, SIG_IGN);
10751302Sbill 		}
10761302Sbill 		if (wanttty > 0)
10771302Sbill 			ioctl(FSHTTY, TIOCSPGRP, &pgrp);
10781302Sbill 		if (wanttty >= 0 && tpgrp >= 0)
10791302Sbill 			setpgrp(0, pgrp);
10801302Sbill 		if (tpgrp > 0)
10811302Sbill 			tpgrp = 0;		/* gave tty away */
10821302Sbill 		/*
10831302Sbill 		 * Nohup and nice apply only to TCOM's but it would be
10841302Sbill 		 * nice (?!?) if you could say "nohup (foo;bar)"
10851302Sbill 		 * Then the parser would have to know about nice/nohup/time
10861302Sbill 		 */
10871302Sbill 		if (t->t_dflg & FNOHUP)
10881302Sbill 			signal(SIGHUP, SIG_IGN);
10891302Sbill 		if (t->t_dflg & FNICE) {
10901302Sbill /* sigh...
10911302Sbill 			nice(20);
10921302Sbill 			nice(-10);
10931302Sbill */
10941302Sbill 			nice(t->t_nice);
10951302Sbill 		}
10961302Sbill 
10971302Sbill 	} else {
10981302Sbill 		palloc(pid, t);
10991302Sbill 		sigrelse(SIGCHLD);
11001302Sbill 	}
11011302Sbill 
11021302Sbill 	return (pid);
11031302Sbill }
11041302Sbill 
11051302Sbill okpcntl()
11061302Sbill {
11071302Sbill 
11081302Sbill 	if (tpgrp == -1)
11091302Sbill 		error("No job control in this shell");
11101302Sbill 	if (tpgrp == 0)
11111302Sbill 		error("No job control in subshells");
11121302Sbill }
1113