xref: /onnv-gate/usr/src/lib/libshell/common/sh/jobs.c (revision 8462:6e341f5569ba)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  *  Job control for UNIX Shell
234887Schin  *
244887Schin  *   David Korn
254887Schin  *   AT&T Labs
264887Schin  *
274887Schin  *  Written October, 1982
284887Schin  *  Rewritten April, 1988
294887Schin  *  Revised January, 1992
304887Schin  */
314887Schin 
324887Schin #include	"defs.h"
334887Schin #include	<ctype.h>
344887Schin #include	<wait.h>
354887Schin #include	"io.h"
364887Schin #include	"jobs.h"
374887Schin #include	"history.h"
384887Schin 
394887Schin #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
404887Schin #   undef  WCONTINUED
414887Schin #   define WCONTINUED	0
424887Schin #   undef  WIFCONTINUED
434887Schin #   define WIFCONTINUED(wstat)	(0)
444887Schin #endif
454887Schin 
464887Schin #define	NJOB_SAVELIST	4
474887Schin 
484887Schin /*
494887Schin  * temporary hack to get W* macros to work
504887Schin  */
514887Schin #undef wait
524887Schin #define wait    ______wait
534887Schin /*
544887Schin  * This struct saves a link list of processes that have non-zero exit
554887Schin  * status, have had $! saved, but haven't been waited for
564887Schin  */
574887Schin struct jobsave
584887Schin {
594887Schin 	struct jobsave	*next;
604887Schin 	pid_t		pid;
614887Schin 	unsigned short	exitval;
624887Schin };
634887Schin 
644887Schin static struct jobsave *job_savelist;
654887Schin static int njob_savelist;
66*8462SApril.Chin@Sun.COM static struct process *pwfg;
674887Schin 
684887Schin static void init_savelist(void)
694887Schin {
704887Schin 	register struct jobsave *jp;
714887Schin 	while(njob_savelist < NJOB_SAVELIST)
724887Schin 	{
734887Schin 		jp = newof(0,struct jobsave,1,0);
744887Schin 		jp->next = job_savelist;
754887Schin 		job_savelist = jp;
764887Schin 		njob_savelist++;
774887Schin 	}
784887Schin }
794887Schin 
804887Schin /*
814887Schin  * return next on link list of jobsave free list
824887Schin  */
834887Schin static struct jobsave *jobsave_create(pid_t pid)
844887Schin {
854887Schin 	register struct jobsave *jp = job_savelist;
864887Schin 	if(jp)
874887Schin 	{
884887Schin 		njob_savelist--;
894887Schin 		job_savelist = jp->next;
904887Schin 	}
914887Schin 	else
924887Schin 		jp = newof(0,struct jobsave,1,0);
934887Schin 	if(jp)
944887Schin 		jp->pid = pid;
954887Schin 	return(jp);
964887Schin }
974887Schin 
984887Schin struct back_save
994887Schin {
1004887Schin 	int		count;
1014887Schin 	struct jobsave	*list;
1024887Schin };
1034887Schin 
1044887Schin #define BYTE(n)		(((n)+CHAR_BIT-1)/CHAR_BIT)
1054887Schin #define MAXMSG	25
1064887Schin #define SH_STOPSIG	(SH_EXITSIG<<1)
1074887Schin 
1084887Schin #ifdef VSUSP
1094887Schin #   ifndef CNSUSP
1104887Schin #	ifdef _POSIX_VDISABLE
1114887Schin #	   define CNSUSP	_POSIX_VDISABLE
1124887Schin #	else
1134887Schin #	   define CNSUSP	0
1144887Schin #	endif /* _POSIX_VDISABLE */
1154887Schin #   endif /* CNSUSP */
1164887Schin #   ifndef CSWTCH
1174887Schin #	ifdef CSUSP
1184887Schin #	    define CSWTCH	CSUSP
1194887Schin #	else
1204887Schin #	    define CSWTCH	('z'&037)
1214887Schin #	endif /* CSUSP */
1224887Schin #   endif /* CSWTCH */
1234887Schin #endif /* VSUSP */
1244887Schin 
1254887Schin /* Process states */
1264887Schin #define P_EXITSAVE	01
1274887Schin #define P_STOPPED	02
1284887Schin #define P_NOTIFY	04
1294887Schin #define P_SIGNALLED	010
1304887Schin #define P_STTY		020
1314887Schin #define P_DONE		040
1324887Schin #define P_COREDUMP	0100
1334887Schin #define P_DISOWN	0200
1344887Schin #define P_FG		0400
1354887Schin 
1364887Schin static int		job_chksave(pid_t);
1374887Schin static struct process	*job_bypid(pid_t);
1384887Schin static struct process	*job_byjid(int);
1394887Schin static char		*job_sigmsg(int);
1404887Schin static int		job_alloc(void);
1414887Schin static void		job_free(int);
1424887Schin static struct process	*job_unpost(struct process*,int);
1434887Schin static void		job_unlink(struct process*);
1444887Schin static void		job_prmsg(struct process*);
1454887Schin static struct process	*freelist;
1464887Schin static char		beenhere;
1474887Schin static char		possible;
1484887Schin static struct process	dummy;
1494887Schin static char		by_number;
1504887Schin static Sfio_t		*outfile;
1514887Schin static pid_t		lastpid;
1524887Schin static struct back_save	bck;
1534887Schin 
1544887Schin 
1554887Schin #ifdef JOBS
1564887Schin     static void			job_set(struct process*);
1574887Schin     static void			job_reset(struct process*);
1584887Schin     static void			job_waitsafe(int);
1594887Schin     static struct process	*job_byname(char*);
1604887Schin     static struct process	*job_bystring(char*);
1614887Schin     static struct termios	my_stty;  /* terminal state for shell */
1624887Schin     static char			*job_string;
1634887Schin #else
1644887Schin     extern const char		e_coredump[];
1654887Schin #endif /* JOBS */
1664887Schin 
1674887Schin #ifdef SIGTSTP
1684887Schin     static void		job_unstop(struct process*);
1694887Schin     static void		job_fgrp(struct process*, int);
1704887Schin #   ifndef _lib_tcgetpgrp
1714887Schin #	ifdef TIOCGPGRP
1724887Schin 	   static int _i_;
1734887Schin #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
1744887Schin #	endif /* TIOCGPGRP */
1754887Schin 	int tcsetpgrp(int fd,pid_t pgrp)
1764887Schin 	{
1774887Schin 		int pgid = pgrp;
1784887Schin #		ifdef TIOCGPGRP
1794887Schin 			return(ioctl(fd, TIOCSPGRP, &pgid));
1804887Schin #		else
1814887Schin 			return(-1);
1824887Schin #		endif /* TIOCGPGRP */
1834887Schin 	}
1844887Schin #   endif /* _lib_tcgetpgrp */
1854887Schin #else
1864887Schin #   define job_unstop(pw)
1874887Schin #   undef CNSUSP
1884887Schin #endif /* SIGTSTP */
1894887Schin 
1904887Schin #ifndef OTTYDISC
1914887Schin #   undef NTTYDISC
1924887Schin #endif /* OTTYDISC */
1934887Schin 
1944887Schin #ifdef JOBS
1954887Schin 
1964887Schin typedef int (*Waitevent_f)(int,long,int);
1974887Schin 
1984887Schin /*
1994887Schin  * Reap one job
2004887Schin  * When called with sig==0, it does a blocking wait
2014887Schin  */
2024887Schin int job_reap(register int sig)
2034887Schin {
2044887Schin 	register pid_t pid;
2054887Schin 	register struct process *pw;
2064887Schin 	struct process *px;
2074887Schin 	register int flags;
2084887Schin 	struct jobsave *jp;
209*8462SApril.Chin@Sun.COM 	struct back_save *bp;
2104887Schin 	int nochild=0, oerrno, wstat;
2114887Schin 	Waitevent_f waitevent = sh.waitevent;
2124887Schin 	static int wcontinued = WCONTINUED;
213*8462SApril.Chin@Sun.COM 	if (vmbusy())
214*8462SApril.Chin@Sun.COM 	{
215*8462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen");
216*8462SApril.Chin@Sun.COM 		if (getenv("_AST_KSH_VMBUSY_ABORT"))
217*8462SApril.Chin@Sun.COM 			abort();
218*8462SApril.Chin@Sun.COM 	}
2194887Schin #ifdef DEBUG
2204887Schin 	if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0)
2214887Schin 		write(2,"waitsafe\n",9);
2224887Schin 	sfsync(sfstderr);
2234887Schin #endif /* DEBUG */
2244887Schin 	job.savesig = 0;
2254887Schin 	if(sig)
2264887Schin 		flags = WNOHANG|WUNTRACED|wcontinued;
2274887Schin 	else
2284887Schin 		flags = WUNTRACED|wcontinued;
2294887Schin 	sh.waitevent = 0;
2304887Schin 	oerrno = errno;
2314887Schin 	while(1)
2324887Schin 	{
233*8462SApril.Chin@Sun.COM 		if(!(flags&WNOHANG) && !sh.intrap && job.pwlist)
2344887Schin 		{
235*8462SApril.Chin@Sun.COM 			sh_onstate(SH_TTYWAIT);
236*8462SApril.Chin@Sun.COM 			if(waitevent && (*waitevent)(-1,-1L,0))
2374887Schin 				flags |= WNOHANG;
2384887Schin 		}
2394887Schin 		pid = waitpid((pid_t)-1,&wstat,flags);
240*8462SApril.Chin@Sun.COM 		sh_offstate(SH_TTYWAIT);
2414887Schin 
2424887Schin 		/*
2434887Schin 		 * some systems (linux 2.6) may return EINVAL
2444887Schin 		 * when there are no continued children
2454887Schin 		 */
2464887Schin 
2474887Schin 		if (pid<0 && errno==EINVAL && (flags&WCONTINUED))
2484887Schin 			pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED);
2494887Schin 		sh_sigcheck();
2504887Schin 		if(sig && pid<0 && errno==EINTR)
2514887Schin 			continue;
2524887Schin 		if(pid<=0)
2534887Schin 			break;
2544887Schin 		flags |= WNOHANG;
2554887Schin 		job.waitsafe++;
2564887Schin 		jp = 0;
257*8462SApril.Chin@Sun.COM 		lastpid = pid;
2584887Schin 		if(!(pw=job_bypid(pid)))
2594887Schin 		{
2604887Schin #ifdef DEBUG
2614887Schin 			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);
2624887Schin #endif /* DEBUG */
263*8462SApril.Chin@Sun.COM 			if (WIFCONTINUED(wstat) && wcontinued)
264*8462SApril.Chin@Sun.COM 				continue;
2654887Schin 			pw = &dummy;
2664887Schin 			pw->p_exit = 0;
2674887Schin 			pw->p_pgrp = 0;
268*8462SApril.Chin@Sun.COM 			pw->p_exitmin = 0;
2694887Schin 			if(job.toclear)
2704887Schin 				job_clear();
271*8462SApril.Chin@Sun.COM 			if(++bck.count > sh.lim.child_max)
2724887Schin 				job_chksave(0);
2734887Schin 			if(jp = jobsave_create(pid))
2744887Schin 			{
2754887Schin 				jp->next = bck.list;
2764887Schin 				bck.list = jp;
2774887Schin 				jp->exitval = 0;
2784887Schin 			}
2794887Schin 			pw->p_flag = 0;
2804887Schin 			lastpid = pw->p_pid = pid;
2814887Schin 			px = 0;
2824887Schin 			if(jp && WIFSTOPPED(wstat))
2834887Schin 			{
2844887Schin 				jp->exitval = SH_STOPSIG;
2854887Schin 				continue;
2864887Schin 			}
2874887Schin 		}
2884887Schin #ifdef SIGTSTP
2894887Schin 		else
2904887Schin 			px=job_byjid(pw->p_job);
2914887Schin 		if(WIFSTOPPED(wstat))
2924887Schin 		{
2934887Schin 			if(px)
2944887Schin 			{
2954887Schin 				/* move to top of job list */
2964887Schin 				job_unlink(px);
2974887Schin 				px->p_nxtjob = job.pwlist;
2984887Schin 				job.pwlist = px;
2994887Schin 			}
300*8462SApril.Chin@Sun.COM 			pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
3014887Schin 			pw->p_exit = WSTOPSIG(wstat);
3024887Schin 			if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
3034887Schin 				sh_fault(pw->p_exit);
3044887Schin 			continue;
3054887Schin 		}
3064887Schin 		else if (WIFCONTINUED(wstat) && wcontinued)
3074887Schin 			pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED);
3084887Schin 		else
3094887Schin #endif /* SIGTSTP */
3104887Schin 		{
3114887Schin 			/* check for coprocess completion */
3124887Schin 			if(pid==sh.cpid)
3134887Schin 			{
3144887Schin 				sh_close(sh.coutpipe);
3154887Schin 				sh_close(sh.cpipe[1]);
3164887Schin 				sh.cpipe[1] = -1;
3174887Schin 				sh.coutpipe = -1;
3184887Schin 			}
319*8462SApril.Chin@Sun.COM 			else if(sh.subshell)
320*8462SApril.Chin@Sun.COM 				sh_subjobcheck(pid);
321*8462SApril.Chin@Sun.COM 
322*8462SApril.Chin@Sun.COM 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
3234887Schin 			if (WIFSIGNALED(wstat))
3244887Schin 			{
3254887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
3264887Schin 				if (WTERMCORE(wstat))
3274887Schin 					pw->p_flag |= P_COREDUMP;
3284887Schin 				pw->p_exit = WTERMSIG(wstat);
3294887Schin 				/* if process in current jobs terminates from
3304887Schin 				 * an interrupt, propogate to parent shell
3314887Schin 				 */
3324887Schin 				if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
3334887Schin 				{
3344887Schin 					pw->p_flag &= ~P_NOTIFY;
3354887Schin 					sh_offstate(SH_STOPOK);
3364887Schin 					sh_fault(SIGINT);
3374887Schin 					sh_onstate(SH_STOPOK);
3384887Schin 				}
3394887Schin 			}
3404887Schin 			else
3414887Schin 			{
3424887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY);
343*8462SApril.Chin@Sun.COM 				pw->p_exit =  pw->p_exitmin;
344*8462SApril.Chin@Sun.COM 				if(WEXITSTATUS(wstat) > pw->p_exitmin)
3454887Schin 					pw->p_exit = WEXITSTATUS(wstat);
3464887Schin 			}
3474887Schin 			if(pw->p_pgrp==0)
3484887Schin 				pw->p_flag &= ~P_NOTIFY;
3494887Schin 		}
3504887Schin 		if(jp && pw== &dummy)
3514887Schin 		{
3524887Schin 			jp->exitval = pw->p_exit;
3534887Schin 			if(pw->p_flag&P_SIGNALLED)
3544887Schin 				jp->exitval |= SH_EXITSIG;
3554887Schin 		}
3564887Schin #ifdef DEBUG
3574887Schin 		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);
3584887Schin 		sfsync(sfstderr);
3594887Schin #endif /* DEBUG*/
3604887Schin 		/* only top-level process in job should have notify set */
3614887Schin 		if(px && pw != px)
3624887Schin 			pw->p_flag &= ~P_NOTIFY;
363*8462SApril.Chin@Sun.COM 		if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY))
364*8462SApril.Chin@Sun.COM 		{
365*8462SApril.Chin@Sun.COM 			px = job_byjid((int)pw->p_job);
366*8462SApril.Chin@Sun.COM 			for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc);
367*8462SApril.Chin@Sun.COM 			if(!px)
368*8462SApril.Chin@Sun.COM 				tcsetpgrp(JOBTTY,job.mypid);
369*8462SApril.Chin@Sun.COM 		}
370*8462SApril.Chin@Sun.COM 		if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid)))
371*8462SApril.Chin@Sun.COM 		{
372*8462SApril.Chin@Sun.COM 			sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
373*8462SApril.Chin@Sun.COM 			sh.trapnote |= SH_SIGTRAP;
374*8462SApril.Chin@Sun.COM 		}
3754887Schin 	}
3764887Schin 	if(errno==ECHILD)
3774887Schin 	{
3784887Schin 		errno = oerrno;
3794887Schin 		nochild = 1;
3804887Schin 	}
3814887Schin 	sh.waitevent = waitevent;
3824887Schin 	if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
3834887Schin 	{
3844887Schin 		outfile = sfstderr;
3854887Schin 		job_list(pw,JOB_NFLAG|JOB_NLFLAG);
3864887Schin 		job_unpost(pw,1);
3874887Schin 		sfsync(sfstderr);
3884887Schin 	}
3894887Schin 	if(sig)
3904887Schin 		signal(sig, job_waitsafe);
3914887Schin 	return(nochild);
3924887Schin }
3934887Schin 
3944887Schin /*
3954887Schin  * This is the SIGCLD interrupt routine
3964887Schin  */
3974887Schin static void job_waitsafe(int sig)
3984887Schin {
399*8462SApril.Chin@Sun.COM 	if(job.in_critical || vmbusy())
4004887Schin 	{
4014887Schin 		job.savesig = sig;
4024887Schin 		job.waitsafe++;
4034887Schin 	}
4044887Schin 	else
4054887Schin 		job_reap(sig);
4064887Schin }
4074887Schin 
4084887Schin /*
4094887Schin  * initialize job control if possible
4104887Schin  * if lflag is set the switching driver message will not print
4114887Schin  */
412*8462SApril.Chin@Sun.COM void job_init(Shell_t *shp, int lflag)
4134887Schin {
414*8462SApril.Chin@Sun.COM 	register int ntry=0;
4154887Schin 	job.fd = JOBTTY;
4164887Schin 	signal(SIGCHLD,job_waitsafe);
4174887Schin #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
4184887Schin 	signal(SIGCLD,job_waitsafe);
4194887Schin #   endif
4204887Schin 	if(njob_savelist < NJOB_SAVELIST)
4214887Schin 		init_savelist();
4224887Schin 	if(!sh_isoption(SH_INTERACTIVE))
4234887Schin 		return;
4244887Schin 	/* use new line discipline when available */
4254887Schin #ifdef NTTYDISC
4264887Schin #   ifdef FIOLOOKLD
4274887Schin 	if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
4284887Schin #   else
4294887Schin 	if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
4304887Schin #   endif /* FIOLOOKLD */
4314887Schin 		return;
4324887Schin 	if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
4334887Schin 	{
4344887Schin 		/* no job control when running with MPX */
4354887Schin #   if SHOPT_VSH
4364887Schin 		sh_onoption(SH_VIRAW);
4374887Schin #   endif /* SHOPT_VSH */
4384887Schin 		return;
4394887Schin 	}
4404887Schin 	if(job.linedisc==NTTYDISC)
4414887Schin 		job.linedisc = -1;
4424887Schin #endif /* NTTYDISC */
4434887Schin 
4444887Schin 	job.mypgid = getpgrp();
4454887Schin 	/* some systems have job control, but not initialized */
4464887Schin 	if(job.mypgid<=0)
4474887Schin         {
4484887Schin 		/* Get a controlling terminal and set process group */
4494887Schin 		/* This should have already been done by rlogin */
4504887Schin                 register int fd;
4514887Schin                 register char *ttynam;
4524887Schin #ifndef SIGTSTP
453*8462SApril.Chin@Sun.COM                 setpgid(0,shp->pid);
4544887Schin #endif /*SIGTSTP */
4554887Schin                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
4564887Schin                         return;
4574887Schin                 close(JOBTTY);
4584887Schin                 if((fd = open(ttynam,O_RDWR)) <0)
4594887Schin                         return;
4604887Schin                 if(fd!=JOBTTY)
461*8462SApril.Chin@Sun.COM                         sh_iorenumber(shp,fd,JOBTTY);
462*8462SApril.Chin@Sun.COM                 job.mypgid = shp->pid;
4634887Schin #ifdef SIGTSTP
464*8462SApril.Chin@Sun.COM                 tcsetpgrp(JOBTTY,shp->pid);
465*8462SApril.Chin@Sun.COM                 setpgid(0,shp->pid);
4664887Schin #endif /* SIGTSTP */
4674887Schin         }
4684887Schin #ifdef SIGTSTP
4694887Schin 	if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
4704887Schin 	{
4714887Schin 		/* wait until we are in the foreground */
4724887Schin 		while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
4734887Schin 		{
4744887Schin 			if(job.mytgid == -1)
4754887Schin 				return;
4764887Schin 			/* Stop this shell until continued */
4774887Schin 			signal(SIGTTIN,SIG_DFL);
478*8462SApril.Chin@Sun.COM 			kill(shp->pid,SIGTTIN);
4794887Schin 			/* resumes here after continue tries again */
4804887Schin 			if(ntry++ > IOMAXTRY)
4814887Schin 			{
4824887Schin 				errormsg(SH_DICT,0,e_no_start);
4834887Schin 				return;
4844887Schin 			}
4854887Schin 		}
4864887Schin 	}
4874887Schin #endif /* SIGTTIN */
4884887Schin 
4894887Schin #ifdef NTTYDISC
4904887Schin 	/* set the line discipline */
4914887Schin 	if(job.linedisc>=0)
4924887Schin 	{
4934887Schin 		int linedisc = NTTYDISC;
4944887Schin #   ifdef FIOPUSHLD
4954887Schin 		tty_get(JOBTTY,&my_stty);
4964887Schin 		if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
4974887Schin 			return;
4984887Schin 		if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
4994887Schin 		{
5004887Schin 			ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
5014887Schin 			return;
5024887Schin 		}
5034887Schin 		tty_set(JOBTTY,TCSANOW,&my_stty);
5044887Schin #   else
5054887Schin 		if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
5064887Schin 			return;
5074887Schin #   endif /* FIOPUSHLD */
5084887Schin 		if(lflag==0)
5094887Schin 			errormsg(SH_DICT,0,e_newtty);
5104887Schin 		else
5114887Schin 			job.linedisc = -1;
5124887Schin 	}
5134887Schin #endif /* NTTYDISC */
5144887Schin 	if(!possible)
5154887Schin 		return;
5164887Schin 
5174887Schin #ifdef SIGTSTP
5184887Schin 	/* make sure that we are a process group leader */
519*8462SApril.Chin@Sun.COM 	setpgid(0,shp->pid);
5204887Schin #   if defined(SA_NOCLDWAIT) && defined(_lib_sigflag)
5214887Schin 	sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
5224887Schin #   endif /* SA_NOCLDWAIT */
5234887Schin 	signal(SIGTTIN,SIG_IGN);
5244887Schin 	signal(SIGTTOU,SIG_IGN);
5254887Schin 	/* The shell now handles ^Z */
5264887Schin 	signal(SIGTSTP,sh_fault);
527*8462SApril.Chin@Sun.COM 	tcsetpgrp(JOBTTY,shp->pid);
5284887Schin #   ifdef CNSUSP
5294887Schin 	/* set the switch character */
5304887Schin 	tty_get(JOBTTY,&my_stty);
5314887Schin 	job.suspend = (unsigned)my_stty.c_cc[VSUSP];
5324887Schin 	if(job.suspend == (unsigned char)CNSUSP)
5334887Schin 	{
5344887Schin 		my_stty.c_cc[VSUSP] = CSWTCH;
5354887Schin 		tty_set(JOBTTY,TCSAFLUSH,&my_stty);
5364887Schin 	}
5374887Schin #   endif /* CNSUSP */
5384887Schin 	sh_onoption(SH_MONITOR);
5394887Schin 	job.jobcontrol++;
540*8462SApril.Chin@Sun.COM 	job.mypid = shp->pid;
5414887Schin #endif /* SIGTSTP */
5424887Schin 	return;
5434887Schin }
5444887Schin 
5454887Schin 
5464887Schin /*
5474887Schin  * see if there are any stopped jobs
5484887Schin  * restore tty driver and pgrp
5494887Schin  */
550*8462SApril.Chin@Sun.COM int job_close(Shell_t* shp)
5514887Schin {
5524887Schin 	register struct process *pw;
5534887Schin 	register int count = 0, running = 0;
5544887Schin 	if(possible && !job.jobcontrol)
5554887Schin 		return(0);
5564887Schin 	else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
5574887Schin 		return(0);
5584887Schin 	else if(getpid() != job.mypid)
5594887Schin 		return(0);
5604887Schin 	job_lock();
5614887Schin 	if(!tty_check(0))
5624887Schin 		beenhere++;
5634887Schin 	for(pw=job.pwlist;pw;pw=pw->p_nxtjob)
5644887Schin 	{
5654887Schin 		if(!(pw->p_flag&P_STOPPED))
5664887Schin 		{
5674887Schin 			if(!(pw->p_flag&P_DONE))
5684887Schin 				running++;
5694887Schin 			continue;
5704887Schin 		}
5714887Schin 		if(beenhere)
5724887Schin 			killpg(pw->p_pgrp,SIGTERM);
5734887Schin 		count++;
5744887Schin 	}
5754887Schin 	if(beenhere++ == 0 && job.pwlist)
5764887Schin 	{
5774887Schin 		if(count)
5784887Schin 		{
5794887Schin 			errormsg(SH_DICT,0,e_terminate);
5804887Schin 			return(-1);
5814887Schin 		}
582*8462SApril.Chin@Sun.COM 		else if(running && shp->login_sh)
5834887Schin 		{
5844887Schin 			errormsg(SH_DICT,0,e_jobsrunning);
5854887Schin 			return(-1);
5864887Schin 		}
5874887Schin 	}
5884887Schin 	job_unlock();
5894887Schin #   ifdef SIGTSTP
5904887Schin 	if(possible && setpgid(0,job.mypgid)>=0)
5914887Schin 		tcsetpgrp(job.fd,job.mypgid);
5924887Schin #   endif /* SIGTSTP */
5934887Schin #   ifdef NTTYDISC
5944887Schin 	if(job.linedisc>=0)
5954887Schin 	{
5964887Schin 		/* restore old line discipline */
5974887Schin #	ifdef FIOPUSHLD
5984887Schin 		tty_get(job.fd,&my_stty);
5994887Schin 		if (ioctl(job.fd, FIOPOPLD, 0) < 0)
6004887Schin 			return(0);
6014887Schin 		if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
6024887Schin 		{
6034887Schin 			job.linedisc = NTTYDISC;
6044887Schin 			ioctl(job.fd, FIOPUSHLD, &job.linedisc);
6054887Schin 			return(0);
6064887Schin 		}
6074887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
6084887Schin #	else
6094887Schin 		if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
6104887Schin 			return(0);
6114887Schin #	endif /* FIOPUSHLD */
6124887Schin 		errormsg(SH_DICT,0,e_oldtty);
6134887Schin 	}
6144887Schin #   endif /* NTTYDISC */
6154887Schin #   ifdef CNSUSP
6164887Schin 	if(possible && job.suspend==CNSUSP)
6174887Schin 	{
6184887Schin 		tty_get(job.fd,&my_stty);
6194887Schin 		my_stty.c_cc[VSUSP] = CNSUSP;
6204887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
6214887Schin 	}
6224887Schin #   endif /* CNSUSP */
6234887Schin 	job.jobcontrol = 0;
6244887Schin 	return(0);
6254887Schin }
6264887Schin 
6274887Schin static void job_set(register struct process *pw)
6284887Schin {
6294887Schin 	/* save current terminal state */
6304887Schin 	tty_get(job.fd,&my_stty);
6314887Schin 	if(pw->p_flag&P_STTY)
6324887Schin 	{
6334887Schin 		/* restore terminal state for job */
6344887Schin 		tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
6354887Schin 	}
6364887Schin #ifdef SIGTSTP
6374887Schin 	if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid)
6384887Schin 		tcsetpgrp(job.fd,pw->p_fgrp);
6394887Schin 	/* if job is stopped, resume it in the background */
6404887Schin 	job_unstop(pw);
6414887Schin #endif	/* SIGTSTP */
6424887Schin }
6434887Schin 
6444887Schin static void job_reset(register struct process *pw)
6454887Schin {
6464887Schin 	/* save the terminal state for current job */
6474887Schin #ifdef SIGTSTP
6484887Schin 	job_fgrp(pw,tcgetpgrp(job.fd));
649*8462SApril.Chin@Sun.COM 	if(tcsetpgrp(job.fd,job.mypid) !=0)
6504887Schin 		return;
6514887Schin #endif	/* SIGTSTP */
6524887Schin 	/* force the following tty_get() to do a tcgetattr() unless fg */
6534887Schin 	if(!(pw->p_flag&P_FG))
6544887Schin 		tty_set(-1, 0, NIL(struct termios*));
6554887Schin 	if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
6564887Schin 	{
6574887Schin 		if(tty_get(job.fd,&pw->p_stty) == 0)
6584887Schin 			pw->p_flag |= P_STTY;
6594887Schin 		/* restore terminal state for job */
6604887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
6614887Schin 	}
6624887Schin 	beenhere = 0;
6634887Schin }
6644887Schin #endif /* JOBS */
6654887Schin 
6664887Schin /*
6674887Schin  * wait built-in command
6684887Schin  */
6694887Schin 
6704887Schin void job_bwait(char **jobs)
6714887Schin {
6724887Schin 	register char *jp;
6734887Schin 	register struct process *pw;
6744887Schin 	register pid_t pid;
6754887Schin 	if(*jobs==0)
6764887Schin 		job_wait((pid_t)-1);
6774887Schin 	else while(jp = *jobs++)
6784887Schin 	{
6794887Schin #ifdef JOBS
6804887Schin 		if(*jp == '%')
6814887Schin 		{
6824887Schin 			job_lock();
6834887Schin 			pw = job_bystring(jp);
6844887Schin 			job_unlock();
6854887Schin 			if(pw)
6864887Schin 				pid = pw->p_pid;
6874887Schin 			else
6884887Schin 				return;
6894887Schin 		}
6904887Schin 		else
6914887Schin #endif /* JOBS */
6924887Schin 			pid = (int)strtol(jp, (char**)0, 10);
6934887Schin 		job_wait(-pid);
6944887Schin 	}
6954887Schin }
6964887Schin 
6974887Schin #ifdef JOBS
6984887Schin /*
6994887Schin  * execute function <fun> for each job
7004887Schin  */
7014887Schin 
7024887Schin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[])
7034887Schin {
7044887Schin 	register struct process *pw;
7054887Schin 	register int r = 0;
7064887Schin 	register char *jobid, **jobs=joblist;
7074887Schin 	register struct process *px;
7084887Schin 	job_string = 0;
7094887Schin 	outfile = file;
7104887Schin 	by_number = 0;
7114887Schin 	job_lock();
7124887Schin 	pw = job.pwlist;
7134887Schin 	if(jobs==0)
7144887Schin 	{
7154887Schin 		/* do all jobs */
7164887Schin 		for(;pw;pw=px)
7174887Schin 		{
7184887Schin 			px = pw->p_nxtjob;
7194887Schin 			if(pw->p_env != sh.jobenv)
7204887Schin 				continue;
7214887Schin 			if((*fun)(pw,arg))
7224887Schin 				r = 2;
7234887Schin 		}
7244887Schin 	}
7254887Schin 	else if(*jobs==0)	/* current job */
7264887Schin 	{
7274887Schin 		/* skip over non-stop jobs */
7284887Schin 		while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0))
7294887Schin 			pw = pw->p_nxtjob;
7304887Schin 		if((*fun)(pw,arg))
7314887Schin 			r = 2;
7324887Schin 	}
7334887Schin 	else while(jobid = *jobs++)
7344887Schin 	{
7354887Schin 		job_string = jobid;
7364887Schin 		if(*jobid==0)
7374887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
7384887Schin 		if(*jobid == '%')
7394887Schin 			pw = job_bystring(jobid);
7404887Schin 		else
7414887Schin 		{
7424887Schin 			int pid = (int)strtol(jobid, (char**)0, 10);
7434887Schin 			if(pid<0)
7444887Schin 				jobid++;
7454887Schin 			while(isdigit(*jobid))
7464887Schin 				jobid++;
7474887Schin 			if(*jobid)
7484887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
7494887Schin 			if(!(pw = job_bypid(pid)))
7504887Schin 			{
7514887Schin 				pw = &dummy;
7524887Schin 				pw->p_pid = pid;
7534887Schin 				pw->p_pgrp = pid;
7544887Schin 			}
7554887Schin 			by_number = 1;
7564887Schin 		}
7574887Schin 		if((*fun)(pw,arg))
7584887Schin 			r = 2;
7594887Schin 		by_number = 0;
7604887Schin 	}
7614887Schin 	job_unlock();
7624887Schin 	return(r);
7634887Schin }
7644887Schin 
7654887Schin /*
7664887Schin  * send signal <sig> to background process group if not disowned
7674887Schin  */
7684887Schin int job_terminate(register struct process *pw,register int sig)
7694887Schin {
7704887Schin 	if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
7714887Schin 		job_kill(pw,sig);
7724887Schin 	return(0);
7734887Schin }
7744887Schin 
7754887Schin /*
7764887Schin  * list the given job
7774887Schin  * flag JOB_LFLAG for long listing
7784887Schin  * flag JOB_NFLAG for list only jobs marked for notification
7794887Schin  * flag JOB_PFLAG for process id(s) only
7804887Schin  */
7814887Schin 
7824887Schin int job_list(struct process *pw,register int flag)
7834887Schin {
7844887Schin 	register struct process *px = pw;
7854887Schin 	register int  n;
7864887Schin 	register const char *msg;
7874887Schin 	register int msize;
7884887Schin 	if(!pw || pw->p_job<=0)
7894887Schin 		return(1);
7904887Schin 	if(pw->p_env != sh.jobenv)
7914887Schin 		return(0);
7924887Schin 	if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
7934887Schin 		return(0);
7944887Schin 	if((flag&JOB_PFLAG))
7954887Schin 	{
7964887Schin 		sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid);
7974887Schin 		return(0);
7984887Schin 	}
7994887Schin 	if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
8004887Schin 		return(0);
8014887Schin 	job_lock();
8024887Schin 	n = px->p_job;
8034887Schin 	if(px==job.pwlist)
8044887Schin 		msize = '+';
8054887Schin 	else if(px==job.pwlist->p_nxtjob)
8064887Schin 		msize = '-';
8074887Schin 	else
8084887Schin 		msize = ' ';
8094887Schin 	if(flag&JOB_NLFLAG)
8104887Schin 		sfputc(outfile,'\n');
8114887Schin 	sfprintf(outfile,"[%d] %c ",n, msize);
8124887Schin 	do
8134887Schin 	{
8144887Schin 		n = 0;
8154887Schin 		if(flag&JOB_LFLAG)
8164887Schin 			sfprintf(outfile,"%d\t",px->p_pid);
8174887Schin 		if(px->p_flag&P_SIGNALLED)
8184887Schin 			msg = job_sigmsg((int)(px->p_exit));
8194887Schin 		else if(px->p_flag&P_NOTIFY)
8204887Schin 		{
8214887Schin 			msg = sh_translate(e_done);
8224887Schin 			n = px->p_exit;
8234887Schin 		}
8244887Schin 		else
8254887Schin 			msg = sh_translate(e_running);
8264887Schin 		px->p_flag &= ~P_NOTIFY;
8274887Schin 		sfputr(outfile,msg,-1);
8284887Schin 		msize = strlen(msg);
8294887Schin 		if(n)
8304887Schin 		{
8314887Schin 			sfprintf(outfile,"(%d)",(int)n);
8324887Schin 			msize += (3+(n>10)+(n>100));
8334887Schin 		}
8344887Schin 		if(px->p_flag&P_COREDUMP)
8354887Schin 		{
8364887Schin 			msg = sh_translate(e_coredump);
8374887Schin 			sfputr(outfile, msg, -1);
8384887Schin 			msize += strlen(msg);
8394887Schin 		}
8404887Schin 		sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
8414887Schin 		if(flag&JOB_LFLAG)
8424887Schin 			px = px->p_nxtproc;
8434887Schin 		else
8444887Schin 		{
8454887Schin 			while(px=px->p_nxtproc)
8464887Schin 				px->p_flag &= ~P_NOTIFY;
8474887Schin 			px = 0;
8484887Schin 		}
8494887Schin 		if(!px)
8504887Schin 			hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
8514887Schin 		else
8524887Schin 			sfputr(outfile, e_nlspace, -1);
8534887Schin 	}
8544887Schin 	while(px);
8554887Schin 	job_unlock();
8564887Schin 	return(0);
8574887Schin }
8584887Schin 
8594887Schin /*
8604887Schin  * get the process group given the job number
8614887Schin  * This routine returns the process group number or -1
8624887Schin  */
8634887Schin static struct process *job_bystring(register char *ajob)
8644887Schin {
8654887Schin 	register struct process *pw=job.pwlist;
8664887Schin 	register int c;
8674887Schin 	if(*ajob++ != '%' || !pw)
8684887Schin 		return(NIL(struct process*));
8694887Schin 	c = *ajob;
8704887Schin 	if(isdigit(c))
8714887Schin 		pw = job_byjid((int)strtol(ajob, (char**)0, 10));
8724887Schin 	else if(c=='+' || c=='%')
8734887Schin 		;
8744887Schin 	else if(c=='-')
8754887Schin 	{
8764887Schin 		if(pw)
8774887Schin 			pw = job.pwlist->p_nxtjob;
8784887Schin 	}
8794887Schin 	else
8804887Schin 		pw = job_byname(ajob);
8814887Schin 	if(pw && pw->p_flag)
8824887Schin 		return(pw);
8834887Schin 	return(NIL(struct process*));
8844887Schin }
8854887Schin 
8864887Schin /*
8874887Schin  * Kill a job or process
8884887Schin  */
8894887Schin 
8904887Schin int job_kill(register struct process *pw,register int sig)
8914887Schin {
8924887Schin 	register pid_t pid;
8934887Schin 	register int r;
8944887Schin 	const char *msg;
8954887Schin #ifdef SIGTSTP
8964887Schin 	int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
8974887Schin #else
8984887Schin #	define stopsig	1
8994887Schin #endif	/* SIGTSTP */
9004887Schin 	job_lock();
9014887Schin 	errno = ECHILD;
9024887Schin 	if(pw==0)
9034887Schin 		goto error;
9044887Schin 	pid = pw->p_pid;
9054887Schin 	if(by_number)
9064887Schin 	{
9074887Schin 		if(pid==0 && job.jobcontrol)
9084887Schin 			r = job_walk(outfile, job_kill,sig, (char**)0);
9094887Schin #ifdef SIGTSTP
9104887Schin 		if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
9114887Schin 		{
9124887Schin 			/* can't stop login shell */
9134887Schin 			errno = EPERM;
9144887Schin 			r = -1;
9154887Schin 		}
9164887Schin 		else
9174887Schin 		{
9184887Schin 			if(pid>=0)
9194887Schin 			{
9204887Schin 				if((r = kill(pid,sig))>=0 && !stopsig)
9214887Schin 				{
9224887Schin 					if(pw->p_flag&P_STOPPED)
9234887Schin 						pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
9244887Schin 					if(sig)
9254887Schin 						kill(pid,SIGCONT);
9264887Schin 				}
9274887Schin 			}
9284887Schin 			else
9294887Schin 			{
9304887Schin 				if((r = killpg(-pid,sig))>=0 && !stopsig)
9314887Schin 				{
9324887Schin 					job_unstop(job_bypid(pw->p_pid));
9334887Schin 					if(sig)
9344887Schin 						killpg(-pid,SIGCONT);
9354887Schin 				}
9364887Schin 			}
9374887Schin 		}
9384887Schin #else
9394887Schin 		if(pid>=0)
9404887Schin 			r = kill(pid,sig);
9414887Schin 		else
9424887Schin 			r = killpg(-pid,sig);
9434887Schin #endif	/* SIGTSTP */
9444887Schin 	}
9454887Schin 	else
9464887Schin 	{
9474887Schin 		if(pid = pw->p_pgrp)
9484887Schin 		{
9494887Schin 			r = killpg(pid,sig);
9504887Schin #ifdef SIGTSTP
9514887Schin 			if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT))
9524887Schin 				job_unstop(pw);
9534887Schin #endif	/* SIGTSTP */
9544887Schin 			if(r>=0)
9554887Schin 				sh_delay(.05);
9564887Schin 		}
9574887Schin 		while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0)
9584887Schin 		{
9594887Schin #ifdef SIGTSTP
9604887Schin 			if(sig==SIGHUP || sig==SIGTERM)
9614887Schin 				kill(pw->p_pid,SIGCONT);
9624887Schin #endif	/* SIGTSTP */
9634887Schin 			pw = pw->p_nxtproc;
9644887Schin 		}
9654887Schin 	}
9664887Schin 	if(r<0 && job_string)
9674887Schin 	{
9684887Schin 	error:
9694887Schin 		if(pw && by_number)
9704887Schin 			msg = sh_translate(e_no_proc);
9714887Schin 		else
9724887Schin 			msg = sh_translate(e_no_job);
9734887Schin 		if(errno == EPERM)
9744887Schin 			msg = sh_translate(e_access);
9754887Schin 		sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg);
9764887Schin 		r = 2;
9774887Schin 	}
9784887Schin 	sh_delay(.001);
9794887Schin 	job_unlock();
9804887Schin 	return(r);
9814887Schin }
9824887Schin 
9834887Schin /*
9844887Schin  * Get process structure from first letters of jobname
9854887Schin  *
9864887Schin  */
9874887Schin 
9884887Schin static struct process *job_byname(char *name)
9894887Schin {
9904887Schin 	register struct process *pw = job.pwlist;
9914887Schin 	register struct process *pz = 0;
9924887Schin 	register int *flag = 0;
9934887Schin 	register char *cp = name;
9944887Schin 	int offset;
9954887Schin 	if(!sh.hist_ptr)
9964887Schin 		return(NIL(struct process*));
9974887Schin 	if(*cp=='?')
9984887Schin 		cp++,flag= &offset;
9994887Schin 	for(;pw;pw=pw->p_nxtjob)
10004887Schin 	{
10014887Schin 		if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
10024887Schin 		{
10034887Schin 			if(pz)
10044887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1);
10054887Schin 			pz = pw;
10064887Schin 		}
10074887Schin 	}
10084887Schin 	return(pz);
10094887Schin }
10104887Schin 
10114887Schin #else
10124887Schin #   define job_set(x)
10134887Schin #   define job_reset(x)
10144887Schin #endif /* JOBS */
10154887Schin 
10164887Schin 
10174887Schin 
10184887Schin /*
10194887Schin  * Initialize the process posting array
10204887Schin  */
10214887Schin 
10224887Schin void	job_clear(void)
10234887Schin {
10244887Schin 	register struct process *pw, *px;
10254887Schin 	register struct process *pwnext;
10264887Schin 	register int j = BYTE(sh.lim.child_max);
10274887Schin 	register struct jobsave *jp,*jpnext;
10284887Schin 	job_lock();
10294887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
10304887Schin 	{
10314887Schin 		pwnext = pw->p_nxtjob;
10324887Schin 		while(px=pw)
10334887Schin 		{
10344887Schin 			pw = pw->p_nxtproc;
10354887Schin 			free((void*)px);
10364887Schin 		}
10374887Schin 	}
10384887Schin 	for(jp=bck.list; jp;jp=jpnext)
10394887Schin 	{
10404887Schin 		jpnext = jp->next;
10414887Schin 		free((void*)jp);
10424887Schin 	}
10434887Schin 	bck.list = 0;
10444887Schin 	if(njob_savelist < NJOB_SAVELIST)
10454887Schin 		init_savelist();
10464887Schin 	job.pwlist = NIL(struct process*);
10474887Schin 	job.numpost=0;
10484887Schin 	job.waitall = 0;
10494887Schin 	job.curpgid = 0;
10504887Schin 	job.toclear = 0;
10514887Schin 	if(!job.freejobs)
10524887Schin 		job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
10534887Schin 	while(j >=0)
10544887Schin 		job.freejobs[j--]  = 0;
10554887Schin 	job_unlock();
10564887Schin }
10574887Schin 
10584887Schin /*
10594887Schin  * put the process <pid> on the process list and return the job number
10604887Schin  * if non-zero, <join> is the process id of the job to join
10614887Schin  */
10624887Schin 
10634887Schin int job_post(pid_t pid, pid_t join)
10644887Schin {
10654887Schin 	register struct process *pw;
10664887Schin 	register History_t *hp = sh.hist_ptr;
1067*8462SApril.Chin@Sun.COM 	int val;
10684887Schin 	sh.jobenv = sh.curenv;
10694887Schin 	if(njob_savelist < NJOB_SAVELIST)
10704887Schin 		init_savelist();
10714887Schin 	if(job.toclear)
10724887Schin 	{
10734887Schin 		job_clear();
10744887Schin 		return(0);
10754887Schin 	}
10764887Schin 	job_lock();
10774887Schin 	if(pw = job_bypid(pid))
10784887Schin 		job_unpost(pw,0);
10794887Schin 	if(join && (pw=job_bypid(join)))
10804887Schin 	{
10814887Schin 		/* if job to join is not first move it to front */
10824887Schin 		if((pw=job_byjid(pw->p_job)) != job.pwlist)
10834887Schin 		{
10844887Schin 			job_unlink(pw);
10854887Schin 			pw->p_nxtjob = job.pwlist;
10864887Schin 			job.pwlist = pw;
10874887Schin 		}
10884887Schin 	}
10894887Schin 	if(pw=freelist)
10904887Schin 		freelist = pw->p_nxtjob;
10914887Schin 	else
10924887Schin 		pw = new_of(struct process,0);
10934887Schin 	job.numpost++;
10944887Schin 	if(join && job.pwlist)
10954887Schin 	{
10964887Schin 		/* join existing current job */
10974887Schin 		pw->p_nxtjob = job.pwlist->p_nxtjob;
10984887Schin 		pw->p_nxtproc = job.pwlist;
10994887Schin 		pw->p_job = job.pwlist->p_job;
11004887Schin 	}
11014887Schin 	else
11024887Schin 	{
11034887Schin 		/* create a new job */
11044887Schin 		while((pw->p_job = job_alloc()) < 0)
11054887Schin 			job_wait((pid_t)1);
11064887Schin 		pw->p_nxtjob = job.pwlist;
11074887Schin 		pw->p_nxtproc = 0;
11084887Schin 	}
11094887Schin 	job.pwlist = pw;
11104887Schin 	pw->p_env = sh.curenv;
11114887Schin 	pw->p_pid = pid;
11124887Schin 	pw->p_flag = P_EXITSAVE;
1113*8462SApril.Chin@Sun.COM 	pw->p_exitmin = sh.xargexit;
1114*8462SApril.Chin@Sun.COM 	pw->p_exit = 0;
11154887Schin 	if(sh_isstate(SH_MONITOR))
11164887Schin 	{
11174887Schin 		if(killpg(job.curpgid,0)<0 && errno==ESRCH)
11184887Schin 			job.curpgid = pid;
11194887Schin 		pw->p_fgrp = job.curpgid;
11204887Schin 	}
11214887Schin 	else
11224887Schin 		pw->p_fgrp = 0;
11234887Schin 	pw->p_pgrp = pw->p_fgrp;
11244887Schin #ifdef DEBUG
11254887Schin 	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,
11264887Schin 		pw->p_pid,pw->p_pgrp,job.savesig,join);
11274887Schin 	sfsync(sfstderr);
11284887Schin #endif /* DEBUG */
11294887Schin #ifdef JOBS
11304887Schin 	if(hp && !sh_isstate(SH_PROFILE))
11314887Schin 		pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
11324887Schin 	else
11334887Schin 		pw->p_name = -1;
11344887Schin #endif /* JOBS */
1135*8462SApril.Chin@Sun.COM 	if ((val = job_chksave(pid)) >= 0)
11364887Schin 	{
1137*8462SApril.Chin@Sun.COM 		pw->p_exit = val;
11384887Schin 		if(pw->p_exit==SH_STOPSIG)
11394887Schin 		{
11404887Schin 			pw->p_flag |= (P_SIGNALLED|P_STOPPED);
11414887Schin 			pw->p_exit = 0;
11424887Schin 		}
11434887Schin 		else
11444887Schin 			pw->p_flag |= (P_DONE|P_NOTIFY);
11454887Schin 	}
11464887Schin 	lastpid = 0;
11474887Schin 	job_unlock();
11484887Schin 	return(pw->p_job);
11494887Schin }
11504887Schin 
11514887Schin /*
11524887Schin  * Returns a process structure give a process id
11534887Schin  */
11544887Schin 
11554887Schin static struct process *job_bypid(pid_t pid)
11564887Schin {
11574887Schin 	register struct process  *pw, *px;
11584887Schin 	for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
11594887Schin 		for(px=pw; px; px=px->p_nxtproc)
11604887Schin 		{
11614887Schin 			if(px->p_pid==pid)
11624887Schin 				return(px);
11634887Schin 		}
11644887Schin 	return(NIL(struct process*));
11654887Schin }
11664887Schin 
11674887Schin /*
11684887Schin  * return a pointer to a job given the job id
11694887Schin  */
11704887Schin 
11714887Schin static struct process *job_byjid(int jobid)
11724887Schin {
11734887Schin 	register struct process *pw;
11744887Schin 	for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
11754887Schin 	{
11764887Schin 		if(pw->p_job==jobid)
11774887Schin 			break;
11784887Schin 	}
11794887Schin 	return(pw);
11804887Schin }
11814887Schin 
11824887Schin /*
11834887Schin  * print a signal message
11844887Schin  */
11854887Schin static void job_prmsg(register struct process *pw)
11864887Schin {
11874887Schin 	if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
11884887Schin 	{
11894887Schin 		register const char *msg, *dump;
11904887Schin 		msg = job_sigmsg((int)(pw->p_exit));
11914887Schin 		msg = sh_translate(msg);
11924887Schin 		if(pw->p_flag&P_COREDUMP)
11934887Schin 			dump =  sh_translate(e_coredump);
11944887Schin 		else
11954887Schin 			dump = "";
11964887Schin 		if(sh_isstate(SH_INTERACTIVE))
11974887Schin 			sfprintf(sfstderr,"%s%s\n",msg,dump);
11984887Schin 		else
11994887Schin 			errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump);
12004887Schin 	}
12014887Schin }
12024887Schin 
12034887Schin /*
12044887Schin  * Wait for process pid to complete
12054887Schin  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
12064887Schin  * pid=0 to unpost all done processes
12074887Schin  * pid=1 to wait for at least one process to complete
12084887Schin  * pid=-1 to wait for all runing processes
12094887Schin  */
12104887Schin 
1211*8462SApril.Chin@Sun.COM int	job_wait(register pid_t pid)
12124887Schin {
12134887Schin 	register struct process *pw=0,*px;
12144887Schin 	register int	jobid = 0;
1215*8462SApril.Chin@Sun.COM 	int		nochild = 1;
12164887Schin 	char		intr = 0;
12174887Schin 	if(pid <= 0)
12184887Schin 	{
12194887Schin 		if(pid==0)
12204887Schin 			goto done;
12214887Schin 		pid = -pid;
12224887Schin 		intr = 1;
12234887Schin 	}
12244887Schin 	job_lock();
12254887Schin 	if(pid > 1)
12264887Schin 	{
1227*8462SApril.Chin@Sun.COM 		if(pid==sh.spid)
1228*8462SApril.Chin@Sun.COM 			sh.spid = 0;
12294887Schin 		if(!(pw=job_bypid(pid)))
12304887Schin 		{
12314887Schin 			/* check to see whether job status has been saved */
12324887Schin 			if((sh.exitval = job_chksave(pid)) < 0)
12334887Schin 				sh.exitval = ERROR_NOENT;
12344887Schin 			exitset();
12354887Schin 			job_unlock();
1236*8462SApril.Chin@Sun.COM 			return(nochild);
12374887Schin 		}
12384887Schin 		else if(intr && pw->p_env!=sh.curenv)
12394887Schin 		{
12404887Schin 			sh.exitval = ERROR_NOENT;
12414887Schin 			job_unlock();
1242*8462SApril.Chin@Sun.COM 			return(nochild);
12434887Schin 		}
12444887Schin 		jobid = pw->p_job;
12454887Schin 		if(!intr)
12464887Schin 			pw->p_flag &= ~P_EXITSAVE;
12474887Schin 		if(pw->p_pgrp && job.parent!= (pid_t)-1)
12484887Schin 			job_set(job_byjid(jobid));
12494887Schin 	}
1250*8462SApril.Chin@Sun.COM 	pwfg = pw;
12514887Schin #ifdef DEBUG
12524887Schin 	sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid);
12534887Schin 	if(pw)
12544887Schin 		sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag);
12554887Schin #endif /* DEBUG*/
12564887Schin 	errno = 0;
1257*8462SApril.Chin@Sun.COM 	if(sh.coutpipe>=0 && sh.cpid==lastpid)
1258*8462SApril.Chin@Sun.COM 	{
1259*8462SApril.Chin@Sun.COM 		sh_close(sh.coutpipe);
1260*8462SApril.Chin@Sun.COM 		sh_close(sh.cpipe[1]);
1261*8462SApril.Chin@Sun.COM 		sh.cpipe[1] = sh.coutpipe = -1;
1262*8462SApril.Chin@Sun.COM 	}
12634887Schin 	while(1)
12644887Schin 	{
12654887Schin 		if(job.waitsafe)
12664887Schin 		{
12674887Schin 			for(px=job.pwlist;px; px = px->p_nxtjob)
12684887Schin 			{
12694887Schin 				if(px!=pw && (px->p_flag&P_NOTIFY))
12704887Schin 				{
12714887Schin 					if(sh_isoption(SH_NOTIFY))
12724887Schin 					{
12734887Schin 						outfile = sfstderr;
12744887Schin 						job_list(px,JOB_NFLAG|JOB_NLFLAG);
12754887Schin 						sfsync(sfstderr);
12764887Schin 					}
12774887Schin 					else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
12784887Schin 					{
12794887Schin 						job_prmsg(px);
12804887Schin 						px->p_flag &= ~P_NOTIFY;
12814887Schin 					}
12824887Schin 				}
12834887Schin 			}
12844887Schin 		}
12854887Schin 		if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
12864887Schin 		{
12874887Schin #ifdef SIGTSTP
12884887Schin 			if(pw->p_flag&P_STOPPED)
12894887Schin 			{
12904887Schin 				pw->p_flag |= P_EXITSAVE;
12914887Schin 				if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
12924887Schin 				{
12934887Schin 					if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
12944887Schin 						break;
12954887Schin 
12964887Schin 					killpg(pw->p_pgrp,SIGCONT);
12974887Schin 				}
12984887Schin 				else /* ignore stop when non-interactive */
12994887Schin 					pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
13004887Schin 			}
13014887Schin 			else
13024887Schin #endif /* SIGTSTP */
13034887Schin 			{
13044887Schin 				if(pw->p_flag&P_SIGNALLED)
13054887Schin 				{
13064887Schin 					pw->p_flag &= ~P_NOTIFY;
13074887Schin 					job_prmsg(pw);
13084887Schin 				}
13094887Schin 				else if(pw->p_flag&P_DONE)
13104887Schin 					pw->p_flag &= ~P_NOTIFY;
13114887Schin 				if(pw->p_job==jobid)
13124887Schin 				{
13134887Schin 					px = job_byjid(jobid);
13144887Schin 					/* last process in job */
13154887Schin 					if(sh_isoption(SH_PIPEFAIL))
13164887Schin 					{
13174887Schin 						/* last non-zero exit */
13184887Schin 						for(;px;px=px->p_nxtproc)
13194887Schin 						{
13204887Schin 							if(px->p_exit)
13214887Schin 								break;
13224887Schin 						}
13234887Schin 						if(!px)
13244887Schin 							px = pw;
13254887Schin 					}
13264887Schin 					else if(px!=pw)
13274887Schin 						px = 0;
13284887Schin 					if(px)
13294887Schin 					{
13304887Schin 						sh.exitval=px->p_exit;
13314887Schin 						if(px->p_flag&P_SIGNALLED)
13324887Schin 							sh.exitval |= SH_EXITSIG;
13334887Schin 						if(intr)
13344887Schin 							px->p_flag &= ~P_EXITSAVE;
13354887Schin 					}
13364887Schin 				}
13374887Schin 				if(!job.waitall)
13384887Schin 				{
13394887Schin 					if(!sh_isoption(SH_PIPEFAIL))
13404887Schin 						job_unpost(pw,1);
13414887Schin 					break;
13424887Schin 				}
13434887Schin 				else if(!(px=job_unpost(pw,1)))
13444887Schin 					break;
13454887Schin 				pw = px;
13464887Schin 				continue;
13474887Schin 			}
13484887Schin 		}
13494887Schin 		sfsync(sfstderr);
13504887Schin 		job.waitsafe = 0;
13514887Schin 		nochild = job_reap(job.savesig);
13524887Schin 		if(job.waitsafe)
13534887Schin 			continue;
13544887Schin 		if(nochild)
13554887Schin 			break;
13564887Schin 		if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
13574887Schin 			sh_timetraps();
13584887Schin 		if((intr && sh.trapnote) || (pid==1 && !intr))
13594887Schin 			break;
13604887Schin 	}
1361*8462SApril.Chin@Sun.COM 	pwfg = 0;
13624887Schin 	job_unlock();
13634887Schin 	if(pid==1)
1364*8462SApril.Chin@Sun.COM 		return(nochild);
13654887Schin 	exitset();
13664887Schin 	if(pw->p_pgrp)
13674887Schin 	{
13684887Schin 		job_reset(pw);
13694887Schin 		/* propogate keyboard interrupts to parent */
13704887Schin 		if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
13714887Schin 			sh_fault(SIGINT);
13724887Schin #ifdef SIGTSTP
13734887Schin 		else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
13744887Schin 		{
13754887Schin 			job.parent = 0;
13764887Schin 			sh_fault(SIGTSTP);
13774887Schin 		}
13784887Schin #endif /* SIGTSTP */
13794887Schin 	}
13804887Schin 	else
1381*8462SApril.Chin@Sun.COM 	{
1382*8462SApril.Chin@Sun.COM 		if(pw->p_pid == tcgetpgrp(JOBTTY))
1383*8462SApril.Chin@Sun.COM 		{
1384*8462SApril.Chin@Sun.COM 			if(pw->p_pgrp==0)
1385*8462SApril.Chin@Sun.COM 				pw->p_pgrp = pw->p_pid;
1386*8462SApril.Chin@Sun.COM 			job_reset(pw);
1387*8462SApril.Chin@Sun.COM 		}
13884887Schin 		tty_set(-1, 0, NIL(struct termios*));
1389*8462SApril.Chin@Sun.COM 	}
13904887Schin done:
13914887Schin 	if(!job.waitall && sh_isoption(SH_PIPEFAIL))
1392*8462SApril.Chin@Sun.COM 		return(nochild);
13934887Schin 	if(!sh.intrap)
13944887Schin 	{
13954887Schin 		job_lock();
13964887Schin 		for(pw=job.pwlist; pw; pw=px)
13974887Schin 		{
13984887Schin 			px = pw->p_nxtjob;
13994887Schin 			job_unpost(pw,0);
14004887Schin 		}
14014887Schin 		job_unlock();
14024887Schin 	}
1403*8462SApril.Chin@Sun.COM 	return(nochild);
14044887Schin }
14054887Schin 
14064887Schin /*
14074887Schin  * move job to foreground if bgflag == 'f'
14084887Schin  * move job to background if bgflag == 'b'
14094887Schin  * disown job if bgflag == 'd'
14104887Schin  */
14114887Schin 
14124887Schin int job_switch(register struct process *pw,int bgflag)
14134887Schin {
14144887Schin 	register const char *msg;
14154887Schin 	job_lock();
14164887Schin 	if(!pw || !(pw=job_byjid((int)pw->p_job)))
14174887Schin 	{
14184887Schin 		job_unlock();
14194887Schin 		return(1);
14204887Schin 	}
14214887Schin 	if(bgflag=='d')
14224887Schin 	{
14234887Schin 		for(; pw; pw=pw->p_nxtproc)
14244887Schin 			pw->p_flag |= P_DISOWN;
14254887Schin 		job_unlock();
14264887Schin 		return(0);
14274887Schin 	}
14284887Schin #ifdef SIGTSTP
14294887Schin 	if(bgflag=='b')
14304887Schin 	{
14314887Schin 		sfprintf(outfile,"[%d]\t",(int)pw->p_job);
14324887Schin 		sh.bckpid = pw->p_pid;
14334887Schin 		msg = "&";
14344887Schin 	}
14354887Schin 	else
14364887Schin 	{
14374887Schin 		job_unlink(pw);
14384887Schin 		pw->p_nxtjob = job.pwlist;
14394887Schin 		job.pwlist = pw;
14404887Schin 		msg = "";
14414887Schin 	}
14424887Schin 	hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
14434887Schin 	sfputr(outfile,msg,'\n');
14444887Schin 	sfsync(outfile);
14454887Schin 	if(bgflag=='f')
14464887Schin 	{
14474887Schin 		if(!(pw=job_unpost(pw,1)))
14484887Schin 		{
14494887Schin 			job_unlock();
14504887Schin 			return(1);
14514887Schin 		}
14524887Schin 		job.waitall = 1;
14534887Schin 		pw->p_flag |= P_FG;
14544887Schin 		job_wait(pw->p_pid);
14554887Schin 		job.waitall = 0;
14564887Schin 	}
14574887Schin 	else if(pw->p_flag&P_STOPPED)
14584887Schin 		job_unstop(pw);
14594887Schin #endif /* SIGTSTP */
14604887Schin 	job_unlock();
14614887Schin 	return(0);
14624887Schin }
14634887Schin 
14644887Schin 
14654887Schin #ifdef SIGTSTP
14664887Schin /*
14674887Schin  * Set the foreground group associated with a job
14684887Schin  */
14694887Schin 
14704887Schin static void job_fgrp(register struct process *pw, int newgrp)
14714887Schin {
14724887Schin 	for(; pw; pw=pw->p_nxtproc)
14734887Schin 		pw->p_fgrp = newgrp;
14744887Schin }
14754887Schin 
14764887Schin /*
14774887Schin  * turn off STOP state of a process group and send CONT signals
14784887Schin  */
14794887Schin 
14804887Schin static void job_unstop(register struct process *px)
14814887Schin {
14824887Schin 	register struct process *pw;
14834887Schin 	register int num = 0;
14844887Schin 	for(pw=px ;pw ;pw=pw->p_nxtproc)
14854887Schin 	{
14864887Schin 		if(pw->p_flag&P_STOPPED)
14874887Schin 		{
14884887Schin 			num++;
14894887Schin 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
14904887Schin 		}
14914887Schin 	}
14924887Schin 	if(num!=0)
14934887Schin 	{
14944887Schin 		if(px->p_fgrp != px->p_pgrp)
14954887Schin 			killpg(px->p_fgrp,SIGCONT);
14964887Schin 		killpg(px->p_pgrp,SIGCONT);
14974887Schin 	}
14984887Schin }
14994887Schin #endif	/* SIGTSTP */
15004887Schin 
15014887Schin /*
15024887Schin  * remove a job from table
15034887Schin  * If all the processes have not completed, unpost first non-completed  process
15044887Schin  * Otherwise the job is removed and job_unpost returns NULL.
15054887Schin  * pwlist is reset if the first job is removed
15064887Schin  * if <notify> is non-zero, then jobs with pending notifications are unposted
15074887Schin  */
15084887Schin 
15094887Schin static struct process *job_unpost(register struct process *pwtop,int notify)
15104887Schin {
15114887Schin 	register struct process *pw;
15124887Schin 	/* make sure all processes are done */
15134887Schin #ifdef DEBUG
15144887Schin 	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);
15154887Schin 	sfsync(sfstderr);
15164887Schin #endif /* DEBUG */
15174887Schin 	pwtop = pw = job_byjid((int)pwtop->p_job);
15184887Schin 	for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc);
15194887Schin 	if(pw)
15204887Schin 		return(pw);
15214887Schin 	/* all processes complete, unpost job */
15224887Schin 	job_unlink(pwtop);
15234887Schin 	for(pw=pwtop; pw; pw=pw->p_nxtproc)
15244887Schin 	{
15254887Schin 		/* save the exit status for background jobs */
1526*8462SApril.Chin@Sun.COM 		if((pw->p_flag&P_EXITSAVE) ||  pw->p_pid==sh.spid)
15274887Schin 		{
15284887Schin 			struct jobsave *jp;
15294887Schin 			/* save status for future wait */
15304887Schin 			if(bck.count++ > sh.lim.child_max)
15314887Schin 				job_chksave(0);
15324887Schin 			if(jp = jobsave_create(pw->p_pid))
15334887Schin 			{
15344887Schin 				jp->next = bck.list;
15354887Schin 				bck.list = jp;
15364887Schin 				jp->exitval = pw->p_exit;
15374887Schin 				if(pw->p_flag&P_SIGNALLED)
15384887Schin 					jp->exitval |= SH_EXITSIG;
15394887Schin 			}
15404887Schin 			pw->p_flag &= ~P_EXITSAVE;
15414887Schin 		}
15424887Schin 		pw->p_flag &= ~P_DONE;
15434887Schin 		job.numpost--;
15444887Schin 		pw->p_nxtjob = freelist;
15454887Schin 		freelist = pw;
15464887Schin 	}
15474887Schin #ifdef DEBUG
15484887Schin 	sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job);
15494887Schin 	sfsync(sfstderr);
15504887Schin #endif /* DEBUG */
15514887Schin 	job_free((int)pwtop->p_job);
15524887Schin 	return((struct process*)0);
15534887Schin }
15544887Schin 
15554887Schin /*
15564887Schin  * unlink a job form the job list
15574887Schin  */
15584887Schin static void job_unlink(register struct process *pw)
15594887Schin {
15604887Schin 	register struct process *px;
15614887Schin 	if(pw==job.pwlist)
15624887Schin 	{
15634887Schin 		job.pwlist = pw->p_nxtjob;
15644887Schin 		job.curpgid = 0;
15654887Schin 		return;
15664887Schin 	}
15674887Schin 	for(px=job.pwlist;px;px=px->p_nxtjob)
15684887Schin 		if(px->p_nxtjob == pw)
15694887Schin 		{
15704887Schin 			px->p_nxtjob = pw->p_nxtjob;
15714887Schin 			return;
15724887Schin 		}
15734887Schin }
15744887Schin 
15754887Schin /*
15764887Schin  * get an unused job number
15774887Schin  * freejobs is a bit vector, 0 is unused
15784887Schin  */
15794887Schin 
15804887Schin static int job_alloc(void)
15814887Schin {
15824887Schin 	register int j=0;
15834887Schin 	register unsigned mask = 1;
15844887Schin 	register unsigned char *freeword;
15854887Schin 	register int jmax = BYTE(sh.lim.child_max);
15864887Schin 	/* skip to first word with a free slot */
15874887Schin 	for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
15884887Schin 	if(j >= jmax)
15894887Schin 	{
15904887Schin 		register struct process *pw;
15914887Schin 		for(j=1; j < sh.lim.child_max; j++)
15924887Schin 		{
15934887Schin 			if((pw=job_byjid(j))&& !job_unpost(pw,0))
15944887Schin 				break;
15954887Schin 		}
15964887Schin 		j /= CHAR_BIT;
15974887Schin 		if(j >= jmax)
15984887Schin 			return(-1);
15994887Schin 	}
16004887Schin 	freeword = &job.freejobs[j];
16014887Schin 	j *= CHAR_BIT;
16024887Schin 	for(j++;mask&(*freeword);j++,mask <<=1);
16034887Schin 	*freeword  |= mask;
16044887Schin 	return(j);
16054887Schin }
16064887Schin 
16074887Schin /*
16084887Schin  * return a job number
16094887Schin  */
16104887Schin 
16114887Schin static void job_free(register int n)
16124887Schin {
16134887Schin 	register int j = (--n)/CHAR_BIT;
16144887Schin 	register unsigned mask;
16154887Schin 	n -= j*CHAR_BIT;
16164887Schin 	mask = 1 << n;
16174887Schin 	job.freejobs[j]  &= ~mask;
16184887Schin }
16194887Schin 
16204887Schin static char *job_sigmsg(int sig)
16214887Schin {
16224887Schin 	static char signo[40];
16234887Schin #ifdef apollo
16244887Schin 	/*
16254887Schin 	 * This code handles the formatting for the apollo specific signal
16264887Schin 	 * SIGAPOLLO.
16274887Schin 	 */
16284887Schin 	extern char *apollo_error(void);
16294887Schin 
16304887Schin 	if ( sig == SIGAPOLLO )
16314887Schin 		return( apollo_error() );
16324887Schin #endif /* apollo */
16334887Schin 	if(sig<sh.sigmax && sh.sigmsg[sig])
16344887Schin 		return(sh.sigmsg[sig]);
16354887Schin #if defined(SIGRTMIN) && defined(SIGRTMAX)
1636*8462SApril.Chin@Sun.COM 	if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX])
16374887Schin 	{
16384887Schin 		static char sigrt[20];
1639*8462SApril.Chin@Sun.COM 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2)
1640*8462SApril.Chin@Sun.COM 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig);
1641*8462SApril.Chin@Sun.COM 		else
1642*8462SApril.Chin@Sun.COM 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]);
16434887Schin 		return(sigrt);
16444887Schin 	}
16454887Schin #endif
16464887Schin 	sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig);
16474887Schin 	return(signo);
16484887Schin }
16494887Schin 
16504887Schin /*
16514887Schin  * see whether exit status has been saved and delete it
16524887Schin  * if pid==0, then oldest saved process is deleted
16534887Schin  * If pid is not found a -1 is returned.
16544887Schin  */
16554887Schin static int job_chksave(register pid_t pid)
16564887Schin {
16574887Schin 	register struct jobsave *jp = bck.list, *jpold=0;
16584887Schin 	register int r= -1;
16594887Schin 	while(jp)
16604887Schin 	{
16614887Schin 		if(jp->pid==pid)
16624887Schin 			break;
16634887Schin 		if(pid==0 && !jp->next)
16644887Schin 			break;
16654887Schin 		jpold = jp;
16664887Schin 		jp = jp->next;
16674887Schin 	}
16684887Schin 	if(jp)
16694887Schin 	{
16704887Schin 		r = 0;
16714887Schin 		if(pid)
16724887Schin 			r = jp->exitval;
16734887Schin 		if(jpold)
16744887Schin 			jpold->next = jp->next;
16754887Schin 		else
16764887Schin 			bck.list = jp->next;
16774887Schin 		bck.count--;
16784887Schin 		if(njob_savelist < NJOB_SAVELIST)
16794887Schin 		{
16804887Schin 			njob_savelist++;
16814887Schin 			jp->next = job_savelist;
16824887Schin 			job_savelist = jp;
16834887Schin 		}
16844887Schin 		else
16854887Schin 			free((void*)jp);
16864887Schin 	}
16874887Schin 	return(r);
16884887Schin }
16894887Schin 
16904887Schin void *job_subsave(void)
16914887Schin {
16924887Schin 	struct back_save *bp = new_of(struct back_save,0);
16934887Schin 	job_lock();
16944887Schin 	*bp = bck;
16954887Schin 	bck.count = 0;
16964887Schin 	bck.list = 0;
16974887Schin 	job_unlock();
16984887Schin 	return((void*)bp);
16994887Schin }
17004887Schin 
17014887Schin void job_subrestore(void* ptr)
17024887Schin {
1703*8462SApril.Chin@Sun.COM 	register struct jobsave *jp;
17044887Schin 	register struct back_save *bp = (struct back_save*)ptr;
17054887Schin 	register struct process *pw, *px, *pwnext;
1706*8462SApril.Chin@Sun.COM 	struct jobsave *jpnext;
17074887Schin 	job_lock();
1708*8462SApril.Chin@Sun.COM 	for(jp=bck.list; jp; jp=jpnext)
1709*8462SApril.Chin@Sun.COM 	{
1710*8462SApril.Chin@Sun.COM 		jpnext = jp->next;
1711*8462SApril.Chin@Sun.COM 		if(jp->pid==sh.spid)
1712*8462SApril.Chin@Sun.COM 		{
1713*8462SApril.Chin@Sun.COM 			jp->next = bp->list;
1714*8462SApril.Chin@Sun.COM 			bp->list = jp;
1715*8462SApril.Chin@Sun.COM 		}
1716*8462SApril.Chin@Sun.COM 		else
1717*8462SApril.Chin@Sun.COM 			job_chksave(jp->pid);
1718*8462SApril.Chin@Sun.COM 	}
17194887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
17204887Schin 	{
17214887Schin 		pwnext = pw->p_nxtjob;
17224887Schin 		if(pw->p_env != sh.curenv)
17234887Schin 			continue;
17244887Schin 		for(px=pw; px; px=px->p_nxtproc)
17254887Schin 			px->p_flag |= P_DONE;
17264887Schin 		job_unpost(pw,0);
17274887Schin 	}
1728*8462SApril.Chin@Sun.COM 
1729*8462SApril.Chin@Sun.COM 	/*
1730*8462SApril.Chin@Sun.COM 	 * queue up old lists for disposal by job_reap()
1731*8462SApril.Chin@Sun.COM 	 */
1732*8462SApril.Chin@Sun.COM 
1733*8462SApril.Chin@Sun.COM 	bck = *bp;
1734*8462SApril.Chin@Sun.COM 	free((void*)bp);
17354887Schin 	job_unlock();
17364887Schin }
17374887Schin 
17384887Schin int sh_waitsafe(void)
17394887Schin {
17404887Schin 	return(job.waitsafe);
17414887Schin }
17424887Schin 
17434887Schin void job_fork(pid_t parent)
17444887Schin {
17454887Schin #ifdef DEBUG
17464887Schin 	sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent);
17474887Schin #endif /* DEBUG */
17484887Schin 	switch (parent)
17494887Schin 	{
17504887Schin 	case -1:
17514887Schin 		job_lock();
17524887Schin 		break;
17534887Schin 	case 0:
17544887Schin 		job_unlock();
17554887Schin 		job.waitsafe = 0;
17564887Schin 		job.in_critical = 0;
17574887Schin 		break;
17584887Schin 	default:
17594887Schin 		job_unlock();
17604887Schin 		break;
17614887Schin 	}
17624887Schin }
1763