xref: /titanic_51/usr/src/lib/libshell/common/sh/jobs.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  *  Job control for UNIX Shell
23da2e3ebdSchin  *
24da2e3ebdSchin  *   David Korn
25da2e3ebdSchin  *   AT&T Labs
26da2e3ebdSchin  *
27da2e3ebdSchin  *  Written October, 1982
28da2e3ebdSchin  *  Rewritten April, 1988
29da2e3ebdSchin  *  Revised January, 1992
30da2e3ebdSchin  */
31da2e3ebdSchin 
32da2e3ebdSchin #include	"defs.h"
33da2e3ebdSchin #include	<wait.h>
34da2e3ebdSchin #include	"io.h"
35da2e3ebdSchin #include	"jobs.h"
36da2e3ebdSchin #include	"history.h"
37da2e3ebdSchin 
38da2e3ebdSchin #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
39da2e3ebdSchin #   undef  WCONTINUED
40da2e3ebdSchin #   define WCONTINUED	0
41da2e3ebdSchin #   undef  WIFCONTINUED
42da2e3ebdSchin #   define WIFCONTINUED(wstat)	(0)
43da2e3ebdSchin #endif
44da2e3ebdSchin 
45da2e3ebdSchin #define	NJOB_SAVELIST	4
46da2e3ebdSchin 
47da2e3ebdSchin /*
48da2e3ebdSchin  * temporary hack to get W* macros to work
49da2e3ebdSchin  */
50da2e3ebdSchin #undef wait
51da2e3ebdSchin #define wait    ______wait
52da2e3ebdSchin /*
53da2e3ebdSchin  * This struct saves a link list of processes that have non-zero exit
54da2e3ebdSchin  * status, have had $! saved, but haven't been waited for
55da2e3ebdSchin  */
56da2e3ebdSchin struct jobsave
57da2e3ebdSchin {
58da2e3ebdSchin 	struct jobsave	*next;
59da2e3ebdSchin 	pid_t		pid;
60da2e3ebdSchin 	unsigned short	exitval;
61da2e3ebdSchin };
62da2e3ebdSchin 
63da2e3ebdSchin static struct jobsave *job_savelist;
64da2e3ebdSchin static int njob_savelist;
657c2fbfb3SApril Chin static struct process *pwfg;
66da2e3ebdSchin 
init_savelist(void)67da2e3ebdSchin static void init_savelist(void)
68da2e3ebdSchin {
69da2e3ebdSchin 	register struct jobsave *jp;
70da2e3ebdSchin 	while(njob_savelist < NJOB_SAVELIST)
71da2e3ebdSchin 	{
72da2e3ebdSchin 		jp = newof(0,struct jobsave,1,0);
73da2e3ebdSchin 		jp->next = job_savelist;
74da2e3ebdSchin 		job_savelist = jp;
75da2e3ebdSchin 		njob_savelist++;
76da2e3ebdSchin 	}
77da2e3ebdSchin }
78da2e3ebdSchin 
79da2e3ebdSchin struct back_save
80da2e3ebdSchin {
81da2e3ebdSchin 	int		count;
82da2e3ebdSchin 	struct jobsave	*list;
83da2e3ebdSchin };
84da2e3ebdSchin 
85da2e3ebdSchin #define BYTE(n)		(((n)+CHAR_BIT-1)/CHAR_BIT)
86da2e3ebdSchin #define MAXMSG	25
87da2e3ebdSchin #define SH_STOPSIG	(SH_EXITSIG<<1)
88da2e3ebdSchin 
89da2e3ebdSchin #ifdef VSUSP
90da2e3ebdSchin #   ifndef CNSUSP
91da2e3ebdSchin #	ifdef _POSIX_VDISABLE
92da2e3ebdSchin #	   define CNSUSP	_POSIX_VDISABLE
93da2e3ebdSchin #	else
94da2e3ebdSchin #	   define CNSUSP	0
95da2e3ebdSchin #	endif /* _POSIX_VDISABLE */
96da2e3ebdSchin #   endif /* CNSUSP */
97da2e3ebdSchin #   ifndef CSWTCH
98da2e3ebdSchin #	ifdef CSUSP
99da2e3ebdSchin #	    define CSWTCH	CSUSP
100da2e3ebdSchin #	else
101da2e3ebdSchin #	    define CSWTCH	('z'&037)
102da2e3ebdSchin #	endif /* CSUSP */
103da2e3ebdSchin #   endif /* CSWTCH */
104da2e3ebdSchin #endif /* VSUSP */
105da2e3ebdSchin 
106da2e3ebdSchin /* Process states */
107da2e3ebdSchin #define P_EXITSAVE	01
108da2e3ebdSchin #define P_STOPPED	02
109da2e3ebdSchin #define P_NOTIFY	04
110da2e3ebdSchin #define P_SIGNALLED	010
111da2e3ebdSchin #define P_STTY		020
112da2e3ebdSchin #define P_DONE		040
113da2e3ebdSchin #define P_COREDUMP	0100
114da2e3ebdSchin #define P_DISOWN	0200
115da2e3ebdSchin #define P_FG		0400
11634f9b3eeSRoland Mainz #ifdef SHOPT_BGX
11734f9b3eeSRoland Mainz #define P_BG		01000
11834f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
119da2e3ebdSchin 
120da2e3ebdSchin static int		job_chksave(pid_t);
121da2e3ebdSchin static struct process	*job_bypid(pid_t);
122da2e3ebdSchin static struct process	*job_byjid(int);
123da2e3ebdSchin static char		*job_sigmsg(int);
124da2e3ebdSchin static int		job_alloc(void);
125da2e3ebdSchin static void		job_free(int);
126da2e3ebdSchin static struct process	*job_unpost(struct process*,int);
127da2e3ebdSchin static void		job_unlink(struct process*);
128da2e3ebdSchin static void		job_prmsg(struct process*);
129da2e3ebdSchin static struct process	*freelist;
130da2e3ebdSchin static char		beenhere;
131da2e3ebdSchin static char		possible;
132da2e3ebdSchin static struct process	dummy;
133da2e3ebdSchin static char		by_number;
134da2e3ebdSchin static Sfio_t		*outfile;
135da2e3ebdSchin static pid_t		lastpid;
136da2e3ebdSchin static struct back_save	bck;
137da2e3ebdSchin 
138da2e3ebdSchin #ifdef JOBS
139da2e3ebdSchin     static void			job_set(struct process*);
140da2e3ebdSchin     static void			job_reset(struct process*);
141da2e3ebdSchin     static void			job_waitsafe(int);
142da2e3ebdSchin     static struct process	*job_byname(char*);
143da2e3ebdSchin     static struct process	*job_bystring(char*);
144da2e3ebdSchin     static struct termios	my_stty;  /* terminal state for shell */
145da2e3ebdSchin     static char			*job_string;
146da2e3ebdSchin #else
147da2e3ebdSchin     extern const char		e_coredump[];
148da2e3ebdSchin #endif /* JOBS */
149da2e3ebdSchin 
150da2e3ebdSchin #ifdef SIGTSTP
151da2e3ebdSchin     static void		job_unstop(struct process*);
152da2e3ebdSchin     static void		job_fgrp(struct process*, int);
153da2e3ebdSchin #   ifndef _lib_tcgetpgrp
154da2e3ebdSchin #	ifdef TIOCGPGRP
155da2e3ebdSchin 	   static int _i_;
156da2e3ebdSchin #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
157da2e3ebdSchin #	endif /* TIOCGPGRP */
tcsetpgrp(int fd,pid_t pgrp)158da2e3ebdSchin 	int tcsetpgrp(int fd,pid_t pgrp)
159da2e3ebdSchin 	{
160da2e3ebdSchin 		int pgid = pgrp;
161da2e3ebdSchin #		ifdef TIOCGPGRP
162da2e3ebdSchin 			return(ioctl(fd, TIOCSPGRP, &pgid));
163da2e3ebdSchin #		else
164da2e3ebdSchin 			return(-1);
165da2e3ebdSchin #		endif /* TIOCGPGRP */
166da2e3ebdSchin 	}
167da2e3ebdSchin #   endif /* _lib_tcgetpgrp */
168da2e3ebdSchin #else
169da2e3ebdSchin #   define job_unstop(pw)
170da2e3ebdSchin #   undef CNSUSP
171da2e3ebdSchin #endif /* SIGTSTP */
172da2e3ebdSchin 
173da2e3ebdSchin #ifndef OTTYDISC
174da2e3ebdSchin #   undef NTTYDISC
175da2e3ebdSchin #endif /* OTTYDISC */
176da2e3ebdSchin 
177da2e3ebdSchin #ifdef JOBS
178da2e3ebdSchin 
179da2e3ebdSchin typedef int (*Waitevent_f)(int,long,int);
180da2e3ebdSchin 
18134f9b3eeSRoland Mainz #ifdef SHOPT_BGX
job_chldtrap(Shell_t * shp,const char * trap,int unpost)18234f9b3eeSRoland Mainz void job_chldtrap(Shell_t *shp, const char *trap, int unpost)
18334f9b3eeSRoland Mainz {
18434f9b3eeSRoland Mainz 	register struct process *pw,*pwnext;
18534f9b3eeSRoland Mainz 	pid_t bckpid;
186*3e14f97fSRoger A. Faulkner 	int oldexit,trapnote;
18734f9b3eeSRoland Mainz 	job_lock();
18834f9b3eeSRoland Mainz 	shp->sigflag[SIGCHLD] &= ~SH_SIGTRAP;
189*3e14f97fSRoger A. Faulkner 	trapnote = shp->trapnote;
190*3e14f97fSRoger A. Faulkner 	shp->trapnote = 0;
19134f9b3eeSRoland Mainz 	for(pw=job.pwlist;pw;pw=pwnext)
19234f9b3eeSRoland Mainz 	{
19334f9b3eeSRoland Mainz 		pwnext = pw->p_nxtjob;
19434f9b3eeSRoland Mainz 		if((pw->p_flag&(P_BG|P_DONE)) != (P_BG|P_DONE))
19534f9b3eeSRoland Mainz 			continue;
19634f9b3eeSRoland Mainz 		pw->p_flag &= ~P_BG;
19734f9b3eeSRoland Mainz 		bckpid = shp->bckpid;
19834f9b3eeSRoland Mainz 		oldexit = shp->savexit;
19934f9b3eeSRoland Mainz 		shp->bckpid = pw->p_pid;
20034f9b3eeSRoland Mainz 		shp->savexit = pw->p_exit;
20134f9b3eeSRoland Mainz 		if(pw->p_flag&P_SIGNALLED)
20234f9b3eeSRoland Mainz 			shp->savexit |= SH_EXITSIG;
20334f9b3eeSRoland Mainz 		sh_trap(trap,0);
204*3e14f97fSRoger A. Faulkner 		if(pw->p_pid==bckpid && unpost)
205*3e14f97fSRoger A. Faulkner 			job_unpost(pw,0);
20634f9b3eeSRoland Mainz 		shp->savexit = oldexit;
20734f9b3eeSRoland Mainz 		shp->bckpid = bckpid;
20834f9b3eeSRoland Mainz 	}
209*3e14f97fSRoger A. Faulkner 	shp->trapnote = trapnote;
21034f9b3eeSRoland Mainz 	job_unlock();
21134f9b3eeSRoland Mainz }
21234f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
21334f9b3eeSRoland Mainz 
21434f9b3eeSRoland Mainz /*
21534f9b3eeSRoland Mainz  * return next on link list of jobsave free list
21634f9b3eeSRoland Mainz  */
jobsave_create(pid_t pid)21734f9b3eeSRoland Mainz static struct jobsave *jobsave_create(pid_t pid)
21834f9b3eeSRoland Mainz {
21934f9b3eeSRoland Mainz 	register struct jobsave *jp = job_savelist;
22034f9b3eeSRoland Mainz 	job_chksave(pid);
22134f9b3eeSRoland Mainz 	if(++bck.count > sh.lim.child_max)
22234f9b3eeSRoland Mainz 		job_chksave(0);
22334f9b3eeSRoland Mainz 	if(jp)
22434f9b3eeSRoland Mainz 	{
22534f9b3eeSRoland Mainz 		njob_savelist--;
22634f9b3eeSRoland Mainz 		job_savelist = jp->next;
22734f9b3eeSRoland Mainz 	}
22834f9b3eeSRoland Mainz 	else
22934f9b3eeSRoland Mainz 		jp = newof(0,struct jobsave,1,0);
23034f9b3eeSRoland Mainz 	if(jp)
23134f9b3eeSRoland Mainz 	{
23234f9b3eeSRoland Mainz 		jp->pid = pid;
23334f9b3eeSRoland Mainz 		jp->next = bck.list;
23434f9b3eeSRoland Mainz 		bck.list = jp;
23534f9b3eeSRoland Mainz 		jp->exitval = 0;
23634f9b3eeSRoland Mainz 	}
23734f9b3eeSRoland Mainz 	return(jp);
23834f9b3eeSRoland Mainz }
23934f9b3eeSRoland Mainz 
240da2e3ebdSchin /*
241da2e3ebdSchin  * Reap one job
242da2e3ebdSchin  * When called with sig==0, it does a blocking wait
243da2e3ebdSchin  */
job_reap(register int sig)244da2e3ebdSchin int job_reap(register int sig)
245da2e3ebdSchin {
246da2e3ebdSchin 	register pid_t pid;
247da2e3ebdSchin 	register struct process *pw;
248da2e3ebdSchin 	struct process *px;
249da2e3ebdSchin 	register int flags;
250da2e3ebdSchin 	struct jobsave *jp;
251da2e3ebdSchin 	int nochild=0, oerrno, wstat;
252da2e3ebdSchin 	Waitevent_f waitevent = sh.waitevent;
253da2e3ebdSchin 	static int wcontinued = WCONTINUED;
2547c2fbfb3SApril Chin 	if (vmbusy())
2557c2fbfb3SApril Chin 	{
2567c2fbfb3SApril Chin 		errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen");
2577c2fbfb3SApril Chin 		if (getenv("_AST_KSH_VMBUSY_ABORT"))
2587c2fbfb3SApril Chin 			abort();
2597c2fbfb3SApril Chin 	}
260da2e3ebdSchin #ifdef DEBUG
261da2e3ebdSchin 	if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0)
262da2e3ebdSchin 		write(2,"waitsafe\n",9);
263da2e3ebdSchin 	sfsync(sfstderr);
264da2e3ebdSchin #endif /* DEBUG */
265da2e3ebdSchin 	job.savesig = 0;
266da2e3ebdSchin 	if(sig)
267da2e3ebdSchin 		flags = WNOHANG|WUNTRACED|wcontinued;
268da2e3ebdSchin 	else
269da2e3ebdSchin 		flags = WUNTRACED|wcontinued;
270da2e3ebdSchin 	sh.waitevent = 0;
271da2e3ebdSchin 	oerrno = errno;
272da2e3ebdSchin 	while(1)
273da2e3ebdSchin 	{
2747c2fbfb3SApril Chin 		if(!(flags&WNOHANG) && !sh.intrap && job.pwlist)
275da2e3ebdSchin 		{
2767c2fbfb3SApril Chin 			sh_onstate(SH_TTYWAIT);
2777c2fbfb3SApril Chin 			if(waitevent && (*waitevent)(-1,-1L,0))
278da2e3ebdSchin 				flags |= WNOHANG;
279da2e3ebdSchin 		}
280da2e3ebdSchin 		pid = waitpid((pid_t)-1,&wstat,flags);
2817c2fbfb3SApril Chin 		sh_offstate(SH_TTYWAIT);
282da2e3ebdSchin 
283da2e3ebdSchin 		/*
284da2e3ebdSchin 		 * some systems (linux 2.6) may return EINVAL
285da2e3ebdSchin 		 * when there are no continued children
286da2e3ebdSchin 		 */
287da2e3ebdSchin 
288da2e3ebdSchin 		if (pid<0 && errno==EINVAL && (flags&WCONTINUED))
289da2e3ebdSchin 			pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED);
290da2e3ebdSchin 		sh_sigcheck();
291*3e14f97fSRoger A. Faulkner 		if(pid<0 && errno==EINTR && (sig||job.savesig))
292da2e3ebdSchin 			continue;
293da2e3ebdSchin 		if(pid<=0)
294da2e3ebdSchin 			break;
295da2e3ebdSchin 		flags |= WNOHANG;
296da2e3ebdSchin 		job.waitsafe++;
297da2e3ebdSchin 		jp = 0;
2987c2fbfb3SApril Chin 		lastpid = pid;
299da2e3ebdSchin 		if(!(pw=job_bypid(pid)))
300da2e3ebdSchin 		{
301da2e3ebdSchin #ifdef DEBUG
302da2e3ebdSchin 			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);
303da2e3ebdSchin #endif /* DEBUG */
3047c2fbfb3SApril Chin 			if (WIFCONTINUED(wstat) && wcontinued)
3057c2fbfb3SApril Chin 				continue;
306da2e3ebdSchin 			pw = &dummy;
307da2e3ebdSchin 			pw->p_exit = 0;
308da2e3ebdSchin 			pw->p_pgrp = 0;
3097c2fbfb3SApril Chin 			pw->p_exitmin = 0;
310da2e3ebdSchin 			if(job.toclear)
311da2e3ebdSchin 				job_clear();
31234f9b3eeSRoland Mainz 			jp = jobsave_create(pid);
313da2e3ebdSchin 			pw->p_flag = 0;
314da2e3ebdSchin 			lastpid = pw->p_pid = pid;
315da2e3ebdSchin 			px = 0;
316da2e3ebdSchin 			if(jp && WIFSTOPPED(wstat))
317da2e3ebdSchin 			{
318da2e3ebdSchin 				jp->exitval = SH_STOPSIG;
319da2e3ebdSchin 				continue;
320da2e3ebdSchin 			}
321da2e3ebdSchin 		}
322da2e3ebdSchin #ifdef SIGTSTP
323da2e3ebdSchin 		else
324da2e3ebdSchin 			px=job_byjid(pw->p_job);
325da2e3ebdSchin 		if(WIFSTOPPED(wstat))
326da2e3ebdSchin 		{
327da2e3ebdSchin 			if(px)
328da2e3ebdSchin 			{
329da2e3ebdSchin 				/* move to top of job list */
330da2e3ebdSchin 				job_unlink(px);
331da2e3ebdSchin 				px->p_nxtjob = job.pwlist;
332da2e3ebdSchin 				job.pwlist = px;
333da2e3ebdSchin 			}
334da2e3ebdSchin 			pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
3357c2fbfb3SApril Chin 			pw->p_exit = WSTOPSIG(wstat);
336da2e3ebdSchin 			if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
337da2e3ebdSchin 				sh_fault(pw->p_exit);
338da2e3ebdSchin 			continue;
339da2e3ebdSchin 		}
340da2e3ebdSchin 		else if (WIFCONTINUED(wstat) && wcontinued)
341da2e3ebdSchin 			pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED);
342da2e3ebdSchin 		else
343da2e3ebdSchin #endif /* SIGTSTP */
344da2e3ebdSchin 		{
345da2e3ebdSchin 			/* check for coprocess completion */
346da2e3ebdSchin 			if(pid==sh.cpid)
347da2e3ebdSchin 			{
348da2e3ebdSchin 				sh_close(sh.coutpipe);
349da2e3ebdSchin 				sh_close(sh.cpipe[1]);
350da2e3ebdSchin 				sh.cpipe[1] = -1;
351da2e3ebdSchin 				sh.coutpipe = -1;
352da2e3ebdSchin 			}
3537c2fbfb3SApril Chin 			else if(sh.subshell)
3547c2fbfb3SApril Chin 				sh_subjobcheck(pid);
3557c2fbfb3SApril Chin 
3567c2fbfb3SApril Chin 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
357da2e3ebdSchin 			if (WIFSIGNALED(wstat))
358da2e3ebdSchin 			{
359da2e3ebdSchin 				pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
360da2e3ebdSchin 				if (WTERMCORE(wstat))
361da2e3ebdSchin 					pw->p_flag |= P_COREDUMP;
362da2e3ebdSchin 				pw->p_exit = WTERMSIG(wstat);
363da2e3ebdSchin 				/* if process in current jobs terminates from
364da2e3ebdSchin 				 * an interrupt, propogate to parent shell
365da2e3ebdSchin 				 */
366da2e3ebdSchin 				if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
367da2e3ebdSchin 				{
368da2e3ebdSchin 					pw->p_flag &= ~P_NOTIFY;
369da2e3ebdSchin 					sh_offstate(SH_STOPOK);
370da2e3ebdSchin 					sh_fault(SIGINT);
371da2e3ebdSchin 					sh_onstate(SH_STOPOK);
372da2e3ebdSchin 				}
373da2e3ebdSchin 			}
374da2e3ebdSchin 			else
375da2e3ebdSchin 			{
376da2e3ebdSchin 				pw->p_flag |= (P_DONE|P_NOTIFY);
3777c2fbfb3SApril Chin 				pw->p_exit =  pw->p_exitmin;
3787c2fbfb3SApril Chin 				if(WEXITSTATUS(wstat) > pw->p_exitmin)
379da2e3ebdSchin 					pw->p_exit = WEXITSTATUS(wstat);
380da2e3ebdSchin 			}
38134f9b3eeSRoland Mainz #ifdef SHOPT_BGX
38234f9b3eeSRoland Mainz 			if((pw->p_flag&P_DONE) && (pw->p_flag&P_BG))
38334f9b3eeSRoland Mainz 			{
38434f9b3eeSRoland Mainz 				job.numbjob--;
38534f9b3eeSRoland Mainz 				if(sh.st.trapcom[SIGCHLD])
38634f9b3eeSRoland Mainz 				{
38734f9b3eeSRoland Mainz 					sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
38834f9b3eeSRoland Mainz 					if(sig==0)
38934f9b3eeSRoland Mainz 						job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],0);
39034f9b3eeSRoland Mainz 					else
39134f9b3eeSRoland Mainz 						sh.trapnote |= SH_SIGTRAP;
39234f9b3eeSRoland Mainz 				}
39334f9b3eeSRoland Mainz 				else
39434f9b3eeSRoland Mainz 					pw->p_flag &= ~P_BG;
39534f9b3eeSRoland Mainz 			}
39634f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
397da2e3ebdSchin 			if(pw->p_pgrp==0)
398da2e3ebdSchin 				pw->p_flag &= ~P_NOTIFY;
399da2e3ebdSchin 		}
400da2e3ebdSchin 		if(jp && pw== &dummy)
401da2e3ebdSchin 		{
402da2e3ebdSchin 			jp->exitval = pw->p_exit;
403da2e3ebdSchin 			if(pw->p_flag&P_SIGNALLED)
404da2e3ebdSchin 				jp->exitval |= SH_EXITSIG;
405da2e3ebdSchin 		}
406da2e3ebdSchin #ifdef DEBUG
407da2e3ebdSchin 		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);
408da2e3ebdSchin 		sfsync(sfstderr);
409da2e3ebdSchin #endif /* DEBUG*/
410da2e3ebdSchin 		/* only top-level process in job should have notify set */
411da2e3ebdSchin 		if(px && pw != px)
412da2e3ebdSchin 			pw->p_flag &= ~P_NOTIFY;
4137c2fbfb3SApril Chin 		if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY))
4147c2fbfb3SApril Chin 		{
4157c2fbfb3SApril Chin 			px = job_byjid((int)pw->p_job);
4167c2fbfb3SApril Chin 			for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc);
4177c2fbfb3SApril Chin 			if(!px)
4187c2fbfb3SApril Chin 				tcsetpgrp(JOBTTY,job.mypid);
4197c2fbfb3SApril Chin 		}
42034f9b3eeSRoland Mainz #ifndef SHOPT_BGX
4217c2fbfb3SApril Chin 		if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid)))
4227c2fbfb3SApril Chin 		{
4237c2fbfb3SApril Chin 			sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
4247c2fbfb3SApril Chin 			sh.trapnote |= SH_SIGTRAP;
4257c2fbfb3SApril Chin 		}
42634f9b3eeSRoland Mainz #endif
427da2e3ebdSchin 	}
428da2e3ebdSchin 	if(errno==ECHILD)
429da2e3ebdSchin 	{
430da2e3ebdSchin 		errno = oerrno;
43134f9b3eeSRoland Mainz #ifdef SHOPT_BGX
43234f9b3eeSRoland Mainz 		job.numbjob = 0;
43334f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
434da2e3ebdSchin 		nochild = 1;
435da2e3ebdSchin 	}
436da2e3ebdSchin 	sh.waitevent = waitevent;
437da2e3ebdSchin 	if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
438da2e3ebdSchin 	{
439da2e3ebdSchin 		outfile = sfstderr;
440da2e3ebdSchin 		job_list(pw,JOB_NFLAG|JOB_NLFLAG);
441da2e3ebdSchin 		job_unpost(pw,1);
442da2e3ebdSchin 		sfsync(sfstderr);
443da2e3ebdSchin 	}
444da2e3ebdSchin 	if(sig)
445da2e3ebdSchin 		signal(sig, job_waitsafe);
446da2e3ebdSchin 	return(nochild);
447da2e3ebdSchin }
448da2e3ebdSchin 
449da2e3ebdSchin /*
450da2e3ebdSchin  * This is the SIGCLD interrupt routine
451da2e3ebdSchin  */
job_waitsafe(int sig)452da2e3ebdSchin static void job_waitsafe(int sig)
453da2e3ebdSchin {
4547c2fbfb3SApril Chin 	if(job.in_critical || vmbusy())
455da2e3ebdSchin 	{
456da2e3ebdSchin 		job.savesig = sig;
457da2e3ebdSchin 		job.waitsafe++;
458da2e3ebdSchin 	}
459da2e3ebdSchin 	else
460da2e3ebdSchin 		job_reap(sig);
461da2e3ebdSchin }
462da2e3ebdSchin 
463da2e3ebdSchin /*
464da2e3ebdSchin  * initialize job control if possible
465da2e3ebdSchin  * if lflag is set the switching driver message will not print
466da2e3ebdSchin  */
job_init(Shell_t * shp,int lflag)4677c2fbfb3SApril Chin void job_init(Shell_t *shp, int lflag)
468da2e3ebdSchin {
4697c2fbfb3SApril Chin 	register int ntry=0;
470da2e3ebdSchin 	job.fd = JOBTTY;
471da2e3ebdSchin 	signal(SIGCHLD,job_waitsafe);
472da2e3ebdSchin #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
473da2e3ebdSchin 	signal(SIGCLD,job_waitsafe);
474da2e3ebdSchin #   endif
475da2e3ebdSchin 	if(njob_savelist < NJOB_SAVELIST)
476da2e3ebdSchin 		init_savelist();
477da2e3ebdSchin 	if(!sh_isoption(SH_INTERACTIVE))
478da2e3ebdSchin 		return;
479da2e3ebdSchin 	/* use new line discipline when available */
480da2e3ebdSchin #ifdef NTTYDISC
481da2e3ebdSchin #   ifdef FIOLOOKLD
482da2e3ebdSchin 	if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
483da2e3ebdSchin #   else
484da2e3ebdSchin 	if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
485da2e3ebdSchin #   endif /* FIOLOOKLD */
486da2e3ebdSchin 		return;
487da2e3ebdSchin 	if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
488da2e3ebdSchin 	{
489da2e3ebdSchin 		/* no job control when running with MPX */
490da2e3ebdSchin #   if SHOPT_VSH
491da2e3ebdSchin 		sh_onoption(SH_VIRAW);
492da2e3ebdSchin #   endif /* SHOPT_VSH */
493da2e3ebdSchin 		return;
494da2e3ebdSchin 	}
495da2e3ebdSchin 	if(job.linedisc==NTTYDISC)
496da2e3ebdSchin 		job.linedisc = -1;
497da2e3ebdSchin #endif /* NTTYDISC */
498da2e3ebdSchin 
499da2e3ebdSchin 	job.mypgid = getpgrp();
500da2e3ebdSchin 	/* some systems have job control, but not initialized */
501da2e3ebdSchin 	if(job.mypgid<=0)
502da2e3ebdSchin         {
503da2e3ebdSchin 		/* Get a controlling terminal and set process group */
504da2e3ebdSchin 		/* This should have already been done by rlogin */
505da2e3ebdSchin                 register int fd;
506da2e3ebdSchin                 register char *ttynam;
507da2e3ebdSchin #ifndef SIGTSTP
5087c2fbfb3SApril Chin                 setpgid(0,shp->pid);
509da2e3ebdSchin #endif /*SIGTSTP */
510da2e3ebdSchin                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
511da2e3ebdSchin                         return;
512da2e3ebdSchin                 close(JOBTTY);
513da2e3ebdSchin                 if((fd = open(ttynam,O_RDWR)) <0)
514da2e3ebdSchin                         return;
515da2e3ebdSchin                 if(fd!=JOBTTY)
5167c2fbfb3SApril Chin                         sh_iorenumber(shp,fd,JOBTTY);
5177c2fbfb3SApril Chin                 job.mypgid = shp->pid;
518da2e3ebdSchin #ifdef SIGTSTP
5197c2fbfb3SApril Chin                 tcsetpgrp(JOBTTY,shp->pid);
5207c2fbfb3SApril Chin                 setpgid(0,shp->pid);
521da2e3ebdSchin #endif /* SIGTSTP */
522da2e3ebdSchin         }
523da2e3ebdSchin #ifdef SIGTSTP
524da2e3ebdSchin 	if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
525da2e3ebdSchin 	{
526da2e3ebdSchin 		/* wait until we are in the foreground */
527da2e3ebdSchin 		while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
528da2e3ebdSchin 		{
529da2e3ebdSchin 			if(job.mytgid == -1)
530da2e3ebdSchin 				return;
531da2e3ebdSchin 			/* Stop this shell until continued */
532da2e3ebdSchin 			signal(SIGTTIN,SIG_DFL);
5337c2fbfb3SApril Chin 			kill(shp->pid,SIGTTIN);
534da2e3ebdSchin 			/* resumes here after continue tries again */
535da2e3ebdSchin 			if(ntry++ > IOMAXTRY)
536da2e3ebdSchin 			{
537da2e3ebdSchin 				errormsg(SH_DICT,0,e_no_start);
538da2e3ebdSchin 				return;
539da2e3ebdSchin 			}
540da2e3ebdSchin 		}
541da2e3ebdSchin 	}
542da2e3ebdSchin #endif /* SIGTTIN */
543da2e3ebdSchin 
544da2e3ebdSchin #ifdef NTTYDISC
545da2e3ebdSchin 	/* set the line discipline */
546da2e3ebdSchin 	if(job.linedisc>=0)
547da2e3ebdSchin 	{
548da2e3ebdSchin 		int linedisc = NTTYDISC;
549da2e3ebdSchin #   ifdef FIOPUSHLD
550da2e3ebdSchin 		tty_get(JOBTTY,&my_stty);
551da2e3ebdSchin 		if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
552da2e3ebdSchin 			return;
553da2e3ebdSchin 		if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
554da2e3ebdSchin 		{
555da2e3ebdSchin 			ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
556da2e3ebdSchin 			return;
557da2e3ebdSchin 		}
558da2e3ebdSchin 		tty_set(JOBTTY,TCSANOW,&my_stty);
559da2e3ebdSchin #   else
560da2e3ebdSchin 		if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
561da2e3ebdSchin 			return;
562da2e3ebdSchin #   endif /* FIOPUSHLD */
563da2e3ebdSchin 		if(lflag==0)
564da2e3ebdSchin 			errormsg(SH_DICT,0,e_newtty);
565da2e3ebdSchin 		else
566da2e3ebdSchin 			job.linedisc = -1;
567da2e3ebdSchin 	}
568da2e3ebdSchin #endif /* NTTYDISC */
569da2e3ebdSchin 	if(!possible)
570da2e3ebdSchin 		return;
571da2e3ebdSchin 
572da2e3ebdSchin #ifdef SIGTSTP
573da2e3ebdSchin 	/* make sure that we are a process group leader */
5747c2fbfb3SApril Chin 	setpgid(0,shp->pid);
575*3e14f97fSRoger A. Faulkner #   if defined(SA_NOCLDSTOP) || defined(SA_NOCLDWAIT)
576*3e14f97fSRoger A. Faulkner #   	if !defined(SA_NOCLDSTOP)
577*3e14f97fSRoger A. Faulkner #	    define SA_NOCLDSTOP	0
578*3e14f97fSRoger A. Faulkner #   	endif
579*3e14f97fSRoger A. Faulkner #   	if !defined(SA_NOCLDWAIT)
580*3e14f97fSRoger A. Faulkner #	    define SA_NOCLDWAIT	0
581*3e14f97fSRoger A. Faulkner #   	endif
582da2e3ebdSchin 	sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
583*3e14f97fSRoger A. Faulkner #   endif /* SA_NOCLDSTOP || SA_NOCLDWAIT */
584da2e3ebdSchin 	signal(SIGTTIN,SIG_IGN);
585da2e3ebdSchin 	signal(SIGTTOU,SIG_IGN);
586da2e3ebdSchin 	/* The shell now handles ^Z */
587da2e3ebdSchin 	signal(SIGTSTP,sh_fault);
5887c2fbfb3SApril Chin 	tcsetpgrp(JOBTTY,shp->pid);
589da2e3ebdSchin #   ifdef CNSUSP
590da2e3ebdSchin 	/* set the switch character */
591da2e3ebdSchin 	tty_get(JOBTTY,&my_stty);
592da2e3ebdSchin 	job.suspend = (unsigned)my_stty.c_cc[VSUSP];
593da2e3ebdSchin 	if(job.suspend == (unsigned char)CNSUSP)
594da2e3ebdSchin 	{
595da2e3ebdSchin 		my_stty.c_cc[VSUSP] = CSWTCH;
596da2e3ebdSchin 		tty_set(JOBTTY,TCSAFLUSH,&my_stty);
597da2e3ebdSchin 	}
598da2e3ebdSchin #   endif /* CNSUSP */
599da2e3ebdSchin 	sh_onoption(SH_MONITOR);
600da2e3ebdSchin 	job.jobcontrol++;
6017c2fbfb3SApril Chin 	job.mypid = shp->pid;
602da2e3ebdSchin #endif /* SIGTSTP */
603da2e3ebdSchin 	return;
604da2e3ebdSchin }
605da2e3ebdSchin 
606da2e3ebdSchin 
607da2e3ebdSchin /*
608da2e3ebdSchin  * see if there are any stopped jobs
609da2e3ebdSchin  * restore tty driver and pgrp
610da2e3ebdSchin  */
job_close(Shell_t * shp)6117c2fbfb3SApril Chin int job_close(Shell_t* shp)
612da2e3ebdSchin {
613da2e3ebdSchin 	register struct process *pw;
614da2e3ebdSchin 	register int count = 0, running = 0;
615da2e3ebdSchin 	if(possible && !job.jobcontrol)
616da2e3ebdSchin 		return(0);
617da2e3ebdSchin 	else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
618da2e3ebdSchin 		return(0);
619da2e3ebdSchin 	else if(getpid() != job.mypid)
620da2e3ebdSchin 		return(0);
621da2e3ebdSchin 	job_lock();
622da2e3ebdSchin 	if(!tty_check(0))
623da2e3ebdSchin 		beenhere++;
624da2e3ebdSchin 	for(pw=job.pwlist;pw;pw=pw->p_nxtjob)
625da2e3ebdSchin 	{
626da2e3ebdSchin 		if(!(pw->p_flag&P_STOPPED))
627da2e3ebdSchin 		{
628da2e3ebdSchin 			if(!(pw->p_flag&P_DONE))
629da2e3ebdSchin 				running++;
630da2e3ebdSchin 			continue;
631da2e3ebdSchin 		}
632da2e3ebdSchin 		if(beenhere)
633da2e3ebdSchin 			killpg(pw->p_pgrp,SIGTERM);
634da2e3ebdSchin 		count++;
635da2e3ebdSchin 	}
636da2e3ebdSchin 	if(beenhere++ == 0 && job.pwlist)
637da2e3ebdSchin 	{
638da2e3ebdSchin 		if(count)
639da2e3ebdSchin 		{
640da2e3ebdSchin 			errormsg(SH_DICT,0,e_terminate);
641da2e3ebdSchin 			return(-1);
642da2e3ebdSchin 		}
6437c2fbfb3SApril Chin 		else if(running && shp->login_sh)
644da2e3ebdSchin 		{
645da2e3ebdSchin 			errormsg(SH_DICT,0,e_jobsrunning);
646da2e3ebdSchin 			return(-1);
647da2e3ebdSchin 		}
648da2e3ebdSchin 	}
649da2e3ebdSchin 	job_unlock();
650da2e3ebdSchin #   ifdef SIGTSTP
651da2e3ebdSchin 	if(possible && setpgid(0,job.mypgid)>=0)
652da2e3ebdSchin 		tcsetpgrp(job.fd,job.mypgid);
653da2e3ebdSchin #   endif /* SIGTSTP */
654da2e3ebdSchin #   ifdef NTTYDISC
655da2e3ebdSchin 	if(job.linedisc>=0)
656da2e3ebdSchin 	{
657da2e3ebdSchin 		/* restore old line discipline */
658da2e3ebdSchin #	ifdef FIOPUSHLD
659da2e3ebdSchin 		tty_get(job.fd,&my_stty);
660da2e3ebdSchin 		if (ioctl(job.fd, FIOPOPLD, 0) < 0)
661da2e3ebdSchin 			return(0);
662da2e3ebdSchin 		if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
663da2e3ebdSchin 		{
664da2e3ebdSchin 			job.linedisc = NTTYDISC;
665da2e3ebdSchin 			ioctl(job.fd, FIOPUSHLD, &job.linedisc);
666da2e3ebdSchin 			return(0);
667da2e3ebdSchin 		}
668da2e3ebdSchin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
669da2e3ebdSchin #	else
670da2e3ebdSchin 		if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
671da2e3ebdSchin 			return(0);
672da2e3ebdSchin #	endif /* FIOPUSHLD */
673da2e3ebdSchin 		errormsg(SH_DICT,0,e_oldtty);
674da2e3ebdSchin 	}
675da2e3ebdSchin #   endif /* NTTYDISC */
676da2e3ebdSchin #   ifdef CNSUSP
677da2e3ebdSchin 	if(possible && job.suspend==CNSUSP)
678da2e3ebdSchin 	{
679da2e3ebdSchin 		tty_get(job.fd,&my_stty);
680da2e3ebdSchin 		my_stty.c_cc[VSUSP] = CNSUSP;
681da2e3ebdSchin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
682da2e3ebdSchin 	}
683da2e3ebdSchin #   endif /* CNSUSP */
684da2e3ebdSchin 	job.jobcontrol = 0;
685da2e3ebdSchin 	return(0);
686da2e3ebdSchin }
687da2e3ebdSchin 
job_set(register struct process * pw)688da2e3ebdSchin static void job_set(register struct process *pw)
689da2e3ebdSchin {
690da2e3ebdSchin 	/* save current terminal state */
691da2e3ebdSchin 	tty_get(job.fd,&my_stty);
692da2e3ebdSchin 	if(pw->p_flag&P_STTY)
693da2e3ebdSchin 	{
694da2e3ebdSchin 		/* restore terminal state for job */
695da2e3ebdSchin 		tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
696da2e3ebdSchin 	}
697da2e3ebdSchin #ifdef SIGTSTP
698da2e3ebdSchin 	if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid)
699da2e3ebdSchin 		tcsetpgrp(job.fd,pw->p_fgrp);
700da2e3ebdSchin 	/* if job is stopped, resume it in the background */
701da2e3ebdSchin 	job_unstop(pw);
702da2e3ebdSchin #endif	/* SIGTSTP */
703da2e3ebdSchin }
704da2e3ebdSchin 
job_reset(register struct process * pw)705da2e3ebdSchin static void job_reset(register struct process *pw)
706da2e3ebdSchin {
707da2e3ebdSchin 	/* save the terminal state for current job */
708da2e3ebdSchin #ifdef SIGTSTP
709da2e3ebdSchin 	job_fgrp(pw,tcgetpgrp(job.fd));
7107c2fbfb3SApril Chin 	if(tcsetpgrp(job.fd,job.mypid) !=0)
711da2e3ebdSchin 		return;
712da2e3ebdSchin #endif	/* SIGTSTP */
713da2e3ebdSchin 	/* force the following tty_get() to do a tcgetattr() unless fg */
714da2e3ebdSchin 	if(!(pw->p_flag&P_FG))
715da2e3ebdSchin 		tty_set(-1, 0, NIL(struct termios*));
716da2e3ebdSchin 	if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
717da2e3ebdSchin 	{
718da2e3ebdSchin 		if(tty_get(job.fd,&pw->p_stty) == 0)
719da2e3ebdSchin 			pw->p_flag |= P_STTY;
720da2e3ebdSchin 		/* restore terminal state for job */
721da2e3ebdSchin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
722da2e3ebdSchin 	}
723da2e3ebdSchin 	beenhere = 0;
724da2e3ebdSchin }
725da2e3ebdSchin #endif /* JOBS */
726da2e3ebdSchin 
727da2e3ebdSchin /*
728da2e3ebdSchin  * wait built-in command
729da2e3ebdSchin  */
730da2e3ebdSchin 
job_bwait(char ** jobs)731da2e3ebdSchin void job_bwait(char **jobs)
732da2e3ebdSchin {
733da2e3ebdSchin 	register char *jp;
734da2e3ebdSchin 	register struct process *pw;
735da2e3ebdSchin 	register pid_t pid;
736da2e3ebdSchin 	if(*jobs==0)
737da2e3ebdSchin 		job_wait((pid_t)-1);
738da2e3ebdSchin 	else while(jp = *jobs++)
739da2e3ebdSchin 	{
740da2e3ebdSchin #ifdef JOBS
741da2e3ebdSchin 		if(*jp == '%')
742da2e3ebdSchin 		{
743da2e3ebdSchin 			job_lock();
744da2e3ebdSchin 			pw = job_bystring(jp);
745da2e3ebdSchin 			job_unlock();
746da2e3ebdSchin 			if(pw)
747da2e3ebdSchin 				pid = pw->p_pid;
748da2e3ebdSchin 			else
749da2e3ebdSchin 				return;
750da2e3ebdSchin 		}
751da2e3ebdSchin 		else
752da2e3ebdSchin #endif /* JOBS */
753da2e3ebdSchin 			pid = (int)strtol(jp, (char**)0, 10);
754da2e3ebdSchin 		job_wait(-pid);
755da2e3ebdSchin 	}
756da2e3ebdSchin }
757da2e3ebdSchin 
758da2e3ebdSchin #ifdef JOBS
759da2e3ebdSchin /*
760da2e3ebdSchin  * execute function <fun> for each job
761da2e3ebdSchin  */
762da2e3ebdSchin 
job_walk(Sfio_t * file,int (* fun)(struct process *,int),int arg,char * joblist[])763da2e3ebdSchin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[])
764da2e3ebdSchin {
765da2e3ebdSchin 	register struct process *pw;
766da2e3ebdSchin 	register int r = 0;
767da2e3ebdSchin 	register char *jobid, **jobs=joblist;
768da2e3ebdSchin 	register struct process *px;
769da2e3ebdSchin 	job_string = 0;
770da2e3ebdSchin 	outfile = file;
771da2e3ebdSchin 	by_number = 0;
772da2e3ebdSchin 	job_lock();
773da2e3ebdSchin 	pw = job.pwlist;
774da2e3ebdSchin 	if(jobs==0)
775da2e3ebdSchin 	{
776da2e3ebdSchin 		/* do all jobs */
777da2e3ebdSchin 		for(;pw;pw=px)
778da2e3ebdSchin 		{
779da2e3ebdSchin 			px = pw->p_nxtjob;
780da2e3ebdSchin 			if(pw->p_env != sh.jobenv)
781da2e3ebdSchin 				continue;
782da2e3ebdSchin 			if((*fun)(pw,arg))
783da2e3ebdSchin 				r = 2;
784da2e3ebdSchin 		}
785da2e3ebdSchin 	}
786da2e3ebdSchin 	else if(*jobs==0)	/* current job */
787da2e3ebdSchin 	{
788da2e3ebdSchin 		/* skip over non-stop jobs */
789da2e3ebdSchin 		while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0))
790da2e3ebdSchin 			pw = pw->p_nxtjob;
791da2e3ebdSchin 		if((*fun)(pw,arg))
792da2e3ebdSchin 			r = 2;
793da2e3ebdSchin 	}
794da2e3ebdSchin 	else while(jobid = *jobs++)
795da2e3ebdSchin 	{
796da2e3ebdSchin 		job_string = jobid;
797da2e3ebdSchin 		if(*jobid==0)
798da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
799da2e3ebdSchin 		if(*jobid == '%')
800da2e3ebdSchin 			pw = job_bystring(jobid);
801da2e3ebdSchin 		else
802da2e3ebdSchin 		{
803da2e3ebdSchin 			int pid = (int)strtol(jobid, (char**)0, 10);
804da2e3ebdSchin 			if(pid<0)
805da2e3ebdSchin 				jobid++;
806da2e3ebdSchin 			while(isdigit(*jobid))
807da2e3ebdSchin 				jobid++;
808da2e3ebdSchin 			if(*jobid)
809da2e3ebdSchin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
810da2e3ebdSchin 			if(!(pw = job_bypid(pid)))
811da2e3ebdSchin 			{
812da2e3ebdSchin 				pw = &dummy;
813da2e3ebdSchin 				pw->p_pid = pid;
814da2e3ebdSchin 				pw->p_pgrp = pid;
815da2e3ebdSchin 			}
816da2e3ebdSchin 			by_number = 1;
817da2e3ebdSchin 		}
818da2e3ebdSchin 		if((*fun)(pw,arg))
819da2e3ebdSchin 			r = 2;
820da2e3ebdSchin 		by_number = 0;
821da2e3ebdSchin 	}
822da2e3ebdSchin 	job_unlock();
823da2e3ebdSchin 	return(r);
824da2e3ebdSchin }
825da2e3ebdSchin 
826da2e3ebdSchin /*
827da2e3ebdSchin  * send signal <sig> to background process group if not disowned
828da2e3ebdSchin  */
job_terminate(register struct process * pw,register int sig)829da2e3ebdSchin int job_terminate(register struct process *pw,register int sig)
830da2e3ebdSchin {
831da2e3ebdSchin 	if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
832da2e3ebdSchin 		job_kill(pw,sig);
833da2e3ebdSchin 	return(0);
834da2e3ebdSchin }
835da2e3ebdSchin 
836da2e3ebdSchin /*
837da2e3ebdSchin  * list the given job
838da2e3ebdSchin  * flag JOB_LFLAG for long listing
839da2e3ebdSchin  * flag JOB_NFLAG for list only jobs marked for notification
840da2e3ebdSchin  * flag JOB_PFLAG for process id(s) only
841da2e3ebdSchin  */
842da2e3ebdSchin 
job_list(struct process * pw,register int flag)843da2e3ebdSchin int job_list(struct process *pw,register int flag)
844da2e3ebdSchin {
845da2e3ebdSchin 	register struct process *px = pw;
846da2e3ebdSchin 	register int  n;
847da2e3ebdSchin 	register const char *msg;
848da2e3ebdSchin 	register int msize;
849da2e3ebdSchin 	if(!pw || pw->p_job<=0)
850da2e3ebdSchin 		return(1);
851da2e3ebdSchin 	if(pw->p_env != sh.jobenv)
852da2e3ebdSchin 		return(0);
853da2e3ebdSchin 	if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
854da2e3ebdSchin 		return(0);
855da2e3ebdSchin 	if((flag&JOB_PFLAG))
856da2e3ebdSchin 	{
857da2e3ebdSchin 		sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid);
858da2e3ebdSchin 		return(0);
859da2e3ebdSchin 	}
860da2e3ebdSchin 	if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
861da2e3ebdSchin 		return(0);
862da2e3ebdSchin 	job_lock();
863da2e3ebdSchin 	n = px->p_job;
864da2e3ebdSchin 	if(px==job.pwlist)
865da2e3ebdSchin 		msize = '+';
866da2e3ebdSchin 	else if(px==job.pwlist->p_nxtjob)
867da2e3ebdSchin 		msize = '-';
868da2e3ebdSchin 	else
869da2e3ebdSchin 		msize = ' ';
870da2e3ebdSchin 	if(flag&JOB_NLFLAG)
871da2e3ebdSchin 		sfputc(outfile,'\n');
872da2e3ebdSchin 	sfprintf(outfile,"[%d] %c ",n, msize);
873da2e3ebdSchin 	do
874da2e3ebdSchin 	{
875da2e3ebdSchin 		n = 0;
876da2e3ebdSchin 		if(flag&JOB_LFLAG)
877da2e3ebdSchin 			sfprintf(outfile,"%d\t",px->p_pid);
878da2e3ebdSchin 		if(px->p_flag&P_SIGNALLED)
879da2e3ebdSchin 			msg = job_sigmsg((int)(px->p_exit));
880da2e3ebdSchin 		else if(px->p_flag&P_NOTIFY)
881da2e3ebdSchin 		{
882da2e3ebdSchin 			msg = sh_translate(e_done);
883da2e3ebdSchin 			n = px->p_exit;
884da2e3ebdSchin 		}
885da2e3ebdSchin 		else
886da2e3ebdSchin 			msg = sh_translate(e_running);
887da2e3ebdSchin 		px->p_flag &= ~P_NOTIFY;
888da2e3ebdSchin 		sfputr(outfile,msg,-1);
889da2e3ebdSchin 		msize = strlen(msg);
890da2e3ebdSchin 		if(n)
891da2e3ebdSchin 		{
892da2e3ebdSchin 			sfprintf(outfile,"(%d)",(int)n);
893da2e3ebdSchin 			msize += (3+(n>10)+(n>100));
894da2e3ebdSchin 		}
895da2e3ebdSchin 		if(px->p_flag&P_COREDUMP)
896da2e3ebdSchin 		{
897da2e3ebdSchin 			msg = sh_translate(e_coredump);
898da2e3ebdSchin 			sfputr(outfile, msg, -1);
899da2e3ebdSchin 			msize += strlen(msg);
900da2e3ebdSchin 		}
901da2e3ebdSchin 		sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
902da2e3ebdSchin 		if(flag&JOB_LFLAG)
903da2e3ebdSchin 			px = px->p_nxtproc;
904da2e3ebdSchin 		else
905da2e3ebdSchin 		{
906da2e3ebdSchin 			while(px=px->p_nxtproc)
907da2e3ebdSchin 				px->p_flag &= ~P_NOTIFY;
908da2e3ebdSchin 			px = 0;
909da2e3ebdSchin 		}
910da2e3ebdSchin 		if(!px)
911da2e3ebdSchin 			hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
912da2e3ebdSchin 		else
913da2e3ebdSchin 			sfputr(outfile, e_nlspace, -1);
914da2e3ebdSchin 	}
915da2e3ebdSchin 	while(px);
916da2e3ebdSchin 	job_unlock();
917da2e3ebdSchin 	return(0);
918da2e3ebdSchin }
919da2e3ebdSchin 
920da2e3ebdSchin /*
921da2e3ebdSchin  * get the process group given the job number
922da2e3ebdSchin  * This routine returns the process group number or -1
923da2e3ebdSchin  */
job_bystring(register char * ajob)924da2e3ebdSchin static struct process *job_bystring(register char *ajob)
925da2e3ebdSchin {
926da2e3ebdSchin 	register struct process *pw=job.pwlist;
927da2e3ebdSchin 	register int c;
928da2e3ebdSchin 	if(*ajob++ != '%' || !pw)
929da2e3ebdSchin 		return(NIL(struct process*));
930da2e3ebdSchin 	c = *ajob;
931da2e3ebdSchin 	if(isdigit(c))
932da2e3ebdSchin 		pw = job_byjid((int)strtol(ajob, (char**)0, 10));
933da2e3ebdSchin 	else if(c=='+' || c=='%')
934da2e3ebdSchin 		;
935da2e3ebdSchin 	else if(c=='-')
936da2e3ebdSchin 	{
937da2e3ebdSchin 		if(pw)
938da2e3ebdSchin 			pw = job.pwlist->p_nxtjob;
939da2e3ebdSchin 	}
940da2e3ebdSchin 	else
941da2e3ebdSchin 		pw = job_byname(ajob);
942da2e3ebdSchin 	if(pw && pw->p_flag)
943da2e3ebdSchin 		return(pw);
944da2e3ebdSchin 	return(NIL(struct process*));
945da2e3ebdSchin }
946da2e3ebdSchin 
947da2e3ebdSchin /*
948da2e3ebdSchin  * Kill a job or process
949da2e3ebdSchin  */
950da2e3ebdSchin 
job_kill(register struct process * pw,register int sig)951da2e3ebdSchin int job_kill(register struct process *pw,register int sig)
952da2e3ebdSchin {
953da2e3ebdSchin 	register pid_t pid;
954da2e3ebdSchin 	register int r;
955da2e3ebdSchin 	const char *msg;
956da2e3ebdSchin #ifdef SIGTSTP
957da2e3ebdSchin 	int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
958da2e3ebdSchin #else
959da2e3ebdSchin #	define stopsig	1
960da2e3ebdSchin #endif	/* SIGTSTP */
961da2e3ebdSchin 	job_lock();
962da2e3ebdSchin 	errno = ECHILD;
963da2e3ebdSchin 	if(pw==0)
964da2e3ebdSchin 		goto error;
965da2e3ebdSchin 	pid = pw->p_pid;
966da2e3ebdSchin 	if(by_number)
967da2e3ebdSchin 	{
968da2e3ebdSchin 		if(pid==0 && job.jobcontrol)
969da2e3ebdSchin 			r = job_walk(outfile, job_kill,sig, (char**)0);
970da2e3ebdSchin #ifdef SIGTSTP
971da2e3ebdSchin 		if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
972da2e3ebdSchin 		{
973da2e3ebdSchin 			/* can't stop login shell */
974da2e3ebdSchin 			errno = EPERM;
975da2e3ebdSchin 			r = -1;
976da2e3ebdSchin 		}
977da2e3ebdSchin 		else
978da2e3ebdSchin 		{
979da2e3ebdSchin 			if(pid>=0)
980da2e3ebdSchin 			{
981da2e3ebdSchin 				if((r = kill(pid,sig))>=0 && !stopsig)
982da2e3ebdSchin 				{
983da2e3ebdSchin 					if(pw->p_flag&P_STOPPED)
984da2e3ebdSchin 						pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
985da2e3ebdSchin 					if(sig)
986da2e3ebdSchin 						kill(pid,SIGCONT);
987da2e3ebdSchin 				}
988da2e3ebdSchin 			}
989da2e3ebdSchin 			else
990da2e3ebdSchin 			{
991da2e3ebdSchin 				if((r = killpg(-pid,sig))>=0 && !stopsig)
992da2e3ebdSchin 				{
993da2e3ebdSchin 					job_unstop(job_bypid(pw->p_pid));
994da2e3ebdSchin 					if(sig)
995da2e3ebdSchin 						killpg(-pid,SIGCONT);
996da2e3ebdSchin 				}
997da2e3ebdSchin 			}
998da2e3ebdSchin 		}
999da2e3ebdSchin #else
1000da2e3ebdSchin 		if(pid>=0)
1001da2e3ebdSchin 			r = kill(pid,sig);
1002da2e3ebdSchin 		else
1003da2e3ebdSchin 			r = killpg(-pid,sig);
1004da2e3ebdSchin #endif	/* SIGTSTP */
1005da2e3ebdSchin 	}
1006da2e3ebdSchin 	else
1007da2e3ebdSchin 	{
1008da2e3ebdSchin 		if(pid = pw->p_pgrp)
1009da2e3ebdSchin 		{
1010da2e3ebdSchin 			r = killpg(pid,sig);
1011da2e3ebdSchin #ifdef SIGTSTP
1012da2e3ebdSchin 			if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT))
1013da2e3ebdSchin 				job_unstop(pw);
1014da2e3ebdSchin #endif	/* SIGTSTP */
1015da2e3ebdSchin 			if(r>=0)
1016da2e3ebdSchin 				sh_delay(.05);
1017da2e3ebdSchin 		}
1018da2e3ebdSchin 		while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0)
1019da2e3ebdSchin 		{
1020da2e3ebdSchin #ifdef SIGTSTP
1021da2e3ebdSchin 			if(sig==SIGHUP || sig==SIGTERM)
1022da2e3ebdSchin 				kill(pw->p_pid,SIGCONT);
1023da2e3ebdSchin #endif	/* SIGTSTP */
1024da2e3ebdSchin 			pw = pw->p_nxtproc;
1025da2e3ebdSchin 		}
1026da2e3ebdSchin 	}
1027da2e3ebdSchin 	if(r<0 && job_string)
1028da2e3ebdSchin 	{
1029da2e3ebdSchin 	error:
1030da2e3ebdSchin 		if(pw && by_number)
1031da2e3ebdSchin 			msg = sh_translate(e_no_proc);
1032da2e3ebdSchin 		else
1033da2e3ebdSchin 			msg = sh_translate(e_no_job);
1034da2e3ebdSchin 		if(errno == EPERM)
1035da2e3ebdSchin 			msg = sh_translate(e_access);
1036da2e3ebdSchin 		sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg);
1037da2e3ebdSchin 		r = 2;
1038da2e3ebdSchin 	}
1039da2e3ebdSchin 	sh_delay(.001);
1040da2e3ebdSchin 	job_unlock();
1041da2e3ebdSchin 	return(r);
1042da2e3ebdSchin }
1043da2e3ebdSchin 
1044da2e3ebdSchin /*
1045da2e3ebdSchin  * Get process structure from first letters of jobname
1046da2e3ebdSchin  *
1047da2e3ebdSchin  */
1048da2e3ebdSchin 
job_byname(char * name)1049da2e3ebdSchin static struct process *job_byname(char *name)
1050da2e3ebdSchin {
1051da2e3ebdSchin 	register struct process *pw = job.pwlist;
1052da2e3ebdSchin 	register struct process *pz = 0;
1053da2e3ebdSchin 	register int *flag = 0;
1054da2e3ebdSchin 	register char *cp = name;
1055da2e3ebdSchin 	int offset;
1056da2e3ebdSchin 	if(!sh.hist_ptr)
1057da2e3ebdSchin 		return(NIL(struct process*));
1058da2e3ebdSchin 	if(*cp=='?')
1059da2e3ebdSchin 		cp++,flag= &offset;
1060da2e3ebdSchin 	for(;pw;pw=pw->p_nxtjob)
1061da2e3ebdSchin 	{
1062da2e3ebdSchin 		if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
1063da2e3ebdSchin 		{
1064da2e3ebdSchin 			if(pz)
1065da2e3ebdSchin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1);
1066da2e3ebdSchin 			pz = pw;
1067da2e3ebdSchin 		}
1068da2e3ebdSchin 	}
1069da2e3ebdSchin 	return(pz);
1070da2e3ebdSchin }
1071da2e3ebdSchin 
1072da2e3ebdSchin #else
1073da2e3ebdSchin #   define job_set(x)
1074da2e3ebdSchin #   define job_reset(x)
1075da2e3ebdSchin #endif /* JOBS */
1076da2e3ebdSchin 
1077da2e3ebdSchin 
1078da2e3ebdSchin 
1079da2e3ebdSchin /*
1080da2e3ebdSchin  * Initialize the process posting array
1081da2e3ebdSchin  */
1082da2e3ebdSchin 
job_clear(void)1083da2e3ebdSchin void	job_clear(void)
1084da2e3ebdSchin {
1085da2e3ebdSchin 	register struct process *pw, *px;
1086da2e3ebdSchin 	register struct process *pwnext;
1087da2e3ebdSchin 	register int j = BYTE(sh.lim.child_max);
1088da2e3ebdSchin 	register struct jobsave *jp,*jpnext;
1089da2e3ebdSchin 	job_lock();
1090da2e3ebdSchin 	for(pw=job.pwlist; pw; pw=pwnext)
1091da2e3ebdSchin 	{
1092da2e3ebdSchin 		pwnext = pw->p_nxtjob;
1093da2e3ebdSchin 		while(px=pw)
1094da2e3ebdSchin 		{
1095da2e3ebdSchin 			pw = pw->p_nxtproc;
1096da2e3ebdSchin 			free((void*)px);
1097da2e3ebdSchin 		}
1098da2e3ebdSchin 	}
1099da2e3ebdSchin 	for(jp=bck.list; jp;jp=jpnext)
1100da2e3ebdSchin 	{
1101da2e3ebdSchin 		jpnext = jp->next;
1102da2e3ebdSchin 		free((void*)jp);
1103da2e3ebdSchin 	}
1104da2e3ebdSchin 	bck.list = 0;
1105da2e3ebdSchin 	if(njob_savelist < NJOB_SAVELIST)
1106da2e3ebdSchin 		init_savelist();
1107da2e3ebdSchin 	job.pwlist = NIL(struct process*);
1108da2e3ebdSchin 	job.numpost=0;
110934f9b3eeSRoland Mainz #ifdef SHOPT_BGX
111034f9b3eeSRoland Mainz 	job.numbjob = 0;
111134f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
1112da2e3ebdSchin 	job.waitall = 0;
1113da2e3ebdSchin 	job.curpgid = 0;
1114da2e3ebdSchin 	job.toclear = 0;
1115da2e3ebdSchin 	if(!job.freejobs)
1116da2e3ebdSchin 		job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
1117da2e3ebdSchin 	while(j >=0)
1118da2e3ebdSchin 		job.freejobs[j--]  = 0;
1119da2e3ebdSchin 	job_unlock();
1120da2e3ebdSchin }
1121da2e3ebdSchin 
1122da2e3ebdSchin /*
1123da2e3ebdSchin  * put the process <pid> on the process list and return the job number
1124da2e3ebdSchin  * if non-zero, <join> is the process id of the job to join
1125da2e3ebdSchin  */
1126da2e3ebdSchin 
job_post(pid_t pid,pid_t join)1127da2e3ebdSchin int job_post(pid_t pid, pid_t join)
1128da2e3ebdSchin {
1129da2e3ebdSchin 	register struct process *pw;
1130da2e3ebdSchin 	register History_t *hp = sh.hist_ptr;
113134f9b3eeSRoland Mainz #ifdef SHOPT_BGX
113234f9b3eeSRoland Mainz 	int val,bg=0;
113334f9b3eeSRoland Mainz #else
11347c2fbfb3SApril Chin 	int val;
113534f9b3eeSRoland Mainz #endif
1136da2e3ebdSchin 	sh.jobenv = sh.curenv;
1137da2e3ebdSchin 	if(job.toclear)
1138da2e3ebdSchin 	{
1139da2e3ebdSchin 		job_clear();
1140da2e3ebdSchin 		return(0);
1141da2e3ebdSchin 	}
1142da2e3ebdSchin 	job_lock();
114334f9b3eeSRoland Mainz #ifdef SHOPT_BGX
114434f9b3eeSRoland Mainz 	if(join==1)
114534f9b3eeSRoland Mainz 	{
114634f9b3eeSRoland Mainz 		join = 0;
114734f9b3eeSRoland Mainz 		bg = P_BG;
114834f9b3eeSRoland Mainz 		job.numbjob++;
114934f9b3eeSRoland Mainz 	}
115034f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
115134f9b3eeSRoland Mainz 	if(njob_savelist < NJOB_SAVELIST)
115234f9b3eeSRoland Mainz 		init_savelist();
1153da2e3ebdSchin 	if(pw = job_bypid(pid))
1154da2e3ebdSchin 		job_unpost(pw,0);
1155da2e3ebdSchin 	if(join && (pw=job_bypid(join)))
1156da2e3ebdSchin 	{
1157da2e3ebdSchin 		/* if job to join is not first move it to front */
1158da2e3ebdSchin 		if((pw=job_byjid(pw->p_job)) != job.pwlist)
1159da2e3ebdSchin 		{
1160da2e3ebdSchin 			job_unlink(pw);
1161da2e3ebdSchin 			pw->p_nxtjob = job.pwlist;
1162da2e3ebdSchin 			job.pwlist = pw;
1163da2e3ebdSchin 		}
1164da2e3ebdSchin 	}
1165da2e3ebdSchin 	if(pw=freelist)
1166da2e3ebdSchin 		freelist = pw->p_nxtjob;
1167da2e3ebdSchin 	else
1168da2e3ebdSchin 		pw = new_of(struct process,0);
116934f9b3eeSRoland Mainz 	pw->p_flag = 0;
1170da2e3ebdSchin 	job.numpost++;
1171da2e3ebdSchin 	if(join && job.pwlist)
1172da2e3ebdSchin 	{
1173da2e3ebdSchin 		/* join existing current job */
1174da2e3ebdSchin 		pw->p_nxtjob = job.pwlist->p_nxtjob;
1175da2e3ebdSchin 		pw->p_nxtproc = job.pwlist;
1176da2e3ebdSchin 		pw->p_job = job.pwlist->p_job;
1177da2e3ebdSchin 	}
1178da2e3ebdSchin 	else
1179da2e3ebdSchin 	{
1180da2e3ebdSchin 		/* create a new job */
1181da2e3ebdSchin 		while((pw->p_job = job_alloc()) < 0)
1182da2e3ebdSchin 			job_wait((pid_t)1);
1183da2e3ebdSchin 		pw->p_nxtjob = job.pwlist;
1184da2e3ebdSchin 		pw->p_nxtproc = 0;
1185da2e3ebdSchin 	}
1186da2e3ebdSchin 	job.pwlist = pw;
1187da2e3ebdSchin 	pw->p_env = sh.curenv;
1188da2e3ebdSchin 	pw->p_pid = pid;
1189*3e14f97fSRoger A. Faulkner 	if(!sh.outpipe || (sh_isoption(SH_PIPEFAIL) && job.waitall))
1190da2e3ebdSchin 		pw->p_flag = P_EXITSAVE;
11917c2fbfb3SApril Chin 	pw->p_exitmin = sh.xargexit;
11927c2fbfb3SApril Chin 	pw->p_exit = 0;
1193da2e3ebdSchin 	if(sh_isstate(SH_MONITOR))
1194da2e3ebdSchin 	{
1195da2e3ebdSchin 		if(killpg(job.curpgid,0)<0 && errno==ESRCH)
1196da2e3ebdSchin 			job.curpgid = pid;
1197da2e3ebdSchin 		pw->p_fgrp = job.curpgid;
1198da2e3ebdSchin 	}
1199da2e3ebdSchin 	else
1200da2e3ebdSchin 		pw->p_fgrp = 0;
1201da2e3ebdSchin 	pw->p_pgrp = pw->p_fgrp;
1202da2e3ebdSchin #ifdef DEBUG
1203da2e3ebdSchin 	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,
1204da2e3ebdSchin 		pw->p_pid,pw->p_pgrp,job.savesig,join);
1205da2e3ebdSchin 	sfsync(sfstderr);
1206da2e3ebdSchin #endif /* DEBUG */
1207da2e3ebdSchin #ifdef JOBS
1208da2e3ebdSchin 	if(hp && !sh_isstate(SH_PROFILE))
1209da2e3ebdSchin 		pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
1210da2e3ebdSchin 	else
1211da2e3ebdSchin 		pw->p_name = -1;
1212da2e3ebdSchin #endif /* JOBS */
12137c2fbfb3SApril Chin 	if ((val = job_chksave(pid)) >= 0)
1214da2e3ebdSchin 	{
12157c2fbfb3SApril Chin 		pw->p_exit = val;
1216da2e3ebdSchin 		if(pw->p_exit==SH_STOPSIG)
1217da2e3ebdSchin 		{
1218da2e3ebdSchin 			pw->p_flag |= (P_SIGNALLED|P_STOPPED);
1219da2e3ebdSchin 			pw->p_exit = 0;
1220da2e3ebdSchin 		}
122134f9b3eeSRoland Mainz 		else if(pw->p_exit >= SH_EXITSIG)
122234f9b3eeSRoland Mainz 		{
122334f9b3eeSRoland Mainz 			pw->p_flag |= P_DONE|P_SIGNALLED;
122434f9b3eeSRoland Mainz 			pw->p_exit &= SH_EXITMASK;
122534f9b3eeSRoland Mainz 		}
1226da2e3ebdSchin 		else
1227da2e3ebdSchin 			pw->p_flag |= (P_DONE|P_NOTIFY);
1228da2e3ebdSchin 	}
122934f9b3eeSRoland Mainz #ifdef SHOPT_BGX
123034f9b3eeSRoland Mainz 	if(bg && !(pw->p_flag&P_DONE))
123134f9b3eeSRoland Mainz 		pw->p_flag |= P_BG;
123234f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
1233da2e3ebdSchin 	lastpid = 0;
1234da2e3ebdSchin 	job_unlock();
1235da2e3ebdSchin 	return(pw->p_job);
1236da2e3ebdSchin }
1237da2e3ebdSchin 
1238da2e3ebdSchin /*
1239da2e3ebdSchin  * Returns a process structure give a process id
1240da2e3ebdSchin  */
1241da2e3ebdSchin 
job_bypid(pid_t pid)1242da2e3ebdSchin static struct process *job_bypid(pid_t pid)
1243da2e3ebdSchin {
1244da2e3ebdSchin 	register struct process  *pw, *px;
1245da2e3ebdSchin 	for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
1246da2e3ebdSchin 		for(px=pw; px; px=px->p_nxtproc)
1247da2e3ebdSchin 		{
1248da2e3ebdSchin 			if(px->p_pid==pid)
1249da2e3ebdSchin 				return(px);
1250da2e3ebdSchin 		}
1251da2e3ebdSchin 	return(NIL(struct process*));
1252da2e3ebdSchin }
1253da2e3ebdSchin 
1254da2e3ebdSchin /*
1255da2e3ebdSchin  * return a pointer to a job given the job id
1256da2e3ebdSchin  */
1257da2e3ebdSchin 
job_byjid(int jobid)1258da2e3ebdSchin static struct process *job_byjid(int jobid)
1259da2e3ebdSchin {
1260da2e3ebdSchin 	register struct process *pw;
1261da2e3ebdSchin 	for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
1262da2e3ebdSchin 	{
1263da2e3ebdSchin 		if(pw->p_job==jobid)
1264da2e3ebdSchin 			break;
1265da2e3ebdSchin 	}
1266da2e3ebdSchin 	return(pw);
1267da2e3ebdSchin }
1268da2e3ebdSchin 
1269da2e3ebdSchin /*
1270da2e3ebdSchin  * print a signal message
1271da2e3ebdSchin  */
job_prmsg(register struct process * pw)1272da2e3ebdSchin static void job_prmsg(register struct process *pw)
1273da2e3ebdSchin {
1274da2e3ebdSchin 	if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
1275da2e3ebdSchin 	{
1276da2e3ebdSchin 		register const char *msg, *dump;
1277da2e3ebdSchin 		msg = job_sigmsg((int)(pw->p_exit));
1278da2e3ebdSchin 		msg = sh_translate(msg);
1279da2e3ebdSchin 		if(pw->p_flag&P_COREDUMP)
1280da2e3ebdSchin 			dump =  sh_translate(e_coredump);
1281da2e3ebdSchin 		else
1282da2e3ebdSchin 			dump = "";
1283da2e3ebdSchin 		if(sh_isstate(SH_INTERACTIVE))
1284da2e3ebdSchin 			sfprintf(sfstderr,"%s%s\n",msg,dump);
1285da2e3ebdSchin 		else
1286da2e3ebdSchin 			errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump);
1287da2e3ebdSchin 	}
1288da2e3ebdSchin }
1289da2e3ebdSchin 
1290da2e3ebdSchin /*
1291da2e3ebdSchin  * Wait for process pid to complete
1292da2e3ebdSchin  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
1293da2e3ebdSchin  * pid=0 to unpost all done processes
1294da2e3ebdSchin  * pid=1 to wait for at least one process to complete
1295da2e3ebdSchin  * pid=-1 to wait for all runing processes
1296da2e3ebdSchin  */
1297da2e3ebdSchin 
job_wait(register pid_t pid)12987c2fbfb3SApril Chin int	job_wait(register pid_t pid)
1299da2e3ebdSchin {
1300da2e3ebdSchin 	register struct process *pw=0,*px;
1301da2e3ebdSchin 	register int	jobid = 0;
13027c2fbfb3SApril Chin 	int		nochild = 1;
1303da2e3ebdSchin 	char		intr = 0;
1304da2e3ebdSchin 	if(pid <= 0)
1305da2e3ebdSchin 	{
1306da2e3ebdSchin 		if(pid==0)
1307da2e3ebdSchin 			goto done;
1308da2e3ebdSchin 		pid = -pid;
1309da2e3ebdSchin 		intr = 1;
1310da2e3ebdSchin 	}
1311da2e3ebdSchin 	job_lock();
1312da2e3ebdSchin 	if(pid > 1)
1313da2e3ebdSchin 	{
13147c2fbfb3SApril Chin 		if(pid==sh.spid)
13157c2fbfb3SApril Chin 			sh.spid = 0;
1316da2e3ebdSchin 		if(!(pw=job_bypid(pid)))
1317da2e3ebdSchin 		{
1318da2e3ebdSchin 			/* check to see whether job status has been saved */
1319da2e3ebdSchin 			if((sh.exitval = job_chksave(pid)) < 0)
1320da2e3ebdSchin 				sh.exitval = ERROR_NOENT;
1321da2e3ebdSchin 			exitset();
1322da2e3ebdSchin 			job_unlock();
13237c2fbfb3SApril Chin 			return(nochild);
1324da2e3ebdSchin 		}
1325da2e3ebdSchin 		else if(intr && pw->p_env!=sh.curenv)
1326da2e3ebdSchin 		{
1327da2e3ebdSchin 			sh.exitval = ERROR_NOENT;
1328da2e3ebdSchin 			job_unlock();
13297c2fbfb3SApril Chin 			return(nochild);
1330da2e3ebdSchin 		}
1331da2e3ebdSchin 		jobid = pw->p_job;
1332da2e3ebdSchin 		if(!intr)
1333da2e3ebdSchin 			pw->p_flag &= ~P_EXITSAVE;
1334da2e3ebdSchin 		if(pw->p_pgrp && job.parent!= (pid_t)-1)
1335da2e3ebdSchin 			job_set(job_byjid(jobid));
1336da2e3ebdSchin 	}
13377c2fbfb3SApril Chin 	pwfg = pw;
1338da2e3ebdSchin #ifdef DEBUG
1339da2e3ebdSchin 	sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid);
1340da2e3ebdSchin 	if(pw)
1341da2e3ebdSchin 		sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag);
1342da2e3ebdSchin #endif /* DEBUG*/
1343da2e3ebdSchin 	errno = 0;
13447c2fbfb3SApril Chin 	if(sh.coutpipe>=0 && sh.cpid==lastpid)
13457c2fbfb3SApril Chin 	{
13467c2fbfb3SApril Chin 		sh_close(sh.coutpipe);
13477c2fbfb3SApril Chin 		sh_close(sh.cpipe[1]);
13487c2fbfb3SApril Chin 		sh.cpipe[1] = sh.coutpipe = -1;
13497c2fbfb3SApril Chin 	}
1350da2e3ebdSchin 	while(1)
1351da2e3ebdSchin 	{
1352da2e3ebdSchin 		if(job.waitsafe)
1353da2e3ebdSchin 		{
1354da2e3ebdSchin 			for(px=job.pwlist;px; px = px->p_nxtjob)
1355da2e3ebdSchin 			{
1356da2e3ebdSchin 				if(px!=pw && (px->p_flag&P_NOTIFY))
1357da2e3ebdSchin 				{
1358da2e3ebdSchin 					if(sh_isoption(SH_NOTIFY))
1359da2e3ebdSchin 					{
1360da2e3ebdSchin 						outfile = sfstderr;
1361da2e3ebdSchin 						job_list(px,JOB_NFLAG|JOB_NLFLAG);
1362da2e3ebdSchin 						sfsync(sfstderr);
1363da2e3ebdSchin 					}
1364da2e3ebdSchin 					else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
1365da2e3ebdSchin 					{
1366da2e3ebdSchin 						job_prmsg(px);
1367da2e3ebdSchin 						px->p_flag &= ~P_NOTIFY;
1368da2e3ebdSchin 					}
1369da2e3ebdSchin 				}
1370da2e3ebdSchin 			}
1371da2e3ebdSchin 		}
1372da2e3ebdSchin 		if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
1373da2e3ebdSchin 		{
1374da2e3ebdSchin #ifdef SIGTSTP
1375da2e3ebdSchin 			if(pw->p_flag&P_STOPPED)
1376da2e3ebdSchin 			{
1377da2e3ebdSchin 				pw->p_flag |= P_EXITSAVE;
1378da2e3ebdSchin 				if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
1379da2e3ebdSchin 				{
1380da2e3ebdSchin 					if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
1381da2e3ebdSchin 						break;
1382da2e3ebdSchin 
1383da2e3ebdSchin 					killpg(pw->p_pgrp,SIGCONT);
1384da2e3ebdSchin 				}
1385da2e3ebdSchin 				else /* ignore stop when non-interactive */
1386da2e3ebdSchin 					pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
1387da2e3ebdSchin 			}
1388da2e3ebdSchin 			else
1389da2e3ebdSchin #endif /* SIGTSTP */
1390da2e3ebdSchin 			{
1391da2e3ebdSchin 				if(pw->p_flag&P_SIGNALLED)
1392da2e3ebdSchin 				{
1393da2e3ebdSchin 					pw->p_flag &= ~P_NOTIFY;
1394da2e3ebdSchin 					job_prmsg(pw);
1395da2e3ebdSchin 				}
1396da2e3ebdSchin 				else if(pw->p_flag&P_DONE)
1397da2e3ebdSchin 					pw->p_flag &= ~P_NOTIFY;
1398da2e3ebdSchin 				if(pw->p_job==jobid)
1399da2e3ebdSchin 				{
1400da2e3ebdSchin 					px = job_byjid(jobid);
1401da2e3ebdSchin 					/* last process in job */
1402da2e3ebdSchin 					if(sh_isoption(SH_PIPEFAIL))
1403da2e3ebdSchin 					{
1404da2e3ebdSchin 						/* last non-zero exit */
1405da2e3ebdSchin 						for(;px;px=px->p_nxtproc)
1406da2e3ebdSchin 						{
1407da2e3ebdSchin 							if(px->p_exit)
1408da2e3ebdSchin 								break;
1409da2e3ebdSchin 						}
1410da2e3ebdSchin 						if(!px)
1411da2e3ebdSchin 							px = pw;
1412da2e3ebdSchin 					}
1413da2e3ebdSchin 					else if(px!=pw)
1414da2e3ebdSchin 						px = 0;
1415da2e3ebdSchin 					if(px)
1416da2e3ebdSchin 					{
1417da2e3ebdSchin 						sh.exitval=px->p_exit;
1418da2e3ebdSchin 						if(px->p_flag&P_SIGNALLED)
1419da2e3ebdSchin 							sh.exitval |= SH_EXITSIG;
1420da2e3ebdSchin 						if(intr)
1421da2e3ebdSchin 							px->p_flag &= ~P_EXITSAVE;
1422da2e3ebdSchin 					}
1423da2e3ebdSchin 				}
142434f9b3eeSRoland Mainz 				px = job_unpost(pw,1);
1425*3e14f97fSRoger A. Faulkner 				if(!px || !sh_isoption(SH_PIPEFAIL) || !job.waitall)
1426da2e3ebdSchin 					break;
1427da2e3ebdSchin 				pw = px;
1428da2e3ebdSchin 				continue;
1429da2e3ebdSchin 			}
1430da2e3ebdSchin 		}
1431da2e3ebdSchin 		sfsync(sfstderr);
1432da2e3ebdSchin 		job.waitsafe = 0;
1433da2e3ebdSchin 		nochild = job_reap(job.savesig);
1434da2e3ebdSchin 		if(job.waitsafe)
1435da2e3ebdSchin 			continue;
1436da2e3ebdSchin 		if(nochild)
1437da2e3ebdSchin 			break;
1438da2e3ebdSchin 		if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
1439da2e3ebdSchin 			sh_timetraps();
1440da2e3ebdSchin 		if((intr && sh.trapnote) || (pid==1 && !intr))
1441da2e3ebdSchin 			break;
1442da2e3ebdSchin 	}
14437c2fbfb3SApril Chin 	pwfg = 0;
1444da2e3ebdSchin 	job_unlock();
1445da2e3ebdSchin 	if(pid==1)
14467c2fbfb3SApril Chin 		return(nochild);
1447da2e3ebdSchin 	exitset();
1448da2e3ebdSchin 	if(pw->p_pgrp)
1449da2e3ebdSchin 	{
1450da2e3ebdSchin 		job_reset(pw);
1451da2e3ebdSchin 		/* propogate keyboard interrupts to parent */
1452da2e3ebdSchin 		if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
1453da2e3ebdSchin 			sh_fault(SIGINT);
1454da2e3ebdSchin #ifdef SIGTSTP
1455da2e3ebdSchin 		else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
1456da2e3ebdSchin 		{
1457da2e3ebdSchin 			job.parent = 0;
1458da2e3ebdSchin 			sh_fault(SIGTSTP);
1459da2e3ebdSchin 		}
1460da2e3ebdSchin #endif /* SIGTSTP */
1461da2e3ebdSchin 	}
1462da2e3ebdSchin 	else
14637c2fbfb3SApril Chin 	{
14647c2fbfb3SApril Chin 		if(pw->p_pid == tcgetpgrp(JOBTTY))
14657c2fbfb3SApril Chin 		{
14667c2fbfb3SApril Chin 			if(pw->p_pgrp==0)
14677c2fbfb3SApril Chin 				pw->p_pgrp = pw->p_pid;
14687c2fbfb3SApril Chin 			job_reset(pw);
14697c2fbfb3SApril Chin 		}
1470da2e3ebdSchin 		tty_set(-1, 0, NIL(struct termios*));
14717c2fbfb3SApril Chin 	}
1472da2e3ebdSchin done:
1473da2e3ebdSchin 	if(!job.waitall && sh_isoption(SH_PIPEFAIL))
14747c2fbfb3SApril Chin 		return(nochild);
1475da2e3ebdSchin 	if(!sh.intrap)
1476da2e3ebdSchin 	{
1477da2e3ebdSchin 		job_lock();
1478da2e3ebdSchin 		for(pw=job.pwlist; pw; pw=px)
1479da2e3ebdSchin 		{
1480da2e3ebdSchin 			px = pw->p_nxtjob;
1481da2e3ebdSchin 			job_unpost(pw,0);
1482da2e3ebdSchin 		}
1483da2e3ebdSchin 		job_unlock();
1484da2e3ebdSchin 	}
14857c2fbfb3SApril Chin 	return(nochild);
1486da2e3ebdSchin }
1487da2e3ebdSchin 
1488da2e3ebdSchin /*
1489da2e3ebdSchin  * move job to foreground if bgflag == 'f'
1490da2e3ebdSchin  * move job to background if bgflag == 'b'
1491da2e3ebdSchin  * disown job if bgflag == 'd'
1492da2e3ebdSchin  */
1493da2e3ebdSchin 
job_switch(register struct process * pw,int bgflag)1494da2e3ebdSchin int job_switch(register struct process *pw,int bgflag)
1495da2e3ebdSchin {
1496da2e3ebdSchin 	register const char *msg;
1497da2e3ebdSchin 	job_lock();
1498da2e3ebdSchin 	if(!pw || !(pw=job_byjid((int)pw->p_job)))
1499da2e3ebdSchin 	{
1500da2e3ebdSchin 		job_unlock();
1501da2e3ebdSchin 		return(1);
1502da2e3ebdSchin 	}
1503da2e3ebdSchin 	if(bgflag=='d')
1504da2e3ebdSchin 	{
1505da2e3ebdSchin 		for(; pw; pw=pw->p_nxtproc)
1506da2e3ebdSchin 			pw->p_flag |= P_DISOWN;
1507da2e3ebdSchin 		job_unlock();
1508da2e3ebdSchin 		return(0);
1509da2e3ebdSchin 	}
1510da2e3ebdSchin #ifdef SIGTSTP
1511da2e3ebdSchin 	if(bgflag=='b')
1512da2e3ebdSchin 	{
1513da2e3ebdSchin 		sfprintf(outfile,"[%d]\t",(int)pw->p_job);
1514da2e3ebdSchin 		sh.bckpid = pw->p_pid;
151534f9b3eeSRoland Mainz #ifdef SHOPT_BGX
151634f9b3eeSRoland Mainz 		pw->p_flag |= P_BG;
151734f9b3eeSRoland Mainz #endif
1518da2e3ebdSchin 		msg = "&";
1519da2e3ebdSchin 	}
1520da2e3ebdSchin 	else
1521da2e3ebdSchin 	{
1522da2e3ebdSchin 		job_unlink(pw);
1523da2e3ebdSchin 		pw->p_nxtjob = job.pwlist;
1524da2e3ebdSchin 		job.pwlist = pw;
1525da2e3ebdSchin 		msg = "";
1526da2e3ebdSchin 	}
1527da2e3ebdSchin 	hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
1528da2e3ebdSchin 	sfputr(outfile,msg,'\n');
1529da2e3ebdSchin 	sfsync(outfile);
1530da2e3ebdSchin 	if(bgflag=='f')
1531da2e3ebdSchin 	{
1532da2e3ebdSchin 		if(!(pw=job_unpost(pw,1)))
1533da2e3ebdSchin 		{
1534da2e3ebdSchin 			job_unlock();
1535da2e3ebdSchin 			return(1);
1536da2e3ebdSchin 		}
1537da2e3ebdSchin 		job.waitall = 1;
1538da2e3ebdSchin 		pw->p_flag |= P_FG;
153934f9b3eeSRoland Mainz #ifdef SHOPT_BGX
154034f9b3eeSRoland Mainz 		pw->p_flag &= ~P_BG;
154134f9b3eeSRoland Mainz #endif
1542da2e3ebdSchin 		job_wait(pw->p_pid);
1543da2e3ebdSchin 		job.waitall = 0;
1544da2e3ebdSchin 	}
1545da2e3ebdSchin 	else if(pw->p_flag&P_STOPPED)
1546da2e3ebdSchin 		job_unstop(pw);
1547da2e3ebdSchin #endif /* SIGTSTP */
1548da2e3ebdSchin 	job_unlock();
1549da2e3ebdSchin 	return(0);
1550da2e3ebdSchin }
1551da2e3ebdSchin 
1552da2e3ebdSchin 
1553da2e3ebdSchin #ifdef SIGTSTP
1554da2e3ebdSchin /*
1555da2e3ebdSchin  * Set the foreground group associated with a job
1556da2e3ebdSchin  */
1557da2e3ebdSchin 
job_fgrp(register struct process * pw,int newgrp)1558da2e3ebdSchin static void job_fgrp(register struct process *pw, int newgrp)
1559da2e3ebdSchin {
1560da2e3ebdSchin 	for(; pw; pw=pw->p_nxtproc)
1561da2e3ebdSchin 		pw->p_fgrp = newgrp;
1562da2e3ebdSchin }
1563da2e3ebdSchin 
1564da2e3ebdSchin /*
1565da2e3ebdSchin  * turn off STOP state of a process group and send CONT signals
1566da2e3ebdSchin  */
1567da2e3ebdSchin 
job_unstop(register struct process * px)1568da2e3ebdSchin static void job_unstop(register struct process *px)
1569da2e3ebdSchin {
1570da2e3ebdSchin 	register struct process *pw;
1571da2e3ebdSchin 	register int num = 0;
1572da2e3ebdSchin 	for(pw=px ;pw ;pw=pw->p_nxtproc)
1573da2e3ebdSchin 	{
1574da2e3ebdSchin 		if(pw->p_flag&P_STOPPED)
1575da2e3ebdSchin 		{
1576da2e3ebdSchin 			num++;
1577da2e3ebdSchin 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
1578da2e3ebdSchin 		}
1579da2e3ebdSchin 	}
1580da2e3ebdSchin 	if(num!=0)
1581da2e3ebdSchin 	{
1582da2e3ebdSchin 		if(px->p_fgrp != px->p_pgrp)
1583da2e3ebdSchin 			killpg(px->p_fgrp,SIGCONT);
1584da2e3ebdSchin 		killpg(px->p_pgrp,SIGCONT);
1585da2e3ebdSchin 	}
1586da2e3ebdSchin }
1587da2e3ebdSchin #endif	/* SIGTSTP */
1588da2e3ebdSchin 
1589da2e3ebdSchin /*
1590da2e3ebdSchin  * remove a job from table
1591da2e3ebdSchin  * If all the processes have not completed, unpost first non-completed  process
1592da2e3ebdSchin  * Otherwise the job is removed and job_unpost returns NULL.
1593da2e3ebdSchin  * pwlist is reset if the first job is removed
1594da2e3ebdSchin  * if <notify> is non-zero, then jobs with pending notifications are unposted
1595da2e3ebdSchin  */
1596da2e3ebdSchin 
job_unpost(register struct process * pwtop,int notify)1597da2e3ebdSchin static struct process *job_unpost(register struct process *pwtop,int notify)
1598da2e3ebdSchin {
1599da2e3ebdSchin 	register struct process *pw;
1600da2e3ebdSchin 	/* make sure all processes are done */
1601da2e3ebdSchin #ifdef DEBUG
1602da2e3ebdSchin 	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);
1603da2e3ebdSchin 	sfsync(sfstderr);
1604da2e3ebdSchin #endif /* DEBUG */
1605da2e3ebdSchin 	pwtop = pw = job_byjid((int)pwtop->p_job);
160634f9b3eeSRoland Mainz #ifdef SHOPT_BGX
160734f9b3eeSRoland Mainz 	if(pw->p_flag&P_BG)
160834f9b3eeSRoland Mainz 		return(pw);
160934f9b3eeSRoland Mainz #endif /* SHOPT_BGX */
1610da2e3ebdSchin 	for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc);
1611da2e3ebdSchin 	if(pw)
1612da2e3ebdSchin 		return(pw);
1613da2e3ebdSchin 	/* all processes complete, unpost job */
1614da2e3ebdSchin 	job_unlink(pwtop);
1615da2e3ebdSchin 	for(pw=pwtop; pw; pw=pw->p_nxtproc)
1616da2e3ebdSchin 	{
1617da2e3ebdSchin 		/* save the exit status for background jobs */
16187c2fbfb3SApril Chin 		if((pw->p_flag&P_EXITSAVE) ||  pw->p_pid==sh.spid)
1619da2e3ebdSchin 		{
1620da2e3ebdSchin 			struct jobsave *jp;
1621da2e3ebdSchin 			/* save status for future wait */
1622da2e3ebdSchin 			if(jp = jobsave_create(pw->p_pid))
1623da2e3ebdSchin 			{
1624da2e3ebdSchin 				jp->exitval = pw->p_exit;
1625da2e3ebdSchin 				if(pw->p_flag&P_SIGNALLED)
1626da2e3ebdSchin 					jp->exitval |= SH_EXITSIG;
1627da2e3ebdSchin 			}
1628da2e3ebdSchin 			pw->p_flag &= ~P_EXITSAVE;
1629da2e3ebdSchin 		}
1630da2e3ebdSchin 		pw->p_flag &= ~P_DONE;
1631da2e3ebdSchin 		job.numpost--;
1632da2e3ebdSchin 		pw->p_nxtjob = freelist;
1633da2e3ebdSchin 		freelist = pw;
1634da2e3ebdSchin 	}
1635*3e14f97fSRoger A. Faulkner 	pwtop->p_pid = 0;
1636da2e3ebdSchin #ifdef DEBUG
1637da2e3ebdSchin 	sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job);
1638da2e3ebdSchin 	sfsync(sfstderr);
1639da2e3ebdSchin #endif /* DEBUG */
1640da2e3ebdSchin 	job_free((int)pwtop->p_job);
1641da2e3ebdSchin 	return((struct process*)0);
1642da2e3ebdSchin }
1643da2e3ebdSchin 
1644da2e3ebdSchin /*
1645da2e3ebdSchin  * unlink a job form the job list
1646da2e3ebdSchin  */
job_unlink(register struct process * pw)1647da2e3ebdSchin static void job_unlink(register struct process *pw)
1648da2e3ebdSchin {
1649da2e3ebdSchin 	register struct process *px;
1650da2e3ebdSchin 	if(pw==job.pwlist)
1651da2e3ebdSchin 	{
1652da2e3ebdSchin 		job.pwlist = pw->p_nxtjob;
1653da2e3ebdSchin 		job.curpgid = 0;
1654da2e3ebdSchin 		return;
1655da2e3ebdSchin 	}
1656da2e3ebdSchin 	for(px=job.pwlist;px;px=px->p_nxtjob)
1657da2e3ebdSchin 		if(px->p_nxtjob == pw)
1658da2e3ebdSchin 		{
1659da2e3ebdSchin 			px->p_nxtjob = pw->p_nxtjob;
1660da2e3ebdSchin 			return;
1661da2e3ebdSchin 		}
1662da2e3ebdSchin }
1663da2e3ebdSchin 
1664da2e3ebdSchin /*
1665da2e3ebdSchin  * get an unused job number
1666da2e3ebdSchin  * freejobs is a bit vector, 0 is unused
1667da2e3ebdSchin  */
1668da2e3ebdSchin 
job_alloc(void)1669da2e3ebdSchin static int job_alloc(void)
1670da2e3ebdSchin {
1671da2e3ebdSchin 	register int j=0;
1672da2e3ebdSchin 	register unsigned mask = 1;
1673da2e3ebdSchin 	register unsigned char *freeword;
1674da2e3ebdSchin 	register int jmax = BYTE(sh.lim.child_max);
1675da2e3ebdSchin 	/* skip to first word with a free slot */
1676da2e3ebdSchin 	for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
1677da2e3ebdSchin 	if(j >= jmax)
1678da2e3ebdSchin 	{
1679da2e3ebdSchin 		register struct process *pw;
1680da2e3ebdSchin 		for(j=1; j < sh.lim.child_max; j++)
1681da2e3ebdSchin 		{
1682da2e3ebdSchin 			if((pw=job_byjid(j))&& !job_unpost(pw,0))
1683da2e3ebdSchin 				break;
1684da2e3ebdSchin 		}
1685da2e3ebdSchin 		j /= CHAR_BIT;
1686da2e3ebdSchin 		if(j >= jmax)
1687da2e3ebdSchin 			return(-1);
1688da2e3ebdSchin 	}
1689da2e3ebdSchin 	freeword = &job.freejobs[j];
1690da2e3ebdSchin 	j *= CHAR_BIT;
1691da2e3ebdSchin 	for(j++;mask&(*freeword);j++,mask <<=1);
1692da2e3ebdSchin 	*freeword  |= mask;
1693da2e3ebdSchin 	return(j);
1694da2e3ebdSchin }
1695da2e3ebdSchin 
1696da2e3ebdSchin /*
1697da2e3ebdSchin  * return a job number
1698da2e3ebdSchin  */
1699da2e3ebdSchin 
job_free(register int n)1700da2e3ebdSchin static void job_free(register int n)
1701da2e3ebdSchin {
1702da2e3ebdSchin 	register int j = (--n)/CHAR_BIT;
1703da2e3ebdSchin 	register unsigned mask;
1704da2e3ebdSchin 	n -= j*CHAR_BIT;
1705da2e3ebdSchin 	mask = 1 << n;
1706da2e3ebdSchin 	job.freejobs[j]  &= ~mask;
1707da2e3ebdSchin }
1708da2e3ebdSchin 
job_sigmsg(int sig)1709da2e3ebdSchin static char *job_sigmsg(int sig)
1710da2e3ebdSchin {
1711da2e3ebdSchin 	static char signo[40];
1712da2e3ebdSchin #ifdef apollo
1713da2e3ebdSchin 	/*
1714da2e3ebdSchin 	 * This code handles the formatting for the apollo specific signal
1715da2e3ebdSchin 	 * SIGAPOLLO.
1716da2e3ebdSchin 	 */
1717da2e3ebdSchin 	extern char *apollo_error(void);
1718da2e3ebdSchin 
1719da2e3ebdSchin 	if ( sig == SIGAPOLLO )
1720da2e3ebdSchin 		return( apollo_error() );
1721da2e3ebdSchin #endif /* apollo */
172234f9b3eeSRoland Mainz 	if(sig<=sh.sigmax && sh.sigmsg[sig])
1723da2e3ebdSchin 		return(sh.sigmsg[sig]);
1724da2e3ebdSchin #if defined(SIGRTMIN) && defined(SIGRTMAX)
17257c2fbfb3SApril Chin 	if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX])
1726da2e3ebdSchin 	{
1727da2e3ebdSchin 		static char sigrt[20];
17287c2fbfb3SApril Chin 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2)
17297c2fbfb3SApril Chin 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig);
17307c2fbfb3SApril Chin 		else
17317c2fbfb3SApril Chin 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]);
1732da2e3ebdSchin 		return(sigrt);
1733da2e3ebdSchin 	}
1734da2e3ebdSchin #endif
1735da2e3ebdSchin 	sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig);
1736da2e3ebdSchin 	return(signo);
1737da2e3ebdSchin }
1738da2e3ebdSchin 
1739da2e3ebdSchin /*
1740da2e3ebdSchin  * see whether exit status has been saved and delete it
1741da2e3ebdSchin  * if pid==0, then oldest saved process is deleted
1742da2e3ebdSchin  * If pid is not found a -1 is returned.
1743da2e3ebdSchin  */
job_chksave(register pid_t pid)1744da2e3ebdSchin static int job_chksave(register pid_t pid)
1745da2e3ebdSchin {
1746da2e3ebdSchin 	register struct jobsave *jp = bck.list, *jpold=0;
1747da2e3ebdSchin 	register int r= -1;
174834f9b3eeSRoland Mainz 	register int count=bck.count;
174934f9b3eeSRoland Mainz 	while(jp && count-->0)
1750da2e3ebdSchin 	{
1751da2e3ebdSchin 		if(jp->pid==pid)
1752da2e3ebdSchin 			break;
1753da2e3ebdSchin 		if(pid==0 && !jp->next)
1754da2e3ebdSchin 			break;
1755da2e3ebdSchin 		jpold = jp;
1756da2e3ebdSchin 		jp = jp->next;
1757da2e3ebdSchin 	}
1758da2e3ebdSchin 	if(jp)
1759da2e3ebdSchin 	{
1760da2e3ebdSchin 		r = 0;
1761da2e3ebdSchin 		if(pid)
1762da2e3ebdSchin 			r = jp->exitval;
1763da2e3ebdSchin 		if(jpold)
1764da2e3ebdSchin 			jpold->next = jp->next;
1765da2e3ebdSchin 		else
1766da2e3ebdSchin 			bck.list = jp->next;
1767da2e3ebdSchin 		bck.count--;
1768da2e3ebdSchin 		if(njob_savelist < NJOB_SAVELIST)
1769da2e3ebdSchin 		{
1770da2e3ebdSchin 			njob_savelist++;
1771da2e3ebdSchin 			jp->next = job_savelist;
1772da2e3ebdSchin 			job_savelist = jp;
1773da2e3ebdSchin 		}
1774da2e3ebdSchin 		else
1775da2e3ebdSchin 			free((void*)jp);
1776da2e3ebdSchin 	}
1777da2e3ebdSchin 	return(r);
1778da2e3ebdSchin }
1779da2e3ebdSchin 
job_subsave(void)1780da2e3ebdSchin void *job_subsave(void)
1781da2e3ebdSchin {
1782da2e3ebdSchin 	struct back_save *bp = new_of(struct back_save,0);
1783da2e3ebdSchin 	job_lock();
1784da2e3ebdSchin 	*bp = bck;
1785da2e3ebdSchin 	bck.count = 0;
1786da2e3ebdSchin 	bck.list = 0;
1787da2e3ebdSchin 	job_unlock();
1788da2e3ebdSchin 	return((void*)bp);
1789da2e3ebdSchin }
1790da2e3ebdSchin 
job_subrestore(void * ptr)1791da2e3ebdSchin void job_subrestore(void* ptr)
1792da2e3ebdSchin {
17937c2fbfb3SApril Chin 	register struct jobsave *jp;
1794da2e3ebdSchin 	register struct back_save *bp = (struct back_save*)ptr;
1795da2e3ebdSchin 	register struct process *pw, *px, *pwnext;
17967c2fbfb3SApril Chin 	struct jobsave *jpnext;
1797da2e3ebdSchin 	job_lock();
17987c2fbfb3SApril Chin 	for(jp=bck.list; jp; jp=jpnext)
17997c2fbfb3SApril Chin 	{
18007c2fbfb3SApril Chin 		jpnext = jp->next;
18017c2fbfb3SApril Chin 		if(jp->pid==sh.spid)
18027c2fbfb3SApril Chin 		{
18037c2fbfb3SApril Chin 			jp->next = bp->list;
18047c2fbfb3SApril Chin 			bp->list = jp;
180534f9b3eeSRoland Mainz 			bp->count++;
18067c2fbfb3SApril Chin 		}
18077c2fbfb3SApril Chin 		else
18087c2fbfb3SApril Chin 			job_chksave(jp->pid);
18097c2fbfb3SApril Chin 	}
1810da2e3ebdSchin 	for(pw=job.pwlist; pw; pw=pwnext)
1811da2e3ebdSchin 	{
1812da2e3ebdSchin 		pwnext = pw->p_nxtjob;
181334f9b3eeSRoland Mainz 		if(pw->p_env != sh.curenv || pw->p_pid==sh.pipepid)
1814da2e3ebdSchin 			continue;
1815da2e3ebdSchin 		for(px=pw; px; px=px->p_nxtproc)
1816da2e3ebdSchin 			px->p_flag |= P_DONE;
1817da2e3ebdSchin 		job_unpost(pw,0);
1818da2e3ebdSchin 	}
18197c2fbfb3SApril Chin 
18207c2fbfb3SApril Chin 	/*
18217c2fbfb3SApril Chin 	 * queue up old lists for disposal by job_reap()
18227c2fbfb3SApril Chin 	 */
18237c2fbfb3SApril Chin 
18247c2fbfb3SApril Chin 	bck = *bp;
18257c2fbfb3SApril Chin 	free((void*)bp);
1826da2e3ebdSchin 	job_unlock();
1827da2e3ebdSchin }
1828da2e3ebdSchin 
sh_waitsafe(void)1829da2e3ebdSchin int sh_waitsafe(void)
1830da2e3ebdSchin {
1831da2e3ebdSchin 	return(job.waitsafe);
1832da2e3ebdSchin }
1833da2e3ebdSchin 
job_fork(pid_t parent)1834da2e3ebdSchin void job_fork(pid_t parent)
1835da2e3ebdSchin {
1836da2e3ebdSchin #ifdef DEBUG
1837da2e3ebdSchin 	sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent);
1838da2e3ebdSchin #endif /* DEBUG */
1839da2e3ebdSchin 	switch (parent)
1840da2e3ebdSchin 	{
1841da2e3ebdSchin 	case -1:
1842da2e3ebdSchin 		job_lock();
1843da2e3ebdSchin 		break;
1844da2e3ebdSchin 	case 0:
1845da2e3ebdSchin 		job_unlock();
1846da2e3ebdSchin 		job.waitsafe = 0;
1847da2e3ebdSchin 		job.in_critical = 0;
1848da2e3ebdSchin 		break;
1849da2e3ebdSchin 	default:
1850*3e14f97fSRoger A. Faulkner 		job_chksave(parent);
1851da2e3ebdSchin 		job_unlock();
1852da2e3ebdSchin 		break;
1853da2e3ebdSchin 	}
1854da2e3ebdSchin }
1855