xref: /onnv-gate/usr/src/lib/libshell/common/sh/jobs.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.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	<wait.h>
344887Schin #include	"io.h"
354887Schin #include	"jobs.h"
364887Schin #include	"history.h"
374887Schin 
384887Schin #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
394887Schin #   undef  WCONTINUED
404887Schin #   define WCONTINUED	0
414887Schin #   undef  WIFCONTINUED
424887Schin #   define WIFCONTINUED(wstat)	(0)
434887Schin #endif
444887Schin 
454887Schin #define	NJOB_SAVELIST	4
464887Schin 
474887Schin /*
484887Schin  * temporary hack to get W* macros to work
494887Schin  */
504887Schin #undef wait
514887Schin #define wait    ______wait
524887Schin /*
534887Schin  * This struct saves a link list of processes that have non-zero exit
544887Schin  * status, have had $! saved, but haven't been waited for
554887Schin  */
564887Schin struct jobsave
574887Schin {
584887Schin 	struct jobsave	*next;
594887Schin 	pid_t		pid;
604887Schin 	unsigned short	exitval;
614887Schin };
624887Schin 
634887Schin static struct jobsave *job_savelist;
644887Schin static int njob_savelist;
658462SApril.Chin@Sun.COM static struct process *pwfg;
664887Schin 
init_savelist(void)674887Schin static void init_savelist(void)
684887Schin {
694887Schin 	register struct jobsave *jp;
704887Schin 	while(njob_savelist < NJOB_SAVELIST)
714887Schin 	{
724887Schin 		jp = newof(0,struct jobsave,1,0);
734887Schin 		jp->next = job_savelist;
744887Schin 		job_savelist = jp;
754887Schin 		njob_savelist++;
764887Schin 	}
774887Schin }
784887Schin 
794887Schin struct back_save
804887Schin {
814887Schin 	int		count;
824887Schin 	struct jobsave	*list;
834887Schin };
844887Schin 
854887Schin #define BYTE(n)		(((n)+CHAR_BIT-1)/CHAR_BIT)
864887Schin #define MAXMSG	25
874887Schin #define SH_STOPSIG	(SH_EXITSIG<<1)
884887Schin 
894887Schin #ifdef VSUSP
904887Schin #   ifndef CNSUSP
914887Schin #	ifdef _POSIX_VDISABLE
924887Schin #	   define CNSUSP	_POSIX_VDISABLE
934887Schin #	else
944887Schin #	   define CNSUSP	0
954887Schin #	endif /* _POSIX_VDISABLE */
964887Schin #   endif /* CNSUSP */
974887Schin #   ifndef CSWTCH
984887Schin #	ifdef CSUSP
994887Schin #	    define CSWTCH	CSUSP
1004887Schin #	else
1014887Schin #	    define CSWTCH	('z'&037)
1024887Schin #	endif /* CSUSP */
1034887Schin #   endif /* CSWTCH */
1044887Schin #endif /* VSUSP */
1054887Schin 
1064887Schin /* Process states */
1074887Schin #define P_EXITSAVE	01
1084887Schin #define P_STOPPED	02
1094887Schin #define P_NOTIFY	04
1104887Schin #define P_SIGNALLED	010
1114887Schin #define P_STTY		020
1124887Schin #define P_DONE		040
1134887Schin #define P_COREDUMP	0100
1144887Schin #define P_DISOWN	0200
1154887Schin #define P_FG		0400
11610898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
11710898Sroland.mainz@nrubsig.org #define P_BG		01000
11810898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
1194887Schin 
1204887Schin static int		job_chksave(pid_t);
1214887Schin static struct process	*job_bypid(pid_t);
1224887Schin static struct process	*job_byjid(int);
1234887Schin static char		*job_sigmsg(int);
1244887Schin static int		job_alloc(void);
1254887Schin static void		job_free(int);
1264887Schin static struct process	*job_unpost(struct process*,int);
1274887Schin static void		job_unlink(struct process*);
1284887Schin static void		job_prmsg(struct process*);
1294887Schin static struct process	*freelist;
1304887Schin static char		beenhere;
1314887Schin static char		possible;
1324887Schin static struct process	dummy;
1334887Schin static char		by_number;
1344887Schin static Sfio_t		*outfile;
1354887Schin static pid_t		lastpid;
1364887Schin static struct back_save	bck;
1374887Schin 
1384887Schin #ifdef JOBS
1394887Schin     static void			job_set(struct process*);
1404887Schin     static void			job_reset(struct process*);
1414887Schin     static void			job_waitsafe(int);
1424887Schin     static struct process	*job_byname(char*);
1434887Schin     static struct process	*job_bystring(char*);
1444887Schin     static struct termios	my_stty;  /* terminal state for shell */
1454887Schin     static char			*job_string;
1464887Schin #else
1474887Schin     extern const char		e_coredump[];
1484887Schin #endif /* JOBS */
1494887Schin 
1504887Schin #ifdef SIGTSTP
1514887Schin     static void		job_unstop(struct process*);
1524887Schin     static void		job_fgrp(struct process*, int);
1534887Schin #   ifndef _lib_tcgetpgrp
1544887Schin #	ifdef TIOCGPGRP
1554887Schin 	   static int _i_;
1564887Schin #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
1574887Schin #	endif /* TIOCGPGRP */
tcsetpgrp(int fd,pid_t pgrp)1584887Schin 	int tcsetpgrp(int fd,pid_t pgrp)
1594887Schin 	{
1604887Schin 		int pgid = pgrp;
1614887Schin #		ifdef TIOCGPGRP
1624887Schin 			return(ioctl(fd, TIOCSPGRP, &pgid));
1634887Schin #		else
1644887Schin 			return(-1);
1654887Schin #		endif /* TIOCGPGRP */
1664887Schin 	}
1674887Schin #   endif /* _lib_tcgetpgrp */
1684887Schin #else
1694887Schin #   define job_unstop(pw)
1704887Schin #   undef CNSUSP
1714887Schin #endif /* SIGTSTP */
1724887Schin 
1734887Schin #ifndef OTTYDISC
1744887Schin #   undef NTTYDISC
1754887Schin #endif /* OTTYDISC */
1764887Schin 
1774887Schin #ifdef JOBS
1784887Schin 
1794887Schin typedef int (*Waitevent_f)(int,long,int);
1804887Schin 
18110898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
job_chldtrap(Shell_t * shp,const char * trap,int unpost)18210898Sroland.mainz@nrubsig.org void job_chldtrap(Shell_t *shp, const char *trap, int unpost)
18310898Sroland.mainz@nrubsig.org {
18410898Sroland.mainz@nrubsig.org 	register struct process *pw,*pwnext;
18510898Sroland.mainz@nrubsig.org 	pid_t bckpid;
186*12068SRoger.Faulkner@Oracle.COM 	int oldexit,trapnote;
18710898Sroland.mainz@nrubsig.org 	job_lock();
18810898Sroland.mainz@nrubsig.org 	shp->sigflag[SIGCHLD] &= ~SH_SIGTRAP;
189*12068SRoger.Faulkner@Oracle.COM 	trapnote = shp->trapnote;
190*12068SRoger.Faulkner@Oracle.COM 	shp->trapnote = 0;
19110898Sroland.mainz@nrubsig.org 	for(pw=job.pwlist;pw;pw=pwnext)
19210898Sroland.mainz@nrubsig.org 	{
19310898Sroland.mainz@nrubsig.org 		pwnext = pw->p_nxtjob;
19410898Sroland.mainz@nrubsig.org 		if((pw->p_flag&(P_BG|P_DONE)) != (P_BG|P_DONE))
19510898Sroland.mainz@nrubsig.org 			continue;
19610898Sroland.mainz@nrubsig.org 		pw->p_flag &= ~P_BG;
19710898Sroland.mainz@nrubsig.org 		bckpid = shp->bckpid;
19810898Sroland.mainz@nrubsig.org 		oldexit = shp->savexit;
19910898Sroland.mainz@nrubsig.org 		shp->bckpid = pw->p_pid;
20010898Sroland.mainz@nrubsig.org 		shp->savexit = pw->p_exit;
20110898Sroland.mainz@nrubsig.org 		if(pw->p_flag&P_SIGNALLED)
20210898Sroland.mainz@nrubsig.org 			shp->savexit |= SH_EXITSIG;
20310898Sroland.mainz@nrubsig.org 		sh_trap(trap,0);
204*12068SRoger.Faulkner@Oracle.COM 		if(pw->p_pid==bckpid && unpost)
205*12068SRoger.Faulkner@Oracle.COM 			job_unpost(pw,0);
20610898Sroland.mainz@nrubsig.org 		shp->savexit = oldexit;
20710898Sroland.mainz@nrubsig.org 		shp->bckpid = bckpid;
20810898Sroland.mainz@nrubsig.org 	}
209*12068SRoger.Faulkner@Oracle.COM 	shp->trapnote = trapnote;
21010898Sroland.mainz@nrubsig.org 	job_unlock();
21110898Sroland.mainz@nrubsig.org }
21210898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
21310898Sroland.mainz@nrubsig.org 
21410898Sroland.mainz@nrubsig.org /*
21510898Sroland.mainz@nrubsig.org  * return next on link list of jobsave free list
21610898Sroland.mainz@nrubsig.org  */
jobsave_create(pid_t pid)21710898Sroland.mainz@nrubsig.org static struct jobsave *jobsave_create(pid_t pid)
21810898Sroland.mainz@nrubsig.org {
21910898Sroland.mainz@nrubsig.org 	register struct jobsave *jp = job_savelist;
22010898Sroland.mainz@nrubsig.org 	job_chksave(pid);
22110898Sroland.mainz@nrubsig.org 	if(++bck.count > sh.lim.child_max)
22210898Sroland.mainz@nrubsig.org 		job_chksave(0);
22310898Sroland.mainz@nrubsig.org 	if(jp)
22410898Sroland.mainz@nrubsig.org 	{
22510898Sroland.mainz@nrubsig.org 		njob_savelist--;
22610898Sroland.mainz@nrubsig.org 		job_savelist = jp->next;
22710898Sroland.mainz@nrubsig.org 	}
22810898Sroland.mainz@nrubsig.org 	else
22910898Sroland.mainz@nrubsig.org 		jp = newof(0,struct jobsave,1,0);
23010898Sroland.mainz@nrubsig.org 	if(jp)
23110898Sroland.mainz@nrubsig.org 	{
23210898Sroland.mainz@nrubsig.org 		jp->pid = pid;
23310898Sroland.mainz@nrubsig.org 		jp->next = bck.list;
23410898Sroland.mainz@nrubsig.org 		bck.list = jp;
23510898Sroland.mainz@nrubsig.org 		jp->exitval = 0;
23610898Sroland.mainz@nrubsig.org 	}
23710898Sroland.mainz@nrubsig.org 	return(jp);
23810898Sroland.mainz@nrubsig.org }
23910898Sroland.mainz@nrubsig.org 
2404887Schin /*
2414887Schin  * Reap one job
2424887Schin  * When called with sig==0, it does a blocking wait
2434887Schin  */
job_reap(register int sig)2444887Schin int job_reap(register int sig)
2454887Schin {
2464887Schin 	register pid_t pid;
2474887Schin 	register struct process *pw;
2484887Schin 	struct process *px;
2494887Schin 	register int flags;
2504887Schin 	struct jobsave *jp;
2514887Schin 	int nochild=0, oerrno, wstat;
2524887Schin 	Waitevent_f waitevent = sh.waitevent;
2534887Schin 	static int wcontinued = WCONTINUED;
2548462SApril.Chin@Sun.COM 	if (vmbusy())
2558462SApril.Chin@Sun.COM 	{
2568462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen");
2578462SApril.Chin@Sun.COM 		if (getenv("_AST_KSH_VMBUSY_ABORT"))
2588462SApril.Chin@Sun.COM 			abort();
2598462SApril.Chin@Sun.COM 	}
2604887Schin #ifdef DEBUG
2614887Schin 	if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0)
2624887Schin 		write(2,"waitsafe\n",9);
2634887Schin 	sfsync(sfstderr);
2644887Schin #endif /* DEBUG */
2654887Schin 	job.savesig = 0;
2664887Schin 	if(sig)
2674887Schin 		flags = WNOHANG|WUNTRACED|wcontinued;
2684887Schin 	else
2694887Schin 		flags = WUNTRACED|wcontinued;
2704887Schin 	sh.waitevent = 0;
2714887Schin 	oerrno = errno;
2724887Schin 	while(1)
2734887Schin 	{
2748462SApril.Chin@Sun.COM 		if(!(flags&WNOHANG) && !sh.intrap && job.pwlist)
2754887Schin 		{
2768462SApril.Chin@Sun.COM 			sh_onstate(SH_TTYWAIT);
2778462SApril.Chin@Sun.COM 			if(waitevent && (*waitevent)(-1,-1L,0))
2784887Schin 				flags |= WNOHANG;
2794887Schin 		}
2804887Schin 		pid = waitpid((pid_t)-1,&wstat,flags);
2818462SApril.Chin@Sun.COM 		sh_offstate(SH_TTYWAIT);
2824887Schin 
2834887Schin 		/*
2844887Schin 		 * some systems (linux 2.6) may return EINVAL
2854887Schin 		 * when there are no continued children
2864887Schin 		 */
2874887Schin 
2884887Schin 		if (pid<0 && errno==EINVAL && (flags&WCONTINUED))
2894887Schin 			pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED);
2904887Schin 		sh_sigcheck();
291*12068SRoger.Faulkner@Oracle.COM 		if(pid<0 && errno==EINTR && (sig||job.savesig))
2924887Schin 			continue;
2934887Schin 		if(pid<=0)
2944887Schin 			break;
2954887Schin 		flags |= WNOHANG;
2964887Schin 		job.waitsafe++;
2974887Schin 		jp = 0;
2988462SApril.Chin@Sun.COM 		lastpid = pid;
2994887Schin 		if(!(pw=job_bypid(pid)))
3004887Schin 		{
3014887Schin #ifdef DEBUG
3024887Schin 			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);
3034887Schin #endif /* DEBUG */
3048462SApril.Chin@Sun.COM 			if (WIFCONTINUED(wstat) && wcontinued)
3058462SApril.Chin@Sun.COM 				continue;
3064887Schin 			pw = &dummy;
3074887Schin 			pw->p_exit = 0;
3084887Schin 			pw->p_pgrp = 0;
3098462SApril.Chin@Sun.COM 			pw->p_exitmin = 0;
3104887Schin 			if(job.toclear)
3114887Schin 				job_clear();
31210898Sroland.mainz@nrubsig.org 			jp = jobsave_create(pid);
3134887Schin 			pw->p_flag = 0;
3144887Schin 			lastpid = pw->p_pid = pid;
3154887Schin 			px = 0;
3164887Schin 			if(jp && WIFSTOPPED(wstat))
3174887Schin 			{
3184887Schin 				jp->exitval = SH_STOPSIG;
3194887Schin 				continue;
3204887Schin 			}
3214887Schin 		}
3224887Schin #ifdef SIGTSTP
3234887Schin 		else
3244887Schin 			px=job_byjid(pw->p_job);
3254887Schin 		if(WIFSTOPPED(wstat))
3264887Schin 		{
3274887Schin 			if(px)
3284887Schin 			{
3294887Schin 				/* move to top of job list */
3304887Schin 				job_unlink(px);
3314887Schin 				px->p_nxtjob = job.pwlist;
3324887Schin 				job.pwlist = px;
3334887Schin 			}
3348462SApril.Chin@Sun.COM 			pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
3354887Schin 			pw->p_exit = WSTOPSIG(wstat);
3364887Schin 			if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
3374887Schin 				sh_fault(pw->p_exit);
3384887Schin 			continue;
3394887Schin 		}
3404887Schin 		else if (WIFCONTINUED(wstat) && wcontinued)
3414887Schin 			pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED);
3424887Schin 		else
3434887Schin #endif /* SIGTSTP */
3444887Schin 		{
3454887Schin 			/* check for coprocess completion */
3464887Schin 			if(pid==sh.cpid)
3474887Schin 			{
3484887Schin 				sh_close(sh.coutpipe);
3494887Schin 				sh_close(sh.cpipe[1]);
3504887Schin 				sh.cpipe[1] = -1;
3514887Schin 				sh.coutpipe = -1;
3524887Schin 			}
3538462SApril.Chin@Sun.COM 			else if(sh.subshell)
3548462SApril.Chin@Sun.COM 				sh_subjobcheck(pid);
3558462SApril.Chin@Sun.COM 
3568462SApril.Chin@Sun.COM 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
3574887Schin 			if (WIFSIGNALED(wstat))
3584887Schin 			{
3594887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
3604887Schin 				if (WTERMCORE(wstat))
3614887Schin 					pw->p_flag |= P_COREDUMP;
3624887Schin 				pw->p_exit = WTERMSIG(wstat);
3634887Schin 				/* if process in current jobs terminates from
3644887Schin 				 * an interrupt, propogate to parent shell
3654887Schin 				 */
3664887Schin 				if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
3674887Schin 				{
3684887Schin 					pw->p_flag &= ~P_NOTIFY;
3694887Schin 					sh_offstate(SH_STOPOK);
3704887Schin 					sh_fault(SIGINT);
3714887Schin 					sh_onstate(SH_STOPOK);
3724887Schin 				}
3734887Schin 			}
3744887Schin 			else
3754887Schin 			{
3764887Schin 				pw->p_flag |= (P_DONE|P_NOTIFY);
3778462SApril.Chin@Sun.COM 				pw->p_exit =  pw->p_exitmin;
3788462SApril.Chin@Sun.COM 				if(WEXITSTATUS(wstat) > pw->p_exitmin)
3794887Schin 					pw->p_exit = WEXITSTATUS(wstat);
3804887Schin 			}
38110898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
38210898Sroland.mainz@nrubsig.org 			if((pw->p_flag&P_DONE) && (pw->p_flag&P_BG))
38310898Sroland.mainz@nrubsig.org 			{
38410898Sroland.mainz@nrubsig.org 				job.numbjob--;
38510898Sroland.mainz@nrubsig.org 				if(sh.st.trapcom[SIGCHLD])
38610898Sroland.mainz@nrubsig.org 				{
38710898Sroland.mainz@nrubsig.org 					sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
38810898Sroland.mainz@nrubsig.org 					if(sig==0)
38910898Sroland.mainz@nrubsig.org 						job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],0);
39010898Sroland.mainz@nrubsig.org 					else
39110898Sroland.mainz@nrubsig.org 						sh.trapnote |= SH_SIGTRAP;
39210898Sroland.mainz@nrubsig.org 				}
39310898Sroland.mainz@nrubsig.org 				else
39410898Sroland.mainz@nrubsig.org 					pw->p_flag &= ~P_BG;
39510898Sroland.mainz@nrubsig.org 			}
39610898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
3974887Schin 			if(pw->p_pgrp==0)
3984887Schin 				pw->p_flag &= ~P_NOTIFY;
3994887Schin 		}
4004887Schin 		if(jp && pw== &dummy)
4014887Schin 		{
4024887Schin 			jp->exitval = pw->p_exit;
4034887Schin 			if(pw->p_flag&P_SIGNALLED)
4044887Schin 				jp->exitval |= SH_EXITSIG;
4054887Schin 		}
4064887Schin #ifdef DEBUG
4074887Schin 		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);
4084887Schin 		sfsync(sfstderr);
4094887Schin #endif /* DEBUG*/
4104887Schin 		/* only top-level process in job should have notify set */
4114887Schin 		if(px && pw != px)
4124887Schin 			pw->p_flag &= ~P_NOTIFY;
4138462SApril.Chin@Sun.COM 		if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY))
4148462SApril.Chin@Sun.COM 		{
4158462SApril.Chin@Sun.COM 			px = job_byjid((int)pw->p_job);
4168462SApril.Chin@Sun.COM 			for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc);
4178462SApril.Chin@Sun.COM 			if(!px)
4188462SApril.Chin@Sun.COM 				tcsetpgrp(JOBTTY,job.mypid);
4198462SApril.Chin@Sun.COM 		}
42010898Sroland.mainz@nrubsig.org #ifndef SHOPT_BGX
4218462SApril.Chin@Sun.COM 		if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid)))
4228462SApril.Chin@Sun.COM 		{
4238462SApril.Chin@Sun.COM 			sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
4248462SApril.Chin@Sun.COM 			sh.trapnote |= SH_SIGTRAP;
4258462SApril.Chin@Sun.COM 		}
42610898Sroland.mainz@nrubsig.org #endif
4274887Schin 	}
4284887Schin 	if(errno==ECHILD)
4294887Schin 	{
4304887Schin 		errno = oerrno;
43110898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
43210898Sroland.mainz@nrubsig.org 		job.numbjob = 0;
43310898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
4344887Schin 		nochild = 1;
4354887Schin 	}
4364887Schin 	sh.waitevent = waitevent;
4374887Schin 	if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
4384887Schin 	{
4394887Schin 		outfile = sfstderr;
4404887Schin 		job_list(pw,JOB_NFLAG|JOB_NLFLAG);
4414887Schin 		job_unpost(pw,1);
4424887Schin 		sfsync(sfstderr);
4434887Schin 	}
4444887Schin 	if(sig)
4454887Schin 		signal(sig, job_waitsafe);
4464887Schin 	return(nochild);
4474887Schin }
4484887Schin 
4494887Schin /*
4504887Schin  * This is the SIGCLD interrupt routine
4514887Schin  */
job_waitsafe(int sig)4524887Schin static void job_waitsafe(int sig)
4534887Schin {
4548462SApril.Chin@Sun.COM 	if(job.in_critical || vmbusy())
4554887Schin 	{
4564887Schin 		job.savesig = sig;
4574887Schin 		job.waitsafe++;
4584887Schin 	}
4594887Schin 	else
4604887Schin 		job_reap(sig);
4614887Schin }
4624887Schin 
4634887Schin /*
4644887Schin  * initialize job control if possible
4654887Schin  * if lflag is set the switching driver message will not print
4664887Schin  */
job_init(Shell_t * shp,int lflag)4678462SApril.Chin@Sun.COM void job_init(Shell_t *shp, int lflag)
4684887Schin {
4698462SApril.Chin@Sun.COM 	register int ntry=0;
4704887Schin 	job.fd = JOBTTY;
4714887Schin 	signal(SIGCHLD,job_waitsafe);
4724887Schin #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
4734887Schin 	signal(SIGCLD,job_waitsafe);
4744887Schin #   endif
4754887Schin 	if(njob_savelist < NJOB_SAVELIST)
4764887Schin 		init_savelist();
4774887Schin 	if(!sh_isoption(SH_INTERACTIVE))
4784887Schin 		return;
4794887Schin 	/* use new line discipline when available */
4804887Schin #ifdef NTTYDISC
4814887Schin #   ifdef FIOLOOKLD
4824887Schin 	if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
4834887Schin #   else
4844887Schin 	if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
4854887Schin #   endif /* FIOLOOKLD */
4864887Schin 		return;
4874887Schin 	if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
4884887Schin 	{
4894887Schin 		/* no job control when running with MPX */
4904887Schin #   if SHOPT_VSH
4914887Schin 		sh_onoption(SH_VIRAW);
4924887Schin #   endif /* SHOPT_VSH */
4934887Schin 		return;
4944887Schin 	}
4954887Schin 	if(job.linedisc==NTTYDISC)
4964887Schin 		job.linedisc = -1;
4974887Schin #endif /* NTTYDISC */
4984887Schin 
4994887Schin 	job.mypgid = getpgrp();
5004887Schin 	/* some systems have job control, but not initialized */
5014887Schin 	if(job.mypgid<=0)
5024887Schin         {
5034887Schin 		/* Get a controlling terminal and set process group */
5044887Schin 		/* This should have already been done by rlogin */
5054887Schin                 register int fd;
5064887Schin                 register char *ttynam;
5074887Schin #ifndef SIGTSTP
5088462SApril.Chin@Sun.COM                 setpgid(0,shp->pid);
5094887Schin #endif /*SIGTSTP */
5104887Schin                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
5114887Schin                         return;
5124887Schin                 close(JOBTTY);
5134887Schin                 if((fd = open(ttynam,O_RDWR)) <0)
5144887Schin                         return;
5154887Schin                 if(fd!=JOBTTY)
5168462SApril.Chin@Sun.COM                         sh_iorenumber(shp,fd,JOBTTY);
5178462SApril.Chin@Sun.COM                 job.mypgid = shp->pid;
5184887Schin #ifdef SIGTSTP
5198462SApril.Chin@Sun.COM                 tcsetpgrp(JOBTTY,shp->pid);
5208462SApril.Chin@Sun.COM                 setpgid(0,shp->pid);
5214887Schin #endif /* SIGTSTP */
5224887Schin         }
5234887Schin #ifdef SIGTSTP
5244887Schin 	if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
5254887Schin 	{
5264887Schin 		/* wait until we are in the foreground */
5274887Schin 		while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
5284887Schin 		{
5294887Schin 			if(job.mytgid == -1)
5304887Schin 				return;
5314887Schin 			/* Stop this shell until continued */
5324887Schin 			signal(SIGTTIN,SIG_DFL);
5338462SApril.Chin@Sun.COM 			kill(shp->pid,SIGTTIN);
5344887Schin 			/* resumes here after continue tries again */
5354887Schin 			if(ntry++ > IOMAXTRY)
5364887Schin 			{
5374887Schin 				errormsg(SH_DICT,0,e_no_start);
5384887Schin 				return;
5394887Schin 			}
5404887Schin 		}
5414887Schin 	}
5424887Schin #endif /* SIGTTIN */
5434887Schin 
5444887Schin #ifdef NTTYDISC
5454887Schin 	/* set the line discipline */
5464887Schin 	if(job.linedisc>=0)
5474887Schin 	{
5484887Schin 		int linedisc = NTTYDISC;
5494887Schin #   ifdef FIOPUSHLD
5504887Schin 		tty_get(JOBTTY,&my_stty);
5514887Schin 		if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
5524887Schin 			return;
5534887Schin 		if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
5544887Schin 		{
5554887Schin 			ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
5564887Schin 			return;
5574887Schin 		}
5584887Schin 		tty_set(JOBTTY,TCSANOW,&my_stty);
5594887Schin #   else
5604887Schin 		if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
5614887Schin 			return;
5624887Schin #   endif /* FIOPUSHLD */
5634887Schin 		if(lflag==0)
5644887Schin 			errormsg(SH_DICT,0,e_newtty);
5654887Schin 		else
5664887Schin 			job.linedisc = -1;
5674887Schin 	}
5684887Schin #endif /* NTTYDISC */
5694887Schin 	if(!possible)
5704887Schin 		return;
5714887Schin 
5724887Schin #ifdef SIGTSTP
5734887Schin 	/* make sure that we are a process group leader */
5748462SApril.Chin@Sun.COM 	setpgid(0,shp->pid);
575*12068SRoger.Faulkner@Oracle.COM #   if defined(SA_NOCLDSTOP) || defined(SA_NOCLDWAIT)
576*12068SRoger.Faulkner@Oracle.COM #   	if !defined(SA_NOCLDSTOP)
577*12068SRoger.Faulkner@Oracle.COM #	    define SA_NOCLDSTOP	0
578*12068SRoger.Faulkner@Oracle.COM #   	endif
579*12068SRoger.Faulkner@Oracle.COM #   	if !defined(SA_NOCLDWAIT)
580*12068SRoger.Faulkner@Oracle.COM #	    define SA_NOCLDWAIT	0
581*12068SRoger.Faulkner@Oracle.COM #   	endif
5824887Schin 	sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
583*12068SRoger.Faulkner@Oracle.COM #   endif /* SA_NOCLDSTOP || SA_NOCLDWAIT */
5844887Schin 	signal(SIGTTIN,SIG_IGN);
5854887Schin 	signal(SIGTTOU,SIG_IGN);
5864887Schin 	/* The shell now handles ^Z */
5874887Schin 	signal(SIGTSTP,sh_fault);
5888462SApril.Chin@Sun.COM 	tcsetpgrp(JOBTTY,shp->pid);
5894887Schin #   ifdef CNSUSP
5904887Schin 	/* set the switch character */
5914887Schin 	tty_get(JOBTTY,&my_stty);
5924887Schin 	job.suspend = (unsigned)my_stty.c_cc[VSUSP];
5934887Schin 	if(job.suspend == (unsigned char)CNSUSP)
5944887Schin 	{
5954887Schin 		my_stty.c_cc[VSUSP] = CSWTCH;
5964887Schin 		tty_set(JOBTTY,TCSAFLUSH,&my_stty);
5974887Schin 	}
5984887Schin #   endif /* CNSUSP */
5994887Schin 	sh_onoption(SH_MONITOR);
6004887Schin 	job.jobcontrol++;
6018462SApril.Chin@Sun.COM 	job.mypid = shp->pid;
6024887Schin #endif /* SIGTSTP */
6034887Schin 	return;
6044887Schin }
6054887Schin 
6064887Schin 
6074887Schin /*
6084887Schin  * see if there are any stopped jobs
6094887Schin  * restore tty driver and pgrp
6104887Schin  */
job_close(Shell_t * shp)6118462SApril.Chin@Sun.COM int job_close(Shell_t* shp)
6124887Schin {
6134887Schin 	register struct process *pw;
6144887Schin 	register int count = 0, running = 0;
6154887Schin 	if(possible && !job.jobcontrol)
6164887Schin 		return(0);
6174887Schin 	else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
6184887Schin 		return(0);
6194887Schin 	else if(getpid() != job.mypid)
6204887Schin 		return(0);
6214887Schin 	job_lock();
6224887Schin 	if(!tty_check(0))
6234887Schin 		beenhere++;
6244887Schin 	for(pw=job.pwlist;pw;pw=pw->p_nxtjob)
6254887Schin 	{
6264887Schin 		if(!(pw->p_flag&P_STOPPED))
6274887Schin 		{
6284887Schin 			if(!(pw->p_flag&P_DONE))
6294887Schin 				running++;
6304887Schin 			continue;
6314887Schin 		}
6324887Schin 		if(beenhere)
6334887Schin 			killpg(pw->p_pgrp,SIGTERM);
6344887Schin 		count++;
6354887Schin 	}
6364887Schin 	if(beenhere++ == 0 && job.pwlist)
6374887Schin 	{
6384887Schin 		if(count)
6394887Schin 		{
6404887Schin 			errormsg(SH_DICT,0,e_terminate);
6414887Schin 			return(-1);
6424887Schin 		}
6438462SApril.Chin@Sun.COM 		else if(running && shp->login_sh)
6444887Schin 		{
6454887Schin 			errormsg(SH_DICT,0,e_jobsrunning);
6464887Schin 			return(-1);
6474887Schin 		}
6484887Schin 	}
6494887Schin 	job_unlock();
6504887Schin #   ifdef SIGTSTP
6514887Schin 	if(possible && setpgid(0,job.mypgid)>=0)
6524887Schin 		tcsetpgrp(job.fd,job.mypgid);
6534887Schin #   endif /* SIGTSTP */
6544887Schin #   ifdef NTTYDISC
6554887Schin 	if(job.linedisc>=0)
6564887Schin 	{
6574887Schin 		/* restore old line discipline */
6584887Schin #	ifdef FIOPUSHLD
6594887Schin 		tty_get(job.fd,&my_stty);
6604887Schin 		if (ioctl(job.fd, FIOPOPLD, 0) < 0)
6614887Schin 			return(0);
6624887Schin 		if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
6634887Schin 		{
6644887Schin 			job.linedisc = NTTYDISC;
6654887Schin 			ioctl(job.fd, FIOPUSHLD, &job.linedisc);
6664887Schin 			return(0);
6674887Schin 		}
6684887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
6694887Schin #	else
6704887Schin 		if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
6714887Schin 			return(0);
6724887Schin #	endif /* FIOPUSHLD */
6734887Schin 		errormsg(SH_DICT,0,e_oldtty);
6744887Schin 	}
6754887Schin #   endif /* NTTYDISC */
6764887Schin #   ifdef CNSUSP
6774887Schin 	if(possible && job.suspend==CNSUSP)
6784887Schin 	{
6794887Schin 		tty_get(job.fd,&my_stty);
6804887Schin 		my_stty.c_cc[VSUSP] = CNSUSP;
6814887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
6824887Schin 	}
6834887Schin #   endif /* CNSUSP */
6844887Schin 	job.jobcontrol = 0;
6854887Schin 	return(0);
6864887Schin }
6874887Schin 
job_set(register struct process * pw)6884887Schin static void job_set(register struct process *pw)
6894887Schin {
6904887Schin 	/* save current terminal state */
6914887Schin 	tty_get(job.fd,&my_stty);
6924887Schin 	if(pw->p_flag&P_STTY)
6934887Schin 	{
6944887Schin 		/* restore terminal state for job */
6954887Schin 		tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
6964887Schin 	}
6974887Schin #ifdef SIGTSTP
6984887Schin 	if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid)
6994887Schin 		tcsetpgrp(job.fd,pw->p_fgrp);
7004887Schin 	/* if job is stopped, resume it in the background */
7014887Schin 	job_unstop(pw);
7024887Schin #endif	/* SIGTSTP */
7034887Schin }
7044887Schin 
job_reset(register struct process * pw)7054887Schin static void job_reset(register struct process *pw)
7064887Schin {
7074887Schin 	/* save the terminal state for current job */
7084887Schin #ifdef SIGTSTP
7094887Schin 	job_fgrp(pw,tcgetpgrp(job.fd));
7108462SApril.Chin@Sun.COM 	if(tcsetpgrp(job.fd,job.mypid) !=0)
7114887Schin 		return;
7124887Schin #endif	/* SIGTSTP */
7134887Schin 	/* force the following tty_get() to do a tcgetattr() unless fg */
7144887Schin 	if(!(pw->p_flag&P_FG))
7154887Schin 		tty_set(-1, 0, NIL(struct termios*));
7164887Schin 	if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
7174887Schin 	{
7184887Schin 		if(tty_get(job.fd,&pw->p_stty) == 0)
7194887Schin 			pw->p_flag |= P_STTY;
7204887Schin 		/* restore terminal state for job */
7214887Schin 		tty_set(job.fd,TCSAFLUSH,&my_stty);
7224887Schin 	}
7234887Schin 	beenhere = 0;
7244887Schin }
7254887Schin #endif /* JOBS */
7264887Schin 
7274887Schin /*
7284887Schin  * wait built-in command
7294887Schin  */
7304887Schin 
job_bwait(char ** jobs)7314887Schin void job_bwait(char **jobs)
7324887Schin {
7334887Schin 	register char *jp;
7344887Schin 	register struct process *pw;
7354887Schin 	register pid_t pid;
7364887Schin 	if(*jobs==0)
7374887Schin 		job_wait((pid_t)-1);
7384887Schin 	else while(jp = *jobs++)
7394887Schin 	{
7404887Schin #ifdef JOBS
7414887Schin 		if(*jp == '%')
7424887Schin 		{
7434887Schin 			job_lock();
7444887Schin 			pw = job_bystring(jp);
7454887Schin 			job_unlock();
7464887Schin 			if(pw)
7474887Schin 				pid = pw->p_pid;
7484887Schin 			else
7494887Schin 				return;
7504887Schin 		}
7514887Schin 		else
7524887Schin #endif /* JOBS */
7534887Schin 			pid = (int)strtol(jp, (char**)0, 10);
7544887Schin 		job_wait(-pid);
7554887Schin 	}
7564887Schin }
7574887Schin 
7584887Schin #ifdef JOBS
7594887Schin /*
7604887Schin  * execute function <fun> for each job
7614887Schin  */
7624887Schin 
job_walk(Sfio_t * file,int (* fun)(struct process *,int),int arg,char * joblist[])7634887Schin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[])
7644887Schin {
7654887Schin 	register struct process *pw;
7664887Schin 	register int r = 0;
7674887Schin 	register char *jobid, **jobs=joblist;
7684887Schin 	register struct process *px;
7694887Schin 	job_string = 0;
7704887Schin 	outfile = file;
7714887Schin 	by_number = 0;
7724887Schin 	job_lock();
7734887Schin 	pw = job.pwlist;
7744887Schin 	if(jobs==0)
7754887Schin 	{
7764887Schin 		/* do all jobs */
7774887Schin 		for(;pw;pw=px)
7784887Schin 		{
7794887Schin 			px = pw->p_nxtjob;
7804887Schin 			if(pw->p_env != sh.jobenv)
7814887Schin 				continue;
7824887Schin 			if((*fun)(pw,arg))
7834887Schin 				r = 2;
7844887Schin 		}
7854887Schin 	}
7864887Schin 	else if(*jobs==0)	/* current job */
7874887Schin 	{
7884887Schin 		/* skip over non-stop jobs */
7894887Schin 		while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0))
7904887Schin 			pw = pw->p_nxtjob;
7914887Schin 		if((*fun)(pw,arg))
7924887Schin 			r = 2;
7934887Schin 	}
7944887Schin 	else while(jobid = *jobs++)
7954887Schin 	{
7964887Schin 		job_string = jobid;
7974887Schin 		if(*jobid==0)
7984887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
7994887Schin 		if(*jobid == '%')
8004887Schin 			pw = job_bystring(jobid);
8014887Schin 		else
8024887Schin 		{
8034887Schin 			int pid = (int)strtol(jobid, (char**)0, 10);
8044887Schin 			if(pid<0)
8054887Schin 				jobid++;
8064887Schin 			while(isdigit(*jobid))
8074887Schin 				jobid++;
8084887Schin 			if(*jobid)
8094887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
8104887Schin 			if(!(pw = job_bypid(pid)))
8114887Schin 			{
8124887Schin 				pw = &dummy;
8134887Schin 				pw->p_pid = pid;
8144887Schin 				pw->p_pgrp = pid;
8154887Schin 			}
8164887Schin 			by_number = 1;
8174887Schin 		}
8184887Schin 		if((*fun)(pw,arg))
8194887Schin 			r = 2;
8204887Schin 		by_number = 0;
8214887Schin 	}
8224887Schin 	job_unlock();
8234887Schin 	return(r);
8244887Schin }
8254887Schin 
8264887Schin /*
8274887Schin  * send signal <sig> to background process group if not disowned
8284887Schin  */
job_terminate(register struct process * pw,register int sig)8294887Schin int job_terminate(register struct process *pw,register int sig)
8304887Schin {
8314887Schin 	if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
8324887Schin 		job_kill(pw,sig);
8334887Schin 	return(0);
8344887Schin }
8354887Schin 
8364887Schin /*
8374887Schin  * list the given job
8384887Schin  * flag JOB_LFLAG for long listing
8394887Schin  * flag JOB_NFLAG for list only jobs marked for notification
8404887Schin  * flag JOB_PFLAG for process id(s) only
8414887Schin  */
8424887Schin 
job_list(struct process * pw,register int flag)8434887Schin int job_list(struct process *pw,register int flag)
8444887Schin {
8454887Schin 	register struct process *px = pw;
8464887Schin 	register int  n;
8474887Schin 	register const char *msg;
8484887Schin 	register int msize;
8494887Schin 	if(!pw || pw->p_job<=0)
8504887Schin 		return(1);
8514887Schin 	if(pw->p_env != sh.jobenv)
8524887Schin 		return(0);
8534887Schin 	if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
8544887Schin 		return(0);
8554887Schin 	if((flag&JOB_PFLAG))
8564887Schin 	{
8574887Schin 		sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid);
8584887Schin 		return(0);
8594887Schin 	}
8604887Schin 	if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
8614887Schin 		return(0);
8624887Schin 	job_lock();
8634887Schin 	n = px->p_job;
8644887Schin 	if(px==job.pwlist)
8654887Schin 		msize = '+';
8664887Schin 	else if(px==job.pwlist->p_nxtjob)
8674887Schin 		msize = '-';
8684887Schin 	else
8694887Schin 		msize = ' ';
8704887Schin 	if(flag&JOB_NLFLAG)
8714887Schin 		sfputc(outfile,'\n');
8724887Schin 	sfprintf(outfile,"[%d] %c ",n, msize);
8734887Schin 	do
8744887Schin 	{
8754887Schin 		n = 0;
8764887Schin 		if(flag&JOB_LFLAG)
8774887Schin 			sfprintf(outfile,"%d\t",px->p_pid);
8784887Schin 		if(px->p_flag&P_SIGNALLED)
8794887Schin 			msg = job_sigmsg((int)(px->p_exit));
8804887Schin 		else if(px->p_flag&P_NOTIFY)
8814887Schin 		{
8824887Schin 			msg = sh_translate(e_done);
8834887Schin 			n = px->p_exit;
8844887Schin 		}
8854887Schin 		else
8864887Schin 			msg = sh_translate(e_running);
8874887Schin 		px->p_flag &= ~P_NOTIFY;
8884887Schin 		sfputr(outfile,msg,-1);
8894887Schin 		msize = strlen(msg);
8904887Schin 		if(n)
8914887Schin 		{
8924887Schin 			sfprintf(outfile,"(%d)",(int)n);
8934887Schin 			msize += (3+(n>10)+(n>100));
8944887Schin 		}
8954887Schin 		if(px->p_flag&P_COREDUMP)
8964887Schin 		{
8974887Schin 			msg = sh_translate(e_coredump);
8984887Schin 			sfputr(outfile, msg, -1);
8994887Schin 			msize += strlen(msg);
9004887Schin 		}
9014887Schin 		sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
9024887Schin 		if(flag&JOB_LFLAG)
9034887Schin 			px = px->p_nxtproc;
9044887Schin 		else
9054887Schin 		{
9064887Schin 			while(px=px->p_nxtproc)
9074887Schin 				px->p_flag &= ~P_NOTIFY;
9084887Schin 			px = 0;
9094887Schin 		}
9104887Schin 		if(!px)
9114887Schin 			hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
9124887Schin 		else
9134887Schin 			sfputr(outfile, e_nlspace, -1);
9144887Schin 	}
9154887Schin 	while(px);
9164887Schin 	job_unlock();
9174887Schin 	return(0);
9184887Schin }
9194887Schin 
9204887Schin /*
9214887Schin  * get the process group given the job number
9224887Schin  * This routine returns the process group number or -1
9234887Schin  */
job_bystring(register char * ajob)9244887Schin static struct process *job_bystring(register char *ajob)
9254887Schin {
9264887Schin 	register struct process *pw=job.pwlist;
9274887Schin 	register int c;
9284887Schin 	if(*ajob++ != '%' || !pw)
9294887Schin 		return(NIL(struct process*));
9304887Schin 	c = *ajob;
9314887Schin 	if(isdigit(c))
9324887Schin 		pw = job_byjid((int)strtol(ajob, (char**)0, 10));
9334887Schin 	else if(c=='+' || c=='%')
9344887Schin 		;
9354887Schin 	else if(c=='-')
9364887Schin 	{
9374887Schin 		if(pw)
9384887Schin 			pw = job.pwlist->p_nxtjob;
9394887Schin 	}
9404887Schin 	else
9414887Schin 		pw = job_byname(ajob);
9424887Schin 	if(pw && pw->p_flag)
9434887Schin 		return(pw);
9444887Schin 	return(NIL(struct process*));
9454887Schin }
9464887Schin 
9474887Schin /*
9484887Schin  * Kill a job or process
9494887Schin  */
9504887Schin 
job_kill(register struct process * pw,register int sig)9514887Schin int job_kill(register struct process *pw,register int sig)
9524887Schin {
9534887Schin 	register pid_t pid;
9544887Schin 	register int r;
9554887Schin 	const char *msg;
9564887Schin #ifdef SIGTSTP
9574887Schin 	int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
9584887Schin #else
9594887Schin #	define stopsig	1
9604887Schin #endif	/* SIGTSTP */
9614887Schin 	job_lock();
9624887Schin 	errno = ECHILD;
9634887Schin 	if(pw==0)
9644887Schin 		goto error;
9654887Schin 	pid = pw->p_pid;
9664887Schin 	if(by_number)
9674887Schin 	{
9684887Schin 		if(pid==0 && job.jobcontrol)
9694887Schin 			r = job_walk(outfile, job_kill,sig, (char**)0);
9704887Schin #ifdef SIGTSTP
9714887Schin 		if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
9724887Schin 		{
9734887Schin 			/* can't stop login shell */
9744887Schin 			errno = EPERM;
9754887Schin 			r = -1;
9764887Schin 		}
9774887Schin 		else
9784887Schin 		{
9794887Schin 			if(pid>=0)
9804887Schin 			{
9814887Schin 				if((r = kill(pid,sig))>=0 && !stopsig)
9824887Schin 				{
9834887Schin 					if(pw->p_flag&P_STOPPED)
9844887Schin 						pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
9854887Schin 					if(sig)
9864887Schin 						kill(pid,SIGCONT);
9874887Schin 				}
9884887Schin 			}
9894887Schin 			else
9904887Schin 			{
9914887Schin 				if((r = killpg(-pid,sig))>=0 && !stopsig)
9924887Schin 				{
9934887Schin 					job_unstop(job_bypid(pw->p_pid));
9944887Schin 					if(sig)
9954887Schin 						killpg(-pid,SIGCONT);
9964887Schin 				}
9974887Schin 			}
9984887Schin 		}
9994887Schin #else
10004887Schin 		if(pid>=0)
10014887Schin 			r = kill(pid,sig);
10024887Schin 		else
10034887Schin 			r = killpg(-pid,sig);
10044887Schin #endif	/* SIGTSTP */
10054887Schin 	}
10064887Schin 	else
10074887Schin 	{
10084887Schin 		if(pid = pw->p_pgrp)
10094887Schin 		{
10104887Schin 			r = killpg(pid,sig);
10114887Schin #ifdef SIGTSTP
10124887Schin 			if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT))
10134887Schin 				job_unstop(pw);
10144887Schin #endif	/* SIGTSTP */
10154887Schin 			if(r>=0)
10164887Schin 				sh_delay(.05);
10174887Schin 		}
10184887Schin 		while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0)
10194887Schin 		{
10204887Schin #ifdef SIGTSTP
10214887Schin 			if(sig==SIGHUP || sig==SIGTERM)
10224887Schin 				kill(pw->p_pid,SIGCONT);
10234887Schin #endif	/* SIGTSTP */
10244887Schin 			pw = pw->p_nxtproc;
10254887Schin 		}
10264887Schin 	}
10274887Schin 	if(r<0 && job_string)
10284887Schin 	{
10294887Schin 	error:
10304887Schin 		if(pw && by_number)
10314887Schin 			msg = sh_translate(e_no_proc);
10324887Schin 		else
10334887Schin 			msg = sh_translate(e_no_job);
10344887Schin 		if(errno == EPERM)
10354887Schin 			msg = sh_translate(e_access);
10364887Schin 		sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg);
10374887Schin 		r = 2;
10384887Schin 	}
10394887Schin 	sh_delay(.001);
10404887Schin 	job_unlock();
10414887Schin 	return(r);
10424887Schin }
10434887Schin 
10444887Schin /*
10454887Schin  * Get process structure from first letters of jobname
10464887Schin  *
10474887Schin  */
10484887Schin 
job_byname(char * name)10494887Schin static struct process *job_byname(char *name)
10504887Schin {
10514887Schin 	register struct process *pw = job.pwlist;
10524887Schin 	register struct process *pz = 0;
10534887Schin 	register int *flag = 0;
10544887Schin 	register char *cp = name;
10554887Schin 	int offset;
10564887Schin 	if(!sh.hist_ptr)
10574887Schin 		return(NIL(struct process*));
10584887Schin 	if(*cp=='?')
10594887Schin 		cp++,flag= &offset;
10604887Schin 	for(;pw;pw=pw->p_nxtjob)
10614887Schin 	{
10624887Schin 		if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
10634887Schin 		{
10644887Schin 			if(pz)
10654887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1);
10664887Schin 			pz = pw;
10674887Schin 		}
10684887Schin 	}
10694887Schin 	return(pz);
10704887Schin }
10714887Schin 
10724887Schin #else
10734887Schin #   define job_set(x)
10744887Schin #   define job_reset(x)
10754887Schin #endif /* JOBS */
10764887Schin 
10774887Schin 
10784887Schin 
10794887Schin /*
10804887Schin  * Initialize the process posting array
10814887Schin  */
10824887Schin 
job_clear(void)10834887Schin void	job_clear(void)
10844887Schin {
10854887Schin 	register struct process *pw, *px;
10864887Schin 	register struct process *pwnext;
10874887Schin 	register int j = BYTE(sh.lim.child_max);
10884887Schin 	register struct jobsave *jp,*jpnext;
10894887Schin 	job_lock();
10904887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
10914887Schin 	{
10924887Schin 		pwnext = pw->p_nxtjob;
10934887Schin 		while(px=pw)
10944887Schin 		{
10954887Schin 			pw = pw->p_nxtproc;
10964887Schin 			free((void*)px);
10974887Schin 		}
10984887Schin 	}
10994887Schin 	for(jp=bck.list; jp;jp=jpnext)
11004887Schin 	{
11014887Schin 		jpnext = jp->next;
11024887Schin 		free((void*)jp);
11034887Schin 	}
11044887Schin 	bck.list = 0;
11054887Schin 	if(njob_savelist < NJOB_SAVELIST)
11064887Schin 		init_savelist();
11074887Schin 	job.pwlist = NIL(struct process*);
11084887Schin 	job.numpost=0;
110910898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
111010898Sroland.mainz@nrubsig.org 	job.numbjob = 0;
111110898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
11124887Schin 	job.waitall = 0;
11134887Schin 	job.curpgid = 0;
11144887Schin 	job.toclear = 0;
11154887Schin 	if(!job.freejobs)
11164887Schin 		job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
11174887Schin 	while(j >=0)
11184887Schin 		job.freejobs[j--]  = 0;
11194887Schin 	job_unlock();
11204887Schin }
11214887Schin 
11224887Schin /*
11234887Schin  * put the process <pid> on the process list and return the job number
11244887Schin  * if non-zero, <join> is the process id of the job to join
11254887Schin  */
11264887Schin 
job_post(pid_t pid,pid_t join)11274887Schin int job_post(pid_t pid, pid_t join)
11284887Schin {
11294887Schin 	register struct process *pw;
11304887Schin 	register History_t *hp = sh.hist_ptr;
113110898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
113210898Sroland.mainz@nrubsig.org 	int val,bg=0;
113310898Sroland.mainz@nrubsig.org #else
11348462SApril.Chin@Sun.COM 	int val;
113510898Sroland.mainz@nrubsig.org #endif
11364887Schin 	sh.jobenv = sh.curenv;
11374887Schin 	if(job.toclear)
11384887Schin 	{
11394887Schin 		job_clear();
11404887Schin 		return(0);
11414887Schin 	}
11424887Schin 	job_lock();
114310898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
114410898Sroland.mainz@nrubsig.org 	if(join==1)
114510898Sroland.mainz@nrubsig.org 	{
114610898Sroland.mainz@nrubsig.org 		join = 0;
114710898Sroland.mainz@nrubsig.org 		bg = P_BG;
114810898Sroland.mainz@nrubsig.org 		job.numbjob++;
114910898Sroland.mainz@nrubsig.org 	}
115010898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
115110898Sroland.mainz@nrubsig.org 	if(njob_savelist < NJOB_SAVELIST)
115210898Sroland.mainz@nrubsig.org 		init_savelist();
11534887Schin 	if(pw = job_bypid(pid))
11544887Schin 		job_unpost(pw,0);
11554887Schin 	if(join && (pw=job_bypid(join)))
11564887Schin 	{
11574887Schin 		/* if job to join is not first move it to front */
11584887Schin 		if((pw=job_byjid(pw->p_job)) != job.pwlist)
11594887Schin 		{
11604887Schin 			job_unlink(pw);
11614887Schin 			pw->p_nxtjob = job.pwlist;
11624887Schin 			job.pwlist = pw;
11634887Schin 		}
11644887Schin 	}
11654887Schin 	if(pw=freelist)
11664887Schin 		freelist = pw->p_nxtjob;
11674887Schin 	else
11684887Schin 		pw = new_of(struct process,0);
116910898Sroland.mainz@nrubsig.org 	pw->p_flag = 0;
11704887Schin 	job.numpost++;
11714887Schin 	if(join && job.pwlist)
11724887Schin 	{
11734887Schin 		/* join existing current job */
11744887Schin 		pw->p_nxtjob = job.pwlist->p_nxtjob;
11754887Schin 		pw->p_nxtproc = job.pwlist;
11764887Schin 		pw->p_job = job.pwlist->p_job;
11774887Schin 	}
11784887Schin 	else
11794887Schin 	{
11804887Schin 		/* create a new job */
11814887Schin 		while((pw->p_job = job_alloc()) < 0)
11824887Schin 			job_wait((pid_t)1);
11834887Schin 		pw->p_nxtjob = job.pwlist;
11844887Schin 		pw->p_nxtproc = 0;
11854887Schin 	}
11864887Schin 	job.pwlist = pw;
11874887Schin 	pw->p_env = sh.curenv;
11884887Schin 	pw->p_pid = pid;
1189*12068SRoger.Faulkner@Oracle.COM 	if(!sh.outpipe || (sh_isoption(SH_PIPEFAIL) && job.waitall))
119010898Sroland.mainz@nrubsig.org 		pw->p_flag = P_EXITSAVE;
11918462SApril.Chin@Sun.COM 	pw->p_exitmin = sh.xargexit;
11928462SApril.Chin@Sun.COM 	pw->p_exit = 0;
11934887Schin 	if(sh_isstate(SH_MONITOR))
11944887Schin 	{
11954887Schin 		if(killpg(job.curpgid,0)<0 && errno==ESRCH)
11964887Schin 			job.curpgid = pid;
11974887Schin 		pw->p_fgrp = job.curpgid;
11984887Schin 	}
11994887Schin 	else
12004887Schin 		pw->p_fgrp = 0;
12014887Schin 	pw->p_pgrp = pw->p_fgrp;
12024887Schin #ifdef DEBUG
12034887Schin 	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,
12044887Schin 		pw->p_pid,pw->p_pgrp,job.savesig,join);
12054887Schin 	sfsync(sfstderr);
12064887Schin #endif /* DEBUG */
12074887Schin #ifdef JOBS
12084887Schin 	if(hp && !sh_isstate(SH_PROFILE))
12094887Schin 		pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
12104887Schin 	else
12114887Schin 		pw->p_name = -1;
12124887Schin #endif /* JOBS */
12138462SApril.Chin@Sun.COM 	if ((val = job_chksave(pid)) >= 0)
12144887Schin 	{
12158462SApril.Chin@Sun.COM 		pw->p_exit = val;
12164887Schin 		if(pw->p_exit==SH_STOPSIG)
12174887Schin 		{
12184887Schin 			pw->p_flag |= (P_SIGNALLED|P_STOPPED);
12194887Schin 			pw->p_exit = 0;
12204887Schin 		}
122110898Sroland.mainz@nrubsig.org 		else if(pw->p_exit >= SH_EXITSIG)
122210898Sroland.mainz@nrubsig.org 		{
122310898Sroland.mainz@nrubsig.org 			pw->p_flag |= P_DONE|P_SIGNALLED;
122410898Sroland.mainz@nrubsig.org 			pw->p_exit &= SH_EXITMASK;
122510898Sroland.mainz@nrubsig.org 		}
12264887Schin 		else
12274887Schin 			pw->p_flag |= (P_DONE|P_NOTIFY);
12284887Schin 	}
122910898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
123010898Sroland.mainz@nrubsig.org 	if(bg && !(pw->p_flag&P_DONE))
123110898Sroland.mainz@nrubsig.org 		pw->p_flag |= P_BG;
123210898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
12334887Schin 	lastpid = 0;
12344887Schin 	job_unlock();
12354887Schin 	return(pw->p_job);
12364887Schin }
12374887Schin 
12384887Schin /*
12394887Schin  * Returns a process structure give a process id
12404887Schin  */
12414887Schin 
job_bypid(pid_t pid)12424887Schin static struct process *job_bypid(pid_t pid)
12434887Schin {
12444887Schin 	register struct process  *pw, *px;
12454887Schin 	for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
12464887Schin 		for(px=pw; px; px=px->p_nxtproc)
12474887Schin 		{
12484887Schin 			if(px->p_pid==pid)
12494887Schin 				return(px);
12504887Schin 		}
12514887Schin 	return(NIL(struct process*));
12524887Schin }
12534887Schin 
12544887Schin /*
12554887Schin  * return a pointer to a job given the job id
12564887Schin  */
12574887Schin 
job_byjid(int jobid)12584887Schin static struct process *job_byjid(int jobid)
12594887Schin {
12604887Schin 	register struct process *pw;
12614887Schin 	for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
12624887Schin 	{
12634887Schin 		if(pw->p_job==jobid)
12644887Schin 			break;
12654887Schin 	}
12664887Schin 	return(pw);
12674887Schin }
12684887Schin 
12694887Schin /*
12704887Schin  * print a signal message
12714887Schin  */
job_prmsg(register struct process * pw)12724887Schin static void job_prmsg(register struct process *pw)
12734887Schin {
12744887Schin 	if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
12754887Schin 	{
12764887Schin 		register const char *msg, *dump;
12774887Schin 		msg = job_sigmsg((int)(pw->p_exit));
12784887Schin 		msg = sh_translate(msg);
12794887Schin 		if(pw->p_flag&P_COREDUMP)
12804887Schin 			dump =  sh_translate(e_coredump);
12814887Schin 		else
12824887Schin 			dump = "";
12834887Schin 		if(sh_isstate(SH_INTERACTIVE))
12844887Schin 			sfprintf(sfstderr,"%s%s\n",msg,dump);
12854887Schin 		else
12864887Schin 			errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump);
12874887Schin 	}
12884887Schin }
12894887Schin 
12904887Schin /*
12914887Schin  * Wait for process pid to complete
12924887Schin  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
12934887Schin  * pid=0 to unpost all done processes
12944887Schin  * pid=1 to wait for at least one process to complete
12954887Schin  * pid=-1 to wait for all runing processes
12964887Schin  */
12974887Schin 
job_wait(register pid_t pid)12988462SApril.Chin@Sun.COM int	job_wait(register pid_t pid)
12994887Schin {
13004887Schin 	register struct process *pw=0,*px;
13014887Schin 	register int	jobid = 0;
13028462SApril.Chin@Sun.COM 	int		nochild = 1;
13034887Schin 	char		intr = 0;
13044887Schin 	if(pid <= 0)
13054887Schin 	{
13064887Schin 		if(pid==0)
13074887Schin 			goto done;
13084887Schin 		pid = -pid;
13094887Schin 		intr = 1;
13104887Schin 	}
13114887Schin 	job_lock();
13124887Schin 	if(pid > 1)
13134887Schin 	{
13148462SApril.Chin@Sun.COM 		if(pid==sh.spid)
13158462SApril.Chin@Sun.COM 			sh.spid = 0;
13164887Schin 		if(!(pw=job_bypid(pid)))
13174887Schin 		{
13184887Schin 			/* check to see whether job status has been saved */
13194887Schin 			if((sh.exitval = job_chksave(pid)) < 0)
13204887Schin 				sh.exitval = ERROR_NOENT;
13214887Schin 			exitset();
13224887Schin 			job_unlock();
13238462SApril.Chin@Sun.COM 			return(nochild);
13244887Schin 		}
13254887Schin 		else if(intr && pw->p_env!=sh.curenv)
13264887Schin 		{
13274887Schin 			sh.exitval = ERROR_NOENT;
13284887Schin 			job_unlock();
13298462SApril.Chin@Sun.COM 			return(nochild);
13304887Schin 		}
13314887Schin 		jobid = pw->p_job;
13324887Schin 		if(!intr)
13334887Schin 			pw->p_flag &= ~P_EXITSAVE;
13344887Schin 		if(pw->p_pgrp && job.parent!= (pid_t)-1)
13354887Schin 			job_set(job_byjid(jobid));
13364887Schin 	}
13378462SApril.Chin@Sun.COM 	pwfg = pw;
13384887Schin #ifdef DEBUG
13394887Schin 	sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid);
13404887Schin 	if(pw)
13414887Schin 		sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag);
13424887Schin #endif /* DEBUG*/
13434887Schin 	errno = 0;
13448462SApril.Chin@Sun.COM 	if(sh.coutpipe>=0 && sh.cpid==lastpid)
13458462SApril.Chin@Sun.COM 	{
13468462SApril.Chin@Sun.COM 		sh_close(sh.coutpipe);
13478462SApril.Chin@Sun.COM 		sh_close(sh.cpipe[1]);
13488462SApril.Chin@Sun.COM 		sh.cpipe[1] = sh.coutpipe = -1;
13498462SApril.Chin@Sun.COM 	}
13504887Schin 	while(1)
13514887Schin 	{
13524887Schin 		if(job.waitsafe)
13534887Schin 		{
13544887Schin 			for(px=job.pwlist;px; px = px->p_nxtjob)
13554887Schin 			{
13564887Schin 				if(px!=pw && (px->p_flag&P_NOTIFY))
13574887Schin 				{
13584887Schin 					if(sh_isoption(SH_NOTIFY))
13594887Schin 					{
13604887Schin 						outfile = sfstderr;
13614887Schin 						job_list(px,JOB_NFLAG|JOB_NLFLAG);
13624887Schin 						sfsync(sfstderr);
13634887Schin 					}
13644887Schin 					else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
13654887Schin 					{
13664887Schin 						job_prmsg(px);
13674887Schin 						px->p_flag &= ~P_NOTIFY;
13684887Schin 					}
13694887Schin 				}
13704887Schin 			}
13714887Schin 		}
13724887Schin 		if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
13734887Schin 		{
13744887Schin #ifdef SIGTSTP
13754887Schin 			if(pw->p_flag&P_STOPPED)
13764887Schin 			{
13774887Schin 				pw->p_flag |= P_EXITSAVE;
13784887Schin 				if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
13794887Schin 				{
13804887Schin 					if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
13814887Schin 						break;
13824887Schin 
13834887Schin 					killpg(pw->p_pgrp,SIGCONT);
13844887Schin 				}
13854887Schin 				else /* ignore stop when non-interactive */
13864887Schin 					pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
13874887Schin 			}
13884887Schin 			else
13894887Schin #endif /* SIGTSTP */
13904887Schin 			{
13914887Schin 				if(pw->p_flag&P_SIGNALLED)
13924887Schin 				{
13934887Schin 					pw->p_flag &= ~P_NOTIFY;
13944887Schin 					job_prmsg(pw);
13954887Schin 				}
13964887Schin 				else if(pw->p_flag&P_DONE)
13974887Schin 					pw->p_flag &= ~P_NOTIFY;
13984887Schin 				if(pw->p_job==jobid)
13994887Schin 				{
14004887Schin 					px = job_byjid(jobid);
14014887Schin 					/* last process in job */
14024887Schin 					if(sh_isoption(SH_PIPEFAIL))
14034887Schin 					{
14044887Schin 						/* last non-zero exit */
14054887Schin 						for(;px;px=px->p_nxtproc)
14064887Schin 						{
14074887Schin 							if(px->p_exit)
14084887Schin 								break;
14094887Schin 						}
14104887Schin 						if(!px)
14114887Schin 							px = pw;
14124887Schin 					}
14134887Schin 					else if(px!=pw)
14144887Schin 						px = 0;
14154887Schin 					if(px)
14164887Schin 					{
14174887Schin 						sh.exitval=px->p_exit;
14184887Schin 						if(px->p_flag&P_SIGNALLED)
14194887Schin 							sh.exitval |= SH_EXITSIG;
14204887Schin 						if(intr)
14214887Schin 							px->p_flag &= ~P_EXITSAVE;
14224887Schin 					}
14234887Schin 				}
142410898Sroland.mainz@nrubsig.org 				px = job_unpost(pw,1);
1425*12068SRoger.Faulkner@Oracle.COM 				if(!px || !sh_isoption(SH_PIPEFAIL) || !job.waitall)
14264887Schin 					break;
14274887Schin 				pw = px;
14284887Schin 				continue;
14294887Schin 			}
14304887Schin 		}
14314887Schin 		sfsync(sfstderr);
14324887Schin 		job.waitsafe = 0;
14334887Schin 		nochild = job_reap(job.savesig);
14344887Schin 		if(job.waitsafe)
14354887Schin 			continue;
14364887Schin 		if(nochild)
14374887Schin 			break;
14384887Schin 		if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
14394887Schin 			sh_timetraps();
14404887Schin 		if((intr && sh.trapnote) || (pid==1 && !intr))
14414887Schin 			break;
14424887Schin 	}
14438462SApril.Chin@Sun.COM 	pwfg = 0;
14444887Schin 	job_unlock();
14454887Schin 	if(pid==1)
14468462SApril.Chin@Sun.COM 		return(nochild);
14474887Schin 	exitset();
14484887Schin 	if(pw->p_pgrp)
14494887Schin 	{
14504887Schin 		job_reset(pw);
14514887Schin 		/* propogate keyboard interrupts to parent */
14524887Schin 		if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
14534887Schin 			sh_fault(SIGINT);
14544887Schin #ifdef SIGTSTP
14554887Schin 		else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
14564887Schin 		{
14574887Schin 			job.parent = 0;
14584887Schin 			sh_fault(SIGTSTP);
14594887Schin 		}
14604887Schin #endif /* SIGTSTP */
14614887Schin 	}
14624887Schin 	else
14638462SApril.Chin@Sun.COM 	{
14648462SApril.Chin@Sun.COM 		if(pw->p_pid == tcgetpgrp(JOBTTY))
14658462SApril.Chin@Sun.COM 		{
14668462SApril.Chin@Sun.COM 			if(pw->p_pgrp==0)
14678462SApril.Chin@Sun.COM 				pw->p_pgrp = pw->p_pid;
14688462SApril.Chin@Sun.COM 			job_reset(pw);
14698462SApril.Chin@Sun.COM 		}
14704887Schin 		tty_set(-1, 0, NIL(struct termios*));
14718462SApril.Chin@Sun.COM 	}
14724887Schin done:
14734887Schin 	if(!job.waitall && sh_isoption(SH_PIPEFAIL))
14748462SApril.Chin@Sun.COM 		return(nochild);
14754887Schin 	if(!sh.intrap)
14764887Schin 	{
14774887Schin 		job_lock();
14784887Schin 		for(pw=job.pwlist; pw; pw=px)
14794887Schin 		{
14804887Schin 			px = pw->p_nxtjob;
14814887Schin 			job_unpost(pw,0);
14824887Schin 		}
14834887Schin 		job_unlock();
14844887Schin 	}
14858462SApril.Chin@Sun.COM 	return(nochild);
14864887Schin }
14874887Schin 
14884887Schin /*
14894887Schin  * move job to foreground if bgflag == 'f'
14904887Schin  * move job to background if bgflag == 'b'
14914887Schin  * disown job if bgflag == 'd'
14924887Schin  */
14934887Schin 
job_switch(register struct process * pw,int bgflag)14944887Schin int job_switch(register struct process *pw,int bgflag)
14954887Schin {
14964887Schin 	register const char *msg;
14974887Schin 	job_lock();
14984887Schin 	if(!pw || !(pw=job_byjid((int)pw->p_job)))
14994887Schin 	{
15004887Schin 		job_unlock();
15014887Schin 		return(1);
15024887Schin 	}
15034887Schin 	if(bgflag=='d')
15044887Schin 	{
15054887Schin 		for(; pw; pw=pw->p_nxtproc)
15064887Schin 			pw->p_flag |= P_DISOWN;
15074887Schin 		job_unlock();
15084887Schin 		return(0);
15094887Schin 	}
15104887Schin #ifdef SIGTSTP
15114887Schin 	if(bgflag=='b')
15124887Schin 	{
15134887Schin 		sfprintf(outfile,"[%d]\t",(int)pw->p_job);
15144887Schin 		sh.bckpid = pw->p_pid;
151510898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
151610898Sroland.mainz@nrubsig.org 		pw->p_flag |= P_BG;
151710898Sroland.mainz@nrubsig.org #endif
15184887Schin 		msg = "&";
15194887Schin 	}
15204887Schin 	else
15214887Schin 	{
15224887Schin 		job_unlink(pw);
15234887Schin 		pw->p_nxtjob = job.pwlist;
15244887Schin 		job.pwlist = pw;
15254887Schin 		msg = "";
15264887Schin 	}
15274887Schin 	hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
15284887Schin 	sfputr(outfile,msg,'\n');
15294887Schin 	sfsync(outfile);
15304887Schin 	if(bgflag=='f')
15314887Schin 	{
15324887Schin 		if(!(pw=job_unpost(pw,1)))
15334887Schin 		{
15344887Schin 			job_unlock();
15354887Schin 			return(1);
15364887Schin 		}
15374887Schin 		job.waitall = 1;
15384887Schin 		pw->p_flag |= P_FG;
153910898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
154010898Sroland.mainz@nrubsig.org 		pw->p_flag &= ~P_BG;
154110898Sroland.mainz@nrubsig.org #endif
15424887Schin 		job_wait(pw->p_pid);
15434887Schin 		job.waitall = 0;
15444887Schin 	}
15454887Schin 	else if(pw->p_flag&P_STOPPED)
15464887Schin 		job_unstop(pw);
15474887Schin #endif /* SIGTSTP */
15484887Schin 	job_unlock();
15494887Schin 	return(0);
15504887Schin }
15514887Schin 
15524887Schin 
15534887Schin #ifdef SIGTSTP
15544887Schin /*
15554887Schin  * Set the foreground group associated with a job
15564887Schin  */
15574887Schin 
job_fgrp(register struct process * pw,int newgrp)15584887Schin static void job_fgrp(register struct process *pw, int newgrp)
15594887Schin {
15604887Schin 	for(; pw; pw=pw->p_nxtproc)
15614887Schin 		pw->p_fgrp = newgrp;
15624887Schin }
15634887Schin 
15644887Schin /*
15654887Schin  * turn off STOP state of a process group and send CONT signals
15664887Schin  */
15674887Schin 
job_unstop(register struct process * px)15684887Schin static void job_unstop(register struct process *px)
15694887Schin {
15704887Schin 	register struct process *pw;
15714887Schin 	register int num = 0;
15724887Schin 	for(pw=px ;pw ;pw=pw->p_nxtproc)
15734887Schin 	{
15744887Schin 		if(pw->p_flag&P_STOPPED)
15754887Schin 		{
15764887Schin 			num++;
15774887Schin 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
15784887Schin 		}
15794887Schin 	}
15804887Schin 	if(num!=0)
15814887Schin 	{
15824887Schin 		if(px->p_fgrp != px->p_pgrp)
15834887Schin 			killpg(px->p_fgrp,SIGCONT);
15844887Schin 		killpg(px->p_pgrp,SIGCONT);
15854887Schin 	}
15864887Schin }
15874887Schin #endif	/* SIGTSTP */
15884887Schin 
15894887Schin /*
15904887Schin  * remove a job from table
15914887Schin  * If all the processes have not completed, unpost first non-completed  process
15924887Schin  * Otherwise the job is removed and job_unpost returns NULL.
15934887Schin  * pwlist is reset if the first job is removed
15944887Schin  * if <notify> is non-zero, then jobs with pending notifications are unposted
15954887Schin  */
15964887Schin 
job_unpost(register struct process * pwtop,int notify)15974887Schin static struct process *job_unpost(register struct process *pwtop,int notify)
15984887Schin {
15994887Schin 	register struct process *pw;
16004887Schin 	/* make sure all processes are done */
16014887Schin #ifdef DEBUG
16024887Schin 	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);
16034887Schin 	sfsync(sfstderr);
16044887Schin #endif /* DEBUG */
16054887Schin 	pwtop = pw = job_byjid((int)pwtop->p_job);
160610898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX
160710898Sroland.mainz@nrubsig.org 	if(pw->p_flag&P_BG)
160810898Sroland.mainz@nrubsig.org 		return(pw);
160910898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */
16104887Schin 	for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc);
16114887Schin 	if(pw)
16124887Schin 		return(pw);
16134887Schin 	/* all processes complete, unpost job */
16144887Schin 	job_unlink(pwtop);
16154887Schin 	for(pw=pwtop; pw; pw=pw->p_nxtproc)
16164887Schin 	{
16174887Schin 		/* save the exit status for background jobs */
16188462SApril.Chin@Sun.COM 		if((pw->p_flag&P_EXITSAVE) ||  pw->p_pid==sh.spid)
16194887Schin 		{
16204887Schin 			struct jobsave *jp;
16214887Schin 			/* save status for future wait */
16224887Schin 			if(jp = jobsave_create(pw->p_pid))
16234887Schin 			{
16244887Schin 				jp->exitval = pw->p_exit;
16254887Schin 				if(pw->p_flag&P_SIGNALLED)
16264887Schin 					jp->exitval |= SH_EXITSIG;
16274887Schin 			}
16284887Schin 			pw->p_flag &= ~P_EXITSAVE;
16294887Schin 		}
16304887Schin 		pw->p_flag &= ~P_DONE;
16314887Schin 		job.numpost--;
16324887Schin 		pw->p_nxtjob = freelist;
16334887Schin 		freelist = pw;
16344887Schin 	}
1635*12068SRoger.Faulkner@Oracle.COM 	pwtop->p_pid = 0;
16364887Schin #ifdef DEBUG
16374887Schin 	sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job);
16384887Schin 	sfsync(sfstderr);
16394887Schin #endif /* DEBUG */
16404887Schin 	job_free((int)pwtop->p_job);
16414887Schin 	return((struct process*)0);
16424887Schin }
16434887Schin 
16444887Schin /*
16454887Schin  * unlink a job form the job list
16464887Schin  */
job_unlink(register struct process * pw)16474887Schin static void job_unlink(register struct process *pw)
16484887Schin {
16494887Schin 	register struct process *px;
16504887Schin 	if(pw==job.pwlist)
16514887Schin 	{
16524887Schin 		job.pwlist = pw->p_nxtjob;
16534887Schin 		job.curpgid = 0;
16544887Schin 		return;
16554887Schin 	}
16564887Schin 	for(px=job.pwlist;px;px=px->p_nxtjob)
16574887Schin 		if(px->p_nxtjob == pw)
16584887Schin 		{
16594887Schin 			px->p_nxtjob = pw->p_nxtjob;
16604887Schin 			return;
16614887Schin 		}
16624887Schin }
16634887Schin 
16644887Schin /*
16654887Schin  * get an unused job number
16664887Schin  * freejobs is a bit vector, 0 is unused
16674887Schin  */
16684887Schin 
job_alloc(void)16694887Schin static int job_alloc(void)
16704887Schin {
16714887Schin 	register int j=0;
16724887Schin 	register unsigned mask = 1;
16734887Schin 	register unsigned char *freeword;
16744887Schin 	register int jmax = BYTE(sh.lim.child_max);
16754887Schin 	/* skip to first word with a free slot */
16764887Schin 	for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
16774887Schin 	if(j >= jmax)
16784887Schin 	{
16794887Schin 		register struct process *pw;
16804887Schin 		for(j=1; j < sh.lim.child_max; j++)
16814887Schin 		{
16824887Schin 			if((pw=job_byjid(j))&& !job_unpost(pw,0))
16834887Schin 				break;
16844887Schin 		}
16854887Schin 		j /= CHAR_BIT;
16864887Schin 		if(j >= jmax)
16874887Schin 			return(-1);
16884887Schin 	}
16894887Schin 	freeword = &job.freejobs[j];
16904887Schin 	j *= CHAR_BIT;
16914887Schin 	for(j++;mask&(*freeword);j++,mask <<=1);
16924887Schin 	*freeword  |= mask;
16934887Schin 	return(j);
16944887Schin }
16954887Schin 
16964887Schin /*
16974887Schin  * return a job number
16984887Schin  */
16994887Schin 
job_free(register int n)17004887Schin static void job_free(register int n)
17014887Schin {
17024887Schin 	register int j = (--n)/CHAR_BIT;
17034887Schin 	register unsigned mask;
17044887Schin 	n -= j*CHAR_BIT;
17054887Schin 	mask = 1 << n;
17064887Schin 	job.freejobs[j]  &= ~mask;
17074887Schin }
17084887Schin 
job_sigmsg(int sig)17094887Schin static char *job_sigmsg(int sig)
17104887Schin {
17114887Schin 	static char signo[40];
17124887Schin #ifdef apollo
17134887Schin 	/*
17144887Schin 	 * This code handles the formatting for the apollo specific signal
17154887Schin 	 * SIGAPOLLO.
17164887Schin 	 */
17174887Schin 	extern char *apollo_error(void);
17184887Schin 
17194887Schin 	if ( sig == SIGAPOLLO )
17204887Schin 		return( apollo_error() );
17214887Schin #endif /* apollo */
172210898Sroland.mainz@nrubsig.org 	if(sig<=sh.sigmax && sh.sigmsg[sig])
17234887Schin 		return(sh.sigmsg[sig]);
17244887Schin #if defined(SIGRTMIN) && defined(SIGRTMAX)
17258462SApril.Chin@Sun.COM 	if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX])
17264887Schin 	{
17274887Schin 		static char sigrt[20];
17288462SApril.Chin@Sun.COM 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2)
17298462SApril.Chin@Sun.COM 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig);
17308462SApril.Chin@Sun.COM 		else
17318462SApril.Chin@Sun.COM 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]);
17324887Schin 		return(sigrt);
17334887Schin 	}
17344887Schin #endif
17354887Schin 	sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig);
17364887Schin 	return(signo);
17374887Schin }
17384887Schin 
17394887Schin /*
17404887Schin  * see whether exit status has been saved and delete it
17414887Schin  * if pid==0, then oldest saved process is deleted
17424887Schin  * If pid is not found a -1 is returned.
17434887Schin  */
job_chksave(register pid_t pid)17444887Schin static int job_chksave(register pid_t pid)
17454887Schin {
17464887Schin 	register struct jobsave *jp = bck.list, *jpold=0;
17474887Schin 	register int r= -1;
174810898Sroland.mainz@nrubsig.org 	register int count=bck.count;
174910898Sroland.mainz@nrubsig.org 	while(jp && count-->0)
17504887Schin 	{
17514887Schin 		if(jp->pid==pid)
17524887Schin 			break;
17534887Schin 		if(pid==0 && !jp->next)
17544887Schin 			break;
17554887Schin 		jpold = jp;
17564887Schin 		jp = jp->next;
17574887Schin 	}
17584887Schin 	if(jp)
17594887Schin 	{
17604887Schin 		r = 0;
17614887Schin 		if(pid)
17624887Schin 			r = jp->exitval;
17634887Schin 		if(jpold)
17644887Schin 			jpold->next = jp->next;
17654887Schin 		else
17664887Schin 			bck.list = jp->next;
17674887Schin 		bck.count--;
17684887Schin 		if(njob_savelist < NJOB_SAVELIST)
17694887Schin 		{
17704887Schin 			njob_savelist++;
17714887Schin 			jp->next = job_savelist;
17724887Schin 			job_savelist = jp;
17734887Schin 		}
17744887Schin 		else
17754887Schin 			free((void*)jp);
17764887Schin 	}
17774887Schin 	return(r);
17784887Schin }
17794887Schin 
job_subsave(void)17804887Schin void *job_subsave(void)
17814887Schin {
17824887Schin 	struct back_save *bp = new_of(struct back_save,0);
17834887Schin 	job_lock();
17844887Schin 	*bp = bck;
17854887Schin 	bck.count = 0;
17864887Schin 	bck.list = 0;
17874887Schin 	job_unlock();
17884887Schin 	return((void*)bp);
17894887Schin }
17904887Schin 
job_subrestore(void * ptr)17914887Schin void job_subrestore(void* ptr)
17924887Schin {
17938462SApril.Chin@Sun.COM 	register struct jobsave *jp;
17944887Schin 	register struct back_save *bp = (struct back_save*)ptr;
17954887Schin 	register struct process *pw, *px, *pwnext;
17968462SApril.Chin@Sun.COM 	struct jobsave *jpnext;
17974887Schin 	job_lock();
17988462SApril.Chin@Sun.COM 	for(jp=bck.list; jp; jp=jpnext)
17998462SApril.Chin@Sun.COM 	{
18008462SApril.Chin@Sun.COM 		jpnext = jp->next;
18018462SApril.Chin@Sun.COM 		if(jp->pid==sh.spid)
18028462SApril.Chin@Sun.COM 		{
18038462SApril.Chin@Sun.COM 			jp->next = bp->list;
18048462SApril.Chin@Sun.COM 			bp->list = jp;
180510898Sroland.mainz@nrubsig.org 			bp->count++;
18068462SApril.Chin@Sun.COM 		}
18078462SApril.Chin@Sun.COM 		else
18088462SApril.Chin@Sun.COM 			job_chksave(jp->pid);
18098462SApril.Chin@Sun.COM 	}
18104887Schin 	for(pw=job.pwlist; pw; pw=pwnext)
18114887Schin 	{
18124887Schin 		pwnext = pw->p_nxtjob;
181310898Sroland.mainz@nrubsig.org 		if(pw->p_env != sh.curenv || pw->p_pid==sh.pipepid)
18144887Schin 			continue;
18154887Schin 		for(px=pw; px; px=px->p_nxtproc)
18164887Schin 			px->p_flag |= P_DONE;
18174887Schin 		job_unpost(pw,0);
18184887Schin 	}
18198462SApril.Chin@Sun.COM 
18208462SApril.Chin@Sun.COM 	/*
18218462SApril.Chin@Sun.COM 	 * queue up old lists for disposal by job_reap()
18228462SApril.Chin@Sun.COM 	 */
18238462SApril.Chin@Sun.COM 
18248462SApril.Chin@Sun.COM 	bck = *bp;
18258462SApril.Chin@Sun.COM 	free((void*)bp);
18264887Schin 	job_unlock();
18274887Schin }
18284887Schin 
sh_waitsafe(void)18294887Schin int sh_waitsafe(void)
18304887Schin {
18314887Schin 	return(job.waitsafe);
18324887Schin }
18334887Schin 
job_fork(pid_t parent)18344887Schin void job_fork(pid_t parent)
18354887Schin {
18364887Schin #ifdef DEBUG
18374887Schin 	sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent);
18384887Schin #endif /* DEBUG */
18394887Schin 	switch (parent)
18404887Schin 	{
18414887Schin 	case -1:
18424887Schin 		job_lock();
18434887Schin 		break;
18444887Schin 	case 0:
18454887Schin 		job_unlock();
18464887Schin 		job.waitsafe = 0;
18474887Schin 		job.in_critical = 0;
18484887Schin 		break;
18494887Schin 	default:
1850*12068SRoger.Faulkner@Oracle.COM 		job_chksave(parent);
18514887Schin 		job_unlock();
18524887Schin 		break;
18534887Schin 	}
18544887Schin }
1855