xref: /onnv-gate/usr/src/lib/libshell/common/sh/jobs.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  *  Job control for UNIX Shell
23*4887Schin  *
24*4887Schin  *   David Korn
25*4887Schin  *   AT&T Labs
26*4887Schin  *
27*4887Schin  *  Written October, 1982
28*4887Schin  *  Rewritten April, 1988
29*4887Schin  *  Revised January, 1992
30*4887Schin  */
31*4887Schin 
32*4887Schin #include	"defs.h"
33*4887Schin #include	<ctype.h>
34*4887Schin #include	<wait.h>
35*4887Schin #include	"io.h"
36*4887Schin #include	"jobs.h"
37*4887Schin #include	"history.h"
38*4887Schin 
39*4887Schin #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
40*4887Schin #   undef  WCONTINUED
41*4887Schin #   define WCONTINUED	0
42*4887Schin #   undef  WIFCONTINUED
43*4887Schin #   define WIFCONTINUED(wstat)	(0)
44*4887Schin #endif
45*4887Schin 
46*4887Schin #define	NJOB_SAVELIST	4
47*4887Schin 
48*4887Schin /*
49*4887Schin  * temporary hack to get W* macros to work
50*4887Schin  */
51*4887Schin #undef wait
52*4887Schin #define wait    ______wait
53*4887Schin /*
54*4887Schin  * This struct saves a link list of processes that have non-zero exit
55*4887Schin  * status, have had $! saved, but haven't been waited for
56*4887Schin  */
57*4887Schin struct jobsave
58*4887Schin {
59*4887Schin 	struct jobsave	*next;
60*4887Schin 	pid_t		pid;
61*4887Schin 	unsigned short	exitval;
62*4887Schin };
63*4887Schin 
64*4887Schin static struct jobsave *job_savelist;
65*4887Schin static int njob_savelist;
66*4887Schin 
67*4887Schin static void init_savelist(void)
68*4887Schin {
69*4887Schin 	register struct jobsave *jp;
70*4887Schin 	while(njob_savelist < NJOB_SAVELIST)
71*4887Schin 	{
72*4887Schin 		jp = newof(0,struct jobsave,1,0);
73*4887Schin 		jp->next = job_savelist;
74*4887Schin 		job_savelist = jp;
75*4887Schin 		njob_savelist++;
76*4887Schin 	}
77*4887Schin }
78*4887Schin 
79*4887Schin /*
80*4887Schin  * return next on link list of jobsave free list
81*4887Schin  */
82*4887Schin static struct jobsave *jobsave_create(pid_t pid)
83*4887Schin {
84*4887Schin 	register struct jobsave *jp = job_savelist;
85*4887Schin 	if(jp)
86*4887Schin 	{
87*4887Schin 		njob_savelist--;
88*4887Schin 		job_savelist = jp->next;
89*4887Schin 	}
90*4887Schin 	else
91*4887Schin 		jp = newof(0,struct jobsave,1,0);
92*4887Schin 	if(jp)
93*4887Schin 		jp->pid = pid;
94*4887Schin 	return(jp);
95*4887Schin }
96*4887Schin 
97*4887Schin struct back_save
98*4887Schin {
99*4887Schin 	int		count;
100*4887Schin 	struct jobsave	*list;
101*4887Schin };
102*4887Schin 
103*4887Schin #define BYTE(n)		(((n)+CHAR_BIT-1)/CHAR_BIT)
104*4887Schin #define MAXMSG	25
105*4887Schin #define SH_STOPSIG	(SH_EXITSIG<<1)
106*4887Schin 
107*4887Schin #ifdef VSUSP
108*4887Schin #   ifndef CNSUSP
109*4887Schin #	ifdef _POSIX_VDISABLE
110*4887Schin #	   define CNSUSP	_POSIX_VDISABLE
111*4887Schin #	else
112*4887Schin #	   define CNSUSP	0
113*4887Schin #	endif /* _POSIX_VDISABLE */
114*4887Schin #   endif /* CNSUSP */
115*4887Schin #   ifndef CSWTCH
116*4887Schin #	ifdef CSUSP
117*4887Schin #	    define CSWTCH	CSUSP
118*4887Schin #	else
119*4887Schin #	    define CSWTCH	('z'&037)
120*4887Schin #	endif /* CSUSP */
121*4887Schin #   endif /* CSWTCH */
122*4887Schin #endif /* VSUSP */
123*4887Schin 
124*4887Schin /* Process states */
125*4887Schin #define P_EXITSAVE	01
126*4887Schin #define P_STOPPED	02
127*4887Schin #define P_NOTIFY	04
128*4887Schin #define P_SIGNALLED	010
129*4887Schin #define P_STTY		020
130*4887Schin #define P_DONE		040
131*4887Schin #define P_COREDUMP	0100
132*4887Schin #define P_DISOWN	0200
133*4887Schin #define P_FG		0400
134*4887Schin 
135*4887Schin static int		job_chksave(pid_t);
136*4887Schin static struct process	*job_bypid(pid_t);
137*4887Schin static struct process	*job_byjid(int);
138*4887Schin static char		*job_sigmsg(int);
139*4887Schin static int		job_alloc(void);
140*4887Schin static void		job_free(int);
141*4887Schin static struct process	*job_unpost(struct process*,int);
142*4887Schin static void		job_unlink(struct process*);
143*4887Schin static void		job_prmsg(struct process*);
144*4887Schin static struct process	*freelist;
145*4887Schin static char		beenhere;
146*4887Schin static char		possible;
147*4887Schin static struct process	dummy;
148*4887Schin static char		by_number;
149*4887Schin static Sfio_t		*outfile;
150*4887Schin static pid_t		lastpid;
151*4887Schin static struct back_save	bck;
152*4887Schin 
153*4887Schin 
154*4887Schin #ifdef JOBS
155*4887Schin     static void			job_set(struct process*);
156*4887Schin     static void			job_reset(struct process*);
157*4887Schin     static void			job_waitsafe(int);
158*4887Schin     static struct process	*job_byname(char*);
159*4887Schin     static struct process	*job_bystring(char*);
160*4887Schin     static struct termios	my_stty;  /* terminal state for shell */
161*4887Schin     static char			*job_string;
162*4887Schin #else
163*4887Schin     extern const char		e_coredump[];
164*4887Schin #endif /* JOBS */
165*4887Schin 
166*4887Schin #ifdef SIGTSTP
167*4887Schin     static void		job_unstop(struct process*);
168*4887Schin     static void		job_fgrp(struct process*, int);
169*4887Schin #   ifndef _lib_tcgetpgrp
170*4887Schin #	ifdef TIOCGPGRP
171*4887Schin 	   static int _i_;
172*4887Schin #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
173*4887Schin #	endif /* TIOCGPGRP */
174*4887Schin 	int tcsetpgrp(int fd,pid_t pgrp)
175*4887Schin 	{
176*4887Schin 		int pgid = pgrp;
177*4887Schin #		ifdef TIOCGPGRP
178*4887Schin 			return(ioctl(fd, TIOCSPGRP, &pgid));
179*4887Schin #		else
180*4887Schin 			return(-1);
181*4887Schin #		endif /* TIOCGPGRP */
182*4887Schin 	}
183*4887Schin #   endif /* _lib_tcgetpgrp */
184*4887Schin #else
185*4887Schin #   define job_unstop(pw)
186*4887Schin #   undef CNSUSP
187*4887Schin #endif /* SIGTSTP */
188*4887Schin 
189*4887Schin #ifndef OTTYDISC
190*4887Schin #   undef NTTYDISC
191*4887Schin #endif /* OTTYDISC */
192*4887Schin 
193*4887Schin #ifdef JOBS
194*4887Schin 
195*4887Schin typedef int (*Waitevent_f)(int,long,int);
196*4887Schin 
197*4887Schin /*
198*4887Schin  * Reap one job
199*4887Schin  * When called with sig==0, it does a blocking wait
200*4887Schin  */
201*4887Schin int job_reap(register int sig)
202*4887Schin {
203*4887Schin 	register pid_t pid;
204*4887Schin 	register struct process *pw;
205*4887Schin 	struct process *px;
206*4887Schin 	register int flags;
207*4887Schin 	struct process dummy;
208*4887Schin 	struct jobsave *jp;
209*4887Schin 	int nochild=0, oerrno, wstat;
210*4887Schin 	Waitevent_f waitevent = sh.waitevent;
211*4887Schin 	static int wcontinued = WCONTINUED;
212*4887Schin #ifdef DEBUG
213*4887Schin 	if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0)
214*4887Schin 		write(2,"waitsafe\n",9);
215*4887Schin 	sfsync(sfstderr);
216*4887Schin #endif /* DEBUG */
217*4887Schin 	job.savesig = 0;
218*4887Schin 	if(sig)
219*4887Schin 		flags = WNOHANG|WUNTRACED|wcontinued;
220*4887Schin 	else
221*4887Schin 		flags = WUNTRACED|wcontinued;
222*4887Schin 	sh.waitevent = 0;
223*4887Schin 	oerrno = errno;
224*4887Schin 	while(1)
225*4887Schin 	{
226*4887Schin 		if(!(flags&WNOHANG) && !sh.intrap && waitevent && job.pwlist)
227*4887Schin 		{
228*4887Schin 			if((*waitevent)(-1,-1L,0))
229*4887Schin 				flags |= WNOHANG;
230*4887Schin 		}
231*4887Schin 		pid = waitpid((pid_t)-1,&wstat,flags);
232*4887Schin 
233*4887Schin 		/*
234*4887Schin 		 * some systems (linux 2.6) may return EINVAL
235*4887Schin 		 * when there are no continued children
236*4887Schin 		 */
237*4887Schin 
238*4887Schin 		if (pid<0 && errno==EINVAL && (flags&WCONTINUED))
239*4887Schin 			pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED);
240*4887Schin 		sh_sigcheck();
241*4887Schin 		if(sig && pid<0 && errno==EINTR)
242*4887Schin 			continue;
243*4887Schin 		if(pid<=0)
244*4887Schin 			break;
245*4887Schin 		flags |= WNOHANG;
246*4887Schin 		job.waitsafe++;
247*4887Schin 		jp = 0;
248*4887Schin 		if(!(pw=job_bypid(pid)))
249*4887Schin 		{
250*4887Schin #ifdef DEBUG
251*4887Schin 			sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d unknown job pid=%d pw=%x\n",__LINE__,getpid(),job.in_critical,pid,pw);
252*4887Schin #endif /* DEBUG */
253*4887Schin 			pw = &dummy;
254*4887Schin 			pw->p_exit = 0;
255*4887Schin 			pw->p_pgrp = 0;
256*4887Schin 			if(job.toclear)
257*4887Schin 				job_clear();
258*4887Schin 			if(bck.count++ > sh.lim.child_max)
259*4887Schin 				job_chksave(0);
260*4887Schin 			if(jp = jobsave_create(pid))
261*4887Schin 			{
262*4887Schin 				jp->next = bck.list;
263*4887Schin 				bck.list = jp;
264*4887Schin 				jp->exitval = 0;
265*4887Schin 			}
266*4887Schin 			pw->p_flag = 0;
267*4887Schin 			lastpid = pw->p_pid = pid;
268*4887Schin 			px = 0;
269*4887Schin 			if(jp && WIFSTOPPED(wstat))
270*4887Schin 			{
271*4887Schin 				jp->exitval = SH_STOPSIG;
272*4887Schin 				continue;
273*4887Schin 			}
274*4887Schin 		}
275*4887Schin #ifdef SIGTSTP
276*4887Schin 		else
277*4887Schin 			px=job_byjid(pw->p_job);
278*4887Schin 		if(WIFSTOPPED(wstat))
279*4887Schin 		{
280*4887Schin 			if(px)
281*4887Schin 			{
282*4887Schin 				/* move to top of job list */
283*4887Schin 				job_unlink(px);
284*4887Schin 				px->p_nxtjob = job.pwlist;
285*4887Schin 				job.pwlist = px;
286*4887Schin 			}
287*4887Schin 			pw->p_exit = WSTOPSIG(wstat);
288*4887Schin 			pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
289*4887Schin 			if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
290*4887Schin 				sh_fault(pw->p_exit);
291*4887Schin 			continue;
292*4887Schin 		}
293*4887Schin 		else if (WIFCONTINUED(wstat) && wcontinued)
294*4887Schin 		{
295*4887Schin 			pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED);
296*4887Schin 			pw->p_exit = 0;
297*4887Schin 		}
298*4887Schin 		else
299*4887Schin #endif /* SIGTSTP */
300*4887Schin 		{
301*4887Schin 			/* check for coprocess completion */
302*4887Schin 			if(pid==sh.cpid)
303*4887Schin 			{
304*4887Schin 				sh_close(sh.coutpipe);
305*4887Schin 				sh_close(sh.cpipe[1]);
306*4887Schin 				sh.cpipe[1] = -1;
307*4887Schin 				sh.coutpipe = -1;
308*4887Schin 			}
309*4887Schin 			if (WIFSIGNALED(wstat))
310*4887Schin 			{
311*4887Schin 				pw->p_flag &= ~P_STOPPED;
312*4887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
313*4887Schin 				if (WTERMCORE(wstat))
314*4887Schin 					pw->p_flag |= P_COREDUMP;
315*4887Schin 				pw->p_exit = WTERMSIG(wstat);
316*4887Schin 				/* if process in current jobs terminates from
317*4887Schin 				 * an interrupt, propogate to parent shell
318*4887Schin 				 */
319*4887Schin 				if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
320*4887Schin 				{
321*4887Schin 					pw->p_flag &= ~P_NOTIFY;
322*4887Schin 					sh_offstate(SH_STOPOK);
323*4887Schin 					sh_fault(SIGINT);
324*4887Schin 					sh_onstate(SH_STOPOK);
325*4887Schin 				}
326*4887Schin 			}
327*4887Schin 			else
328*4887Schin 			{
329*4887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY);
330*4887Schin 				if(WEXITSTATUS(wstat) > pw->p_exit)
331*4887Schin 					pw->p_exit = WEXITSTATUS(wstat);
332*4887Schin 			}
333*4887Schin 			if(pw->p_pgrp==0)
334*4887Schin 				pw->p_flag &= ~P_NOTIFY;
335*4887Schin 		}
336*4887Schin 		if(jp && pw== &dummy)
337*4887Schin 		{
338*4887Schin 			jp->exitval = pw->p_exit;
339*4887Schin 			if(pw->p_flag&P_SIGNALLED)
340*4887Schin 				jp->exitval |= SH_EXITSIG;
341*4887Schin 		}
342*4887Schin #ifdef DEBUG
343*4887Schin 		sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d job %d with pid %d flags=%o complete with status=%x exit=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job,pid,pw->p_flag,wstat,pw->p_exit);
344*4887Schin 		sfsync(sfstderr);
345*4887Schin #endif /* DEBUG*/
346*4887Schin 		/* only top-level process in job should have notify set */
347*4887Schin 		if(px && pw != px)
348*4887Schin 			pw->p_flag &= ~P_NOTIFY;
349*4887Schin 	}
350*4887Schin 	if(errno==ECHILD)
351*4887Schin 	{
352*4887Schin 		errno = oerrno;
353*4887Schin 		nochild = 1;
354*4887Schin 	}
355*4887Schin 	sh.waitevent = waitevent;
356*4887Schin 	if(!sh.intrap && sh.st.trapcom[SIGCHLD])
357*4887Schin 	{
358*4887Schin 		sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
359*4887Schin 		sh.trapnote |= SH_SIGTRAP;
360*4887Schin 	}
361*4887Schin 	if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
362*4887Schin 	{
363*4887Schin 		outfile = sfstderr;
364*4887Schin 		job_list(pw,JOB_NFLAG|JOB_NLFLAG);
365*4887Schin 		job_unpost(pw,1);
366*4887Schin 		sfsync(sfstderr);
367*4887Schin 	}
368*4887Schin 	if(sig)
369*4887Schin 		signal(sig, job_waitsafe);
370*4887Schin 	return(nochild);
371*4887Schin }
372*4887Schin 
373*4887Schin /*
374*4887Schin  * This is the SIGCLD interrupt routine
375*4887Schin  */
376*4887Schin static void job_waitsafe(int sig)
377*4887Schin {
378*4887Schin 	if(job.in_critical)
379*4887Schin 	{
380*4887Schin 		job.savesig = sig;
381*4887Schin 		job.waitsafe++;
382*4887Schin 	}
383*4887Schin 	else
384*4887Schin 		job_reap(sig);
385*4887Schin }
386*4887Schin 
387*4887Schin /*
388*4887Schin  * initialize job control if possible
389*4887Schin  * if lflag is set the switching driver message will not print
390*4887Schin  */
391*4887Schin void job_init(int lflag)
392*4887Schin {
393*4887Schin 	register int i,ntry=0;
394*4887Schin 	job.fd = JOBTTY;
395*4887Schin 	signal(SIGCHLD,job_waitsafe);
396*4887Schin #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
397*4887Schin 	signal(SIGCLD,job_waitsafe);
398*4887Schin #   endif
399*4887Schin 	if(njob_savelist < NJOB_SAVELIST)
400*4887Schin 		init_savelist();
401*4887Schin 	if(!sh_isoption(SH_INTERACTIVE))
402*4887Schin 		return;
403*4887Schin 	/* use new line discipline when available */
404*4887Schin #ifdef NTTYDISC
405*4887Schin #   ifdef FIOLOOKLD
406*4887Schin 	if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
407*4887Schin #   else
408*4887Schin 	if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
409*4887Schin #   endif /* FIOLOOKLD */
410*4887Schin 		return;
411*4887Schin 	if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
412*4887Schin 	{
413*4887Schin 		/* no job control when running with MPX */
414*4887Schin #   if SHOPT_VSH
415*4887Schin 		sh_onoption(SH_VIRAW);
416*4887Schin #   endif /* SHOPT_VSH */
417*4887Schin 		return;
418*4887Schin 	}
419*4887Schin 	if(job.linedisc==NTTYDISC)
420*4887Schin 		job.linedisc = -1;
421*4887Schin #endif /* NTTYDISC */
422*4887Schin 
423*4887Schin 	job.mypgid = getpgrp();
424*4887Schin 	/* some systems have job control, but not initialized */
425*4887Schin 	if(job.mypgid<=0)
426*4887Schin         {
427*4887Schin 		/* Get a controlling terminal and set process group */
428*4887Schin 		/* This should have already been done by rlogin */
429*4887Schin                 register int fd;
430*4887Schin                 register char *ttynam;
431*4887Schin #ifndef SIGTSTP
432*4887Schin                 setpgid(0,sh.pid);
433*4887Schin #endif /*SIGTSTP */
434*4887Schin                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
435*4887Schin                         return;
436*4887Schin                 close(JOBTTY);
437*4887Schin                 if((fd = open(ttynam,O_RDWR)) <0)
438*4887Schin                         return;
439*4887Schin                 if(fd!=JOBTTY)
440*4887Schin                         sh_iorenumber(fd,JOBTTY);
441*4887Schin                 job.mypgid = sh.pid;
442*4887Schin #ifdef SIGTSTP
443*4887Schin                 tcsetpgrp(JOBTTY,sh.pid);
444*4887Schin                 setpgid(0,sh.pid);
445*4887Schin #endif /* SIGTSTP */
446*4887Schin         }
447*4887Schin #ifdef SIGTSTP
448*4887Schin 	if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
449*4887Schin 	{
450*4887Schin 		/* wait until we are in the foreground */
451*4887Schin 		while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
452*4887Schin 		{
453*4887Schin 			if(job.mytgid == -1)
454*4887Schin 				return;
455*4887Schin 			/* Stop this shell until continued */
456*4887Schin 			signal(SIGTTIN,SIG_DFL);
457*4887Schin 			kill(sh.pid,SIGTTIN);
458*4887Schin 			/* resumes here after continue tries again */
459*4887Schin 			if(ntry++ > IOMAXTRY)
460*4887Schin 			{
461*4887Schin 				errormsg(SH_DICT,0,e_no_start);
462*4887Schin 				return;
463*4887Schin 			}
464*4887Schin 		}
465*4887Schin 	}
466*4887Schin #endif /* SIGTTIN */
467*4887Schin 
468*4887Schin #ifdef NTTYDISC
469*4887Schin 	/* set the line discipline */
470*4887Schin 	if(job.linedisc>=0)
471*4887Schin 	{
472*4887Schin 		int linedisc = NTTYDISC;
473*4887Schin #   ifdef FIOPUSHLD
474*4887Schin 		tty_get(JOBTTY,&my_stty);
475*4887Schin 		if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
476*4887Schin 			return;
477*4887Schin 		if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
478*4887Schin 		{
479*4887Schin 			ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
480*4887Schin 			return;
481*4887Schin 		}
482*4887Schin 		tty_set(JOBTTY,TCSANOW,&my_stty);
483*4887Schin #   else
484*4887Schin 		if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
485*4887Schin 			return;
486*4887Schin #   endif /* FIOPUSHLD */
487*4887Schin 		if(lflag==0)
488*4887Schin 			errormsg(SH_DICT,0,e_newtty);
489*4887Schin 		else
490*4887Schin 			job.linedisc = -1;
491*4887Schin 	}
492*4887Schin #endif /* NTTYDISC */
493*4887Schin 	if(!possible)
494*4887Schin 		return;
495*4887Schin 
496*4887Schin #ifdef SIGTSTP
497*4887Schin 	/* make sure that we are a process group leader */
498*4887Schin 	setpgid(0,sh.pid);
499*4887Schin #   if defined(SA_NOCLDWAIT) && defined(_lib_sigflag)
500*4887Schin 	sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
501*4887Schin #   endif /* SA_NOCLDWAIT */
502*4887Schin 	signal(SIGTTIN,SIG_IGN);
503*4887Schin 	signal(SIGTTOU,SIG_IGN);
504*4887Schin 	/* The shell now handles ^Z */
505*4887Schin 	signal(SIGTSTP,sh_fault);
506*4887Schin 	tcsetpgrp(JOBTTY,sh.pid);
507*4887Schin #   ifdef CNSUSP
508*4887Schin 	/* set the switch character */
509*4887Schin 	tty_get(JOBTTY,&my_stty);
510*4887Schin 	job.suspend = (unsigned)my_stty.c_cc[VSUSP];
511*4887Schin 	if(job.suspend == (unsigned char)CNSUSP)
512*4887Schin 	{
513*4887Schin 		my_stty.c_cc[VSUSP] = CSWTCH;
514*4887Schin 		tty_set(JOBTTY,TCSAFLUSH,&my_stty);
515*4887Schin 	}
516*4887Schin #   endif /* CNSUSP */
517*4887Schin 	sh_onoption(SH_MONITOR);
518*4887Schin 	job.jobcontrol++;
519*4887Schin 	job.mypid = sh.pid;
520*4887Schin #endif /* SIGTSTP */
521*4887Schin 	return;
522*4887Schin }
523*4887Schin 
524*4887Schin 
525*4887Schin /*
526*4887Schin  * see if there are any stopped jobs
527*4887Schin  * restore tty driver and pgrp
528*4887Schin  */
529*4887Schin int job_close(void)
530*4887Schin {
531*4887Schin 	register struct process *pw;
532*4887Schin 	register int count = 0, running = 0;
533*4887Schin 	if(possible && !job.jobcontrol)
534*4887Schin 		return(0);
535*4887Schin 	else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
536*4887Schin 		return(0);
537*4887Schin 	else if(getpid() != job.mypid)
538*4887Schin 		return(0);
539*4887Schin 	job_lock();
540*4887Schin 	if(!tty_check(0))
541*4887Schin 		beenhere++;
542*4887Schin 	for(pw=job.pwlist;pw;pw=pw->p_nxtjob)
543*4887Schin 	{
544*4887Schin 		if(!(pw->p_flag&P_STOPPED))
545*4887Schin 		{
546*4887Schin 			if(!(pw->p_flag&P_DONE))
547*4887Schin 				running++;
548*4887Schin 			continue;
549*4887Schin 		}
550*4887Schin 		if(beenhere)
551*4887Schin 			killpg(pw->p_pgrp,SIGTERM);
552*4887Schin 		count++;
553*4887Schin 	}
554*4887Schin 	if(beenhere++ == 0 && job.pwlist)
555*4887Schin 	{
556*4887Schin 		if(count)
557*4887Schin 		{
558*4887Schin 			errormsg(SH_DICT,0,e_terminate);
559*4887Schin 			return(-1);
560*4887Schin 		}
561*4887Schin 		else if(running && sh.login_sh)
562*4887Schin 		{
563*4887Schin 			errormsg(SH_DICT,0,e_jobsrunning);
564*4887Schin 			return(-1);
565*4887Schin 		}
566*4887Schin 	}
567*4887Schin 	job_unlock();
568*4887Schin #   ifdef SIGTSTP
569*4887Schin 	if(possible && setpgid(0,job.mypgid)>=0)
570*4887Schin 		tcsetpgrp(job.fd,job.mypgid);
571*4887Schin #   endif /* SIGTSTP */
572*4887Schin #   ifdef NTTYDISC
573*4887Schin 	if(job.linedisc>=0)
574*4887Schin 	{
575*4887Schin 		/* restore old line discipline */
576*4887Schin #	ifdef FIOPUSHLD
577*4887Schin 		tty_get(job.fd,&my_stty);
578*4887Schin 		if (ioctl(job.fd, FIOPOPLD, 0) < 0)
579*4887Schin 			return(0);
580*4887Schin 		if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
581*4887Schin 		{
582*4887Schin 			job.linedisc = NTTYDISC;
583*4887Schin 			ioctl(job.fd, FIOPUSHLD, &job.linedisc);
584*4887Schin 			return(0);
585*4887Schin 		}
586*4887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
587*4887Schin #	else
588*4887Schin 		if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
589*4887Schin 			return(0);
590*4887Schin #	endif /* FIOPUSHLD */
591*4887Schin 		errormsg(SH_DICT,0,e_oldtty);
592*4887Schin 	}
593*4887Schin #   endif /* NTTYDISC */
594*4887Schin #   ifdef CNSUSP
595*4887Schin 	if(possible && job.suspend==CNSUSP)
596*4887Schin 	{
597*4887Schin 		tty_get(job.fd,&my_stty);
598*4887Schin 		my_stty.c_cc[VSUSP] = CNSUSP;
599*4887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
600*4887Schin 	}
601*4887Schin #   endif /* CNSUSP */
602*4887Schin 	job.jobcontrol = 0;
603*4887Schin 	return(0);
604*4887Schin }
605*4887Schin 
606*4887Schin static void job_set(register struct process *pw)
607*4887Schin {
608*4887Schin 	/* save current terminal state */
609*4887Schin 	tty_get(job.fd,&my_stty);
610*4887Schin 	if(pw->p_flag&P_STTY)
611*4887Schin 	{
612*4887Schin 		/* restore terminal state for job */
613*4887Schin 		tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
614*4887Schin 	}
615*4887Schin #ifdef SIGTSTP
616*4887Schin 	if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid)
617*4887Schin 		tcsetpgrp(job.fd,pw->p_fgrp);
618*4887Schin 	/* if job is stopped, resume it in the background */
619*4887Schin 	job_unstop(pw);
620*4887Schin #endif	/* SIGTSTP */
621*4887Schin }
622*4887Schin 
623*4887Schin static void job_reset(register struct process *pw)
624*4887Schin {
625*4887Schin 	/* save the terminal state for current job */
626*4887Schin #ifdef SIGTSTP
627*4887Schin 	job_fgrp(pw,tcgetpgrp(job.fd));
628*4887Schin 	if(tcsetpgrp(job.fd,sh.pid) !=0)
629*4887Schin 		return;
630*4887Schin #endif	/* SIGTSTP */
631*4887Schin 	/* force the following tty_get() to do a tcgetattr() unless fg */
632*4887Schin 	if(!(pw->p_flag&P_FG))
633*4887Schin 		tty_set(-1, 0, NIL(struct termios*));
634*4887Schin 	if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
635*4887Schin 	{
636*4887Schin 		if(tty_get(job.fd,&pw->p_stty) == 0)
637*4887Schin 			pw->p_flag |= P_STTY;
638*4887Schin 		/* restore terminal state for job */
639*4887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
640*4887Schin 	}
641*4887Schin 	beenhere = 0;
642*4887Schin }
643*4887Schin #endif /* JOBS */
644*4887Schin 
645*4887Schin /*
646*4887Schin  * wait built-in command
647*4887Schin  */
648*4887Schin 
649*4887Schin void job_bwait(char **jobs)
650*4887Schin {
651*4887Schin 	register char *jp;
652*4887Schin 	register struct process *pw;
653*4887Schin 	register pid_t pid;
654*4887Schin 	if(*jobs==0)
655*4887Schin 		job_wait((pid_t)-1);
656*4887Schin 	else while(jp = *jobs++)
657*4887Schin 	{
658*4887Schin #ifdef JOBS
659*4887Schin 		if(*jp == '%')
660*4887Schin 		{
661*4887Schin 			job_lock();
662*4887Schin 			pw = job_bystring(jp);
663*4887Schin 			job_unlock();
664*4887Schin 			if(pw)
665*4887Schin 				pid = pw->p_pid;
666*4887Schin 			else
667*4887Schin 				return;
668*4887Schin 		}
669*4887Schin 		else
670*4887Schin #endif /* JOBS */
671*4887Schin 			pid = (int)strtol(jp, (char**)0, 10);
672*4887Schin 		job_wait(-pid);
673*4887Schin 	}
674*4887Schin }
675*4887Schin 
676*4887Schin #ifdef JOBS
677*4887Schin /*
678*4887Schin  * execute function <fun> for each job
679*4887Schin  */
680*4887Schin 
681*4887Schin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[])
682*4887Schin {
683*4887Schin 	register struct process *pw;
684*4887Schin 	register int r = 0;
685*4887Schin 	register char *jobid, **jobs=joblist;
686*4887Schin 	register struct process *px;
687*4887Schin 	job_string = 0;
688*4887Schin 	outfile = file;
689*4887Schin 	by_number = 0;
690*4887Schin 	job_lock();
691*4887Schin 	pw = job.pwlist;
692*4887Schin 	if(jobs==0)
693*4887Schin 	{
694*4887Schin 		/* do all jobs */
695*4887Schin 		for(;pw;pw=px)
696*4887Schin 		{
697*4887Schin 			px = pw->p_nxtjob;
698*4887Schin 			if(pw->p_env != sh.jobenv)
699*4887Schin 				continue;
700*4887Schin 			if((*fun)(pw,arg))
701*4887Schin 				r = 2;
702*4887Schin 		}
703*4887Schin 	}
704*4887Schin 	else if(*jobs==0)	/* current job */
705*4887Schin 	{
706*4887Schin 		/* skip over non-stop jobs */
707*4887Schin 		while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0))
708*4887Schin 			pw = pw->p_nxtjob;
709*4887Schin 		if((*fun)(pw,arg))
710*4887Schin 			r = 2;
711*4887Schin 	}
712*4887Schin 	else while(jobid = *jobs++)
713*4887Schin 	{
714*4887Schin 		job_string = jobid;
715*4887Schin 		if(*jobid==0)
716*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
717*4887Schin 		if(*jobid == '%')
718*4887Schin 			pw = job_bystring(jobid);
719*4887Schin 		else
720*4887Schin 		{
721*4887Schin 			int pid = (int)strtol(jobid, (char**)0, 10);
722*4887Schin 			if(pid<0)
723*4887Schin 				jobid++;
724*4887Schin 			while(isdigit(*jobid))
725*4887Schin 				jobid++;
726*4887Schin 			if(*jobid)
727*4887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
728*4887Schin 			if(!(pw = job_bypid(pid)))
729*4887Schin 			{
730*4887Schin 				pw = &dummy;
731*4887Schin 				pw->p_pid = pid;
732*4887Schin 				pw->p_pgrp = pid;
733*4887Schin 			}
734*4887Schin 			by_number = 1;
735*4887Schin 		}
736*4887Schin 		if((*fun)(pw,arg))
737*4887Schin 			r = 2;
738*4887Schin 		by_number = 0;
739*4887Schin 	}
740*4887Schin 	job_unlock();
741*4887Schin 	return(r);
742*4887Schin }
743*4887Schin 
744*4887Schin /*
745*4887Schin  * send signal <sig> to background process group if not disowned
746*4887Schin  */
747*4887Schin int job_terminate(register struct process *pw,register int sig)
748*4887Schin {
749*4887Schin 	if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
750*4887Schin 		job_kill(pw,sig);
751*4887Schin 	return(0);
752*4887Schin }
753*4887Schin 
754*4887Schin /*
755*4887Schin  * list the given job
756*4887Schin  * flag JOB_LFLAG for long listing
757*4887Schin  * flag JOB_NFLAG for list only jobs marked for notification
758*4887Schin  * flag JOB_PFLAG for process id(s) only
759*4887Schin  */
760*4887Schin 
761*4887Schin int job_list(struct process *pw,register int flag)
762*4887Schin {
763*4887Schin 	register struct process *px = pw;
764*4887Schin 	register int  n;
765*4887Schin 	register const char *msg;
766*4887Schin 	register int msize;
767*4887Schin 	if(!pw || pw->p_job<=0)
768*4887Schin 		return(1);
769*4887Schin 	if(pw->p_env != sh.jobenv)
770*4887Schin 		return(0);
771*4887Schin 	if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
772*4887Schin 		return(0);
773*4887Schin 	if((flag&JOB_PFLAG))
774*4887Schin 	{
775*4887Schin 		sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid);
776*4887Schin 		return(0);
777*4887Schin 	}
778*4887Schin 	if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
779*4887Schin 		return(0);
780*4887Schin 	job_lock();
781*4887Schin 	n = px->p_job;
782*4887Schin 	if(px==job.pwlist)
783*4887Schin 		msize = '+';
784*4887Schin 	else if(px==job.pwlist->p_nxtjob)
785*4887Schin 		msize = '-';
786*4887Schin 	else
787*4887Schin 		msize = ' ';
788*4887Schin 	if(flag&JOB_NLFLAG)
789*4887Schin 		sfputc(outfile,'\n');
790*4887Schin 	sfprintf(outfile,"[%d] %c ",n, msize);
791*4887Schin 	do
792*4887Schin 	{
793*4887Schin 		n = 0;
794*4887Schin 		if(flag&JOB_LFLAG)
795*4887Schin 			sfprintf(outfile,"%d\t",px->p_pid);
796*4887Schin 		if(px->p_flag&P_SIGNALLED)
797*4887Schin 			msg = job_sigmsg((int)(px->p_exit));
798*4887Schin 		else if(px->p_flag&P_NOTIFY)
799*4887Schin 		{
800*4887Schin 			msg = sh_translate(e_done);
801*4887Schin 			n = px->p_exit;
802*4887Schin 		}
803*4887Schin 		else
804*4887Schin 			msg = sh_translate(e_running);
805*4887Schin 		px->p_flag &= ~P_NOTIFY;
806*4887Schin 		sfputr(outfile,msg,-1);
807*4887Schin 		msize = strlen(msg);
808*4887Schin 		if(n)
809*4887Schin 		{
810*4887Schin 			sfprintf(outfile,"(%d)",(int)n);
811*4887Schin 			msize += (3+(n>10)+(n>100));
812*4887Schin 		}
813*4887Schin 		if(px->p_flag&P_COREDUMP)
814*4887Schin 		{
815*4887Schin 			msg = sh_translate(e_coredump);
816*4887Schin 			sfputr(outfile, msg, -1);
817*4887Schin 			msize += strlen(msg);
818*4887Schin 		}
819*4887Schin 		sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
820*4887Schin 		if(flag&JOB_LFLAG)
821*4887Schin 			px = px->p_nxtproc;
822*4887Schin 		else
823*4887Schin 		{
824*4887Schin 			while(px=px->p_nxtproc)
825*4887Schin 				px->p_flag &= ~P_NOTIFY;
826*4887Schin 			px = 0;
827*4887Schin 		}
828*4887Schin 		if(!px)
829*4887Schin 			hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
830*4887Schin 		else
831*4887Schin 			sfputr(outfile, e_nlspace, -1);
832*4887Schin 	}
833*4887Schin 	while(px);
834*4887Schin 	job_unlock();
835*4887Schin 	return(0);
836*4887Schin }
837*4887Schin 
838*4887Schin /*
839*4887Schin  * get the process group given the job number
840*4887Schin  * This routine returns the process group number or -1
841*4887Schin  */
842*4887Schin static struct process *job_bystring(register char *ajob)
843*4887Schin {
844*4887Schin 	register struct process *pw=job.pwlist;
845*4887Schin 	register int c;
846*4887Schin 	if(*ajob++ != '%' || !pw)
847*4887Schin 		return(NIL(struct process*));
848*4887Schin 	c = *ajob;
849*4887Schin 	if(isdigit(c))
850*4887Schin 		pw = job_byjid((int)strtol(ajob, (char**)0, 10));
851*4887Schin 	else if(c=='+' || c=='%')
852*4887Schin 		;
853*4887Schin 	else if(c=='-')
854*4887Schin 	{
855*4887Schin 		if(pw)
856*4887Schin 			pw = job.pwlist->p_nxtjob;
857*4887Schin 	}
858*4887Schin 	else
859*4887Schin 		pw = job_byname(ajob);
860*4887Schin 	if(pw && pw->p_flag)
861*4887Schin 		return(pw);
862*4887Schin 	return(NIL(struct process*));
863*4887Schin }
864*4887Schin 
865*4887Schin /*
866*4887Schin  * Kill a job or process
867*4887Schin  */
868*4887Schin 
869*4887Schin int job_kill(register struct process *pw,register int sig)
870*4887Schin {
871*4887Schin 	register pid_t pid;
872*4887Schin 	register int r;
873*4887Schin 	const char *msg;
874*4887Schin #ifdef SIGTSTP
875*4887Schin 	int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
876*4887Schin #else
877*4887Schin #	define stopsig	1
878*4887Schin #endif	/* SIGTSTP */
879*4887Schin 	job_lock();
880*4887Schin 	errno = ECHILD;
881*4887Schin 	if(pw==0)
882*4887Schin 		goto error;
883*4887Schin 	pid = pw->p_pid;
884*4887Schin 	if(by_number)
885*4887Schin 	{
886*4887Schin 		if(pid==0 && job.jobcontrol)
887*4887Schin 			r = job_walk(outfile, job_kill,sig, (char**)0);
888*4887Schin #ifdef SIGTSTP
889*4887Schin 		if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
890*4887Schin 		{
891*4887Schin 			/* can't stop login shell */
892*4887Schin 			errno = EPERM;
893*4887Schin 			r = -1;
894*4887Schin 		}
895*4887Schin 		else
896*4887Schin 		{
897*4887Schin 			if(pid>=0)
898*4887Schin 			{
899*4887Schin 				if((r = kill(pid,sig))>=0 && !stopsig)
900*4887Schin 				{
901*4887Schin 					if(pw->p_flag&P_STOPPED)
902*4887Schin 						pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
903*4887Schin 					if(sig)
904*4887Schin 						kill(pid,SIGCONT);
905*4887Schin 				}
906*4887Schin 			}
907*4887Schin 			else
908*4887Schin 			{
909*4887Schin 				if((r = killpg(-pid,sig))>=0 && !stopsig)
910*4887Schin 				{
911*4887Schin 					job_unstop(job_bypid(pw->p_pid));
912*4887Schin 					if(sig)
913*4887Schin 						killpg(-pid,SIGCONT);
914*4887Schin 				}
915*4887Schin 			}
916*4887Schin 		}
917*4887Schin #else
918*4887Schin 		if(pid>=0)
919*4887Schin 			r = kill(pid,sig);
920*4887Schin 		else
921*4887Schin 			r = killpg(-pid,sig);
922*4887Schin #endif	/* SIGTSTP */
923*4887Schin 	}
924*4887Schin 	else
925*4887Schin 	{
926*4887Schin 		if(pid = pw->p_pgrp)
927*4887Schin 		{
928*4887Schin 			r = killpg(pid,sig);
929*4887Schin #ifdef SIGTSTP
930*4887Schin 			if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT))
931*4887Schin 				job_unstop(pw);
932*4887Schin #endif	/* SIGTSTP */
933*4887Schin 			if(r>=0)
934*4887Schin 				sh_delay(.05);
935*4887Schin 		}
936*4887Schin 		while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0)
937*4887Schin 		{
938*4887Schin #ifdef SIGTSTP
939*4887Schin 			if(sig==SIGHUP || sig==SIGTERM)
940*4887Schin 				kill(pw->p_pid,SIGCONT);
941*4887Schin #endif	/* SIGTSTP */
942*4887Schin 			pw = pw->p_nxtproc;
943*4887Schin 		}
944*4887Schin 	}
945*4887Schin 	if(r<0 && job_string)
946*4887Schin 	{
947*4887Schin 	error:
948*4887Schin 		if(pw && by_number)
949*4887Schin 			msg = sh_translate(e_no_proc);
950*4887Schin 		else
951*4887Schin 			msg = sh_translate(e_no_job);
952*4887Schin 		if(errno == EPERM)
953*4887Schin 			msg = sh_translate(e_access);
954*4887Schin 		sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg);
955*4887Schin 		r = 2;
956*4887Schin 	}
957*4887Schin 	sh_delay(.001);
958*4887Schin 	job_unlock();
959*4887Schin 	return(r);
960*4887Schin }
961*4887Schin 
962*4887Schin /*
963*4887Schin  * Get process structure from first letters of jobname
964*4887Schin  *
965*4887Schin  */
966*4887Schin 
967*4887Schin static struct process *job_byname(char *name)
968*4887Schin {
969*4887Schin 	register struct process *pw = job.pwlist;
970*4887Schin 	register struct process *pz = 0;
971*4887Schin 	register int *flag = 0;
972*4887Schin 	register char *cp = name;
973*4887Schin 	int offset;
974*4887Schin 	if(!sh.hist_ptr)
975*4887Schin 		return(NIL(struct process*));
976*4887Schin 	if(*cp=='?')
977*4887Schin 		cp++,flag= &offset;
978*4887Schin 	for(;pw;pw=pw->p_nxtjob)
979*4887Schin 	{
980*4887Schin 		if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
981*4887Schin 		{
982*4887Schin 			if(pz)
983*4887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1);
984*4887Schin 			pz = pw;
985*4887Schin 		}
986*4887Schin 	}
987*4887Schin 	return(pz);
988*4887Schin }
989*4887Schin 
990*4887Schin #else
991*4887Schin #   define job_set(x)
992*4887Schin #   define job_reset(x)
993*4887Schin #endif /* JOBS */
994*4887Schin 
995*4887Schin 
996*4887Schin 
997*4887Schin /*
998*4887Schin  * Initialize the process posting array
999*4887Schin  */
1000*4887Schin 
1001*4887Schin void	job_clear(void)
1002*4887Schin {
1003*4887Schin 	register struct process *pw, *px;
1004*4887Schin 	register struct process *pwnext;
1005*4887Schin 	register int j = BYTE(sh.lim.child_max);
1006*4887Schin 	register struct jobsave *jp,*jpnext;
1007*4887Schin 	job_lock();
1008*4887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
1009*4887Schin 	{
1010*4887Schin 		pwnext = pw->p_nxtjob;
1011*4887Schin 		while(px=pw)
1012*4887Schin 		{
1013*4887Schin 			pw = pw->p_nxtproc;
1014*4887Schin 			free((void*)px);
1015*4887Schin 		}
1016*4887Schin 	}
1017*4887Schin 	for(jp=bck.list; jp;jp=jpnext)
1018*4887Schin 	{
1019*4887Schin 		jpnext = jp->next;
1020*4887Schin 		free((void*)jp);
1021*4887Schin 	}
1022*4887Schin 	bck.list = 0;
1023*4887Schin 	if(njob_savelist < NJOB_SAVELIST)
1024*4887Schin 		init_savelist();
1025*4887Schin 	job.pwlist = NIL(struct process*);
1026*4887Schin 	job.numpost=0;
1027*4887Schin 	job.waitall = 0;
1028*4887Schin 	job.curpgid = 0;
1029*4887Schin 	job.toclear = 0;
1030*4887Schin 	if(!job.freejobs)
1031*4887Schin 		job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
1032*4887Schin 	while(j >=0)
1033*4887Schin 		job.freejobs[j--]  = 0;
1034*4887Schin 	job_unlock();
1035*4887Schin }
1036*4887Schin 
1037*4887Schin /*
1038*4887Schin  * put the process <pid> on the process list and return the job number
1039*4887Schin  * if non-zero, <join> is the process id of the job to join
1040*4887Schin  */
1041*4887Schin 
1042*4887Schin int job_post(pid_t pid, pid_t join)
1043*4887Schin {
1044*4887Schin 	register struct process *pw;
1045*4887Schin 	register History_t *hp = sh.hist_ptr;
1046*4887Schin 	sh.jobenv = sh.curenv;
1047*4887Schin 	if(njob_savelist < NJOB_SAVELIST)
1048*4887Schin 		init_savelist();
1049*4887Schin 	if(job.toclear)
1050*4887Schin 	{
1051*4887Schin 		job_clear();
1052*4887Schin 		return(0);
1053*4887Schin 	}
1054*4887Schin 	job_lock();
1055*4887Schin 	if(pw = job_bypid(pid))
1056*4887Schin 		job_unpost(pw,0);
1057*4887Schin 	if(join && (pw=job_bypid(join)))
1058*4887Schin 	{
1059*4887Schin 		/* if job to join is not first move it to front */
1060*4887Schin 		if((pw=job_byjid(pw->p_job)) != job.pwlist)
1061*4887Schin 		{
1062*4887Schin 			job_unlink(pw);
1063*4887Schin 			pw->p_nxtjob = job.pwlist;
1064*4887Schin 			job.pwlist = pw;
1065*4887Schin 		}
1066*4887Schin 	}
1067*4887Schin 	if(pw=freelist)
1068*4887Schin 		freelist = pw->p_nxtjob;
1069*4887Schin 	else
1070*4887Schin 		pw = new_of(struct process,0);
1071*4887Schin 	job.numpost++;
1072*4887Schin 	if(join && job.pwlist)
1073*4887Schin 	{
1074*4887Schin 		/* join existing current job */
1075*4887Schin 		pw->p_nxtjob = job.pwlist->p_nxtjob;
1076*4887Schin 		pw->p_nxtproc = job.pwlist;
1077*4887Schin 		pw->p_job = job.pwlist->p_job;
1078*4887Schin 	}
1079*4887Schin 	else
1080*4887Schin 	{
1081*4887Schin 		/* create a new job */
1082*4887Schin 		while((pw->p_job = job_alloc()) < 0)
1083*4887Schin 			job_wait((pid_t)1);
1084*4887Schin 		pw->p_nxtjob = job.pwlist;
1085*4887Schin 		pw->p_nxtproc = 0;
1086*4887Schin 	}
1087*4887Schin 	job.pwlist = pw;
1088*4887Schin 	pw->p_env = sh.curenv;
1089*4887Schin 	pw->p_pid = pid;
1090*4887Schin 	pw->p_flag = P_EXITSAVE;
1091*4887Schin 	pw->p_exit = sh.xargexit;
1092*4887Schin 	sh.xargexit = 0;
1093*4887Schin 	if(sh_isstate(SH_MONITOR))
1094*4887Schin 	{
1095*4887Schin 		if(killpg(job.curpgid,0)<0 && errno==ESRCH)
1096*4887Schin 			job.curpgid = pid;
1097*4887Schin 		pw->p_fgrp = job.curpgid;
1098*4887Schin 	}
1099*4887Schin 	else
1100*4887Schin 		pw->p_fgrp = 0;
1101*4887Schin 	pw->p_pgrp = pw->p_fgrp;
1102*4887Schin #ifdef DEBUG
1103*4887Schin 	sfprintf(sfstderr,"ksh: job line %4d: post pid=%d critical=%d job=%d pid=%d pgid=%d savesig=%d join=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job,
1104*4887Schin 		pw->p_pid,pw->p_pgrp,job.savesig,join);
1105*4887Schin 	sfsync(sfstderr);
1106*4887Schin #endif /* DEBUG */
1107*4887Schin #ifdef JOBS
1108*4887Schin 	if(hp && !sh_isstate(SH_PROFILE))
1109*4887Schin 		pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
1110*4887Schin 	else
1111*4887Schin 		pw->p_name = -1;
1112*4887Schin #endif /* JOBS */
1113*4887Schin 	if(pid==lastpid)
1114*4887Schin 	{
1115*4887Schin 		int val =  job_chksave(pid);
1116*4887Schin 		pw->p_exit = val>0?val:0;
1117*4887Schin 		if(pw->p_exit==SH_STOPSIG)
1118*4887Schin 		{
1119*4887Schin 			pw->p_flag |= (P_SIGNALLED|P_STOPPED);
1120*4887Schin 			pw->p_exit = 0;
1121*4887Schin 		}
1122*4887Schin 		else
1123*4887Schin 			pw->p_flag |= (P_DONE|P_NOTIFY);
1124*4887Schin 	}
1125*4887Schin 	lastpid = 0;
1126*4887Schin 	job_unlock();
1127*4887Schin 	return(pw->p_job);
1128*4887Schin }
1129*4887Schin 
1130*4887Schin /*
1131*4887Schin  * Returns a process structure give a process id
1132*4887Schin  */
1133*4887Schin 
1134*4887Schin static struct process *job_bypid(pid_t pid)
1135*4887Schin {
1136*4887Schin 	register struct process  *pw, *px;
1137*4887Schin 	for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
1138*4887Schin 		for(px=pw; px; px=px->p_nxtproc)
1139*4887Schin 		{
1140*4887Schin 			if(px->p_pid==pid)
1141*4887Schin 				return(px);
1142*4887Schin 		}
1143*4887Schin 	return(NIL(struct process*));
1144*4887Schin }
1145*4887Schin 
1146*4887Schin /*
1147*4887Schin  * return a pointer to a job given the job id
1148*4887Schin  */
1149*4887Schin 
1150*4887Schin static struct process *job_byjid(int jobid)
1151*4887Schin {
1152*4887Schin 	register struct process *pw;
1153*4887Schin 	for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
1154*4887Schin 	{
1155*4887Schin 		if(pw->p_job==jobid)
1156*4887Schin 			break;
1157*4887Schin 	}
1158*4887Schin 	return(pw);
1159*4887Schin }
1160*4887Schin 
1161*4887Schin /*
1162*4887Schin  * print a signal message
1163*4887Schin  */
1164*4887Schin static void job_prmsg(register struct process *pw)
1165*4887Schin {
1166*4887Schin 	if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
1167*4887Schin 	{
1168*4887Schin 		register const char *msg, *dump;
1169*4887Schin 		msg = job_sigmsg((int)(pw->p_exit));
1170*4887Schin 		msg = sh_translate(msg);
1171*4887Schin 		if(pw->p_flag&P_COREDUMP)
1172*4887Schin 			dump =  sh_translate(e_coredump);
1173*4887Schin 		else
1174*4887Schin 			dump = "";
1175*4887Schin 		if(sh_isstate(SH_INTERACTIVE))
1176*4887Schin 			sfprintf(sfstderr,"%s%s\n",msg,dump);
1177*4887Schin 		else
1178*4887Schin 			errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump);
1179*4887Schin 	}
1180*4887Schin }
1181*4887Schin 
1182*4887Schin /*
1183*4887Schin  * Wait for process pid to complete
1184*4887Schin  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
1185*4887Schin  * pid=0 to unpost all done processes
1186*4887Schin  * pid=1 to wait for at least one process to complete
1187*4887Schin  * pid=-1 to wait for all runing processes
1188*4887Schin  */
1189*4887Schin 
1190*4887Schin void	job_wait(register pid_t pid)
1191*4887Schin {
1192*4887Schin 	register struct process *pw=0,*px;
1193*4887Schin 	register int	jobid = 0;
1194*4887Schin 	int		nochild;
1195*4887Schin 	char		intr = 0;
1196*4887Schin 	if(pid <= 0)
1197*4887Schin 	{
1198*4887Schin 		if(pid==0)
1199*4887Schin 			goto done;
1200*4887Schin 		pid = -pid;
1201*4887Schin 		intr = 1;
1202*4887Schin 	}
1203*4887Schin 	job_lock();
1204*4887Schin 	if(pid > 1)
1205*4887Schin 	{
1206*4887Schin 		if(!(pw=job_bypid(pid)))
1207*4887Schin 		{
1208*4887Schin 			/* check to see whether job status has been saved */
1209*4887Schin 			if((sh.exitval = job_chksave(pid)) < 0)
1210*4887Schin 				sh.exitval = ERROR_NOENT;
1211*4887Schin 			exitset();
1212*4887Schin 			job_unlock();
1213*4887Schin 			return;
1214*4887Schin 		}
1215*4887Schin 		else if(intr && pw->p_env!=sh.curenv)
1216*4887Schin 		{
1217*4887Schin 			sh.exitval = ERROR_NOENT;
1218*4887Schin 			job_unlock();
1219*4887Schin 			return;
1220*4887Schin 		}
1221*4887Schin 		jobid = pw->p_job;
1222*4887Schin 		if(!intr)
1223*4887Schin 			pw->p_flag &= ~P_EXITSAVE;
1224*4887Schin 		if(pw->p_pgrp && job.parent!= (pid_t)-1)
1225*4887Schin 			job_set(job_byjid(jobid));
1226*4887Schin 	}
1227*4887Schin #ifdef DEBUG
1228*4887Schin 	sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid);
1229*4887Schin 	if(pw)
1230*4887Schin 		sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag);
1231*4887Schin #endif /* DEBUG*/
1232*4887Schin 	errno = 0;
1233*4887Schin 	while(1)
1234*4887Schin 	{
1235*4887Schin 		if(job.waitsafe)
1236*4887Schin 		{
1237*4887Schin 			for(px=job.pwlist;px; px = px->p_nxtjob)
1238*4887Schin 			{
1239*4887Schin 				if(px!=pw && (px->p_flag&P_NOTIFY))
1240*4887Schin 				{
1241*4887Schin 					if(sh_isoption(SH_NOTIFY))
1242*4887Schin 					{
1243*4887Schin 						outfile = sfstderr;
1244*4887Schin 						job_list(px,JOB_NFLAG|JOB_NLFLAG);
1245*4887Schin 						sfsync(sfstderr);
1246*4887Schin 					}
1247*4887Schin 					else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
1248*4887Schin 					{
1249*4887Schin 						job_prmsg(px);
1250*4887Schin 						px->p_flag &= ~P_NOTIFY;
1251*4887Schin 					}
1252*4887Schin 				}
1253*4887Schin 			}
1254*4887Schin 		}
1255*4887Schin 		if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
1256*4887Schin 		{
1257*4887Schin #ifdef SIGTSTP
1258*4887Schin 			if(pw->p_flag&P_STOPPED)
1259*4887Schin 			{
1260*4887Schin 				pw->p_flag |= P_EXITSAVE;
1261*4887Schin 				if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
1262*4887Schin 				{
1263*4887Schin 					if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
1264*4887Schin 						break;
1265*4887Schin 
1266*4887Schin 					killpg(pw->p_pgrp,SIGCONT);
1267*4887Schin 				}
1268*4887Schin 				else /* ignore stop when non-interactive */
1269*4887Schin 					pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
1270*4887Schin 			}
1271*4887Schin 			else
1272*4887Schin #endif /* SIGTSTP */
1273*4887Schin 			{
1274*4887Schin 				if(pw->p_flag&P_SIGNALLED)
1275*4887Schin 				{
1276*4887Schin 					pw->p_flag &= ~P_NOTIFY;
1277*4887Schin 					job_prmsg(pw);
1278*4887Schin 				}
1279*4887Schin 				else if(pw->p_flag&P_DONE)
1280*4887Schin 					pw->p_flag &= ~P_NOTIFY;
1281*4887Schin 				if(pw->p_job==jobid)
1282*4887Schin 				{
1283*4887Schin 					px = job_byjid(jobid);
1284*4887Schin 					/* last process in job */
1285*4887Schin 					if(sh_isoption(SH_PIPEFAIL))
1286*4887Schin 					{
1287*4887Schin 						/* last non-zero exit */
1288*4887Schin 						for(;px;px=px->p_nxtproc)
1289*4887Schin 						{
1290*4887Schin 							if(px->p_exit)
1291*4887Schin 								break;
1292*4887Schin 						}
1293*4887Schin 						if(!px)
1294*4887Schin 							px = pw;
1295*4887Schin 					}
1296*4887Schin 					else if(px!=pw)
1297*4887Schin 						px = 0;
1298*4887Schin 					if(px)
1299*4887Schin 					{
1300*4887Schin 						sh.exitval=px->p_exit;
1301*4887Schin 						if(px->p_flag&P_SIGNALLED)
1302*4887Schin 							sh.exitval |= SH_EXITSIG;
1303*4887Schin 						if(intr)
1304*4887Schin 							px->p_flag &= ~P_EXITSAVE;
1305*4887Schin 					}
1306*4887Schin 				}
1307*4887Schin 				if(!job.waitall)
1308*4887Schin 				{
1309*4887Schin 					if(!sh_isoption(SH_PIPEFAIL))
1310*4887Schin 						job_unpost(pw,1);
1311*4887Schin 					break;
1312*4887Schin 				}
1313*4887Schin 				else if(!(px=job_unpost(pw,1)))
1314*4887Schin 					break;
1315*4887Schin 				pw = px;
1316*4887Schin 				continue;
1317*4887Schin 			}
1318*4887Schin 		}
1319*4887Schin 		sfsync(sfstderr);
1320*4887Schin 		job.waitsafe = 0;
1321*4887Schin 		nochild = job_reap(job.savesig);
1322*4887Schin 		if(job.waitsafe)
1323*4887Schin 			continue;
1324*4887Schin 		if(nochild)
1325*4887Schin 			break;
1326*4887Schin 		if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
1327*4887Schin 			sh_timetraps();
1328*4887Schin 		if((intr && sh.trapnote) || (pid==1 && !intr))
1329*4887Schin 			break;
1330*4887Schin 	}
1331*4887Schin 	job_unlock();
1332*4887Schin 	if(pid==1)
1333*4887Schin 		return;
1334*4887Schin 	exitset();
1335*4887Schin 	if(pw->p_pgrp)
1336*4887Schin 	{
1337*4887Schin 		job_reset(pw);
1338*4887Schin 		/* propogate keyboard interrupts to parent */
1339*4887Schin 		if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
1340*4887Schin 			sh_fault(SIGINT);
1341*4887Schin #ifdef SIGTSTP
1342*4887Schin 		else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
1343*4887Schin 		{
1344*4887Schin 			job.parent = 0;
1345*4887Schin 			sh_fault(SIGTSTP);
1346*4887Schin 		}
1347*4887Schin #endif /* SIGTSTP */
1348*4887Schin 	}
1349*4887Schin 	else
1350*4887Schin 		tty_set(-1, 0, NIL(struct termios*));
1351*4887Schin done:
1352*4887Schin 	if(!job.waitall && sh_isoption(SH_PIPEFAIL))
1353*4887Schin 		return;
1354*4887Schin 	if(!sh.intrap)
1355*4887Schin 	{
1356*4887Schin 		job_lock();
1357*4887Schin 		for(pw=job.pwlist; pw; pw=px)
1358*4887Schin 		{
1359*4887Schin 			px = pw->p_nxtjob;
1360*4887Schin 			job_unpost(pw,0);
1361*4887Schin 		}
1362*4887Schin 		job_unlock();
1363*4887Schin 	}
1364*4887Schin }
1365*4887Schin 
1366*4887Schin /*
1367*4887Schin  * move job to foreground if bgflag == 'f'
1368*4887Schin  * move job to background if bgflag == 'b'
1369*4887Schin  * disown job if bgflag == 'd'
1370*4887Schin  */
1371*4887Schin 
1372*4887Schin int job_switch(register struct process *pw,int bgflag)
1373*4887Schin {
1374*4887Schin 	register const char *msg;
1375*4887Schin 	job_lock();
1376*4887Schin 	if(!pw || !(pw=job_byjid((int)pw->p_job)))
1377*4887Schin 	{
1378*4887Schin 		job_unlock();
1379*4887Schin 		return(1);
1380*4887Schin 	}
1381*4887Schin 	if(bgflag=='d')
1382*4887Schin 	{
1383*4887Schin 		for(; pw; pw=pw->p_nxtproc)
1384*4887Schin 			pw->p_flag |= P_DISOWN;
1385*4887Schin 		job_unlock();
1386*4887Schin 		return(0);
1387*4887Schin 	}
1388*4887Schin #ifdef SIGTSTP
1389*4887Schin 	if(bgflag=='b')
1390*4887Schin 	{
1391*4887Schin 		sfprintf(outfile,"[%d]\t",(int)pw->p_job);
1392*4887Schin 		sh.bckpid = pw->p_pid;
1393*4887Schin 		msg = "&";
1394*4887Schin 	}
1395*4887Schin 	else
1396*4887Schin 	{
1397*4887Schin 		job_unlink(pw);
1398*4887Schin 		pw->p_nxtjob = job.pwlist;
1399*4887Schin 		job.pwlist = pw;
1400*4887Schin 		msg = "";
1401*4887Schin 	}
1402*4887Schin 	hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
1403*4887Schin 	sfputr(outfile,msg,'\n');
1404*4887Schin 	sfsync(outfile);
1405*4887Schin 	if(bgflag=='f')
1406*4887Schin 	{
1407*4887Schin 		if(!(pw=job_unpost(pw,1)))
1408*4887Schin 		{
1409*4887Schin 			job_unlock();
1410*4887Schin 			return(1);
1411*4887Schin 		}
1412*4887Schin 		job.waitall = 1;
1413*4887Schin 		pw->p_flag |= P_FG;
1414*4887Schin 		job_wait(pw->p_pid);
1415*4887Schin 		job.waitall = 0;
1416*4887Schin 	}
1417*4887Schin 	else if(pw->p_flag&P_STOPPED)
1418*4887Schin 		job_unstop(pw);
1419*4887Schin #endif /* SIGTSTP */
1420*4887Schin 	job_unlock();
1421*4887Schin 	return(0);
1422*4887Schin }
1423*4887Schin 
1424*4887Schin 
1425*4887Schin #ifdef SIGTSTP
1426*4887Schin /*
1427*4887Schin  * Set the foreground group associated with a job
1428*4887Schin  */
1429*4887Schin 
1430*4887Schin static void job_fgrp(register struct process *pw, int newgrp)
1431*4887Schin {
1432*4887Schin 	for(; pw; pw=pw->p_nxtproc)
1433*4887Schin 		pw->p_fgrp = newgrp;
1434*4887Schin }
1435*4887Schin 
1436*4887Schin /*
1437*4887Schin  * turn off STOP state of a process group and send CONT signals
1438*4887Schin  */
1439*4887Schin 
1440*4887Schin static void job_unstop(register struct process *px)
1441*4887Schin {
1442*4887Schin 	register struct process *pw;
1443*4887Schin 	register int num = 0;
1444*4887Schin 	for(pw=px ;pw ;pw=pw->p_nxtproc)
1445*4887Schin 	{
1446*4887Schin 		if(pw->p_flag&P_STOPPED)
1447*4887Schin 		{
1448*4887Schin 			num++;
1449*4887Schin 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
1450*4887Schin 		}
1451*4887Schin 	}
1452*4887Schin 	if(num!=0)
1453*4887Schin 	{
1454*4887Schin 		if(px->p_fgrp != px->p_pgrp)
1455*4887Schin 			killpg(px->p_fgrp,SIGCONT);
1456*4887Schin 		killpg(px->p_pgrp,SIGCONT);
1457*4887Schin 	}
1458*4887Schin }
1459*4887Schin #endif	/* SIGTSTP */
1460*4887Schin 
1461*4887Schin /*
1462*4887Schin  * remove a job from table
1463*4887Schin  * If all the processes have not completed, unpost first non-completed  process
1464*4887Schin  * Otherwise the job is removed and job_unpost returns NULL.
1465*4887Schin  * pwlist is reset if the first job is removed
1466*4887Schin  * if <notify> is non-zero, then jobs with pending notifications are unposted
1467*4887Schin  */
1468*4887Schin 
1469*4887Schin static struct process *job_unpost(register struct process *pwtop,int notify)
1470*4887Schin {
1471*4887Schin 	register struct process *pw;
1472*4887Schin 	/* make sure all processes are done */
1473*4887Schin #ifdef DEBUG
1474*4887Schin 	sfprintf(sfstderr,"ksh: job line %4d: drop pid=%d critical=%d pid=%d env=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_pid,pwtop->p_env);
1475*4887Schin 	sfsync(sfstderr);
1476*4887Schin #endif /* DEBUG */
1477*4887Schin 	pwtop = pw = job_byjid((int)pwtop->p_job);
1478*4887Schin 	for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc);
1479*4887Schin 	if(pw)
1480*4887Schin 		return(pw);
1481*4887Schin 	/* all processes complete, unpost job */
1482*4887Schin 	job_unlink(pwtop);
1483*4887Schin 	for(pw=pwtop; pw; pw=pw->p_nxtproc)
1484*4887Schin 	{
1485*4887Schin 		/* save the exit status for background jobs */
1486*4887Schin 		if(pw->p_flag&P_EXITSAVE)
1487*4887Schin 		{
1488*4887Schin 			struct jobsave *jp;
1489*4887Schin 			/* save status for future wait */
1490*4887Schin 			if(bck.count++ > sh.lim.child_max)
1491*4887Schin 				job_chksave(0);
1492*4887Schin 			if(jp = jobsave_create(pw->p_pid))
1493*4887Schin 			{
1494*4887Schin 				jp->next = bck.list;
1495*4887Schin 				bck.list = jp;
1496*4887Schin 				jp->exitval = pw->p_exit;
1497*4887Schin 				if(pw->p_flag&P_SIGNALLED)
1498*4887Schin 					jp->exitval |= SH_EXITSIG;
1499*4887Schin 			}
1500*4887Schin 			pw->p_flag &= ~P_EXITSAVE;
1501*4887Schin 		}
1502*4887Schin 		pw->p_flag &= ~P_DONE;
1503*4887Schin 		job.numpost--;
1504*4887Schin 		pw->p_nxtjob = freelist;
1505*4887Schin 		freelist = pw;
1506*4887Schin 	}
1507*4887Schin #ifdef DEBUG
1508*4887Schin 	sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job);
1509*4887Schin 	sfsync(sfstderr);
1510*4887Schin #endif /* DEBUG */
1511*4887Schin 	job_free((int)pwtop->p_job);
1512*4887Schin 	return((struct process*)0);
1513*4887Schin }
1514*4887Schin 
1515*4887Schin /*
1516*4887Schin  * unlink a job form the job list
1517*4887Schin  */
1518*4887Schin static void job_unlink(register struct process *pw)
1519*4887Schin {
1520*4887Schin 	register struct process *px;
1521*4887Schin 	if(pw==job.pwlist)
1522*4887Schin 	{
1523*4887Schin 		job.pwlist = pw->p_nxtjob;
1524*4887Schin 		job.curpgid = 0;
1525*4887Schin 		return;
1526*4887Schin 	}
1527*4887Schin 	for(px=job.pwlist;px;px=px->p_nxtjob)
1528*4887Schin 		if(px->p_nxtjob == pw)
1529*4887Schin 		{
1530*4887Schin 			px->p_nxtjob = pw->p_nxtjob;
1531*4887Schin 			return;
1532*4887Schin 		}
1533*4887Schin }
1534*4887Schin 
1535*4887Schin /*
1536*4887Schin  * get an unused job number
1537*4887Schin  * freejobs is a bit vector, 0 is unused
1538*4887Schin  */
1539*4887Schin 
1540*4887Schin static int job_alloc(void)
1541*4887Schin {
1542*4887Schin 	register int j=0;
1543*4887Schin 	register unsigned mask = 1;
1544*4887Schin 	register unsigned char *freeword;
1545*4887Schin 	register int jmax = BYTE(sh.lim.child_max);
1546*4887Schin 	/* skip to first word with a free slot */
1547*4887Schin 	for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
1548*4887Schin 	if(j >= jmax)
1549*4887Schin 	{
1550*4887Schin 		register struct process *pw;
1551*4887Schin 		for(j=1; j < sh.lim.child_max; j++)
1552*4887Schin 		{
1553*4887Schin 			if((pw=job_byjid(j))&& !job_unpost(pw,0))
1554*4887Schin 				break;
1555*4887Schin 		}
1556*4887Schin 		j /= CHAR_BIT;
1557*4887Schin 		if(j >= jmax)
1558*4887Schin 			return(-1);
1559*4887Schin 	}
1560*4887Schin 	freeword = &job.freejobs[j];
1561*4887Schin 	j *= CHAR_BIT;
1562*4887Schin 	for(j++;mask&(*freeword);j++,mask <<=1);
1563*4887Schin 	*freeword  |= mask;
1564*4887Schin 	return(j);
1565*4887Schin }
1566*4887Schin 
1567*4887Schin /*
1568*4887Schin  * return a job number
1569*4887Schin  */
1570*4887Schin 
1571*4887Schin static void job_free(register int n)
1572*4887Schin {
1573*4887Schin 	register int j = (--n)/CHAR_BIT;
1574*4887Schin 	register unsigned mask;
1575*4887Schin 	n -= j*CHAR_BIT;
1576*4887Schin 	mask = 1 << n;
1577*4887Schin 	job.freejobs[j]  &= ~mask;
1578*4887Schin }
1579*4887Schin 
1580*4887Schin static char *job_sigmsg(int sig)
1581*4887Schin {
1582*4887Schin 	static char signo[40];
1583*4887Schin #ifdef apollo
1584*4887Schin 	/*
1585*4887Schin 	 * This code handles the formatting for the apollo specific signal
1586*4887Schin 	 * SIGAPOLLO.
1587*4887Schin 	 */
1588*4887Schin 	extern char *apollo_error(void);
1589*4887Schin 
1590*4887Schin 	if ( sig == SIGAPOLLO )
1591*4887Schin 		return( apollo_error() );
1592*4887Schin #endif /* apollo */
1593*4887Schin 	if(sig<sh.sigmax && sh.sigmsg[sig])
1594*4887Schin 		return(sh.sigmsg[sig]);
1595*4887Schin #if defined(SIGRTMIN) && defined(SIGRTMAX)
1596*4887Schin 	if(sig>=SIGRTMIN && sig<=SIGRTMAX)
1597*4887Schin 	{
1598*4887Schin 		static char sigrt[20];
1599*4887Schin 		sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-SIGRTMIN);
1600*4887Schin 		return(sigrt);
1601*4887Schin 	}
1602*4887Schin #endif
1603*4887Schin 	sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig);
1604*4887Schin 	return(signo);
1605*4887Schin }
1606*4887Schin 
1607*4887Schin /*
1608*4887Schin  * see whether exit status has been saved and delete it
1609*4887Schin  * if pid==0, then oldest saved process is deleted
1610*4887Schin  * If pid is not found a -1 is returned.
1611*4887Schin  */
1612*4887Schin static int job_chksave(register pid_t pid)
1613*4887Schin {
1614*4887Schin 	register struct jobsave *jp = bck.list, *jpold=0;
1615*4887Schin 	register int r= -1;
1616*4887Schin 	while(jp)
1617*4887Schin 	{
1618*4887Schin 		if(jp->pid==pid)
1619*4887Schin 			break;
1620*4887Schin 		if(pid==0 && !jp->next)
1621*4887Schin 			break;
1622*4887Schin 		jpold = jp;
1623*4887Schin 		jp = jp->next;
1624*4887Schin 	}
1625*4887Schin 	if(jp)
1626*4887Schin 	{
1627*4887Schin 		r = 0;
1628*4887Schin 		if(pid)
1629*4887Schin 			r = jp->exitval;
1630*4887Schin 		if(jpold)
1631*4887Schin 			jpold->next = jp->next;
1632*4887Schin 		else
1633*4887Schin 			bck.list = jp->next;
1634*4887Schin 		bck.count--;
1635*4887Schin 		if(njob_savelist < NJOB_SAVELIST)
1636*4887Schin 		{
1637*4887Schin 			njob_savelist++;
1638*4887Schin 			jp->next = job_savelist;
1639*4887Schin 			job_savelist = jp;
1640*4887Schin 		}
1641*4887Schin 		else
1642*4887Schin 			free((void*)jp);
1643*4887Schin 	}
1644*4887Schin 	return(r);
1645*4887Schin }
1646*4887Schin 
1647*4887Schin void *job_subsave(void)
1648*4887Schin {
1649*4887Schin 	struct back_save *bp = new_of(struct back_save,0);
1650*4887Schin 	job_lock();
1651*4887Schin 	*bp = bck;
1652*4887Schin 	bck.count = 0;
1653*4887Schin 	bck.list = 0;
1654*4887Schin 	job_unlock();
1655*4887Schin 	return((void*)bp);
1656*4887Schin }
1657*4887Schin 
1658*4887Schin void job_subrestore(void* ptr)
1659*4887Schin {
1660*4887Schin 	register struct jobsave *jp,*jpnext;
1661*4887Schin 	register struct back_save *bp = (struct back_save*)ptr;
1662*4887Schin 	register struct process *pw, *px, *pwnext;
1663*4887Schin 	job_lock();
1664*4887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
1665*4887Schin 	{
1666*4887Schin 		pwnext = pw->p_nxtjob;
1667*4887Schin 		if(pw->p_env != sh.curenv)
1668*4887Schin 			continue;
1669*4887Schin 		for(px=pw; px; px=px->p_nxtproc)
1670*4887Schin 			px->p_flag |= P_DONE;
1671*4887Schin 		job_unpost(pw,0);
1672*4887Schin 	}
1673*4887Schin 	for(jp=bck.list,bck= *bp; jp; jp=jpnext)
1674*4887Schin 	{
1675*4887Schin 		jpnext = jp->next;
1676*4887Schin 		free((void*)jp);
1677*4887Schin 	}
1678*4887Schin 	free(ptr);
1679*4887Schin 	job_unlock();
1680*4887Schin }
1681*4887Schin 
1682*4887Schin int sh_waitsafe(void)
1683*4887Schin {
1684*4887Schin 	return(job.waitsafe);
1685*4887Schin }
1686*4887Schin 
1687*4887Schin void job_fork(pid_t parent)
1688*4887Schin {
1689*4887Schin #ifdef DEBUG
1690*4887Schin 	sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent);
1691*4887Schin #endif /* DEBUG */
1692*4887Schin 	switch (parent)
1693*4887Schin 	{
1694*4887Schin 	case -1:
1695*4887Schin 		job_lock();
1696*4887Schin 		break;
1697*4887Schin 	case 0:
1698*4887Schin 		job_unlock();
1699*4887Schin 		job.waitsafe = 0;
1700*4887Schin 		job.in_critical = 0;
1701*4887Schin 		break;
1702*4887Schin 	default:
1703*4887Schin 		job_unlock();
1704*4887Schin 		break;
1705*4887Schin 	}
1706*4887Schin }
1707