xref: /csrg-svn/bin/csh/proc.c (revision 1302)
1*1302Sbill static	char *sccsid = "@(#)proc.c 4.1 10/09/80";
2*1302Sbill 
3*1302Sbill #include "sh.h"
4*1302Sbill #include "sh.dir.h"
5*1302Sbill #include "sh.proc.h"
6*1302Sbill #include <wait.h>
7*1302Sbill #include <sys/ioctl.h>
8*1302Sbill 
9*1302Sbill /*
10*1302Sbill  * C Shell - functions that manage processes, handling hanging, termination
11*1302Sbill  */
12*1302Sbill 
13*1302Sbill #define BIGINDEX	9	/* largest desirable job index */
14*1302Sbill 
15*1302Sbill /*
16*1302Sbill  * pchild - called at interrupt level by the SIGCHLD signal
17*1302Sbill  *	indicating that at least one child has terminated or stopped
18*1302Sbill  *	thus at least one wait system call will definitely return a
19*1302Sbill  *	childs status.  Top level routines (like pwait) must be sure
20*1302Sbill  *	to mask interrupts when playing with the proclist data structures!
21*1302Sbill  */
22*1302Sbill pchild()
23*1302Sbill {
24*1302Sbill 	register struct process *pp;
25*1302Sbill 	register struct process	*fp;
26*1302Sbill 	register int pid;
27*1302Sbill 	union wait w;
28*1302Sbill 	int jobflags;
29*1302Sbill #ifdef VMUNIX
30*1302Sbill 	struct vtimes vt;
31*1302Sbill #endif
32*1302Sbill 
33*1302Sbill 	if (!timesdone)
34*1302Sbill 		timesdone++, times(&shtimes);
35*1302Sbill loop:
36*1302Sbill 	pid = wait3(&w.w_status, (setintr ? WNOHANG|WUNTRACED:WNOHANG),
37*1302Sbill #ifndef VMUNIX
38*1302Sbill 	    0);
39*1302Sbill #else
40*1302Sbill 	    &vt);
41*1302Sbill #endif
42*1302Sbill 	if (pid <= 0) {
43*1302Sbill 		if (errno == EINTR) {
44*1302Sbill 			errno = 0;
45*1302Sbill 			goto loop;
46*1302Sbill 		}
47*1302Sbill 		pnoprocesses = pid == -1;
48*1302Sbill 		return;
49*1302Sbill 	}
50*1302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
51*1302Sbill 		if (pid == pp->p_pid)
52*1302Sbill 			goto found;
53*1302Sbill 	goto loop;
54*1302Sbill found:
55*1302Sbill 	if (pid == atoi(value("child")))
56*1302Sbill 		unsetv("child");
57*1302Sbill 	pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
58*1302Sbill 	if (WIFSTOPPED(w)) {
59*1302Sbill 		pp->p_flags |= PSTOPPED;
60*1302Sbill 		pp->p_reason = w.w_stopsig;
61*1302Sbill 	} else {
62*1302Sbill 		if (pp->p_flags & (PTIME|PPTIME) || adrof("time")) {
63*1302Sbill 			time_t oldcutimes, oldcstimes;
64*1302Sbill 			oldcutimes = shtimes.tms_cutime;
65*1302Sbill 			oldcstimes = shtimes.tms_cstime;
66*1302Sbill 			time(&pp->p_etime);
67*1302Sbill 			times(&shtimes);
68*1302Sbill 			pp->p_utime = shtimes.tms_cutime - oldcutimes;
69*1302Sbill 			pp->p_stime = shtimes.tms_cstime - oldcstimes;
70*1302Sbill 		} else
71*1302Sbill 			times(&shtimes);
72*1302Sbill #ifdef VMUNIX
73*1302Sbill 		pp->p_vtimes = vt;
74*1302Sbill #endif
75*1302Sbill 		if (WIFSIGNALED(w)) {
76*1302Sbill 			if (w.w_termsig == SIGINT)
77*1302Sbill 				pp->p_flags |= PINTERRUPTED;
78*1302Sbill 			else
79*1302Sbill 				pp->p_flags |= PSIGNALED;
80*1302Sbill 			if (w.w_coredump)
81*1302Sbill 				pp->p_flags |= PDUMPED;
82*1302Sbill 			pp->p_reason = w.w_termsig;
83*1302Sbill 		} else {
84*1302Sbill 			pp->p_reason = w.w_retcode;
85*1302Sbill #ifdef IIASA
86*1302Sbill 			if (pp->p_reason >= 3)
87*1302Sbill #else
88*1302Sbill 			if (pp->p_reason != 0)
89*1302Sbill #endif
90*1302Sbill 				pp->p_flags |= PAEXITED;
91*1302Sbill 			else
92*1302Sbill 				pp->p_flags |= PNEXITED;
93*1302Sbill 		}
94*1302Sbill 	}
95*1302Sbill 	jobflags = 0;
96*1302Sbill 	fp = pp;
97*1302Sbill 	do {
98*1302Sbill 		if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
99*1302Sbill 		    !child && adrof("time") &&
100*1302Sbill 		    (fp->p_utime + fp->p_stime) / HZ >=
101*1302Sbill 		     atoi(value("time")))
102*1302Sbill 			fp->p_flags |= PTIME;
103*1302Sbill 		jobflags |= fp->p_flags;
104*1302Sbill 	} while ((fp = fp->p_friends) != pp);
105*1302Sbill 	pp->p_flags &= ~PFOREGND;
106*1302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
107*1302Sbill 		pp->p_flags &= ~PPTIME;
108*1302Sbill 		pp->p_flags |= PTIME;
109*1302Sbill 	}
110*1302Sbill 	if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
111*1302Sbill 		fp = pp;
112*1302Sbill 		do {
113*1302Sbill 			if (fp->p_flags&PSTOPPED)
114*1302Sbill 				fp->p_flags |= PREPORTED;
115*1302Sbill 		} while((fp = fp->p_friends) != pp);
116*1302Sbill 		while(fp->p_pid != fp->p_jobid)
117*1302Sbill 			fp = fp->p_friends;
118*1302Sbill 		if (jobflags&PFOREGND) {
119*1302Sbill 			if (jobflags&PSTOPPED) {
120*1302Sbill 				if (pcurrent && pcurrent != fp)
121*1302Sbill 					pprevious = pcurrent;
122*1302Sbill 				pcurrent = fp;
123*1302Sbill 			} else
124*1302Sbill 				pclrcurr(fp);
125*1302Sbill 			if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
126*1302Sbill #ifdef IIASA
127*1302Sbill 			    jobflags & PAEXITED ||
128*1302Sbill #endif
129*1302Sbill 			    !eq(dcwd->di_name, fp->p_cwd->di_name)) {
130*1302Sbill 				if (jobflags & PSTOPPED)
131*1302Sbill 					printf("\n");
132*1302Sbill 				pprint(fp, AREASON|SHELLDIR);
133*1302Sbill 			} else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
134*1302Sbill 				ptprint(fp);
135*1302Sbill 		} else {
136*1302Sbill 			if (jobflags&PNOTIFY || adrof("notify")) {
137*1302Sbill 				printf("\215\n");
138*1302Sbill 				pprint(pp, NUMBER|NAME|REASON);
139*1302Sbill 				if ((jobflags&PSTOPPED) == 0)
140*1302Sbill 					pflush(pp);
141*1302Sbill 			} else {
142*1302Sbill 				if ((jobflags&PSTOPPED) == 0)
143*1302Sbill 					pclrcurr(fp);
144*1302Sbill 				fp->p_flags |= PNEEDNOTE;
145*1302Sbill 				neednote++;
146*1302Sbill 			}
147*1302Sbill 		}
148*1302Sbill 	}
149*1302Sbill 	goto loop;
150*1302Sbill }
151*1302Sbill 
152*1302Sbill pnote()
153*1302Sbill {
154*1302Sbill 	register struct process *pp;
155*1302Sbill 	int flags;
156*1302Sbill 
157*1302Sbill 	neednote = 0;
158*1302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
159*1302Sbill 		if (pp->p_flags & PNEEDNOTE) {
160*1302Sbill 			sighold(SIGCHLD);
161*1302Sbill 			pp->p_flags &= ~PNEEDNOTE;
162*1302Sbill 			flags = pprint(pp, NUMBER|NAME|REASON);
163*1302Sbill 			if ((flags&(PRUNNING|PSTOPPED)) == 0)
164*1302Sbill 				pflush(pp);
165*1302Sbill 			sigrelse(SIGCHLD);
166*1302Sbill 		}
167*1302Sbill 	}
168*1302Sbill }
169*1302Sbill 
170*1302Sbill /*
171*1302Sbill  * pwait - wait for current job to terminate, maintaining integrity
172*1302Sbill  *	of current and previous job indicators.
173*1302Sbill  */
174*1302Sbill pwait()
175*1302Sbill {
176*1302Sbill 	register struct process *fp, *pp;
177*1302Sbill 
178*1302Sbill 	/*
179*1302Sbill 	 * Here's where dead procs get flushed.
180*1302Sbill 	 */
181*1302Sbill 	sighold(SIGCHLD);
182*1302Sbill 	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
183*1302Sbill 		if (pp->p_pid == 0) {
184*1302Sbill 			fp->p_next = pp->p_next;
185*1302Sbill 			xfree(pp->p_command);
186*1302Sbill 			if (pp->p_cwd && --pp->p_cwd->di_count == 0)
187*1302Sbill 				if (pp->p_cwd->di_next == 0)
188*1302Sbill 					dfree(pp->p_cwd);
189*1302Sbill 			xfree((char *)pp);
190*1302Sbill 			pp = fp;
191*1302Sbill 		}
192*1302Sbill 	sigrelse(SIGCHLD);
193*1302Sbill 	if (setintr)
194*1302Sbill 		sigignore(SIGINT);
195*1302Sbill 	pjwait(pcurrjob);
196*1302Sbill }
197*1302Sbill 
198*1302Sbill /*
199*1302Sbill  * pjwait - wait for a job to finish or become stopped
200*1302Sbill  *	It is assumed to be in the foreground state (PFOREGND)
201*1302Sbill  */
202*1302Sbill pjwait(pp)
203*1302Sbill 	register struct process *pp;
204*1302Sbill {
205*1302Sbill 	register struct process *fp;
206*1302Sbill 	int jobflags, reason;
207*1302Sbill 
208*1302Sbill 	fp = pp;
209*1302Sbill 	do {
210*1302Sbill 		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
211*1302Sbill 			printf("BUG: waiting for background job!\n");
212*1302Sbill 	} while ((fp = fp->p_friends) != pp);
213*1302Sbill 	/*
214*1302Sbill 	 * Now keep pausing as long as we are not interrupted (SIGINT),
215*1302Sbill 	 * and the target process, or any of its friends, are running
216*1302Sbill 	 */
217*1302Sbill 	fp = pp;
218*1302Sbill 	for (;;) {
219*1302Sbill 		sighold(SIGCHLD);
220*1302Sbill 		jobflags = 0;
221*1302Sbill 		do
222*1302Sbill 			jobflags |= fp->p_flags;
223*1302Sbill 		while((fp = (fp->p_friends)) != pp);
224*1302Sbill 		if ((jobflags & PRUNNING) == 0)
225*1302Sbill 			break;
226*1302Sbill 		sigpause(SIGCHLD);
227*1302Sbill 	}
228*1302Sbill 	sigrelse(SIGCHLD);
229*1302Sbill 	if (tpgrp > 0)
230*1302Sbill 		ioctl(FSHTTY, TIOCSPGRP, &tpgrp);	/* get tty back */
231*1302Sbill 	if (jobflags & PSTOPPED)
232*1302Sbill 		return;
233*1302Sbill 	if ((jobflags&PINTERRUPTED) && setintr &&
234*1302Sbill 	    (!gointr || !eq(gointr, "-"))) {
235*1302Sbill 		pflush(pp);
236*1302Sbill 		pintr();
237*1302Sbill 		/*NOTREACHED*/
238*1302Sbill 	}
239*1302Sbill 	reason = 0;
240*1302Sbill 	fp = pp;
241*1302Sbill 	do {
242*1302Sbill 		if (fp->p_reason)
243*1302Sbill 			reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
244*1302Sbill 				fp->p_reason | QUOTE : fp->p_reason;
245*1302Sbill 	} while ((fp = fp->p_friends) != pp);
246*1302Sbill 	set("status", putn(reason));
247*1302Sbill 	if (reason && exiterr)
248*1302Sbill 		exitstat();
249*1302Sbill 	pflush(pp);
250*1302Sbill }
251*1302Sbill 
252*1302Sbill /*
253*1302Sbill  * dowait - wait for all processes to finish
254*1302Sbill  */
255*1302Sbill dowait()
256*1302Sbill {
257*1302Sbill 	register struct process *pp;
258*1302Sbill 
259*1302Sbill 	pjobs++;
260*1302Sbill 	if (setintr)
261*1302Sbill 		sigrelse(SIGINT);
262*1302Sbill loop:
263*1302Sbill 	sighold(SIGCHLD);
264*1302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
265*1302Sbill 		if (pp->p_pid && pp->p_pid == pp->p_jobid &&
266*1302Sbill 		    pp->p_flags&PRUNNING) {
267*1302Sbill 			sigpause(SIGCHLD);
268*1302Sbill 			goto loop;
269*1302Sbill 		}
270*1302Sbill 	sigrelse(SIGCHLD);
271*1302Sbill 	pjobs = 0;
272*1302Sbill }
273*1302Sbill 
274*1302Sbill /*
275*1302Sbill  * pflushall - flush all jobs from list (e.g. at fork())
276*1302Sbill  */
277*1302Sbill pflushall()
278*1302Sbill {
279*1302Sbill 	register struct process	*pp;
280*1302Sbill 
281*1302Sbill 	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
282*1302Sbill 		if (pp->p_pid)
283*1302Sbill 			pflush(pp);
284*1302Sbill }
285*1302Sbill 
286*1302Sbill /*
287*1302Sbill  * pflush - flag all process structures in the same job as the
288*1302Sbill  *	the argument process for deletion.  The actual free of the
289*1302Sbill  *	space is not done here since pflush is called at interrupt level.
290*1302Sbill  */
291*1302Sbill pflush(pp)
292*1302Sbill 	register struct process	*pp;
293*1302Sbill {
294*1302Sbill 	register struct process *np;
295*1302Sbill 	register int index;
296*1302Sbill 
297*1302Sbill 	if (pp->p_pid == 0) {
298*1302Sbill 		printf("BUG: process flushed twice");
299*1302Sbill 		return;
300*1302Sbill 	}
301*1302Sbill 	while (pp->p_pid != pp->p_jobid)
302*1302Sbill 		pp = pp->p_friends;
303*1302Sbill 	pclrcurr(pp);
304*1302Sbill 	if (pp == pcurrjob)
305*1302Sbill 		pcurrjob = 0;
306*1302Sbill 	index = pp->p_index;
307*1302Sbill 	np = pp;
308*1302Sbill 	do {
309*1302Sbill 		np->p_index = np->p_pid = 0;
310*1302Sbill 		np->p_flags &= ~PNEEDNOTE;
311*1302Sbill 	} while ((np = np->p_friends) != pp);
312*1302Sbill 	if (index == pmaxindex) {
313*1302Sbill 		for (np = proclist.p_next, index = 0; np; np = np->p_next)
314*1302Sbill 			if (np->p_index > index)
315*1302Sbill 				index = np->p_index;
316*1302Sbill 		pmaxindex = index;
317*1302Sbill 	}
318*1302Sbill }
319*1302Sbill 
320*1302Sbill /*
321*1302Sbill  * pclrcurr - make sure the given job is not the current or previous job;
322*1302Sbill  *	pp MUST be the job leader
323*1302Sbill  */
324*1302Sbill pclrcurr(pp)
325*1302Sbill 	register struct process *pp;
326*1302Sbill {
327*1302Sbill 
328*1302Sbill 	if (pp == pcurrent)
329*1302Sbill 		if (pprevious != PNULL) {
330*1302Sbill 			pcurrent = pprevious;
331*1302Sbill 			pprevious = pgetcurr(pp);
332*1302Sbill 		} else {
333*1302Sbill 			pcurrent = pgetcurr(pp);
334*1302Sbill 			pprevious = pgetcurr(pp);
335*1302Sbill 		}
336*1302Sbill 	else if (pp == pprevious)
337*1302Sbill 		pprevious = pgetcurr(pp);
338*1302Sbill }
339*1302Sbill 
340*1302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */
341*1302Sbill char	command[PMAXLEN+4];
342*1302Sbill int	cmdlen;
343*1302Sbill char	*cmdp;
344*1302Sbill /*
345*1302Sbill  * palloc - allocate a process structure and fill it up.
346*1302Sbill  *	an important assumption is made that the process is running.
347*1302Sbill  */
348*1302Sbill palloc(pid, t)
349*1302Sbill 	int pid;
350*1302Sbill 	register struct command *t;
351*1302Sbill {
352*1302Sbill 	register struct process	*pp;
353*1302Sbill 	int i;
354*1302Sbill 
355*1302Sbill 	pp = (struct process *)calloc(1, sizeof(struct process));
356*1302Sbill 	pp->p_pid = pid;
357*1302Sbill 	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
358*1302Sbill 	if (t->t_dflg & FTIME)
359*1302Sbill 		pp->p_flags |= PPTIME;
360*1302Sbill 	cmdp = command;
361*1302Sbill 	cmdlen = 0;
362*1302Sbill 	padd(t);
363*1302Sbill 	*cmdp++ = 0;
364*1302Sbill 	if (t->t_dflg & FPOU) {
365*1302Sbill 		pp->p_flags |= PPOU;
366*1302Sbill 		if (t->t_dflg & FDIAG)
367*1302Sbill 			pp->p_flags |= PDIAG;
368*1302Sbill 	}
369*1302Sbill 	pp->p_command = savestr(command);
370*1302Sbill 	if (pcurrjob) {
371*1302Sbill 		struct process *fp;
372*1302Sbill 		/* careful here with interrupt level */
373*1302Sbill 		pp->p_cwd = 0;
374*1302Sbill 		pp->p_index = pcurrjob->p_index;
375*1302Sbill 		pp->p_friends = pcurrjob;
376*1302Sbill 		pp->p_jobid = pcurrjob->p_pid;
377*1302Sbill 		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
378*1302Sbill 			;
379*1302Sbill 		fp->p_friends = pp;
380*1302Sbill 	} else {
381*1302Sbill 		pcurrjob = pp;
382*1302Sbill 		pp->p_jobid = pid;
383*1302Sbill 		pp->p_friends = pp;
384*1302Sbill 		pp->p_cwd = dcwd;
385*1302Sbill 		dcwd->di_count++;
386*1302Sbill 		if (pmaxindex < BIGINDEX)
387*1302Sbill 			pp->p_index = ++pmaxindex;
388*1302Sbill 		else {
389*1302Sbill 			struct process *np;
390*1302Sbill 
391*1302Sbill 			for (i = 1; ; i++) {
392*1302Sbill 				for (np = proclist.p_next; np; np = np->p_next)
393*1302Sbill 					if (np->p_index == i)
394*1302Sbill 						goto tryagain;
395*1302Sbill 				pmaxindex = pp->p_index = i;
396*1302Sbill 				break;
397*1302Sbill 			tryagain:;
398*1302Sbill 			}
399*1302Sbill 		}
400*1302Sbill 		if (pcurrent == PNULL)
401*1302Sbill 			pcurrent = pp;
402*1302Sbill 		else if (pprevious == PNULL)
403*1302Sbill 			pprevious = pp;
404*1302Sbill 	}
405*1302Sbill 	pp->p_next = proclist.p_next;
406*1302Sbill 	proclist.p_next = pp;
407*1302Sbill 	time(&pp->p_btime);
408*1302Sbill }
409*1302Sbill 
410*1302Sbill padd(t)
411*1302Sbill 	register struct command *t;
412*1302Sbill {
413*1302Sbill 	char **argp;
414*1302Sbill 
415*1302Sbill 	if (t == 0)
416*1302Sbill 		return;
417*1302Sbill 	switch (t->t_dtyp) {
418*1302Sbill 
419*1302Sbill 	case TPAR:
420*1302Sbill 		pads("( ");
421*1302Sbill 		padd(t->t_dspr);
422*1302Sbill 		pads(" )");
423*1302Sbill 		break;
424*1302Sbill 
425*1302Sbill 	case TCOM:
426*1302Sbill 		for (argp = t->t_dcom; *argp; argp++) {
427*1302Sbill 			pads(*argp);
428*1302Sbill 			if (argp[1])
429*1302Sbill 				pads(" ");
430*1302Sbill 		}
431*1302Sbill 		break;
432*1302Sbill 
433*1302Sbill 	case TFIL:
434*1302Sbill 		padd(t->t_dcar);
435*1302Sbill 		pads(" | ");
436*1302Sbill 		padd(t->t_dcdr);
437*1302Sbill 		return;
438*1302Sbill 
439*1302Sbill 	case TLST:
440*1302Sbill 		padd(t->t_dcar);
441*1302Sbill 		pads("; ");
442*1302Sbill 		padd(t->t_dcdr);
443*1302Sbill 		return;
444*1302Sbill 	}
445*1302Sbill 	if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
446*1302Sbill 		pads((t->t_dflg & FHERE) ? " << " : " < ");
447*1302Sbill 		pads(t->t_dlef);
448*1302Sbill 	}
449*1302Sbill 	if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
450*1302Sbill 		pads((t->t_dflg & FCAT) ? " >>" : " >");
451*1302Sbill 		if (t->t_dflg & FDIAG)
452*1302Sbill 			pads("&");
453*1302Sbill 		pads(" ");
454*1302Sbill 		pads(t->t_drit);
455*1302Sbill 	}
456*1302Sbill }
457*1302Sbill 
458*1302Sbill pads(cp)
459*1302Sbill 	char *cp;
460*1302Sbill {
461*1302Sbill 	register int i = strlen(cp);
462*1302Sbill 
463*1302Sbill 	if (cmdlen >= PMAXLEN)
464*1302Sbill 		return;
465*1302Sbill 	if (cmdlen + i >= PMAXLEN) {
466*1302Sbill 		strcpy(cmdp, " ...");
467*1302Sbill 		cmdlen = PMAXLEN;
468*1302Sbill 		cmdp += 4;
469*1302Sbill 		return;
470*1302Sbill 	}
471*1302Sbill 	strcpy(cmdp, cp);
472*1302Sbill 	cmdp += i;
473*1302Sbill 	cmdlen += i;
474*1302Sbill }
475*1302Sbill 
476*1302Sbill /*
477*1302Sbill  * psavejob - temporarily save the current job on a one level stack
478*1302Sbill  *	so another job can be created.  Used for { } in exp6
479*1302Sbill  *	and `` in globbing.
480*1302Sbill  */
481*1302Sbill psavejob()
482*1302Sbill {
483*1302Sbill 
484*1302Sbill 	pholdjob = pcurrjob;
485*1302Sbill 	pcurrjob = PNULL;
486*1302Sbill }
487*1302Sbill 
488*1302Sbill /*
489*1302Sbill  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
490*1302Sbill  *	somewhere, but pendjob cleans up anyway.
491*1302Sbill  */
492*1302Sbill prestjob()
493*1302Sbill {
494*1302Sbill 
495*1302Sbill 	pcurrjob = pholdjob;
496*1302Sbill 	pholdjob = PNULL;
497*1302Sbill }
498*1302Sbill 
499*1302Sbill /*
500*1302Sbill  * pendjob - indicate that a job (set of commands) has been completed
501*1302Sbill  *	or is about to begin.
502*1302Sbill  */
503*1302Sbill pendjob()
504*1302Sbill {
505*1302Sbill 	register struct process *pp, *tp;
506*1302Sbill 
507*1302Sbill 	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
508*1302Sbill 		pp = pcurrjob;
509*1302Sbill 		while (pp->p_pid != pp->p_jobid)
510*1302Sbill 			pp = pp->p_friends;
511*1302Sbill 		printf("[%d]", pp->p_index);
512*1302Sbill 		tp = pp;
513*1302Sbill 		do {
514*1302Sbill 			printf(" %d", pp->p_pid);
515*1302Sbill 			pp = pp->p_friends;
516*1302Sbill 		} while (pp != tp);
517*1302Sbill 		printf("\n");
518*1302Sbill 	}
519*1302Sbill 	pholdjob = pcurrjob = 0;
520*1302Sbill }
521*1302Sbill 
522*1302Sbill /*
523*1302Sbill  * pprint - print a job
524*1302Sbill  */
525*1302Sbill pprint(pp, flag)
526*1302Sbill 	register struct process	*pp;
527*1302Sbill {
528*1302Sbill 	register status, reason;
529*1302Sbill 	struct process *tp;
530*1302Sbill 	extern char *linp, linbuf[];
531*1302Sbill 	int jobflags, pstatus;
532*1302Sbill 	char *format;
533*1302Sbill 
534*1302Sbill 	while (pp->p_pid != pp->p_jobid)
535*1302Sbill 		pp = pp->p_friends;
536*1302Sbill 	if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
537*1302Sbill 		pp->p_flags &= ~PPTIME;
538*1302Sbill 		pp->p_flags |= PTIME;
539*1302Sbill 	}
540*1302Sbill 	tp = pp;
541*1302Sbill 	status = reason = -1;
542*1302Sbill 	jobflags = 0;
543*1302Sbill 	do {
544*1302Sbill 		jobflags |= pp->p_flags;
545*1302Sbill 		pstatus = pp->p_flags & PALLSTATES;
546*1302Sbill 		if (tp != pp && linp != linbuf && !(flag&FANCY) &&
547*1302Sbill 		    (pstatus == status && pp->p_reason == reason ||
548*1302Sbill 		     !(flag&REASON)))
549*1302Sbill 			printf(" ");
550*1302Sbill 		else {
551*1302Sbill 			if (tp != pp && linp != linbuf)
552*1302Sbill 				printf("\n");
553*1302Sbill 			if(flag&NUMBER)
554*1302Sbill 				if (pp == tp)
555*1302Sbill 					printf("[%d]%s %c ", pp->p_index,
556*1302Sbill 					    pp->p_index < 10 ? " " : "",
557*1302Sbill 					    pp==pcurrent ? '+' :
558*1302Sbill 						(pp == pprevious ? '-' : ' '));
559*1302Sbill 				else
560*1302Sbill 					printf("       ");
561*1302Sbill 			if (flag&FANCY)
562*1302Sbill 				printf("%5d ", pp->p_pid);
563*1302Sbill 			if (flag&(REASON|AREASON)) {
564*1302Sbill 				if (flag&NAME)
565*1302Sbill 					format = "%-21s";
566*1302Sbill 				else
567*1302Sbill 					format = "%s";
568*1302Sbill 				if (pstatus == status)
569*1302Sbill 					if (pp->p_reason == reason) {
570*1302Sbill 						printf(format, "");
571*1302Sbill 						goto prcomd;
572*1302Sbill 					} else
573*1302Sbill 						reason = pp->p_reason;
574*1302Sbill 				else {
575*1302Sbill 					status = pstatus;
576*1302Sbill 					reason = pp->p_reason;
577*1302Sbill 				}
578*1302Sbill 				switch (status) {
579*1302Sbill 
580*1302Sbill 				case PRUNNING:
581*1302Sbill 					printf(format, "Running ");
582*1302Sbill 					break;
583*1302Sbill 
584*1302Sbill 				case PINTERRUPTED:
585*1302Sbill 				case PSTOPPED:
586*1302Sbill 				case PSIGNALED:
587*1302Sbill 					if (flag&REASON || reason != SIGINT ||
588*1302Sbill 					    reason != SIGPIPE)
589*1302Sbill 						printf(format, mesg[pp->p_reason].pname);
590*1302Sbill 					break;
591*1302Sbill 
592*1302Sbill 				case PNEXITED:
593*1302Sbill 				case PAEXITED:
594*1302Sbill 					if (flag & REASON)
595*1302Sbill 						if (pp->p_reason)
596*1302Sbill 							printf("Exit %-16d", pp->p_reason);
597*1302Sbill 						else
598*1302Sbill 							printf(format, "Done");
599*1302Sbill 					break;
600*1302Sbill 
601*1302Sbill 				default:
602*1302Sbill 					printf("BUG: status=%-9o", status);
603*1302Sbill 				}
604*1302Sbill 			}
605*1302Sbill 		}
606*1302Sbill prcomd:
607*1302Sbill 		if (flag&NAME) {
608*1302Sbill 			printf("%s", pp->p_command);
609*1302Sbill 			if (pp->p_flags & PPOU)
610*1302Sbill 				printf(" |");
611*1302Sbill 			if (pp->p_flags & PDIAG)
612*1302Sbill 				printf("&");
613*1302Sbill 		}
614*1302Sbill 		if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
615*1302Sbill 			printf(" (core dumped)");
616*1302Sbill 		if (tp == pp->p_friends) {
617*1302Sbill 			if (flag&AMPERSAND)
618*1302Sbill 				printf(" &");
619*1302Sbill 			if (flag&JOBDIR &&
620*1302Sbill 			    !eq(tp->p_cwd->di_name, dcwd->di_name)) {
621*1302Sbill 				printf(" (wd: ");
622*1302Sbill 				dtildepr(value("home"), tp->p_cwd->di_name);
623*1302Sbill 				printf(")");
624*1302Sbill 			}
625*1302Sbill 		}
626*1302Sbill 		if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
627*1302Sbill 			if (linp != linbuf)
628*1302Sbill 				printf("\n\t");
629*1302Sbill #ifndef VMUNIX
630*1302Sbill 			ptimes(pp->p_utime, pp->p_stime, pp->p_etime-pp->p_btime);
631*1302Sbill #else
632*1302Sbill 			pvtimes(&zvms, &pp->p_vtimes, pp->p_etime - pp->p_btime);
633*1302Sbill #endif
634*1302Sbill 		}
635*1302Sbill 		if (tp == pp->p_friends) {
636*1302Sbill 			if (linp != linbuf)
637*1302Sbill 				printf("\n");
638*1302Sbill 			if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
639*1302Sbill 				printf("(wd now: ");
640*1302Sbill 				dtildepr(value("home"), dcwd->di_name);
641*1302Sbill 				printf(")\n");
642*1302Sbill 			}
643*1302Sbill 		}
644*1302Sbill 	} while ((pp = pp->p_friends) != tp);
645*1302Sbill 	if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
646*1302Sbill 		if (jobflags & NUMBER)
647*1302Sbill 			printf("       ");
648*1302Sbill 		ptprint(tp);
649*1302Sbill 	}
650*1302Sbill 	return (jobflags);
651*1302Sbill }
652*1302Sbill 
653*1302Sbill ptprint(tp)
654*1302Sbill 	register struct process *tp;
655*1302Sbill {
656*1302Sbill 	time_t tetime = 0;
657*1302Sbill #ifdef VMUNIX
658*1302Sbill 	struct vtimes vmt;
659*1302Sbill #else
660*1302Sbill 	time_t tutime = 0, tstime = 0;
661*1302Sbill #endif
662*1302Sbill 	register struct process *pp = tp;
663*1302Sbill 
664*1302Sbill 	vmt = zvms;
665*1302Sbill 	do {
666*1302Sbill #ifdef VMUNIX
667*1302Sbill 		vmsadd(&vmt, &pp->p_vtimes);
668*1302Sbill #else
669*1302Sbill 		tutime += pp->p_utime;
670*1302Sbill 		tstime += pp->p_stime;
671*1302Sbill #endif
672*1302Sbill 		if (pp->p_etime - pp->p_btime > tetime)
673*1302Sbill 			tetime = pp->p_etime - pp->p_btime;
674*1302Sbill 	} while ((pp = pp->p_friends) != tp);
675*1302Sbill #ifdef VMUNIX
676*1302Sbill 	pvtimes(&zvms, &vmt, tetime);
677*1302Sbill #else
678*1302Sbill 	ptimes(tutime, tstime, tetime);
679*1302Sbill #endif
680*1302Sbill }
681*1302Sbill 
682*1302Sbill /*
683*1302Sbill  * dojobs - print all jobs
684*1302Sbill  */
685*1302Sbill dojobs(v)
686*1302Sbill 	char **v;
687*1302Sbill {
688*1302Sbill 	register struct process *pp;
689*1302Sbill 	register int flag = NUMBER|NAME|REASON;
690*1302Sbill 	int i;
691*1302Sbill 
692*1302Sbill 	if (chkstop)
693*1302Sbill 		chkstop = 2;
694*1302Sbill 	if (*++v) {
695*1302Sbill 		if (v[1] || !eq(*v, "-l"))
696*1302Sbill 			error("Usage: jobs [ -l ]");
697*1302Sbill 		flag |= FANCY|JOBDIR;
698*1302Sbill 	}
699*1302Sbill 	for (i = 1; i <= pmaxindex; i++)
700*1302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
701*1302Sbill 			if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
702*1302Sbill 				pp->p_flags &= ~PNEEDNOTE;
703*1302Sbill 				if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
704*1302Sbill 					pflush(pp);
705*1302Sbill 				break;
706*1302Sbill 			}
707*1302Sbill }
708*1302Sbill 
709*1302Sbill /*
710*1302Sbill  * dofg - builtin - put the job into the foreground
711*1302Sbill  */
712*1302Sbill dofg(v)
713*1302Sbill 	char **v;
714*1302Sbill {
715*1302Sbill 	register struct process *pp;
716*1302Sbill 
717*1302Sbill 	okpcntl();
718*1302Sbill 	++v;
719*1302Sbill 	do {
720*1302Sbill 		pp = pfind(*v);
721*1302Sbill 		pstart(pp, 1);
722*1302Sbill 		if (setintr)
723*1302Sbill 			sigignore(SIGINT);
724*1302Sbill 		pjwait(pp);
725*1302Sbill 	} while (*v && *++v);
726*1302Sbill }
727*1302Sbill 
728*1302Sbill /*
729*1302Sbill  * %... - builtin - put the job into the foreground
730*1302Sbill  */
731*1302Sbill dofg1(v)
732*1302Sbill 	char **v;
733*1302Sbill {
734*1302Sbill 	register struct process *pp;
735*1302Sbill 
736*1302Sbill 	okpcntl();
737*1302Sbill 	pp = pfind(v[0]);
738*1302Sbill 	pstart(pp, 1);
739*1302Sbill 	if (setintr)
740*1302Sbill 		sigignore(SIGINT);
741*1302Sbill 	pjwait(pp);
742*1302Sbill }
743*1302Sbill 
744*1302Sbill /*
745*1302Sbill  * dobg - builtin - put the job into the background
746*1302Sbill  */
747*1302Sbill dobg(v)
748*1302Sbill 	char **v;
749*1302Sbill {
750*1302Sbill 	register struct process *pp;
751*1302Sbill 
752*1302Sbill 	okpcntl();
753*1302Sbill 	++v;
754*1302Sbill 	do {
755*1302Sbill 		pp = pfind(*v);
756*1302Sbill 		pstart(pp, 0);
757*1302Sbill 	} while (*v && *++v);
758*1302Sbill }
759*1302Sbill 
760*1302Sbill /*
761*1302Sbill  * %... & - builtin - put the job into the background
762*1302Sbill  */
763*1302Sbill dobg1(v)
764*1302Sbill 	char **v;
765*1302Sbill {
766*1302Sbill 	register struct process *pp;
767*1302Sbill 
768*1302Sbill 	pp = pfind(v[0]);
769*1302Sbill 	pstart(pp, 0);
770*1302Sbill }
771*1302Sbill 
772*1302Sbill /*
773*1302Sbill  * dostop - builtin - stop the job
774*1302Sbill  */
775*1302Sbill dostop(v)
776*1302Sbill 	char **v;
777*1302Sbill {
778*1302Sbill 
779*1302Sbill 	pkill(++v, SIGSTOP);
780*1302Sbill }
781*1302Sbill 
782*1302Sbill /*
783*1302Sbill  * dokill - builtin - superset of kill (1)
784*1302Sbill  */
785*1302Sbill dokill(v)
786*1302Sbill 	char **v;
787*1302Sbill {
788*1302Sbill 	register int signum;
789*1302Sbill 	register char *name;
790*1302Sbill 
791*1302Sbill 	v++;
792*1302Sbill 	if (v[0] && v[0][0] == '-') {
793*1302Sbill 		if (v[0][1] == 'l') {
794*1302Sbill 			for (signum = 1; signum <= NSIG; signum++) {
795*1302Sbill 				if (name = mesg[signum].iname)
796*1302Sbill 					printf("%s ", name);
797*1302Sbill 				if (signum == 16)
798*1302Sbill 					printf("\n");
799*1302Sbill 			}
800*1302Sbill 			printf("\n");
801*1302Sbill 			return;
802*1302Sbill 		}
803*1302Sbill 		if (digit(v[0][1])) {
804*1302Sbill 			signum = atoi(v[0]+1);
805*1302Sbill 			if (signum < 1 || signum > NSIG)
806*1302Sbill 				bferr("Bad signal number");
807*1302Sbill 		} else {
808*1302Sbill 			name = &v[0][1];
809*1302Sbill 			for (signum = 1; signum <= NSIG; signum++)
810*1302Sbill 			if (mesg[signum].iname &&
811*1302Sbill 			    eq(name, mesg[signum].iname))
812*1302Sbill 				goto gotsig;
813*1302Sbill 			setname(name);
814*1302Sbill 			bferr("Unknown signal; kill -l lists signals");
815*1302Sbill 		}
816*1302Sbill gotsig:
817*1302Sbill 		v++;
818*1302Sbill 	} else
819*1302Sbill 		signum = SIGTERM;
820*1302Sbill 	pkill(v, signum);
821*1302Sbill }
822*1302Sbill 
823*1302Sbill pkill(v, signum)
824*1302Sbill 	char **v;
825*1302Sbill 	int signum;
826*1302Sbill {
827*1302Sbill 	register struct process *pp, *np;
828*1302Sbill 	register int jobflags = 0;
829*1302Sbill 	int pid;
830*1302Sbill 	extern char *sys_errlist[];
831*1302Sbill 	int err = 0;
832*1302Sbill 
833*1302Sbill 	if (setintr)
834*1302Sbill 		sighold(SIGINT);
835*1302Sbill 	sighold(SIGCHLD);
836*1302Sbill 	while (*v) {
837*1302Sbill 		if (**v == '%') {
838*1302Sbill 			np = pp = pfind(*v);
839*1302Sbill 			do
840*1302Sbill 				jobflags |= np->p_flags;
841*1302Sbill 			while ((np = np->p_friends) != pp);
842*1302Sbill 			switch (signum) {
843*1302Sbill 
844*1302Sbill 			case SIGSTOP:
845*1302Sbill 			case SIGTSTP:
846*1302Sbill 			case SIGTTIN:
847*1302Sbill 			case SIGTTOU:
848*1302Sbill 				if ((jobflags & PRUNNING) == 0) {
849*1302Sbill 					printf("%s: Already stopped\n", *v);
850*1302Sbill 					err++;
851*1302Sbill 					goto cont;
852*1302Sbill 				}
853*1302Sbill 			}
854*1302Sbill 			killpg(pp->p_jobid, signum);
855*1302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
856*1302Sbill 				killpg(pp->p_jobid, SIGCONT);
857*1302Sbill 		} else if (!digit(**v))
858*1302Sbill 			bferr("Arguments should be jobs or process id's");
859*1302Sbill 		else {
860*1302Sbill 			pid = atoi(*v);
861*1302Sbill 			if (kill(pid, signum) < 0) {
862*1302Sbill 				printf("%d: ", pid);
863*1302Sbill 				printf("%s\n", sys_errlist[errno]);
864*1302Sbill 				err++;
865*1302Sbill 				goto cont;
866*1302Sbill 			}
867*1302Sbill 			if (signum == SIGTERM || signum == SIGHUP)
868*1302Sbill 				kill(pid, SIGCONT);
869*1302Sbill 		}
870*1302Sbill cont:
871*1302Sbill 		v++;
872*1302Sbill 	}
873*1302Sbill 	sigrelse(SIGCHLD);
874*1302Sbill 	if (setintr)
875*1302Sbill 		sigrelse(SIGINT);
876*1302Sbill 	if (err)
877*1302Sbill 		error(NOSTR);
878*1302Sbill }
879*1302Sbill 
880*1302Sbill /*
881*1302Sbill  * pstart - start the job in foreground/background
882*1302Sbill  */
883*1302Sbill pstart(pp, foregnd)
884*1302Sbill 	register struct process *pp;
885*1302Sbill 	int foregnd;
886*1302Sbill {
887*1302Sbill 	register struct process *np;
888*1302Sbill 	int jobflags = 0;
889*1302Sbill 
890*1302Sbill 	sighold(SIGCHLD);
891*1302Sbill 	np = pp;
892*1302Sbill 	do {
893*1302Sbill 		jobflags |= np->p_flags;
894*1302Sbill 		if (np->p_flags&(PRUNNING|PSTOPPED)) {
895*1302Sbill 			np->p_flags |= PRUNNING;
896*1302Sbill 			np->p_flags &= ~PSTOPPED;
897*1302Sbill 			if (foregnd)
898*1302Sbill 				np->p_flags |= PFOREGND;
899*1302Sbill 			else
900*1302Sbill 				np->p_flags &= ~PFOREGND;
901*1302Sbill 		}
902*1302Sbill 	} while((np = np->p_friends) != pp);
903*1302Sbill 	pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
904*1302Sbill 	if (foregnd)
905*1302Sbill 		ioctl(FSHTTY, TIOCSPGRP, &pp->p_jobid);
906*1302Sbill 	if (jobflags&PSTOPPED)
907*1302Sbill 		killpg(pp->p_jobid, SIGCONT);
908*1302Sbill 	sigrelse(SIGCHLD);
909*1302Sbill }
910*1302Sbill 
911*1302Sbill panystop(neednl)
912*1302Sbill {
913*1302Sbill 	register struct process *pp;
914*1302Sbill 
915*1302Sbill 	chkstop = 2;
916*1302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
917*1302Sbill 		if (pp->p_flags & PSTOPPED)
918*1302Sbill 			error("\nThere are stopped jobs" + 1 - neednl);
919*1302Sbill }
920*1302Sbill 
921*1302Sbill struct process *
922*1302Sbill pfind(cp)
923*1302Sbill 	char *cp;
924*1302Sbill {
925*1302Sbill 	register struct process *pp, *np;
926*1302Sbill 
927*1302Sbill 	if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) {
928*1302Sbill 		if (pcurrent == PNULL)
929*1302Sbill 			bferr("No current job");
930*1302Sbill 		return (pcurrent);
931*1302Sbill 	}
932*1302Sbill 	if (eq(cp, "%-") || eq(cp, "%#")) {
933*1302Sbill 		if (pprevious == PNULL)
934*1302Sbill 			bferr("No previous job");
935*1302Sbill 		return (pprevious);
936*1302Sbill 	}
937*1302Sbill 	if (digit(cp[1])) {
938*1302Sbill 		int index = atoi(cp+1);
939*1302Sbill 		for (pp = proclist.p_next; pp; pp = pp->p_next)
940*1302Sbill 			if (pp->p_index == index && pp->p_pid == pp->p_jobid)
941*1302Sbill 				return (pp);
942*1302Sbill 		bferr("No such job");
943*1302Sbill 	}
944*1302Sbill 	np = PNULL;
945*1302Sbill 	for (pp = proclist.p_next; pp; pp = pp->p_next)
946*1302Sbill 		if (pp->p_pid == pp->p_jobid) {
947*1302Sbill 			if (cp[1] == '?') {
948*1302Sbill 				register char *dp;
949*1302Sbill 				for (dp = pp->p_command; *dp; dp++) {
950*1302Sbill 					if (*dp != cp[2])
951*1302Sbill 						continue;
952*1302Sbill 					if (prefix(cp+2, dp))
953*1302Sbill 						goto match;
954*1302Sbill 				}
955*1302Sbill 			} else if (prefix(cp+1, pp->p_command)) {
956*1302Sbill match:
957*1302Sbill 				if (np)
958*1302Sbill 					bferr("Ambiguous");
959*1302Sbill 				np = pp;
960*1302Sbill 			}
961*1302Sbill 		}
962*1302Sbill 	if (np)
963*1302Sbill 		return (np);
964*1302Sbill 	if (cp[1] == '?')
965*1302Sbill 		bferr("No job matches pattern");
966*1302Sbill 	else
967*1302Sbill 		bferr("No such job");
968*1302Sbill }
969*1302Sbill 
970*1302Sbill /*
971*1302Sbill  * pgetcurr - find a job that is not pp and ``most recent''
972*1302Sbill  */
973*1302Sbill struct process *
974*1302Sbill pgetcurr(pp)
975*1302Sbill 	register struct process *pp;
976*1302Sbill {
977*1302Sbill 	register struct process *np;
978*1302Sbill 
979*1302Sbill 	for (np = proclist.p_next; np; np = np->p_next)
980*1302Sbill 		if (np != pcurrent && np != pp && np->p_pid &&
981*1302Sbill 		    np->p_pid == np->p_jobid) {
982*1302Sbill 			return (np);
983*1302Sbill 		}
984*1302Sbill 	return (PNULL);
985*1302Sbill }
986*1302Sbill 
987*1302Sbill /*
988*1302Sbill  * donotify - flag the job so as to report termination asynchronously
989*1302Sbill  */
990*1302Sbill donotify(v)
991*1302Sbill 	char **v;
992*1302Sbill {
993*1302Sbill 	register struct process *pp;
994*1302Sbill 
995*1302Sbill 	pp = pfind(*++v);
996*1302Sbill 	pp->p_flags |= PNOTIFY;
997*1302Sbill }
998*1302Sbill 
999*1302Sbill /*
1000*1302Sbill  * Do the fork and whatever should be done in the child side that
1001*1302Sbill  * should not be done if we are not forking at all (like for simple builtin's)
1002*1302Sbill  * Also do everything that needs any signals fiddled with in the parent side
1003*1302Sbill  *
1004*1302Sbill  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1005*1302Sbill  *	-1:	leave tty alone; inherit pgrp from parent
1006*1302Sbill  *	 0:	already have tty; manipulate process pgrps only
1007*1302Sbill  *	 1:	want to claim tty; manipulate process and tty pgrps
1008*1302Sbill  * It is usually just the value of tpgrp.
1009*1302Sbill  */
1010*1302Sbill pfork(t, wanttty)
1011*1302Sbill 	struct command *t;	/* command we are forking for */
1012*1302Sbill 	int wanttty;
1013*1302Sbill {
1014*1302Sbill 	register int pid;
1015*1302Sbill 	bool ignint = 0;
1016*1302Sbill 	int pgrp;
1017*1302Sbill 
1018*1302Sbill 	/*
1019*1302Sbill 	 * A child will be uninterruptible only under very special
1020*1302Sbill 	 * conditions. Remember that the semantics of '&' is
1021*1302Sbill 	 * implemented by disconnecting the process from the tty so
1022*1302Sbill 	 * signals do not need to ignored just for '&'.
1023*1302Sbill 	 * Thus signals are set to default action for children unless:
1024*1302Sbill 	 *	we have had an "onintr -" (then specifically ignored)
1025*1302Sbill 	 *	we are not playing with signals (inherit action)
1026*1302Sbill 	 */
1027*1302Sbill 	if (setintr)
1028*1302Sbill 		ignint = (tpgrp == -1 && (t->t_dflg&FINT))
1029*1302Sbill 		    || (gointr && eq(gointr, "-"));
1030*1302Sbill 	/*
1031*1302Sbill 	 * Hold SIGCHLD until we have the process installed in our table.
1032*1302Sbill 	 */
1033*1302Sbill 	sighold(SIGCHLD);
1034*1302Sbill 	while ((pid = fork()) < 0)
1035*1302Sbill 		if (setintr == 0)
1036*1302Sbill 			sleep(FORKSLEEP);
1037*1302Sbill 		else {
1038*1302Sbill 			sigrelse(SIGINT);
1039*1302Sbill 			sigrelse(SIGCHLD);
1040*1302Sbill 			error("No more processes");
1041*1302Sbill 		}
1042*1302Sbill 	if (pid == 0) {
1043*1302Sbill 		settimes();
1044*1302Sbill 		pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1045*1302Sbill 		pflushall();
1046*1302Sbill 		pcurrjob = PNULL;
1047*1302Sbill 		timesdone = 0;
1048*1302Sbill 		child++;
1049*1302Sbill 		if (setintr) {
1050*1302Sbill 			setintr = 0;		/* until I think otherwise */
1051*1302Sbill 			sigrelse(SIGCHLD);
1052*1302Sbill 			/*
1053*1302Sbill 			 * Children just get blown away on SIGINT, SIGQUIT
1054*1302Sbill 			 * unless "onintr -" seen.
1055*1302Sbill 			 */
1056*1302Sbill 			signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1057*1302Sbill 			signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1058*1302Sbill 			if (wanttty >= 0) {
1059*1302Sbill 				/* make stoppable */
1060*1302Sbill 				signal(SIGTSTP, SIG_DFL);
1061*1302Sbill 				signal(SIGTTIN, SIG_DFL);
1062*1302Sbill 				signal(SIGTTOU, SIG_DFL);
1063*1302Sbill 			}
1064*1302Sbill 			signal(SIGTERM, parterm);
1065*1302Sbill 		} else if (tpgrp == -1 && (t->t_dflg&FINT)) {
1066*1302Sbill 			signal(SIGINT, SIG_IGN);
1067*1302Sbill 			signal(SIGQUIT, SIG_IGN);
1068*1302Sbill 		}
1069*1302Sbill 		if (wanttty > 0)
1070*1302Sbill 			ioctl(FSHTTY, TIOCSPGRP, &pgrp);
1071*1302Sbill 		if (wanttty >= 0 && tpgrp >= 0)
1072*1302Sbill 			setpgrp(0, pgrp);
1073*1302Sbill 		if (tpgrp > 0)
1074*1302Sbill 			tpgrp = 0;		/* gave tty away */
1075*1302Sbill 		/*
1076*1302Sbill 		 * Nohup and nice apply only to TCOM's but it would be
1077*1302Sbill 		 * nice (?!?) if you could say "nohup (foo;bar)"
1078*1302Sbill 		 * Then the parser would have to know about nice/nohup/time
1079*1302Sbill 		 */
1080*1302Sbill 		if (t->t_dflg & FNOHUP)
1081*1302Sbill 			signal(SIGHUP, SIG_IGN);
1082*1302Sbill 		if (t->t_dflg & FNICE) {
1083*1302Sbill /* sigh...
1084*1302Sbill 			nice(20);
1085*1302Sbill 			nice(-10);
1086*1302Sbill */
1087*1302Sbill 			nice(t->t_nice);
1088*1302Sbill 		}
1089*1302Sbill 
1090*1302Sbill 	} else {
1091*1302Sbill 		palloc(pid, t);
1092*1302Sbill 		sigrelse(SIGCHLD);
1093*1302Sbill 	}
1094*1302Sbill 
1095*1302Sbill 	return (pid);
1096*1302Sbill }
1097*1302Sbill 
1098*1302Sbill okpcntl()
1099*1302Sbill {
1100*1302Sbill 
1101*1302Sbill 	if (tpgrp == -1)
1102*1302Sbill 		error("No job control in this shell");
1103*1302Sbill 	if (tpgrp == 0)
1104*1302Sbill 		error("No job control in subshells");
1105*1302Sbill }
1106