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