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