14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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 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 116*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 117*10898Sroland.mainz@nrubsig.org #define P_BG 01000 118*10898Sroland.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 */ 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 181*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 182*10898Sroland.mainz@nrubsig.org void job_chldtrap(Shell_t *shp, const char *trap, int unpost) 183*10898Sroland.mainz@nrubsig.org { 184*10898Sroland.mainz@nrubsig.org register struct process *pw,*pwnext; 185*10898Sroland.mainz@nrubsig.org pid_t bckpid; 186*10898Sroland.mainz@nrubsig.org int oldexit; 187*10898Sroland.mainz@nrubsig.org job_lock(); 188*10898Sroland.mainz@nrubsig.org shp->sigflag[SIGCHLD] &= ~SH_SIGTRAP; 189*10898Sroland.mainz@nrubsig.org for(pw=job.pwlist;pw;pw=pwnext) 190*10898Sroland.mainz@nrubsig.org { 191*10898Sroland.mainz@nrubsig.org pwnext = pw->p_nxtjob; 192*10898Sroland.mainz@nrubsig.org if((pw->p_flag&(P_BG|P_DONE)) != (P_BG|P_DONE)) 193*10898Sroland.mainz@nrubsig.org continue; 194*10898Sroland.mainz@nrubsig.org pw->p_flag &= ~P_BG; 195*10898Sroland.mainz@nrubsig.org bckpid = shp->bckpid; 196*10898Sroland.mainz@nrubsig.org oldexit = shp->savexit; 197*10898Sroland.mainz@nrubsig.org shp->bckpid = pw->p_pid; 198*10898Sroland.mainz@nrubsig.org shp->savexit = pw->p_exit; 199*10898Sroland.mainz@nrubsig.org if(pw->p_flag&P_SIGNALLED) 200*10898Sroland.mainz@nrubsig.org shp->savexit |= SH_EXITSIG; 201*10898Sroland.mainz@nrubsig.org sh_trap(trap,0); 202*10898Sroland.mainz@nrubsig.org shp->savexit = oldexit; 203*10898Sroland.mainz@nrubsig.org shp->bckpid = bckpid; 204*10898Sroland.mainz@nrubsig.org if(unpost) 205*10898Sroland.mainz@nrubsig.org job_unpost(pw,0); 206*10898Sroland.mainz@nrubsig.org } 207*10898Sroland.mainz@nrubsig.org job_unlock(); 208*10898Sroland.mainz@nrubsig.org } 209*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 210*10898Sroland.mainz@nrubsig.org 211*10898Sroland.mainz@nrubsig.org /* 212*10898Sroland.mainz@nrubsig.org * return next on link list of jobsave free list 213*10898Sroland.mainz@nrubsig.org */ 214*10898Sroland.mainz@nrubsig.org static struct jobsave *jobsave_create(pid_t pid) 215*10898Sroland.mainz@nrubsig.org { 216*10898Sroland.mainz@nrubsig.org register struct jobsave *jp = job_savelist; 217*10898Sroland.mainz@nrubsig.org job_chksave(pid); 218*10898Sroland.mainz@nrubsig.org if(++bck.count > sh.lim.child_max) 219*10898Sroland.mainz@nrubsig.org job_chksave(0); 220*10898Sroland.mainz@nrubsig.org if(jp) 221*10898Sroland.mainz@nrubsig.org { 222*10898Sroland.mainz@nrubsig.org njob_savelist--; 223*10898Sroland.mainz@nrubsig.org job_savelist = jp->next; 224*10898Sroland.mainz@nrubsig.org } 225*10898Sroland.mainz@nrubsig.org else 226*10898Sroland.mainz@nrubsig.org jp = newof(0,struct jobsave,1,0); 227*10898Sroland.mainz@nrubsig.org if(jp) 228*10898Sroland.mainz@nrubsig.org { 229*10898Sroland.mainz@nrubsig.org jp->pid = pid; 230*10898Sroland.mainz@nrubsig.org jp->next = bck.list; 231*10898Sroland.mainz@nrubsig.org bck.list = jp; 232*10898Sroland.mainz@nrubsig.org jp->exitval = 0; 233*10898Sroland.mainz@nrubsig.org } 234*10898Sroland.mainz@nrubsig.org return(jp); 235*10898Sroland.mainz@nrubsig.org } 236*10898Sroland.mainz@nrubsig.org 2374887Schin /* 2384887Schin * Reap one job 2394887Schin * When called with sig==0, it does a blocking wait 2404887Schin */ 2414887Schin int job_reap(register int sig) 2424887Schin { 2434887Schin register pid_t pid; 2444887Schin register struct process *pw; 2454887Schin struct process *px; 2464887Schin register int flags; 2474887Schin struct jobsave *jp; 2484887Schin int nochild=0, oerrno, wstat; 2494887Schin Waitevent_f waitevent = sh.waitevent; 2504887Schin static int wcontinued = WCONTINUED; 2518462SApril.Chin@Sun.COM if (vmbusy()) 2528462SApril.Chin@Sun.COM { 2538462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen"); 2548462SApril.Chin@Sun.COM if (getenv("_AST_KSH_VMBUSY_ABORT")) 2558462SApril.Chin@Sun.COM abort(); 2568462SApril.Chin@Sun.COM } 2574887Schin #ifdef DEBUG 2584887Schin if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0) 2594887Schin write(2,"waitsafe\n",9); 2604887Schin sfsync(sfstderr); 2614887Schin #endif /* DEBUG */ 2624887Schin job.savesig = 0; 2634887Schin if(sig) 2644887Schin flags = WNOHANG|WUNTRACED|wcontinued; 2654887Schin else 2664887Schin flags = WUNTRACED|wcontinued; 2674887Schin sh.waitevent = 0; 2684887Schin oerrno = errno; 2694887Schin while(1) 2704887Schin { 2718462SApril.Chin@Sun.COM if(!(flags&WNOHANG) && !sh.intrap && job.pwlist) 2724887Schin { 2738462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT); 2748462SApril.Chin@Sun.COM if(waitevent && (*waitevent)(-1,-1L,0)) 2754887Schin flags |= WNOHANG; 2764887Schin } 2774887Schin pid = waitpid((pid_t)-1,&wstat,flags); 2788462SApril.Chin@Sun.COM sh_offstate(SH_TTYWAIT); 2794887Schin 2804887Schin /* 2814887Schin * some systems (linux 2.6) may return EINVAL 2824887Schin * when there are no continued children 2834887Schin */ 2844887Schin 2854887Schin if (pid<0 && errno==EINVAL && (flags&WCONTINUED)) 2864887Schin pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED); 2874887Schin sh_sigcheck(); 2884887Schin if(sig && pid<0 && errno==EINTR) 2894887Schin continue; 2904887Schin if(pid<=0) 2914887Schin break; 2924887Schin flags |= WNOHANG; 2934887Schin job.waitsafe++; 2944887Schin jp = 0; 2958462SApril.Chin@Sun.COM lastpid = pid; 2964887Schin if(!(pw=job_bypid(pid))) 2974887Schin { 2984887Schin #ifdef DEBUG 2994887Schin 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); 3004887Schin #endif /* DEBUG */ 3018462SApril.Chin@Sun.COM if (WIFCONTINUED(wstat) && wcontinued) 3028462SApril.Chin@Sun.COM continue; 3034887Schin pw = &dummy; 3044887Schin pw->p_exit = 0; 3054887Schin pw->p_pgrp = 0; 3068462SApril.Chin@Sun.COM pw->p_exitmin = 0; 3074887Schin if(job.toclear) 3084887Schin job_clear(); 309*10898Sroland.mainz@nrubsig.org jp = jobsave_create(pid); 3104887Schin pw->p_flag = 0; 3114887Schin lastpid = pw->p_pid = pid; 3124887Schin px = 0; 3134887Schin if(jp && WIFSTOPPED(wstat)) 3144887Schin { 3154887Schin jp->exitval = SH_STOPSIG; 3164887Schin continue; 3174887Schin } 3184887Schin } 3194887Schin #ifdef SIGTSTP 3204887Schin else 3214887Schin px=job_byjid(pw->p_job); 3224887Schin if(WIFSTOPPED(wstat)) 3234887Schin { 3244887Schin if(px) 3254887Schin { 3264887Schin /* move to top of job list */ 3274887Schin job_unlink(px); 3284887Schin px->p_nxtjob = job.pwlist; 3294887Schin job.pwlist = px; 3304887Schin } 3318462SApril.Chin@Sun.COM pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED); 3324887Schin pw->p_exit = WSTOPSIG(wstat); 3334887Schin if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK)) 3344887Schin sh_fault(pw->p_exit); 3354887Schin continue; 3364887Schin } 3374887Schin else if (WIFCONTINUED(wstat) && wcontinued) 3384887Schin pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED); 3394887Schin else 3404887Schin #endif /* SIGTSTP */ 3414887Schin { 3424887Schin /* check for coprocess completion */ 3434887Schin if(pid==sh.cpid) 3444887Schin { 3454887Schin sh_close(sh.coutpipe); 3464887Schin sh_close(sh.cpipe[1]); 3474887Schin sh.cpipe[1] = -1; 3484887Schin sh.coutpipe = -1; 3494887Schin } 3508462SApril.Chin@Sun.COM else if(sh.subshell) 3518462SApril.Chin@Sun.COM sh_subjobcheck(pid); 3528462SApril.Chin@Sun.COM 3538462SApril.Chin@Sun.COM pw->p_flag &= ~(P_STOPPED|P_SIGNALLED); 3544887Schin if (WIFSIGNALED(wstat)) 3554887Schin { 3564887Schin pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED); 3574887Schin if (WTERMCORE(wstat)) 3584887Schin pw->p_flag |= P_COREDUMP; 3594887Schin pw->p_exit = WTERMSIG(wstat); 3604887Schin /* if process in current jobs terminates from 3614887Schin * an interrupt, propogate to parent shell 3624887Schin */ 3634887Schin if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK)) 3644887Schin { 3654887Schin pw->p_flag &= ~P_NOTIFY; 3664887Schin sh_offstate(SH_STOPOK); 3674887Schin sh_fault(SIGINT); 3684887Schin sh_onstate(SH_STOPOK); 3694887Schin } 3704887Schin } 3714887Schin else 3724887Schin { 3734887Schin pw->p_flag |= (P_DONE|P_NOTIFY); 3748462SApril.Chin@Sun.COM pw->p_exit = pw->p_exitmin; 3758462SApril.Chin@Sun.COM if(WEXITSTATUS(wstat) > pw->p_exitmin) 3764887Schin pw->p_exit = WEXITSTATUS(wstat); 3774887Schin } 378*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 379*10898Sroland.mainz@nrubsig.org if((pw->p_flag&P_DONE) && (pw->p_flag&P_BG)) 380*10898Sroland.mainz@nrubsig.org { 381*10898Sroland.mainz@nrubsig.org job.numbjob--; 382*10898Sroland.mainz@nrubsig.org if(sh.st.trapcom[SIGCHLD]) 383*10898Sroland.mainz@nrubsig.org { 384*10898Sroland.mainz@nrubsig.org sh.sigflag[SIGCHLD] |= SH_SIGTRAP; 385*10898Sroland.mainz@nrubsig.org if(sig==0) 386*10898Sroland.mainz@nrubsig.org job_chldtrap(&sh,sh.st.trapcom[SIGCHLD],0); 387*10898Sroland.mainz@nrubsig.org else 388*10898Sroland.mainz@nrubsig.org sh.trapnote |= SH_SIGTRAP; 389*10898Sroland.mainz@nrubsig.org } 390*10898Sroland.mainz@nrubsig.org else 391*10898Sroland.mainz@nrubsig.org pw->p_flag &= ~P_BG; 392*10898Sroland.mainz@nrubsig.org } 393*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 3944887Schin if(pw->p_pgrp==0) 3954887Schin pw->p_flag &= ~P_NOTIFY; 3964887Schin } 3974887Schin if(jp && pw== &dummy) 3984887Schin { 3994887Schin jp->exitval = pw->p_exit; 4004887Schin if(pw->p_flag&P_SIGNALLED) 4014887Schin jp->exitval |= SH_EXITSIG; 4024887Schin } 4034887Schin #ifdef DEBUG 4044887Schin 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); 4054887Schin sfsync(sfstderr); 4064887Schin #endif /* DEBUG*/ 4074887Schin /* only top-level process in job should have notify set */ 4084887Schin if(px && pw != px) 4094887Schin pw->p_flag &= ~P_NOTIFY; 4108462SApril.Chin@Sun.COM if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY)) 4118462SApril.Chin@Sun.COM { 4128462SApril.Chin@Sun.COM px = job_byjid((int)pw->p_job); 4138462SApril.Chin@Sun.COM for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc); 4148462SApril.Chin@Sun.COM if(!px) 4158462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,job.mypid); 4168462SApril.Chin@Sun.COM } 417*10898Sroland.mainz@nrubsig.org #ifndef SHOPT_BGX 4188462SApril.Chin@Sun.COM if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid))) 4198462SApril.Chin@Sun.COM { 4208462SApril.Chin@Sun.COM sh.sigflag[SIGCHLD] |= SH_SIGTRAP; 4218462SApril.Chin@Sun.COM sh.trapnote |= SH_SIGTRAP; 4228462SApril.Chin@Sun.COM } 423*10898Sroland.mainz@nrubsig.org #endif 4244887Schin } 4254887Schin if(errno==ECHILD) 4264887Schin { 4274887Schin errno = oerrno; 428*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 429*10898Sroland.mainz@nrubsig.org job.numbjob = 0; 430*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 4314887Schin nochild = 1; 4324887Schin } 4334887Schin sh.waitevent = waitevent; 4344887Schin if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT)) 4354887Schin { 4364887Schin outfile = sfstderr; 4374887Schin job_list(pw,JOB_NFLAG|JOB_NLFLAG); 4384887Schin job_unpost(pw,1); 4394887Schin sfsync(sfstderr); 4404887Schin } 4414887Schin if(sig) 4424887Schin signal(sig, job_waitsafe); 4434887Schin return(nochild); 4444887Schin } 4454887Schin 4464887Schin /* 4474887Schin * This is the SIGCLD interrupt routine 4484887Schin */ 4494887Schin static void job_waitsafe(int sig) 4504887Schin { 4518462SApril.Chin@Sun.COM if(job.in_critical || vmbusy()) 4524887Schin { 4534887Schin job.savesig = sig; 4544887Schin job.waitsafe++; 4554887Schin } 4564887Schin else 4574887Schin job_reap(sig); 4584887Schin } 4594887Schin 4604887Schin /* 4614887Schin * initialize job control if possible 4624887Schin * if lflag is set the switching driver message will not print 4634887Schin */ 4648462SApril.Chin@Sun.COM void job_init(Shell_t *shp, int lflag) 4654887Schin { 4668462SApril.Chin@Sun.COM register int ntry=0; 4674887Schin job.fd = JOBTTY; 4684887Schin signal(SIGCHLD,job_waitsafe); 4694887Schin # if defined(SIGCLD) && (SIGCLD!=SIGCHLD) 4704887Schin signal(SIGCLD,job_waitsafe); 4714887Schin # endif 4724887Schin if(njob_savelist < NJOB_SAVELIST) 4734887Schin init_savelist(); 4744887Schin if(!sh_isoption(SH_INTERACTIVE)) 4754887Schin return; 4764887Schin /* use new line discipline when available */ 4774887Schin #ifdef NTTYDISC 4784887Schin # ifdef FIOLOOKLD 4794887Schin if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0) 4804887Schin # else 4814887Schin if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0) 4824887Schin # endif /* FIOLOOKLD */ 4834887Schin return; 4844887Schin if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC) 4854887Schin { 4864887Schin /* no job control when running with MPX */ 4874887Schin # if SHOPT_VSH 4884887Schin sh_onoption(SH_VIRAW); 4894887Schin # endif /* SHOPT_VSH */ 4904887Schin return; 4914887Schin } 4924887Schin if(job.linedisc==NTTYDISC) 4934887Schin job.linedisc = -1; 4944887Schin #endif /* NTTYDISC */ 4954887Schin 4964887Schin job.mypgid = getpgrp(); 4974887Schin /* some systems have job control, but not initialized */ 4984887Schin if(job.mypgid<=0) 4994887Schin { 5004887Schin /* Get a controlling terminal and set process group */ 5014887Schin /* This should have already been done by rlogin */ 5024887Schin register int fd; 5034887Schin register char *ttynam; 5044887Schin #ifndef SIGTSTP 5058462SApril.Chin@Sun.COM setpgid(0,shp->pid); 5064887Schin #endif /*SIGTSTP */ 5074887Schin if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY))) 5084887Schin return; 5094887Schin close(JOBTTY); 5104887Schin if((fd = open(ttynam,O_RDWR)) <0) 5114887Schin return; 5124887Schin if(fd!=JOBTTY) 5138462SApril.Chin@Sun.COM sh_iorenumber(shp,fd,JOBTTY); 5148462SApril.Chin@Sun.COM job.mypgid = shp->pid; 5154887Schin #ifdef SIGTSTP 5168462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,shp->pid); 5178462SApril.Chin@Sun.COM setpgid(0,shp->pid); 5184887Schin #endif /* SIGTSTP */ 5194887Schin } 5204887Schin #ifdef SIGTSTP 5214887Schin if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM) 5224887Schin { 5234887Schin /* wait until we are in the foreground */ 5244887Schin while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid) 5254887Schin { 5264887Schin if(job.mytgid == -1) 5274887Schin return; 5284887Schin /* Stop this shell until continued */ 5294887Schin signal(SIGTTIN,SIG_DFL); 5308462SApril.Chin@Sun.COM kill(shp->pid,SIGTTIN); 5314887Schin /* resumes here after continue tries again */ 5324887Schin if(ntry++ > IOMAXTRY) 5334887Schin { 5344887Schin errormsg(SH_DICT,0,e_no_start); 5354887Schin return; 5364887Schin } 5374887Schin } 5384887Schin } 5394887Schin #endif /* SIGTTIN */ 5404887Schin 5414887Schin #ifdef NTTYDISC 5424887Schin /* set the line discipline */ 5434887Schin if(job.linedisc>=0) 5444887Schin { 5454887Schin int linedisc = NTTYDISC; 5464887Schin # ifdef FIOPUSHLD 5474887Schin tty_get(JOBTTY,&my_stty); 5484887Schin if (ioctl(JOBTTY, FIOPOPLD, 0) < 0) 5494887Schin return; 5504887Schin if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0) 5514887Schin { 5524887Schin ioctl(JOBTTY, FIOPUSHLD, &job.linedisc); 5534887Schin return; 5544887Schin } 5554887Schin tty_set(JOBTTY,TCSANOW,&my_stty); 5564887Schin # else 5574887Schin if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0) 5584887Schin return; 5594887Schin # endif /* FIOPUSHLD */ 5604887Schin if(lflag==0) 5614887Schin errormsg(SH_DICT,0,e_newtty); 5624887Schin else 5634887Schin job.linedisc = -1; 5644887Schin } 5654887Schin #endif /* NTTYDISC */ 5664887Schin if(!possible) 5674887Schin return; 5684887Schin 5694887Schin #ifdef SIGTSTP 5704887Schin /* make sure that we are a process group leader */ 5718462SApril.Chin@Sun.COM setpgid(0,shp->pid); 5724887Schin # if defined(SA_NOCLDWAIT) && defined(_lib_sigflag) 5734887Schin sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0); 5744887Schin # endif /* SA_NOCLDWAIT */ 5754887Schin signal(SIGTTIN,SIG_IGN); 5764887Schin signal(SIGTTOU,SIG_IGN); 5774887Schin /* The shell now handles ^Z */ 5784887Schin signal(SIGTSTP,sh_fault); 5798462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,shp->pid); 5804887Schin # ifdef CNSUSP 5814887Schin /* set the switch character */ 5824887Schin tty_get(JOBTTY,&my_stty); 5834887Schin job.suspend = (unsigned)my_stty.c_cc[VSUSP]; 5844887Schin if(job.suspend == (unsigned char)CNSUSP) 5854887Schin { 5864887Schin my_stty.c_cc[VSUSP] = CSWTCH; 5874887Schin tty_set(JOBTTY,TCSAFLUSH,&my_stty); 5884887Schin } 5894887Schin # endif /* CNSUSP */ 5904887Schin sh_onoption(SH_MONITOR); 5914887Schin job.jobcontrol++; 5928462SApril.Chin@Sun.COM job.mypid = shp->pid; 5934887Schin #endif /* SIGTSTP */ 5944887Schin return; 5954887Schin } 5964887Schin 5974887Schin 5984887Schin /* 5994887Schin * see if there are any stopped jobs 6004887Schin * restore tty driver and pgrp 6014887Schin */ 6028462SApril.Chin@Sun.COM int job_close(Shell_t* shp) 6034887Schin { 6044887Schin register struct process *pw; 6054887Schin register int count = 0, running = 0; 6064887Schin if(possible && !job.jobcontrol) 6074887Schin return(0); 6084887Schin else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED))) 6094887Schin return(0); 6104887Schin else if(getpid() != job.mypid) 6114887Schin return(0); 6124887Schin job_lock(); 6134887Schin if(!tty_check(0)) 6144887Schin beenhere++; 6154887Schin for(pw=job.pwlist;pw;pw=pw->p_nxtjob) 6164887Schin { 6174887Schin if(!(pw->p_flag&P_STOPPED)) 6184887Schin { 6194887Schin if(!(pw->p_flag&P_DONE)) 6204887Schin running++; 6214887Schin continue; 6224887Schin } 6234887Schin if(beenhere) 6244887Schin killpg(pw->p_pgrp,SIGTERM); 6254887Schin count++; 6264887Schin } 6274887Schin if(beenhere++ == 0 && job.pwlist) 6284887Schin { 6294887Schin if(count) 6304887Schin { 6314887Schin errormsg(SH_DICT,0,e_terminate); 6324887Schin return(-1); 6334887Schin } 6348462SApril.Chin@Sun.COM else if(running && shp->login_sh) 6354887Schin { 6364887Schin errormsg(SH_DICT,0,e_jobsrunning); 6374887Schin return(-1); 6384887Schin } 6394887Schin } 6404887Schin job_unlock(); 6414887Schin # ifdef SIGTSTP 6424887Schin if(possible && setpgid(0,job.mypgid)>=0) 6434887Schin tcsetpgrp(job.fd,job.mypgid); 6444887Schin # endif /* SIGTSTP */ 6454887Schin # ifdef NTTYDISC 6464887Schin if(job.linedisc>=0) 6474887Schin { 6484887Schin /* restore old line discipline */ 6494887Schin # ifdef FIOPUSHLD 6504887Schin tty_get(job.fd,&my_stty); 6514887Schin if (ioctl(job.fd, FIOPOPLD, 0) < 0) 6524887Schin return(0); 6534887Schin if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0) 6544887Schin { 6554887Schin job.linedisc = NTTYDISC; 6564887Schin ioctl(job.fd, FIOPUSHLD, &job.linedisc); 6574887Schin return(0); 6584887Schin } 6594887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 6604887Schin # else 6614887Schin if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0) 6624887Schin return(0); 6634887Schin # endif /* FIOPUSHLD */ 6644887Schin errormsg(SH_DICT,0,e_oldtty); 6654887Schin } 6664887Schin # endif /* NTTYDISC */ 6674887Schin # ifdef CNSUSP 6684887Schin if(possible && job.suspend==CNSUSP) 6694887Schin { 6704887Schin tty_get(job.fd,&my_stty); 6714887Schin my_stty.c_cc[VSUSP] = CNSUSP; 6724887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 6734887Schin } 6744887Schin # endif /* CNSUSP */ 6754887Schin job.jobcontrol = 0; 6764887Schin return(0); 6774887Schin } 6784887Schin 6794887Schin static void job_set(register struct process *pw) 6804887Schin { 6814887Schin /* save current terminal state */ 6824887Schin tty_get(job.fd,&my_stty); 6834887Schin if(pw->p_flag&P_STTY) 6844887Schin { 6854887Schin /* restore terminal state for job */ 6864887Schin tty_set(job.fd,TCSAFLUSH,&pw->p_stty); 6874887Schin } 6884887Schin #ifdef SIGTSTP 6894887Schin if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid) 6904887Schin tcsetpgrp(job.fd,pw->p_fgrp); 6914887Schin /* if job is stopped, resume it in the background */ 6924887Schin job_unstop(pw); 6934887Schin #endif /* SIGTSTP */ 6944887Schin } 6954887Schin 6964887Schin static void job_reset(register struct process *pw) 6974887Schin { 6984887Schin /* save the terminal state for current job */ 6994887Schin #ifdef SIGTSTP 7004887Schin job_fgrp(pw,tcgetpgrp(job.fd)); 7018462SApril.Chin@Sun.COM if(tcsetpgrp(job.fd,job.mypid) !=0) 7024887Schin return; 7034887Schin #endif /* SIGTSTP */ 7044887Schin /* force the following tty_get() to do a tcgetattr() unless fg */ 7054887Schin if(!(pw->p_flag&P_FG)) 7064887Schin tty_set(-1, 0, NIL(struct termios*)); 7074887Schin if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP) 7084887Schin { 7094887Schin if(tty_get(job.fd,&pw->p_stty) == 0) 7104887Schin pw->p_flag |= P_STTY; 7114887Schin /* restore terminal state for job */ 7124887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 7134887Schin } 7144887Schin beenhere = 0; 7154887Schin } 7164887Schin #endif /* JOBS */ 7174887Schin 7184887Schin /* 7194887Schin * wait built-in command 7204887Schin */ 7214887Schin 7224887Schin void job_bwait(char **jobs) 7234887Schin { 7244887Schin register char *jp; 7254887Schin register struct process *pw; 7264887Schin register pid_t pid; 7274887Schin if(*jobs==0) 7284887Schin job_wait((pid_t)-1); 7294887Schin else while(jp = *jobs++) 7304887Schin { 7314887Schin #ifdef JOBS 7324887Schin if(*jp == '%') 7334887Schin { 7344887Schin job_lock(); 7354887Schin pw = job_bystring(jp); 7364887Schin job_unlock(); 7374887Schin if(pw) 7384887Schin pid = pw->p_pid; 7394887Schin else 7404887Schin return; 7414887Schin } 7424887Schin else 7434887Schin #endif /* JOBS */ 7444887Schin pid = (int)strtol(jp, (char**)0, 10); 7454887Schin job_wait(-pid); 7464887Schin } 7474887Schin } 7484887Schin 7494887Schin #ifdef JOBS 7504887Schin /* 7514887Schin * execute function <fun> for each job 7524887Schin */ 7534887Schin 7544887Schin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[]) 7554887Schin { 7564887Schin register struct process *pw; 7574887Schin register int r = 0; 7584887Schin register char *jobid, **jobs=joblist; 7594887Schin register struct process *px; 7604887Schin job_string = 0; 7614887Schin outfile = file; 7624887Schin by_number = 0; 7634887Schin job_lock(); 7644887Schin pw = job.pwlist; 7654887Schin if(jobs==0) 7664887Schin { 7674887Schin /* do all jobs */ 7684887Schin for(;pw;pw=px) 7694887Schin { 7704887Schin px = pw->p_nxtjob; 7714887Schin if(pw->p_env != sh.jobenv) 7724887Schin continue; 7734887Schin if((*fun)(pw,arg)) 7744887Schin r = 2; 7754887Schin } 7764887Schin } 7774887Schin else if(*jobs==0) /* current job */ 7784887Schin { 7794887Schin /* skip over non-stop jobs */ 7804887Schin while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0)) 7814887Schin pw = pw->p_nxtjob; 7824887Schin if((*fun)(pw,arg)) 7834887Schin r = 2; 7844887Schin } 7854887Schin else while(jobid = *jobs++) 7864887Schin { 7874887Schin job_string = jobid; 7884887Schin if(*jobid==0) 7894887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 7904887Schin if(*jobid == '%') 7914887Schin pw = job_bystring(jobid); 7924887Schin else 7934887Schin { 7944887Schin int pid = (int)strtol(jobid, (char**)0, 10); 7954887Schin if(pid<0) 7964887Schin jobid++; 7974887Schin while(isdigit(*jobid)) 7984887Schin jobid++; 7994887Schin if(*jobid) 8004887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 8014887Schin if(!(pw = job_bypid(pid))) 8024887Schin { 8034887Schin pw = &dummy; 8044887Schin pw->p_pid = pid; 8054887Schin pw->p_pgrp = pid; 8064887Schin } 8074887Schin by_number = 1; 8084887Schin } 8094887Schin if((*fun)(pw,arg)) 8104887Schin r = 2; 8114887Schin by_number = 0; 8124887Schin } 8134887Schin job_unlock(); 8144887Schin return(r); 8154887Schin } 8164887Schin 8174887Schin /* 8184887Schin * send signal <sig> to background process group if not disowned 8194887Schin */ 8204887Schin int job_terminate(register struct process *pw,register int sig) 8214887Schin { 8224887Schin if(pw->p_pgrp && !(pw->p_flag&P_DISOWN)) 8234887Schin job_kill(pw,sig); 8244887Schin return(0); 8254887Schin } 8264887Schin 8274887Schin /* 8284887Schin * list the given job 8294887Schin * flag JOB_LFLAG for long listing 8304887Schin * flag JOB_NFLAG for list only jobs marked for notification 8314887Schin * flag JOB_PFLAG for process id(s) only 8324887Schin */ 8334887Schin 8344887Schin int job_list(struct process *pw,register int flag) 8354887Schin { 8364887Schin register struct process *px = pw; 8374887Schin register int n; 8384887Schin register const char *msg; 8394887Schin register int msize; 8404887Schin if(!pw || pw->p_job<=0) 8414887Schin return(1); 8424887Schin if(pw->p_env != sh.jobenv) 8434887Schin return(0); 8444887Schin if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0)) 8454887Schin return(0); 8464887Schin if((flag&JOB_PFLAG)) 8474887Schin { 8484887Schin sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid); 8494887Schin return(0); 8504887Schin } 8514887Schin if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG)) 8524887Schin return(0); 8534887Schin job_lock(); 8544887Schin n = px->p_job; 8554887Schin if(px==job.pwlist) 8564887Schin msize = '+'; 8574887Schin else if(px==job.pwlist->p_nxtjob) 8584887Schin msize = '-'; 8594887Schin else 8604887Schin msize = ' '; 8614887Schin if(flag&JOB_NLFLAG) 8624887Schin sfputc(outfile,'\n'); 8634887Schin sfprintf(outfile,"[%d] %c ",n, msize); 8644887Schin do 8654887Schin { 8664887Schin n = 0; 8674887Schin if(flag&JOB_LFLAG) 8684887Schin sfprintf(outfile,"%d\t",px->p_pid); 8694887Schin if(px->p_flag&P_SIGNALLED) 8704887Schin msg = job_sigmsg((int)(px->p_exit)); 8714887Schin else if(px->p_flag&P_NOTIFY) 8724887Schin { 8734887Schin msg = sh_translate(e_done); 8744887Schin n = px->p_exit; 8754887Schin } 8764887Schin else 8774887Schin msg = sh_translate(e_running); 8784887Schin px->p_flag &= ~P_NOTIFY; 8794887Schin sfputr(outfile,msg,-1); 8804887Schin msize = strlen(msg); 8814887Schin if(n) 8824887Schin { 8834887Schin sfprintf(outfile,"(%d)",(int)n); 8844887Schin msize += (3+(n>10)+(n>100)); 8854887Schin } 8864887Schin if(px->p_flag&P_COREDUMP) 8874887Schin { 8884887Schin msg = sh_translate(e_coredump); 8894887Schin sfputr(outfile, msg, -1); 8904887Schin msize += strlen(msg); 8914887Schin } 8924887Schin sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1); 8934887Schin if(flag&JOB_LFLAG) 8944887Schin px = px->p_nxtproc; 8954887Schin else 8964887Schin { 8974887Schin while(px=px->p_nxtproc) 8984887Schin px->p_flag &= ~P_NOTIFY; 8994887Schin px = 0; 9004887Schin } 9014887Schin if(!px) 9024887Schin hist_list(sh.hist_ptr,outfile,pw->p_name,0,";"); 9034887Schin else 9044887Schin sfputr(outfile, e_nlspace, -1); 9054887Schin } 9064887Schin while(px); 9074887Schin job_unlock(); 9084887Schin return(0); 9094887Schin } 9104887Schin 9114887Schin /* 9124887Schin * get the process group given the job number 9134887Schin * This routine returns the process group number or -1 9144887Schin */ 9154887Schin static struct process *job_bystring(register char *ajob) 9164887Schin { 9174887Schin register struct process *pw=job.pwlist; 9184887Schin register int c; 9194887Schin if(*ajob++ != '%' || !pw) 9204887Schin return(NIL(struct process*)); 9214887Schin c = *ajob; 9224887Schin if(isdigit(c)) 9234887Schin pw = job_byjid((int)strtol(ajob, (char**)0, 10)); 9244887Schin else if(c=='+' || c=='%') 9254887Schin ; 9264887Schin else if(c=='-') 9274887Schin { 9284887Schin if(pw) 9294887Schin pw = job.pwlist->p_nxtjob; 9304887Schin } 9314887Schin else 9324887Schin pw = job_byname(ajob); 9334887Schin if(pw && pw->p_flag) 9344887Schin return(pw); 9354887Schin return(NIL(struct process*)); 9364887Schin } 9374887Schin 9384887Schin /* 9394887Schin * Kill a job or process 9404887Schin */ 9414887Schin 9424887Schin int job_kill(register struct process *pw,register int sig) 9434887Schin { 9444887Schin register pid_t pid; 9454887Schin register int r; 9464887Schin const char *msg; 9474887Schin #ifdef SIGTSTP 9484887Schin int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU); 9494887Schin #else 9504887Schin # define stopsig 1 9514887Schin #endif /* SIGTSTP */ 9524887Schin job_lock(); 9534887Schin errno = ECHILD; 9544887Schin if(pw==0) 9554887Schin goto error; 9564887Schin pid = pw->p_pid; 9574887Schin if(by_number) 9584887Schin { 9594887Schin if(pid==0 && job.jobcontrol) 9604887Schin r = job_walk(outfile, job_kill,sig, (char**)0); 9614887Schin #ifdef SIGTSTP 9624887Schin if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1) 9634887Schin { 9644887Schin /* can't stop login shell */ 9654887Schin errno = EPERM; 9664887Schin r = -1; 9674887Schin } 9684887Schin else 9694887Schin { 9704887Schin if(pid>=0) 9714887Schin { 9724887Schin if((r = kill(pid,sig))>=0 && !stopsig) 9734887Schin { 9744887Schin if(pw->p_flag&P_STOPPED) 9754887Schin pw->p_flag &= ~(P_STOPPED|P_SIGNALLED); 9764887Schin if(sig) 9774887Schin kill(pid,SIGCONT); 9784887Schin } 9794887Schin } 9804887Schin else 9814887Schin { 9824887Schin if((r = killpg(-pid,sig))>=0 && !stopsig) 9834887Schin { 9844887Schin job_unstop(job_bypid(pw->p_pid)); 9854887Schin if(sig) 9864887Schin killpg(-pid,SIGCONT); 9874887Schin } 9884887Schin } 9894887Schin } 9904887Schin #else 9914887Schin if(pid>=0) 9924887Schin r = kill(pid,sig); 9934887Schin else 9944887Schin r = killpg(-pid,sig); 9954887Schin #endif /* SIGTSTP */ 9964887Schin } 9974887Schin else 9984887Schin { 9994887Schin if(pid = pw->p_pgrp) 10004887Schin { 10014887Schin r = killpg(pid,sig); 10024887Schin #ifdef SIGTSTP 10034887Schin if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT)) 10044887Schin job_unstop(pw); 10054887Schin #endif /* SIGTSTP */ 10064887Schin if(r>=0) 10074887Schin sh_delay(.05); 10084887Schin } 10094887Schin while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0) 10104887Schin { 10114887Schin #ifdef SIGTSTP 10124887Schin if(sig==SIGHUP || sig==SIGTERM) 10134887Schin kill(pw->p_pid,SIGCONT); 10144887Schin #endif /* SIGTSTP */ 10154887Schin pw = pw->p_nxtproc; 10164887Schin } 10174887Schin } 10184887Schin if(r<0 && job_string) 10194887Schin { 10204887Schin error: 10214887Schin if(pw && by_number) 10224887Schin msg = sh_translate(e_no_proc); 10234887Schin else 10244887Schin msg = sh_translate(e_no_job); 10254887Schin if(errno == EPERM) 10264887Schin msg = sh_translate(e_access); 10274887Schin sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg); 10284887Schin r = 2; 10294887Schin } 10304887Schin sh_delay(.001); 10314887Schin job_unlock(); 10324887Schin return(r); 10334887Schin } 10344887Schin 10354887Schin /* 10364887Schin * Get process structure from first letters of jobname 10374887Schin * 10384887Schin */ 10394887Schin 10404887Schin static struct process *job_byname(char *name) 10414887Schin { 10424887Schin register struct process *pw = job.pwlist; 10434887Schin register struct process *pz = 0; 10444887Schin register int *flag = 0; 10454887Schin register char *cp = name; 10464887Schin int offset; 10474887Schin if(!sh.hist_ptr) 10484887Schin return(NIL(struct process*)); 10494887Schin if(*cp=='?') 10504887Schin cp++,flag= &offset; 10514887Schin for(;pw;pw=pw->p_nxtjob) 10524887Schin { 10534887Schin if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0) 10544887Schin { 10554887Schin if(pz) 10564887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1); 10574887Schin pz = pw; 10584887Schin } 10594887Schin } 10604887Schin return(pz); 10614887Schin } 10624887Schin 10634887Schin #else 10644887Schin # define job_set(x) 10654887Schin # define job_reset(x) 10664887Schin #endif /* JOBS */ 10674887Schin 10684887Schin 10694887Schin 10704887Schin /* 10714887Schin * Initialize the process posting array 10724887Schin */ 10734887Schin 10744887Schin void job_clear(void) 10754887Schin { 10764887Schin register struct process *pw, *px; 10774887Schin register struct process *pwnext; 10784887Schin register int j = BYTE(sh.lim.child_max); 10794887Schin register struct jobsave *jp,*jpnext; 10804887Schin job_lock(); 10814887Schin for(pw=job.pwlist; pw; pw=pwnext) 10824887Schin { 10834887Schin pwnext = pw->p_nxtjob; 10844887Schin while(px=pw) 10854887Schin { 10864887Schin pw = pw->p_nxtproc; 10874887Schin free((void*)px); 10884887Schin } 10894887Schin } 10904887Schin for(jp=bck.list; jp;jp=jpnext) 10914887Schin { 10924887Schin jpnext = jp->next; 10934887Schin free((void*)jp); 10944887Schin } 10954887Schin bck.list = 0; 10964887Schin if(njob_savelist < NJOB_SAVELIST) 10974887Schin init_savelist(); 10984887Schin job.pwlist = NIL(struct process*); 10994887Schin job.numpost=0; 1100*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1101*10898Sroland.mainz@nrubsig.org job.numbjob = 0; 1102*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 11034887Schin job.waitall = 0; 11044887Schin job.curpgid = 0; 11054887Schin job.toclear = 0; 11064887Schin if(!job.freejobs) 11074887Schin job.freejobs = (unsigned char*)malloc((unsigned)(j+1)); 11084887Schin while(j >=0) 11094887Schin job.freejobs[j--] = 0; 11104887Schin job_unlock(); 11114887Schin } 11124887Schin 11134887Schin /* 11144887Schin * put the process <pid> on the process list and return the job number 11154887Schin * if non-zero, <join> is the process id of the job to join 11164887Schin */ 11174887Schin 11184887Schin int job_post(pid_t pid, pid_t join) 11194887Schin { 11204887Schin register struct process *pw; 11214887Schin register History_t *hp = sh.hist_ptr; 1122*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1123*10898Sroland.mainz@nrubsig.org int val,bg=0; 1124*10898Sroland.mainz@nrubsig.org #else 11258462SApril.Chin@Sun.COM int val; 1126*10898Sroland.mainz@nrubsig.org #endif 11274887Schin sh.jobenv = sh.curenv; 11284887Schin if(job.toclear) 11294887Schin { 11304887Schin job_clear(); 11314887Schin return(0); 11324887Schin } 11334887Schin job_lock(); 1134*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1135*10898Sroland.mainz@nrubsig.org if(join==1) 1136*10898Sroland.mainz@nrubsig.org { 1137*10898Sroland.mainz@nrubsig.org join = 0; 1138*10898Sroland.mainz@nrubsig.org bg = P_BG; 1139*10898Sroland.mainz@nrubsig.org job.numbjob++; 1140*10898Sroland.mainz@nrubsig.org } 1141*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 1142*10898Sroland.mainz@nrubsig.org if(njob_savelist < NJOB_SAVELIST) 1143*10898Sroland.mainz@nrubsig.org init_savelist(); 11444887Schin if(pw = job_bypid(pid)) 11454887Schin job_unpost(pw,0); 11464887Schin if(join && (pw=job_bypid(join))) 11474887Schin { 11484887Schin /* if job to join is not first move it to front */ 11494887Schin if((pw=job_byjid(pw->p_job)) != job.pwlist) 11504887Schin { 11514887Schin job_unlink(pw); 11524887Schin pw->p_nxtjob = job.pwlist; 11534887Schin job.pwlist = pw; 11544887Schin } 11554887Schin } 11564887Schin if(pw=freelist) 11574887Schin freelist = pw->p_nxtjob; 11584887Schin else 11594887Schin pw = new_of(struct process,0); 1160*10898Sroland.mainz@nrubsig.org pw->p_flag = 0; 11614887Schin job.numpost++; 11624887Schin if(join && job.pwlist) 11634887Schin { 11644887Schin /* join existing current job */ 11654887Schin pw->p_nxtjob = job.pwlist->p_nxtjob; 11664887Schin pw->p_nxtproc = job.pwlist; 11674887Schin pw->p_job = job.pwlist->p_job; 11684887Schin } 11694887Schin else 11704887Schin { 11714887Schin /* create a new job */ 11724887Schin while((pw->p_job = job_alloc()) < 0) 11734887Schin job_wait((pid_t)1); 11744887Schin pw->p_nxtjob = job.pwlist; 11754887Schin pw->p_nxtproc = 0; 11764887Schin } 11774887Schin job.pwlist = pw; 11784887Schin pw->p_env = sh.curenv; 11794887Schin pw->p_pid = pid; 1180*10898Sroland.mainz@nrubsig.org if(!sh.outpipe || sh_isoption(SH_PIPEFAIL)) 1181*10898Sroland.mainz@nrubsig.org pw->p_flag = P_EXITSAVE; 11828462SApril.Chin@Sun.COM pw->p_exitmin = sh.xargexit; 11838462SApril.Chin@Sun.COM pw->p_exit = 0; 11844887Schin if(sh_isstate(SH_MONITOR)) 11854887Schin { 11864887Schin if(killpg(job.curpgid,0)<0 && errno==ESRCH) 11874887Schin job.curpgid = pid; 11884887Schin pw->p_fgrp = job.curpgid; 11894887Schin } 11904887Schin else 11914887Schin pw->p_fgrp = 0; 11924887Schin pw->p_pgrp = pw->p_fgrp; 11934887Schin #ifdef DEBUG 11944887Schin 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, 11954887Schin pw->p_pid,pw->p_pgrp,job.savesig,join); 11964887Schin sfsync(sfstderr); 11974887Schin #endif /* DEBUG */ 11984887Schin #ifdef JOBS 11994887Schin if(hp && !sh_isstate(SH_PROFILE)) 12004887Schin pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1); 12014887Schin else 12024887Schin pw->p_name = -1; 12034887Schin #endif /* JOBS */ 12048462SApril.Chin@Sun.COM if ((val = job_chksave(pid)) >= 0) 12054887Schin { 12068462SApril.Chin@Sun.COM pw->p_exit = val; 12074887Schin if(pw->p_exit==SH_STOPSIG) 12084887Schin { 12094887Schin pw->p_flag |= (P_SIGNALLED|P_STOPPED); 12104887Schin pw->p_exit = 0; 12114887Schin } 1212*10898Sroland.mainz@nrubsig.org else if(pw->p_exit >= SH_EXITSIG) 1213*10898Sroland.mainz@nrubsig.org { 1214*10898Sroland.mainz@nrubsig.org pw->p_flag |= P_DONE|P_SIGNALLED; 1215*10898Sroland.mainz@nrubsig.org pw->p_exit &= SH_EXITMASK; 1216*10898Sroland.mainz@nrubsig.org } 12174887Schin else 12184887Schin pw->p_flag |= (P_DONE|P_NOTIFY); 12194887Schin } 1220*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1221*10898Sroland.mainz@nrubsig.org if(bg && !(pw->p_flag&P_DONE)) 1222*10898Sroland.mainz@nrubsig.org pw->p_flag |= P_BG; 1223*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 12244887Schin lastpid = 0; 12254887Schin job_unlock(); 12264887Schin return(pw->p_job); 12274887Schin } 12284887Schin 12294887Schin /* 12304887Schin * Returns a process structure give a process id 12314887Schin */ 12324887Schin 12334887Schin static struct process *job_bypid(pid_t pid) 12344887Schin { 12354887Schin register struct process *pw, *px; 12364887Schin for(pw=job.pwlist; pw; pw=pw->p_nxtjob) 12374887Schin for(px=pw; px; px=px->p_nxtproc) 12384887Schin { 12394887Schin if(px->p_pid==pid) 12404887Schin return(px); 12414887Schin } 12424887Schin return(NIL(struct process*)); 12434887Schin } 12444887Schin 12454887Schin /* 12464887Schin * return a pointer to a job given the job id 12474887Schin */ 12484887Schin 12494887Schin static struct process *job_byjid(int jobid) 12504887Schin { 12514887Schin register struct process *pw; 12524887Schin for(pw=job.pwlist;pw; pw = pw->p_nxtjob) 12534887Schin { 12544887Schin if(pw->p_job==jobid) 12554887Schin break; 12564887Schin } 12574887Schin return(pw); 12584887Schin } 12594887Schin 12604887Schin /* 12614887Schin * print a signal message 12624887Schin */ 12634887Schin static void job_prmsg(register struct process *pw) 12644887Schin { 12654887Schin if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE) 12664887Schin { 12674887Schin register const char *msg, *dump; 12684887Schin msg = job_sigmsg((int)(pw->p_exit)); 12694887Schin msg = sh_translate(msg); 12704887Schin if(pw->p_flag&P_COREDUMP) 12714887Schin dump = sh_translate(e_coredump); 12724887Schin else 12734887Schin dump = ""; 12744887Schin if(sh_isstate(SH_INTERACTIVE)) 12754887Schin sfprintf(sfstderr,"%s%s\n",msg,dump); 12764887Schin else 12774887Schin errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump); 12784887Schin } 12794887Schin } 12804887Schin 12814887Schin /* 12824887Schin * Wait for process pid to complete 12834887Schin * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin) 12844887Schin * pid=0 to unpost all done processes 12854887Schin * pid=1 to wait for at least one process to complete 12864887Schin * pid=-1 to wait for all runing processes 12874887Schin */ 12884887Schin 12898462SApril.Chin@Sun.COM int job_wait(register pid_t pid) 12904887Schin { 12914887Schin register struct process *pw=0,*px; 12924887Schin register int jobid = 0; 12938462SApril.Chin@Sun.COM int nochild = 1; 12944887Schin char intr = 0; 12954887Schin if(pid <= 0) 12964887Schin { 12974887Schin if(pid==0) 12984887Schin goto done; 12994887Schin pid = -pid; 13004887Schin intr = 1; 13014887Schin } 13024887Schin job_lock(); 13034887Schin if(pid > 1) 13044887Schin { 13058462SApril.Chin@Sun.COM if(pid==sh.spid) 13068462SApril.Chin@Sun.COM sh.spid = 0; 13074887Schin if(!(pw=job_bypid(pid))) 13084887Schin { 13094887Schin /* check to see whether job status has been saved */ 13104887Schin if((sh.exitval = job_chksave(pid)) < 0) 13114887Schin sh.exitval = ERROR_NOENT; 13124887Schin exitset(); 13134887Schin job_unlock(); 13148462SApril.Chin@Sun.COM return(nochild); 13154887Schin } 13164887Schin else if(intr && pw->p_env!=sh.curenv) 13174887Schin { 13184887Schin sh.exitval = ERROR_NOENT; 13194887Schin job_unlock(); 13208462SApril.Chin@Sun.COM return(nochild); 13214887Schin } 13224887Schin jobid = pw->p_job; 13234887Schin if(!intr) 13244887Schin pw->p_flag &= ~P_EXITSAVE; 13254887Schin if(pw->p_pgrp && job.parent!= (pid_t)-1) 13264887Schin job_set(job_byjid(jobid)); 13274887Schin } 13288462SApril.Chin@Sun.COM pwfg = pw; 13294887Schin #ifdef DEBUG 13304887Schin sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid); 13314887Schin if(pw) 13324887Schin sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag); 13334887Schin #endif /* DEBUG*/ 13344887Schin errno = 0; 13358462SApril.Chin@Sun.COM if(sh.coutpipe>=0 && sh.cpid==lastpid) 13368462SApril.Chin@Sun.COM { 13378462SApril.Chin@Sun.COM sh_close(sh.coutpipe); 13388462SApril.Chin@Sun.COM sh_close(sh.cpipe[1]); 13398462SApril.Chin@Sun.COM sh.cpipe[1] = sh.coutpipe = -1; 13408462SApril.Chin@Sun.COM } 13414887Schin while(1) 13424887Schin { 13434887Schin if(job.waitsafe) 13444887Schin { 13454887Schin for(px=job.pwlist;px; px = px->p_nxtjob) 13464887Schin { 13474887Schin if(px!=pw && (px->p_flag&P_NOTIFY)) 13484887Schin { 13494887Schin if(sh_isoption(SH_NOTIFY)) 13504887Schin { 13514887Schin outfile = sfstderr; 13524887Schin job_list(px,JOB_NFLAG|JOB_NLFLAG); 13534887Schin sfsync(sfstderr); 13544887Schin } 13554887Schin else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED)) 13564887Schin { 13574887Schin job_prmsg(px); 13584887Schin px->p_flag &= ~P_NOTIFY; 13594887Schin } 13604887Schin } 13614887Schin } 13624887Schin } 13634887Schin if(pw && (pw->p_flag&(P_DONE|P_STOPPED))) 13644887Schin { 13654887Schin #ifdef SIGTSTP 13664887Schin if(pw->p_flag&P_STOPPED) 13674887Schin { 13684887Schin pw->p_flag |= P_EXITSAVE; 13694887Schin if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED)) 13704887Schin { 13714887Schin if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU) 13724887Schin break; 13734887Schin 13744887Schin killpg(pw->p_pgrp,SIGCONT); 13754887Schin } 13764887Schin else /* ignore stop when non-interactive */ 13774887Schin pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE); 13784887Schin } 13794887Schin else 13804887Schin #endif /* SIGTSTP */ 13814887Schin { 13824887Schin if(pw->p_flag&P_SIGNALLED) 13834887Schin { 13844887Schin pw->p_flag &= ~P_NOTIFY; 13854887Schin job_prmsg(pw); 13864887Schin } 13874887Schin else if(pw->p_flag&P_DONE) 13884887Schin pw->p_flag &= ~P_NOTIFY; 13894887Schin if(pw->p_job==jobid) 13904887Schin { 13914887Schin px = job_byjid(jobid); 13924887Schin /* last process in job */ 13934887Schin if(sh_isoption(SH_PIPEFAIL)) 13944887Schin { 13954887Schin /* last non-zero exit */ 13964887Schin for(;px;px=px->p_nxtproc) 13974887Schin { 13984887Schin if(px->p_exit) 13994887Schin break; 14004887Schin } 14014887Schin if(!px) 14024887Schin px = pw; 14034887Schin } 14044887Schin else if(px!=pw) 14054887Schin px = 0; 14064887Schin if(px) 14074887Schin { 14084887Schin sh.exitval=px->p_exit; 14094887Schin if(px->p_flag&P_SIGNALLED) 14104887Schin sh.exitval |= SH_EXITSIG; 14114887Schin if(intr) 14124887Schin px->p_flag &= ~P_EXITSAVE; 14134887Schin } 14144887Schin } 1415*10898Sroland.mainz@nrubsig.org px = job_unpost(pw,1); 1416*10898Sroland.mainz@nrubsig.org if(!px || !sh_isoption(SH_PIPEFAIL)) 14174887Schin break; 14184887Schin pw = px; 14194887Schin continue; 14204887Schin } 14214887Schin } 14224887Schin sfsync(sfstderr); 14234887Schin job.waitsafe = 0; 14244887Schin nochild = job_reap(job.savesig); 14254887Schin if(job.waitsafe) 14264887Schin continue; 14274887Schin if(nochild) 14284887Schin break; 14294887Schin if(sh.sigflag[SIGALRM]&SH_SIGTRAP) 14304887Schin sh_timetraps(); 14314887Schin if((intr && sh.trapnote) || (pid==1 && !intr)) 14324887Schin break; 14334887Schin } 14348462SApril.Chin@Sun.COM pwfg = 0; 14354887Schin job_unlock(); 14364887Schin if(pid==1) 14378462SApril.Chin@Sun.COM return(nochild); 14384887Schin exitset(); 14394887Schin if(pw->p_pgrp) 14404887Schin { 14414887Schin job_reset(pw); 14424887Schin /* propogate keyboard interrupts to parent */ 14434887Schin if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF)) 14444887Schin sh_fault(SIGINT); 14454887Schin #ifdef SIGTSTP 14464887Schin else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP) 14474887Schin { 14484887Schin job.parent = 0; 14494887Schin sh_fault(SIGTSTP); 14504887Schin } 14514887Schin #endif /* SIGTSTP */ 14524887Schin } 14534887Schin else 14548462SApril.Chin@Sun.COM { 14558462SApril.Chin@Sun.COM if(pw->p_pid == tcgetpgrp(JOBTTY)) 14568462SApril.Chin@Sun.COM { 14578462SApril.Chin@Sun.COM if(pw->p_pgrp==0) 14588462SApril.Chin@Sun.COM pw->p_pgrp = pw->p_pid; 14598462SApril.Chin@Sun.COM job_reset(pw); 14608462SApril.Chin@Sun.COM } 14614887Schin tty_set(-1, 0, NIL(struct termios*)); 14628462SApril.Chin@Sun.COM } 14634887Schin done: 14644887Schin if(!job.waitall && sh_isoption(SH_PIPEFAIL)) 14658462SApril.Chin@Sun.COM return(nochild); 14664887Schin if(!sh.intrap) 14674887Schin { 14684887Schin job_lock(); 14694887Schin for(pw=job.pwlist; pw; pw=px) 14704887Schin { 14714887Schin px = pw->p_nxtjob; 14724887Schin job_unpost(pw,0); 14734887Schin } 14744887Schin job_unlock(); 14754887Schin } 14768462SApril.Chin@Sun.COM return(nochild); 14774887Schin } 14784887Schin 14794887Schin /* 14804887Schin * move job to foreground if bgflag == 'f' 14814887Schin * move job to background if bgflag == 'b' 14824887Schin * disown job if bgflag == 'd' 14834887Schin */ 14844887Schin 14854887Schin int job_switch(register struct process *pw,int bgflag) 14864887Schin { 14874887Schin register const char *msg; 14884887Schin job_lock(); 14894887Schin if(!pw || !(pw=job_byjid((int)pw->p_job))) 14904887Schin { 14914887Schin job_unlock(); 14924887Schin return(1); 14934887Schin } 14944887Schin if(bgflag=='d') 14954887Schin { 14964887Schin for(; pw; pw=pw->p_nxtproc) 14974887Schin pw->p_flag |= P_DISOWN; 14984887Schin job_unlock(); 14994887Schin return(0); 15004887Schin } 15014887Schin #ifdef SIGTSTP 15024887Schin if(bgflag=='b') 15034887Schin { 15044887Schin sfprintf(outfile,"[%d]\t",(int)pw->p_job); 15054887Schin sh.bckpid = pw->p_pid; 1506*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1507*10898Sroland.mainz@nrubsig.org pw->p_flag |= P_BG; 1508*10898Sroland.mainz@nrubsig.org #endif 15094887Schin msg = "&"; 15104887Schin } 15114887Schin else 15124887Schin { 15134887Schin job_unlink(pw); 15144887Schin pw->p_nxtjob = job.pwlist; 15154887Schin job.pwlist = pw; 15164887Schin msg = ""; 15174887Schin } 15184887Schin hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";"); 15194887Schin sfputr(outfile,msg,'\n'); 15204887Schin sfsync(outfile); 15214887Schin if(bgflag=='f') 15224887Schin { 15234887Schin if(!(pw=job_unpost(pw,1))) 15244887Schin { 15254887Schin job_unlock(); 15264887Schin return(1); 15274887Schin } 15284887Schin job.waitall = 1; 15294887Schin pw->p_flag |= P_FG; 1530*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1531*10898Sroland.mainz@nrubsig.org pw->p_flag &= ~P_BG; 1532*10898Sroland.mainz@nrubsig.org #endif 15334887Schin job_wait(pw->p_pid); 15344887Schin job.waitall = 0; 15354887Schin } 15364887Schin else if(pw->p_flag&P_STOPPED) 15374887Schin job_unstop(pw); 15384887Schin #endif /* SIGTSTP */ 15394887Schin job_unlock(); 15404887Schin return(0); 15414887Schin } 15424887Schin 15434887Schin 15444887Schin #ifdef SIGTSTP 15454887Schin /* 15464887Schin * Set the foreground group associated with a job 15474887Schin */ 15484887Schin 15494887Schin static void job_fgrp(register struct process *pw, int newgrp) 15504887Schin { 15514887Schin for(; pw; pw=pw->p_nxtproc) 15524887Schin pw->p_fgrp = newgrp; 15534887Schin } 15544887Schin 15554887Schin /* 15564887Schin * turn off STOP state of a process group and send CONT signals 15574887Schin */ 15584887Schin 15594887Schin static void job_unstop(register struct process *px) 15604887Schin { 15614887Schin register struct process *pw; 15624887Schin register int num = 0; 15634887Schin for(pw=px ;pw ;pw=pw->p_nxtproc) 15644887Schin { 15654887Schin if(pw->p_flag&P_STOPPED) 15664887Schin { 15674887Schin num++; 15684887Schin pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY); 15694887Schin } 15704887Schin } 15714887Schin if(num!=0) 15724887Schin { 15734887Schin if(px->p_fgrp != px->p_pgrp) 15744887Schin killpg(px->p_fgrp,SIGCONT); 15754887Schin killpg(px->p_pgrp,SIGCONT); 15764887Schin } 15774887Schin } 15784887Schin #endif /* SIGTSTP */ 15794887Schin 15804887Schin /* 15814887Schin * remove a job from table 15824887Schin * If all the processes have not completed, unpost first non-completed process 15834887Schin * Otherwise the job is removed and job_unpost returns NULL. 15844887Schin * pwlist is reset if the first job is removed 15854887Schin * if <notify> is non-zero, then jobs with pending notifications are unposted 15864887Schin */ 15874887Schin 15884887Schin static struct process *job_unpost(register struct process *pwtop,int notify) 15894887Schin { 15904887Schin register struct process *pw; 15914887Schin /* make sure all processes are done */ 15924887Schin #ifdef DEBUG 15934887Schin 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); 15944887Schin sfsync(sfstderr); 15954887Schin #endif /* DEBUG */ 15964887Schin pwtop = pw = job_byjid((int)pwtop->p_job); 1597*10898Sroland.mainz@nrubsig.org #ifdef SHOPT_BGX 1598*10898Sroland.mainz@nrubsig.org if(pw->p_flag&P_BG) 1599*10898Sroland.mainz@nrubsig.org return(pw); 1600*10898Sroland.mainz@nrubsig.org #endif /* SHOPT_BGX */ 16014887Schin for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc); 16024887Schin if(pw) 16034887Schin return(pw); 16044887Schin /* all processes complete, unpost job */ 16054887Schin job_unlink(pwtop); 16064887Schin for(pw=pwtop; pw; pw=pw->p_nxtproc) 16074887Schin { 16084887Schin /* save the exit status for background jobs */ 16098462SApril.Chin@Sun.COM if((pw->p_flag&P_EXITSAVE) || pw->p_pid==sh.spid) 16104887Schin { 16114887Schin struct jobsave *jp; 16124887Schin /* save status for future wait */ 16134887Schin if(jp = jobsave_create(pw->p_pid)) 16144887Schin { 16154887Schin jp->exitval = pw->p_exit; 16164887Schin if(pw->p_flag&P_SIGNALLED) 16174887Schin jp->exitval |= SH_EXITSIG; 16184887Schin } 16194887Schin pw->p_flag &= ~P_EXITSAVE; 16204887Schin } 16214887Schin pw->p_flag &= ~P_DONE; 16224887Schin job.numpost--; 16234887Schin pw->p_nxtjob = freelist; 16244887Schin freelist = pw; 16254887Schin } 16264887Schin #ifdef DEBUG 16274887Schin sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job); 16284887Schin sfsync(sfstderr); 16294887Schin #endif /* DEBUG */ 16304887Schin job_free((int)pwtop->p_job); 16314887Schin return((struct process*)0); 16324887Schin } 16334887Schin 16344887Schin /* 16354887Schin * unlink a job form the job list 16364887Schin */ 16374887Schin static void job_unlink(register struct process *pw) 16384887Schin { 16394887Schin register struct process *px; 16404887Schin if(pw==job.pwlist) 16414887Schin { 16424887Schin job.pwlist = pw->p_nxtjob; 16434887Schin job.curpgid = 0; 16444887Schin return; 16454887Schin } 16464887Schin for(px=job.pwlist;px;px=px->p_nxtjob) 16474887Schin if(px->p_nxtjob == pw) 16484887Schin { 16494887Schin px->p_nxtjob = pw->p_nxtjob; 16504887Schin return; 16514887Schin } 16524887Schin } 16534887Schin 16544887Schin /* 16554887Schin * get an unused job number 16564887Schin * freejobs is a bit vector, 0 is unused 16574887Schin */ 16584887Schin 16594887Schin static int job_alloc(void) 16604887Schin { 16614887Schin register int j=0; 16624887Schin register unsigned mask = 1; 16634887Schin register unsigned char *freeword; 16644887Schin register int jmax = BYTE(sh.lim.child_max); 16654887Schin /* skip to first word with a free slot */ 16664887Schin for(j=0;job.freejobs[j] == UCHAR_MAX; j++); 16674887Schin if(j >= jmax) 16684887Schin { 16694887Schin register struct process *pw; 16704887Schin for(j=1; j < sh.lim.child_max; j++) 16714887Schin { 16724887Schin if((pw=job_byjid(j))&& !job_unpost(pw,0)) 16734887Schin break; 16744887Schin } 16754887Schin j /= CHAR_BIT; 16764887Schin if(j >= jmax) 16774887Schin return(-1); 16784887Schin } 16794887Schin freeword = &job.freejobs[j]; 16804887Schin j *= CHAR_BIT; 16814887Schin for(j++;mask&(*freeword);j++,mask <<=1); 16824887Schin *freeword |= mask; 16834887Schin return(j); 16844887Schin } 16854887Schin 16864887Schin /* 16874887Schin * return a job number 16884887Schin */ 16894887Schin 16904887Schin static void job_free(register int n) 16914887Schin { 16924887Schin register int j = (--n)/CHAR_BIT; 16934887Schin register unsigned mask; 16944887Schin n -= j*CHAR_BIT; 16954887Schin mask = 1 << n; 16964887Schin job.freejobs[j] &= ~mask; 16974887Schin } 16984887Schin 16994887Schin static char *job_sigmsg(int sig) 17004887Schin { 17014887Schin static char signo[40]; 17024887Schin #ifdef apollo 17034887Schin /* 17044887Schin * This code handles the formatting for the apollo specific signal 17054887Schin * SIGAPOLLO. 17064887Schin */ 17074887Schin extern char *apollo_error(void); 17084887Schin 17094887Schin if ( sig == SIGAPOLLO ) 17104887Schin return( apollo_error() ); 17114887Schin #endif /* apollo */ 1712*10898Sroland.mainz@nrubsig.org if(sig<=sh.sigmax && sh.sigmsg[sig]) 17134887Schin return(sh.sigmsg[sig]); 17144887Schin #if defined(SIGRTMIN) && defined(SIGRTMAX) 17158462SApril.Chin@Sun.COM if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX]) 17164887Schin { 17174887Schin static char sigrt[20]; 17188462SApril.Chin@Sun.COM if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2) 17198462SApril.Chin@Sun.COM sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig); 17208462SApril.Chin@Sun.COM else 17218462SApril.Chin@Sun.COM sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]); 17224887Schin return(sigrt); 17234887Schin } 17244887Schin #endif 17254887Schin sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig); 17264887Schin return(signo); 17274887Schin } 17284887Schin 17294887Schin /* 17304887Schin * see whether exit status has been saved and delete it 17314887Schin * if pid==0, then oldest saved process is deleted 17324887Schin * If pid is not found a -1 is returned. 17334887Schin */ 17344887Schin static int job_chksave(register pid_t pid) 17354887Schin { 17364887Schin register struct jobsave *jp = bck.list, *jpold=0; 17374887Schin register int r= -1; 1738*10898Sroland.mainz@nrubsig.org register int count=bck.count; 1739*10898Sroland.mainz@nrubsig.org while(jp && count-->0) 17404887Schin { 17414887Schin if(jp->pid==pid) 17424887Schin break; 17434887Schin if(pid==0 && !jp->next) 17444887Schin break; 17454887Schin jpold = jp; 17464887Schin jp = jp->next; 17474887Schin } 17484887Schin if(jp) 17494887Schin { 17504887Schin r = 0; 17514887Schin if(pid) 17524887Schin r = jp->exitval; 17534887Schin if(jpold) 17544887Schin jpold->next = jp->next; 17554887Schin else 17564887Schin bck.list = jp->next; 17574887Schin bck.count--; 17584887Schin if(njob_savelist < NJOB_SAVELIST) 17594887Schin { 17604887Schin njob_savelist++; 17614887Schin jp->next = job_savelist; 17624887Schin job_savelist = jp; 17634887Schin } 17644887Schin else 17654887Schin free((void*)jp); 17664887Schin } 17674887Schin return(r); 17684887Schin } 17694887Schin 17704887Schin void *job_subsave(void) 17714887Schin { 17724887Schin struct back_save *bp = new_of(struct back_save,0); 17734887Schin job_lock(); 17744887Schin *bp = bck; 17754887Schin bck.count = 0; 17764887Schin bck.list = 0; 17774887Schin job_unlock(); 17784887Schin return((void*)bp); 17794887Schin } 17804887Schin 17814887Schin void job_subrestore(void* ptr) 17824887Schin { 17838462SApril.Chin@Sun.COM register struct jobsave *jp; 17844887Schin register struct back_save *bp = (struct back_save*)ptr; 17854887Schin register struct process *pw, *px, *pwnext; 17868462SApril.Chin@Sun.COM struct jobsave *jpnext; 17874887Schin job_lock(); 17888462SApril.Chin@Sun.COM for(jp=bck.list; jp; jp=jpnext) 17898462SApril.Chin@Sun.COM { 17908462SApril.Chin@Sun.COM jpnext = jp->next; 17918462SApril.Chin@Sun.COM if(jp->pid==sh.spid) 17928462SApril.Chin@Sun.COM { 17938462SApril.Chin@Sun.COM jp->next = bp->list; 17948462SApril.Chin@Sun.COM bp->list = jp; 1795*10898Sroland.mainz@nrubsig.org bp->count++; 17968462SApril.Chin@Sun.COM } 17978462SApril.Chin@Sun.COM else 17988462SApril.Chin@Sun.COM job_chksave(jp->pid); 17998462SApril.Chin@Sun.COM } 18004887Schin for(pw=job.pwlist; pw; pw=pwnext) 18014887Schin { 18024887Schin pwnext = pw->p_nxtjob; 1803*10898Sroland.mainz@nrubsig.org if(pw->p_env != sh.curenv || pw->p_pid==sh.pipepid) 18044887Schin continue; 18054887Schin for(px=pw; px; px=px->p_nxtproc) 18064887Schin px->p_flag |= P_DONE; 18074887Schin job_unpost(pw,0); 18084887Schin } 18098462SApril.Chin@Sun.COM 18108462SApril.Chin@Sun.COM /* 18118462SApril.Chin@Sun.COM * queue up old lists for disposal by job_reap() 18128462SApril.Chin@Sun.COM */ 18138462SApril.Chin@Sun.COM 18148462SApril.Chin@Sun.COM bck = *bp; 18158462SApril.Chin@Sun.COM free((void*)bp); 18164887Schin job_unlock(); 18174887Schin } 18184887Schin 18194887Schin int sh_waitsafe(void) 18204887Schin { 18214887Schin return(job.waitsafe); 18224887Schin } 18234887Schin 18244887Schin void job_fork(pid_t parent) 18254887Schin { 18264887Schin #ifdef DEBUG 18274887Schin sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent); 18284887Schin #endif /* DEBUG */ 18294887Schin switch (parent) 18304887Schin { 18314887Schin case -1: 18324887Schin job_lock(); 18334887Schin break; 18344887Schin case 0: 18354887Schin job_unlock(); 18364887Schin job.waitsafe = 0; 18374887Schin job.in_critical = 0; 18384887Schin break; 18394887Schin default: 18404887Schin job_unlock(); 18414887Schin break; 18424887Schin } 18434887Schin } 1844