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