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