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