14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 <ctype.h> 344887Schin #include <wait.h> 354887Schin #include "io.h" 364887Schin #include "jobs.h" 374887Schin #include "history.h" 384887Schin 394887Schin #if !defined(WCONTINUED) || !defined(WIFCONTINUED) 404887Schin # undef WCONTINUED 414887Schin # define WCONTINUED 0 424887Schin # undef WIFCONTINUED 434887Schin # define WIFCONTINUED(wstat) (0) 444887Schin #endif 454887Schin 464887Schin #define NJOB_SAVELIST 4 474887Schin 484887Schin /* 494887Schin * temporary hack to get W* macros to work 504887Schin */ 514887Schin #undef wait 524887Schin #define wait ______wait 534887Schin /* 544887Schin * This struct saves a link list of processes that have non-zero exit 554887Schin * status, have had $! saved, but haven't been waited for 564887Schin */ 574887Schin struct jobsave 584887Schin { 594887Schin struct jobsave *next; 604887Schin pid_t pid; 614887Schin unsigned short exitval; 624887Schin }; 634887Schin 644887Schin static struct jobsave *job_savelist; 654887Schin static int njob_savelist; 66*8462SApril.Chin@Sun.COM static struct process *pwfg; 674887Schin 684887Schin static void init_savelist(void) 694887Schin { 704887Schin register struct jobsave *jp; 714887Schin while(njob_savelist < NJOB_SAVELIST) 724887Schin { 734887Schin jp = newof(0,struct jobsave,1,0); 744887Schin jp->next = job_savelist; 754887Schin job_savelist = jp; 764887Schin njob_savelist++; 774887Schin } 784887Schin } 794887Schin 804887Schin /* 814887Schin * return next on link list of jobsave free list 824887Schin */ 834887Schin static struct jobsave *jobsave_create(pid_t pid) 844887Schin { 854887Schin register struct jobsave *jp = job_savelist; 864887Schin if(jp) 874887Schin { 884887Schin njob_savelist--; 894887Schin job_savelist = jp->next; 904887Schin } 914887Schin else 924887Schin jp = newof(0,struct jobsave,1,0); 934887Schin if(jp) 944887Schin jp->pid = pid; 954887Schin return(jp); 964887Schin } 974887Schin 984887Schin struct back_save 994887Schin { 1004887Schin int count; 1014887Schin struct jobsave *list; 1024887Schin }; 1034887Schin 1044887Schin #define BYTE(n) (((n)+CHAR_BIT-1)/CHAR_BIT) 1054887Schin #define MAXMSG 25 1064887Schin #define SH_STOPSIG (SH_EXITSIG<<1) 1074887Schin 1084887Schin #ifdef VSUSP 1094887Schin # ifndef CNSUSP 1104887Schin # ifdef _POSIX_VDISABLE 1114887Schin # define CNSUSP _POSIX_VDISABLE 1124887Schin # else 1134887Schin # define CNSUSP 0 1144887Schin # endif /* _POSIX_VDISABLE */ 1154887Schin # endif /* CNSUSP */ 1164887Schin # ifndef CSWTCH 1174887Schin # ifdef CSUSP 1184887Schin # define CSWTCH CSUSP 1194887Schin # else 1204887Schin # define CSWTCH ('z'&037) 1214887Schin # endif /* CSUSP */ 1224887Schin # endif /* CSWTCH */ 1234887Schin #endif /* VSUSP */ 1244887Schin 1254887Schin /* Process states */ 1264887Schin #define P_EXITSAVE 01 1274887Schin #define P_STOPPED 02 1284887Schin #define P_NOTIFY 04 1294887Schin #define P_SIGNALLED 010 1304887Schin #define P_STTY 020 1314887Schin #define P_DONE 040 1324887Schin #define P_COREDUMP 0100 1334887Schin #define P_DISOWN 0200 1344887Schin #define P_FG 0400 1354887Schin 1364887Schin static int job_chksave(pid_t); 1374887Schin static struct process *job_bypid(pid_t); 1384887Schin static struct process *job_byjid(int); 1394887Schin static char *job_sigmsg(int); 1404887Schin static int job_alloc(void); 1414887Schin static void job_free(int); 1424887Schin static struct process *job_unpost(struct process*,int); 1434887Schin static void job_unlink(struct process*); 1444887Schin static void job_prmsg(struct process*); 1454887Schin static struct process *freelist; 1464887Schin static char beenhere; 1474887Schin static char possible; 1484887Schin static struct process dummy; 1494887Schin static char by_number; 1504887Schin static Sfio_t *outfile; 1514887Schin static pid_t lastpid; 1524887Schin static struct back_save bck; 1534887Schin 1544887Schin 1554887Schin #ifdef JOBS 1564887Schin static void job_set(struct process*); 1574887Schin static void job_reset(struct process*); 1584887Schin static void job_waitsafe(int); 1594887Schin static struct process *job_byname(char*); 1604887Schin static struct process *job_bystring(char*); 1614887Schin static struct termios my_stty; /* terminal state for shell */ 1624887Schin static char *job_string; 1634887Schin #else 1644887Schin extern const char e_coredump[]; 1654887Schin #endif /* JOBS */ 1664887Schin 1674887Schin #ifdef SIGTSTP 1684887Schin static void job_unstop(struct process*); 1694887Schin static void job_fgrp(struct process*, int); 1704887Schin # ifndef _lib_tcgetpgrp 1714887Schin # ifdef TIOCGPGRP 1724887Schin static int _i_; 1734887Schin # define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1) 1744887Schin # endif /* TIOCGPGRP */ 1754887Schin int tcsetpgrp(int fd,pid_t pgrp) 1764887Schin { 1774887Schin int pgid = pgrp; 1784887Schin # ifdef TIOCGPGRP 1794887Schin return(ioctl(fd, TIOCSPGRP, &pgid)); 1804887Schin # else 1814887Schin return(-1); 1824887Schin # endif /* TIOCGPGRP */ 1834887Schin } 1844887Schin # endif /* _lib_tcgetpgrp */ 1854887Schin #else 1864887Schin # define job_unstop(pw) 1874887Schin # undef CNSUSP 1884887Schin #endif /* SIGTSTP */ 1894887Schin 1904887Schin #ifndef OTTYDISC 1914887Schin # undef NTTYDISC 1924887Schin #endif /* OTTYDISC */ 1934887Schin 1944887Schin #ifdef JOBS 1954887Schin 1964887Schin typedef int (*Waitevent_f)(int,long,int); 1974887Schin 1984887Schin /* 1994887Schin * Reap one job 2004887Schin * When called with sig==0, it does a blocking wait 2014887Schin */ 2024887Schin int job_reap(register int sig) 2034887Schin { 2044887Schin register pid_t pid; 2054887Schin register struct process *pw; 2064887Schin struct process *px; 2074887Schin register int flags; 2084887Schin struct jobsave *jp; 209*8462SApril.Chin@Sun.COM struct back_save *bp; 2104887Schin int nochild=0, oerrno, wstat; 2114887Schin Waitevent_f waitevent = sh.waitevent; 2124887Schin static int wcontinued = WCONTINUED; 213*8462SApril.Chin@Sun.COM if (vmbusy()) 214*8462SApril.Chin@Sun.COM { 215*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen"); 216*8462SApril.Chin@Sun.COM if (getenv("_AST_KSH_VMBUSY_ABORT")) 217*8462SApril.Chin@Sun.COM abort(); 218*8462SApril.Chin@Sun.COM } 2194887Schin #ifdef DEBUG 2204887Schin if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0) 2214887Schin write(2,"waitsafe\n",9); 2224887Schin sfsync(sfstderr); 2234887Schin #endif /* DEBUG */ 2244887Schin job.savesig = 0; 2254887Schin if(sig) 2264887Schin flags = WNOHANG|WUNTRACED|wcontinued; 2274887Schin else 2284887Schin flags = WUNTRACED|wcontinued; 2294887Schin sh.waitevent = 0; 2304887Schin oerrno = errno; 2314887Schin while(1) 2324887Schin { 233*8462SApril.Chin@Sun.COM if(!(flags&WNOHANG) && !sh.intrap && job.pwlist) 2344887Schin { 235*8462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT); 236*8462SApril.Chin@Sun.COM if(waitevent && (*waitevent)(-1,-1L,0)) 2374887Schin flags |= WNOHANG; 2384887Schin } 2394887Schin pid = waitpid((pid_t)-1,&wstat,flags); 240*8462SApril.Chin@Sun.COM sh_offstate(SH_TTYWAIT); 2414887Schin 2424887Schin /* 2434887Schin * some systems (linux 2.6) may return EINVAL 2444887Schin * when there are no continued children 2454887Schin */ 2464887Schin 2474887Schin if (pid<0 && errno==EINVAL && (flags&WCONTINUED)) 2484887Schin pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED); 2494887Schin sh_sigcheck(); 2504887Schin if(sig && pid<0 && errno==EINTR) 2514887Schin continue; 2524887Schin if(pid<=0) 2534887Schin break; 2544887Schin flags |= WNOHANG; 2554887Schin job.waitsafe++; 2564887Schin jp = 0; 257*8462SApril.Chin@Sun.COM lastpid = pid; 2584887Schin if(!(pw=job_bypid(pid))) 2594887Schin { 2604887Schin #ifdef DEBUG 2614887Schin 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); 2624887Schin #endif /* DEBUG */ 263*8462SApril.Chin@Sun.COM if (WIFCONTINUED(wstat) && wcontinued) 264*8462SApril.Chin@Sun.COM continue; 2654887Schin pw = &dummy; 2664887Schin pw->p_exit = 0; 2674887Schin pw->p_pgrp = 0; 268*8462SApril.Chin@Sun.COM pw->p_exitmin = 0; 2694887Schin if(job.toclear) 2704887Schin job_clear(); 271*8462SApril.Chin@Sun.COM if(++bck.count > sh.lim.child_max) 2724887Schin job_chksave(0); 2734887Schin if(jp = jobsave_create(pid)) 2744887Schin { 2754887Schin jp->next = bck.list; 2764887Schin bck.list = jp; 2774887Schin jp->exitval = 0; 2784887Schin } 2794887Schin pw->p_flag = 0; 2804887Schin lastpid = pw->p_pid = pid; 2814887Schin px = 0; 2824887Schin if(jp && WIFSTOPPED(wstat)) 2834887Schin { 2844887Schin jp->exitval = SH_STOPSIG; 2854887Schin continue; 2864887Schin } 2874887Schin } 2884887Schin #ifdef SIGTSTP 2894887Schin else 2904887Schin px=job_byjid(pw->p_job); 2914887Schin if(WIFSTOPPED(wstat)) 2924887Schin { 2934887Schin if(px) 2944887Schin { 2954887Schin /* move to top of job list */ 2964887Schin job_unlink(px); 2974887Schin px->p_nxtjob = job.pwlist; 2984887Schin job.pwlist = px; 2994887Schin } 300*8462SApril.Chin@Sun.COM pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED); 3014887Schin pw->p_exit = WSTOPSIG(wstat); 3024887Schin if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK)) 3034887Schin sh_fault(pw->p_exit); 3044887Schin continue; 3054887Schin } 3064887Schin else if (WIFCONTINUED(wstat) && wcontinued) 3074887Schin pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED); 3084887Schin else 3094887Schin #endif /* SIGTSTP */ 3104887Schin { 3114887Schin /* check for coprocess completion */ 3124887Schin if(pid==sh.cpid) 3134887Schin { 3144887Schin sh_close(sh.coutpipe); 3154887Schin sh_close(sh.cpipe[1]); 3164887Schin sh.cpipe[1] = -1; 3174887Schin sh.coutpipe = -1; 3184887Schin } 319*8462SApril.Chin@Sun.COM else if(sh.subshell) 320*8462SApril.Chin@Sun.COM sh_subjobcheck(pid); 321*8462SApril.Chin@Sun.COM 322*8462SApril.Chin@Sun.COM pw->p_flag &= ~(P_STOPPED|P_SIGNALLED); 3234887Schin if (WIFSIGNALED(wstat)) 3244887Schin { 3254887Schin pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED); 3264887Schin if (WTERMCORE(wstat)) 3274887Schin pw->p_flag |= P_COREDUMP; 3284887Schin pw->p_exit = WTERMSIG(wstat); 3294887Schin /* if process in current jobs terminates from 3304887Schin * an interrupt, propogate to parent shell 3314887Schin */ 3324887Schin if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK)) 3334887Schin { 3344887Schin pw->p_flag &= ~P_NOTIFY; 3354887Schin sh_offstate(SH_STOPOK); 3364887Schin sh_fault(SIGINT); 3374887Schin sh_onstate(SH_STOPOK); 3384887Schin } 3394887Schin } 3404887Schin else 3414887Schin { 3424887Schin pw->p_flag |= (P_DONE|P_NOTIFY); 343*8462SApril.Chin@Sun.COM pw->p_exit = pw->p_exitmin; 344*8462SApril.Chin@Sun.COM if(WEXITSTATUS(wstat) > pw->p_exitmin) 3454887Schin pw->p_exit = WEXITSTATUS(wstat); 3464887Schin } 3474887Schin if(pw->p_pgrp==0) 3484887Schin pw->p_flag &= ~P_NOTIFY; 3494887Schin } 3504887Schin if(jp && pw== &dummy) 3514887Schin { 3524887Schin jp->exitval = pw->p_exit; 3534887Schin if(pw->p_flag&P_SIGNALLED) 3544887Schin jp->exitval |= SH_EXITSIG; 3554887Schin } 3564887Schin #ifdef DEBUG 3574887Schin 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); 3584887Schin sfsync(sfstderr); 3594887Schin #endif /* DEBUG*/ 3604887Schin /* only top-level process in job should have notify set */ 3614887Schin if(px && pw != px) 3624887Schin pw->p_flag &= ~P_NOTIFY; 363*8462SApril.Chin@Sun.COM if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY)) 364*8462SApril.Chin@Sun.COM { 365*8462SApril.Chin@Sun.COM px = job_byjid((int)pw->p_job); 366*8462SApril.Chin@Sun.COM for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc); 367*8462SApril.Chin@Sun.COM if(!px) 368*8462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,job.mypid); 369*8462SApril.Chin@Sun.COM } 370*8462SApril.Chin@Sun.COM if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid))) 371*8462SApril.Chin@Sun.COM { 372*8462SApril.Chin@Sun.COM sh.sigflag[SIGCHLD] |= SH_SIGTRAP; 373*8462SApril.Chin@Sun.COM sh.trapnote |= SH_SIGTRAP; 374*8462SApril.Chin@Sun.COM } 3754887Schin } 3764887Schin if(errno==ECHILD) 3774887Schin { 3784887Schin errno = oerrno; 3794887Schin nochild = 1; 3804887Schin } 3814887Schin sh.waitevent = waitevent; 3824887Schin if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT)) 3834887Schin { 3844887Schin outfile = sfstderr; 3854887Schin job_list(pw,JOB_NFLAG|JOB_NLFLAG); 3864887Schin job_unpost(pw,1); 3874887Schin sfsync(sfstderr); 3884887Schin } 3894887Schin if(sig) 3904887Schin signal(sig, job_waitsafe); 3914887Schin return(nochild); 3924887Schin } 3934887Schin 3944887Schin /* 3954887Schin * This is the SIGCLD interrupt routine 3964887Schin */ 3974887Schin static void job_waitsafe(int sig) 3984887Schin { 399*8462SApril.Chin@Sun.COM if(job.in_critical || vmbusy()) 4004887Schin { 4014887Schin job.savesig = sig; 4024887Schin job.waitsafe++; 4034887Schin } 4044887Schin else 4054887Schin job_reap(sig); 4064887Schin } 4074887Schin 4084887Schin /* 4094887Schin * initialize job control if possible 4104887Schin * if lflag is set the switching driver message will not print 4114887Schin */ 412*8462SApril.Chin@Sun.COM void job_init(Shell_t *shp, int lflag) 4134887Schin { 414*8462SApril.Chin@Sun.COM register int ntry=0; 4154887Schin job.fd = JOBTTY; 4164887Schin signal(SIGCHLD,job_waitsafe); 4174887Schin # if defined(SIGCLD) && (SIGCLD!=SIGCHLD) 4184887Schin signal(SIGCLD,job_waitsafe); 4194887Schin # endif 4204887Schin if(njob_savelist < NJOB_SAVELIST) 4214887Schin init_savelist(); 4224887Schin if(!sh_isoption(SH_INTERACTIVE)) 4234887Schin return; 4244887Schin /* use new line discipline when available */ 4254887Schin #ifdef NTTYDISC 4264887Schin # ifdef FIOLOOKLD 4274887Schin if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0) 4284887Schin # else 4294887Schin if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0) 4304887Schin # endif /* FIOLOOKLD */ 4314887Schin return; 4324887Schin if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC) 4334887Schin { 4344887Schin /* no job control when running with MPX */ 4354887Schin # if SHOPT_VSH 4364887Schin sh_onoption(SH_VIRAW); 4374887Schin # endif /* SHOPT_VSH */ 4384887Schin return; 4394887Schin } 4404887Schin if(job.linedisc==NTTYDISC) 4414887Schin job.linedisc = -1; 4424887Schin #endif /* NTTYDISC */ 4434887Schin 4444887Schin job.mypgid = getpgrp(); 4454887Schin /* some systems have job control, but not initialized */ 4464887Schin if(job.mypgid<=0) 4474887Schin { 4484887Schin /* Get a controlling terminal and set process group */ 4494887Schin /* This should have already been done by rlogin */ 4504887Schin register int fd; 4514887Schin register char *ttynam; 4524887Schin #ifndef SIGTSTP 453*8462SApril.Chin@Sun.COM setpgid(0,shp->pid); 4544887Schin #endif /*SIGTSTP */ 4554887Schin if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY))) 4564887Schin return; 4574887Schin close(JOBTTY); 4584887Schin if((fd = open(ttynam,O_RDWR)) <0) 4594887Schin return; 4604887Schin if(fd!=JOBTTY) 461*8462SApril.Chin@Sun.COM sh_iorenumber(shp,fd,JOBTTY); 462*8462SApril.Chin@Sun.COM job.mypgid = shp->pid; 4634887Schin #ifdef SIGTSTP 464*8462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,shp->pid); 465*8462SApril.Chin@Sun.COM setpgid(0,shp->pid); 4664887Schin #endif /* SIGTSTP */ 4674887Schin } 4684887Schin #ifdef SIGTSTP 4694887Schin if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM) 4704887Schin { 4714887Schin /* wait until we are in the foreground */ 4724887Schin while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid) 4734887Schin { 4744887Schin if(job.mytgid == -1) 4754887Schin return; 4764887Schin /* Stop this shell until continued */ 4774887Schin signal(SIGTTIN,SIG_DFL); 478*8462SApril.Chin@Sun.COM kill(shp->pid,SIGTTIN); 4794887Schin /* resumes here after continue tries again */ 4804887Schin if(ntry++ > IOMAXTRY) 4814887Schin { 4824887Schin errormsg(SH_DICT,0,e_no_start); 4834887Schin return; 4844887Schin } 4854887Schin } 4864887Schin } 4874887Schin #endif /* SIGTTIN */ 4884887Schin 4894887Schin #ifdef NTTYDISC 4904887Schin /* set the line discipline */ 4914887Schin if(job.linedisc>=0) 4924887Schin { 4934887Schin int linedisc = NTTYDISC; 4944887Schin # ifdef FIOPUSHLD 4954887Schin tty_get(JOBTTY,&my_stty); 4964887Schin if (ioctl(JOBTTY, FIOPOPLD, 0) < 0) 4974887Schin return; 4984887Schin if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0) 4994887Schin { 5004887Schin ioctl(JOBTTY, FIOPUSHLD, &job.linedisc); 5014887Schin return; 5024887Schin } 5034887Schin tty_set(JOBTTY,TCSANOW,&my_stty); 5044887Schin # else 5054887Schin if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0) 5064887Schin return; 5074887Schin # endif /* FIOPUSHLD */ 5084887Schin if(lflag==0) 5094887Schin errormsg(SH_DICT,0,e_newtty); 5104887Schin else 5114887Schin job.linedisc = -1; 5124887Schin } 5134887Schin #endif /* NTTYDISC */ 5144887Schin if(!possible) 5154887Schin return; 5164887Schin 5174887Schin #ifdef SIGTSTP 5184887Schin /* make sure that we are a process group leader */ 519*8462SApril.Chin@Sun.COM setpgid(0,shp->pid); 5204887Schin # if defined(SA_NOCLDWAIT) && defined(_lib_sigflag) 5214887Schin sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0); 5224887Schin # endif /* SA_NOCLDWAIT */ 5234887Schin signal(SIGTTIN,SIG_IGN); 5244887Schin signal(SIGTTOU,SIG_IGN); 5254887Schin /* The shell now handles ^Z */ 5264887Schin signal(SIGTSTP,sh_fault); 527*8462SApril.Chin@Sun.COM tcsetpgrp(JOBTTY,shp->pid); 5284887Schin # ifdef CNSUSP 5294887Schin /* set the switch character */ 5304887Schin tty_get(JOBTTY,&my_stty); 5314887Schin job.suspend = (unsigned)my_stty.c_cc[VSUSP]; 5324887Schin if(job.suspend == (unsigned char)CNSUSP) 5334887Schin { 5344887Schin my_stty.c_cc[VSUSP] = CSWTCH; 5354887Schin tty_set(JOBTTY,TCSAFLUSH,&my_stty); 5364887Schin } 5374887Schin # endif /* CNSUSP */ 5384887Schin sh_onoption(SH_MONITOR); 5394887Schin job.jobcontrol++; 540*8462SApril.Chin@Sun.COM job.mypid = shp->pid; 5414887Schin #endif /* SIGTSTP */ 5424887Schin return; 5434887Schin } 5444887Schin 5454887Schin 5464887Schin /* 5474887Schin * see if there are any stopped jobs 5484887Schin * restore tty driver and pgrp 5494887Schin */ 550*8462SApril.Chin@Sun.COM int job_close(Shell_t* shp) 5514887Schin { 5524887Schin register struct process *pw; 5534887Schin register int count = 0, running = 0; 5544887Schin if(possible && !job.jobcontrol) 5554887Schin return(0); 5564887Schin else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED))) 5574887Schin return(0); 5584887Schin else if(getpid() != job.mypid) 5594887Schin return(0); 5604887Schin job_lock(); 5614887Schin if(!tty_check(0)) 5624887Schin beenhere++; 5634887Schin for(pw=job.pwlist;pw;pw=pw->p_nxtjob) 5644887Schin { 5654887Schin if(!(pw->p_flag&P_STOPPED)) 5664887Schin { 5674887Schin if(!(pw->p_flag&P_DONE)) 5684887Schin running++; 5694887Schin continue; 5704887Schin } 5714887Schin if(beenhere) 5724887Schin killpg(pw->p_pgrp,SIGTERM); 5734887Schin count++; 5744887Schin } 5754887Schin if(beenhere++ == 0 && job.pwlist) 5764887Schin { 5774887Schin if(count) 5784887Schin { 5794887Schin errormsg(SH_DICT,0,e_terminate); 5804887Schin return(-1); 5814887Schin } 582*8462SApril.Chin@Sun.COM else if(running && shp->login_sh) 5834887Schin { 5844887Schin errormsg(SH_DICT,0,e_jobsrunning); 5854887Schin return(-1); 5864887Schin } 5874887Schin } 5884887Schin job_unlock(); 5894887Schin # ifdef SIGTSTP 5904887Schin if(possible && setpgid(0,job.mypgid)>=0) 5914887Schin tcsetpgrp(job.fd,job.mypgid); 5924887Schin # endif /* SIGTSTP */ 5934887Schin # ifdef NTTYDISC 5944887Schin if(job.linedisc>=0) 5954887Schin { 5964887Schin /* restore old line discipline */ 5974887Schin # ifdef FIOPUSHLD 5984887Schin tty_get(job.fd,&my_stty); 5994887Schin if (ioctl(job.fd, FIOPOPLD, 0) < 0) 6004887Schin return(0); 6014887Schin if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0) 6024887Schin { 6034887Schin job.linedisc = NTTYDISC; 6044887Schin ioctl(job.fd, FIOPUSHLD, &job.linedisc); 6054887Schin return(0); 6064887Schin } 6074887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 6084887Schin # else 6094887Schin if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0) 6104887Schin return(0); 6114887Schin # endif /* FIOPUSHLD */ 6124887Schin errormsg(SH_DICT,0,e_oldtty); 6134887Schin } 6144887Schin # endif /* NTTYDISC */ 6154887Schin # ifdef CNSUSP 6164887Schin if(possible && job.suspend==CNSUSP) 6174887Schin { 6184887Schin tty_get(job.fd,&my_stty); 6194887Schin my_stty.c_cc[VSUSP] = CNSUSP; 6204887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 6214887Schin } 6224887Schin # endif /* CNSUSP */ 6234887Schin job.jobcontrol = 0; 6244887Schin return(0); 6254887Schin } 6264887Schin 6274887Schin static void job_set(register struct process *pw) 6284887Schin { 6294887Schin /* save current terminal state */ 6304887Schin tty_get(job.fd,&my_stty); 6314887Schin if(pw->p_flag&P_STTY) 6324887Schin { 6334887Schin /* restore terminal state for job */ 6344887Schin tty_set(job.fd,TCSAFLUSH,&pw->p_stty); 6354887Schin } 6364887Schin #ifdef SIGTSTP 6374887Schin if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid) 6384887Schin tcsetpgrp(job.fd,pw->p_fgrp); 6394887Schin /* if job is stopped, resume it in the background */ 6404887Schin job_unstop(pw); 6414887Schin #endif /* SIGTSTP */ 6424887Schin } 6434887Schin 6444887Schin static void job_reset(register struct process *pw) 6454887Schin { 6464887Schin /* save the terminal state for current job */ 6474887Schin #ifdef SIGTSTP 6484887Schin job_fgrp(pw,tcgetpgrp(job.fd)); 649*8462SApril.Chin@Sun.COM if(tcsetpgrp(job.fd,job.mypid) !=0) 6504887Schin return; 6514887Schin #endif /* SIGTSTP */ 6524887Schin /* force the following tty_get() to do a tcgetattr() unless fg */ 6534887Schin if(!(pw->p_flag&P_FG)) 6544887Schin tty_set(-1, 0, NIL(struct termios*)); 6554887Schin if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP) 6564887Schin { 6574887Schin if(tty_get(job.fd,&pw->p_stty) == 0) 6584887Schin pw->p_flag |= P_STTY; 6594887Schin /* restore terminal state for job */ 6604887Schin tty_set(job.fd,TCSAFLUSH,&my_stty); 6614887Schin } 6624887Schin beenhere = 0; 6634887Schin } 6644887Schin #endif /* JOBS */ 6654887Schin 6664887Schin /* 6674887Schin * wait built-in command 6684887Schin */ 6694887Schin 6704887Schin void job_bwait(char **jobs) 6714887Schin { 6724887Schin register char *jp; 6734887Schin register struct process *pw; 6744887Schin register pid_t pid; 6754887Schin if(*jobs==0) 6764887Schin job_wait((pid_t)-1); 6774887Schin else while(jp = *jobs++) 6784887Schin { 6794887Schin #ifdef JOBS 6804887Schin if(*jp == '%') 6814887Schin { 6824887Schin job_lock(); 6834887Schin pw = job_bystring(jp); 6844887Schin job_unlock(); 6854887Schin if(pw) 6864887Schin pid = pw->p_pid; 6874887Schin else 6884887Schin return; 6894887Schin } 6904887Schin else 6914887Schin #endif /* JOBS */ 6924887Schin pid = (int)strtol(jp, (char**)0, 10); 6934887Schin job_wait(-pid); 6944887Schin } 6954887Schin } 6964887Schin 6974887Schin #ifdef JOBS 6984887Schin /* 6994887Schin * execute function <fun> for each job 7004887Schin */ 7014887Schin 7024887Schin int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[]) 7034887Schin { 7044887Schin register struct process *pw; 7054887Schin register int r = 0; 7064887Schin register char *jobid, **jobs=joblist; 7074887Schin register struct process *px; 7084887Schin job_string = 0; 7094887Schin outfile = file; 7104887Schin by_number = 0; 7114887Schin job_lock(); 7124887Schin pw = job.pwlist; 7134887Schin if(jobs==0) 7144887Schin { 7154887Schin /* do all jobs */ 7164887Schin for(;pw;pw=px) 7174887Schin { 7184887Schin px = pw->p_nxtjob; 7194887Schin if(pw->p_env != sh.jobenv) 7204887Schin continue; 7214887Schin if((*fun)(pw,arg)) 7224887Schin r = 2; 7234887Schin } 7244887Schin } 7254887Schin else if(*jobs==0) /* current job */ 7264887Schin { 7274887Schin /* skip over non-stop jobs */ 7284887Schin while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0)) 7294887Schin pw = pw->p_nxtjob; 7304887Schin if((*fun)(pw,arg)) 7314887Schin r = 2; 7324887Schin } 7334887Schin else while(jobid = *jobs++) 7344887Schin { 7354887Schin job_string = jobid; 7364887Schin if(*jobid==0) 7374887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 7384887Schin if(*jobid == '%') 7394887Schin pw = job_bystring(jobid); 7404887Schin else 7414887Schin { 7424887Schin int pid = (int)strtol(jobid, (char**)0, 10); 7434887Schin if(pid<0) 7444887Schin jobid++; 7454887Schin while(isdigit(*jobid)) 7464887Schin jobid++; 7474887Schin if(*jobid) 7484887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 7494887Schin if(!(pw = job_bypid(pid))) 7504887Schin { 7514887Schin pw = &dummy; 7524887Schin pw->p_pid = pid; 7534887Schin pw->p_pgrp = pid; 7544887Schin } 7554887Schin by_number = 1; 7564887Schin } 7574887Schin if((*fun)(pw,arg)) 7584887Schin r = 2; 7594887Schin by_number = 0; 7604887Schin } 7614887Schin job_unlock(); 7624887Schin return(r); 7634887Schin } 7644887Schin 7654887Schin /* 7664887Schin * send signal <sig> to background process group if not disowned 7674887Schin */ 7684887Schin int job_terminate(register struct process *pw,register int sig) 7694887Schin { 7704887Schin if(pw->p_pgrp && !(pw->p_flag&P_DISOWN)) 7714887Schin job_kill(pw,sig); 7724887Schin return(0); 7734887Schin } 7744887Schin 7754887Schin /* 7764887Schin * list the given job 7774887Schin * flag JOB_LFLAG for long listing 7784887Schin * flag JOB_NFLAG for list only jobs marked for notification 7794887Schin * flag JOB_PFLAG for process id(s) only 7804887Schin */ 7814887Schin 7824887Schin int job_list(struct process *pw,register int flag) 7834887Schin { 7844887Schin register struct process *px = pw; 7854887Schin register int n; 7864887Schin register const char *msg; 7874887Schin register int msize; 7884887Schin if(!pw || pw->p_job<=0) 7894887Schin return(1); 7904887Schin if(pw->p_env != sh.jobenv) 7914887Schin return(0); 7924887Schin if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0)) 7934887Schin return(0); 7944887Schin if((flag&JOB_PFLAG)) 7954887Schin { 7964887Schin sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid); 7974887Schin return(0); 7984887Schin } 7994887Schin if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG)) 8004887Schin return(0); 8014887Schin job_lock(); 8024887Schin n = px->p_job; 8034887Schin if(px==job.pwlist) 8044887Schin msize = '+'; 8054887Schin else if(px==job.pwlist->p_nxtjob) 8064887Schin msize = '-'; 8074887Schin else 8084887Schin msize = ' '; 8094887Schin if(flag&JOB_NLFLAG) 8104887Schin sfputc(outfile,'\n'); 8114887Schin sfprintf(outfile,"[%d] %c ",n, msize); 8124887Schin do 8134887Schin { 8144887Schin n = 0; 8154887Schin if(flag&JOB_LFLAG) 8164887Schin sfprintf(outfile,"%d\t",px->p_pid); 8174887Schin if(px->p_flag&P_SIGNALLED) 8184887Schin msg = job_sigmsg((int)(px->p_exit)); 8194887Schin else if(px->p_flag&P_NOTIFY) 8204887Schin { 8214887Schin msg = sh_translate(e_done); 8224887Schin n = px->p_exit; 8234887Schin } 8244887Schin else 8254887Schin msg = sh_translate(e_running); 8264887Schin px->p_flag &= ~P_NOTIFY; 8274887Schin sfputr(outfile,msg,-1); 8284887Schin msize = strlen(msg); 8294887Schin if(n) 8304887Schin { 8314887Schin sfprintf(outfile,"(%d)",(int)n); 8324887Schin msize += (3+(n>10)+(n>100)); 8334887Schin } 8344887Schin if(px->p_flag&P_COREDUMP) 8354887Schin { 8364887Schin msg = sh_translate(e_coredump); 8374887Schin sfputr(outfile, msg, -1); 8384887Schin msize += strlen(msg); 8394887Schin } 8404887Schin sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1); 8414887Schin if(flag&JOB_LFLAG) 8424887Schin px = px->p_nxtproc; 8434887Schin else 8444887Schin { 8454887Schin while(px=px->p_nxtproc) 8464887Schin px->p_flag &= ~P_NOTIFY; 8474887Schin px = 0; 8484887Schin } 8494887Schin if(!px) 8504887Schin hist_list(sh.hist_ptr,outfile,pw->p_name,0,";"); 8514887Schin else 8524887Schin sfputr(outfile, e_nlspace, -1); 8534887Schin } 8544887Schin while(px); 8554887Schin job_unlock(); 8564887Schin return(0); 8574887Schin } 8584887Schin 8594887Schin /* 8604887Schin * get the process group given the job number 8614887Schin * This routine returns the process group number or -1 8624887Schin */ 8634887Schin static struct process *job_bystring(register char *ajob) 8644887Schin { 8654887Schin register struct process *pw=job.pwlist; 8664887Schin register int c; 8674887Schin if(*ajob++ != '%' || !pw) 8684887Schin return(NIL(struct process*)); 8694887Schin c = *ajob; 8704887Schin if(isdigit(c)) 8714887Schin pw = job_byjid((int)strtol(ajob, (char**)0, 10)); 8724887Schin else if(c=='+' || c=='%') 8734887Schin ; 8744887Schin else if(c=='-') 8754887Schin { 8764887Schin if(pw) 8774887Schin pw = job.pwlist->p_nxtjob; 8784887Schin } 8794887Schin else 8804887Schin pw = job_byname(ajob); 8814887Schin if(pw && pw->p_flag) 8824887Schin return(pw); 8834887Schin return(NIL(struct process*)); 8844887Schin } 8854887Schin 8864887Schin /* 8874887Schin * Kill a job or process 8884887Schin */ 8894887Schin 8904887Schin int job_kill(register struct process *pw,register int sig) 8914887Schin { 8924887Schin register pid_t pid; 8934887Schin register int r; 8944887Schin const char *msg; 8954887Schin #ifdef SIGTSTP 8964887Schin int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU); 8974887Schin #else 8984887Schin # define stopsig 1 8994887Schin #endif /* SIGTSTP */ 9004887Schin job_lock(); 9014887Schin errno = ECHILD; 9024887Schin if(pw==0) 9034887Schin goto error; 9044887Schin pid = pw->p_pid; 9054887Schin if(by_number) 9064887Schin { 9074887Schin if(pid==0 && job.jobcontrol) 9084887Schin r = job_walk(outfile, job_kill,sig, (char**)0); 9094887Schin #ifdef SIGTSTP 9104887Schin if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1) 9114887Schin { 9124887Schin /* can't stop login shell */ 9134887Schin errno = EPERM; 9144887Schin r = -1; 9154887Schin } 9164887Schin else 9174887Schin { 9184887Schin if(pid>=0) 9194887Schin { 9204887Schin if((r = kill(pid,sig))>=0 && !stopsig) 9214887Schin { 9224887Schin if(pw->p_flag&P_STOPPED) 9234887Schin pw->p_flag &= ~(P_STOPPED|P_SIGNALLED); 9244887Schin if(sig) 9254887Schin kill(pid,SIGCONT); 9264887Schin } 9274887Schin } 9284887Schin else 9294887Schin { 9304887Schin if((r = killpg(-pid,sig))>=0 && !stopsig) 9314887Schin { 9324887Schin job_unstop(job_bypid(pw->p_pid)); 9334887Schin if(sig) 9344887Schin killpg(-pid,SIGCONT); 9354887Schin } 9364887Schin } 9374887Schin } 9384887Schin #else 9394887Schin if(pid>=0) 9404887Schin r = kill(pid,sig); 9414887Schin else 9424887Schin r = killpg(-pid,sig); 9434887Schin #endif /* SIGTSTP */ 9444887Schin } 9454887Schin else 9464887Schin { 9474887Schin if(pid = pw->p_pgrp) 9484887Schin { 9494887Schin r = killpg(pid,sig); 9504887Schin #ifdef SIGTSTP 9514887Schin if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT)) 9524887Schin job_unstop(pw); 9534887Schin #endif /* SIGTSTP */ 9544887Schin if(r>=0) 9554887Schin sh_delay(.05); 9564887Schin } 9574887Schin while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0) 9584887Schin { 9594887Schin #ifdef SIGTSTP 9604887Schin if(sig==SIGHUP || sig==SIGTERM) 9614887Schin kill(pw->p_pid,SIGCONT); 9624887Schin #endif /* SIGTSTP */ 9634887Schin pw = pw->p_nxtproc; 9644887Schin } 9654887Schin } 9664887Schin if(r<0 && job_string) 9674887Schin { 9684887Schin error: 9694887Schin if(pw && by_number) 9704887Schin msg = sh_translate(e_no_proc); 9714887Schin else 9724887Schin msg = sh_translate(e_no_job); 9734887Schin if(errno == EPERM) 9744887Schin msg = sh_translate(e_access); 9754887Schin sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg); 9764887Schin r = 2; 9774887Schin } 9784887Schin sh_delay(.001); 9794887Schin job_unlock(); 9804887Schin return(r); 9814887Schin } 9824887Schin 9834887Schin /* 9844887Schin * Get process structure from first letters of jobname 9854887Schin * 9864887Schin */ 9874887Schin 9884887Schin static struct process *job_byname(char *name) 9894887Schin { 9904887Schin register struct process *pw = job.pwlist; 9914887Schin register struct process *pz = 0; 9924887Schin register int *flag = 0; 9934887Schin register char *cp = name; 9944887Schin int offset; 9954887Schin if(!sh.hist_ptr) 9964887Schin return(NIL(struct process*)); 9974887Schin if(*cp=='?') 9984887Schin cp++,flag= &offset; 9994887Schin for(;pw;pw=pw->p_nxtjob) 10004887Schin { 10014887Schin if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0) 10024887Schin { 10034887Schin if(pz) 10044887Schin errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1); 10054887Schin pz = pw; 10064887Schin } 10074887Schin } 10084887Schin return(pz); 10094887Schin } 10104887Schin 10114887Schin #else 10124887Schin # define job_set(x) 10134887Schin # define job_reset(x) 10144887Schin #endif /* JOBS */ 10154887Schin 10164887Schin 10174887Schin 10184887Schin /* 10194887Schin * Initialize the process posting array 10204887Schin */ 10214887Schin 10224887Schin void job_clear(void) 10234887Schin { 10244887Schin register struct process *pw, *px; 10254887Schin register struct process *pwnext; 10264887Schin register int j = BYTE(sh.lim.child_max); 10274887Schin register struct jobsave *jp,*jpnext; 10284887Schin job_lock(); 10294887Schin for(pw=job.pwlist; pw; pw=pwnext) 10304887Schin { 10314887Schin pwnext = pw->p_nxtjob; 10324887Schin while(px=pw) 10334887Schin { 10344887Schin pw = pw->p_nxtproc; 10354887Schin free((void*)px); 10364887Schin } 10374887Schin } 10384887Schin for(jp=bck.list; jp;jp=jpnext) 10394887Schin { 10404887Schin jpnext = jp->next; 10414887Schin free((void*)jp); 10424887Schin } 10434887Schin bck.list = 0; 10444887Schin if(njob_savelist < NJOB_SAVELIST) 10454887Schin init_savelist(); 10464887Schin job.pwlist = NIL(struct process*); 10474887Schin job.numpost=0; 10484887Schin job.waitall = 0; 10494887Schin job.curpgid = 0; 10504887Schin job.toclear = 0; 10514887Schin if(!job.freejobs) 10524887Schin job.freejobs = (unsigned char*)malloc((unsigned)(j+1)); 10534887Schin while(j >=0) 10544887Schin job.freejobs[j--] = 0; 10554887Schin job_unlock(); 10564887Schin } 10574887Schin 10584887Schin /* 10594887Schin * put the process <pid> on the process list and return the job number 10604887Schin * if non-zero, <join> is the process id of the job to join 10614887Schin */ 10624887Schin 10634887Schin int job_post(pid_t pid, pid_t join) 10644887Schin { 10654887Schin register struct process *pw; 10664887Schin register History_t *hp = sh.hist_ptr; 1067*8462SApril.Chin@Sun.COM int val; 10684887Schin sh.jobenv = sh.curenv; 10694887Schin if(njob_savelist < NJOB_SAVELIST) 10704887Schin init_savelist(); 10714887Schin if(job.toclear) 10724887Schin { 10734887Schin job_clear(); 10744887Schin return(0); 10754887Schin } 10764887Schin job_lock(); 10774887Schin if(pw = job_bypid(pid)) 10784887Schin job_unpost(pw,0); 10794887Schin if(join && (pw=job_bypid(join))) 10804887Schin { 10814887Schin /* if job to join is not first move it to front */ 10824887Schin if((pw=job_byjid(pw->p_job)) != job.pwlist) 10834887Schin { 10844887Schin job_unlink(pw); 10854887Schin pw->p_nxtjob = job.pwlist; 10864887Schin job.pwlist = pw; 10874887Schin } 10884887Schin } 10894887Schin if(pw=freelist) 10904887Schin freelist = pw->p_nxtjob; 10914887Schin else 10924887Schin pw = new_of(struct process,0); 10934887Schin job.numpost++; 10944887Schin if(join && job.pwlist) 10954887Schin { 10964887Schin /* join existing current job */ 10974887Schin pw->p_nxtjob = job.pwlist->p_nxtjob; 10984887Schin pw->p_nxtproc = job.pwlist; 10994887Schin pw->p_job = job.pwlist->p_job; 11004887Schin } 11014887Schin else 11024887Schin { 11034887Schin /* create a new job */ 11044887Schin while((pw->p_job = job_alloc()) < 0) 11054887Schin job_wait((pid_t)1); 11064887Schin pw->p_nxtjob = job.pwlist; 11074887Schin pw->p_nxtproc = 0; 11084887Schin } 11094887Schin job.pwlist = pw; 11104887Schin pw->p_env = sh.curenv; 11114887Schin pw->p_pid = pid; 11124887Schin pw->p_flag = P_EXITSAVE; 1113*8462SApril.Chin@Sun.COM pw->p_exitmin = sh.xargexit; 1114*8462SApril.Chin@Sun.COM pw->p_exit = 0; 11154887Schin if(sh_isstate(SH_MONITOR)) 11164887Schin { 11174887Schin if(killpg(job.curpgid,0)<0 && errno==ESRCH) 11184887Schin job.curpgid = pid; 11194887Schin pw->p_fgrp = job.curpgid; 11204887Schin } 11214887Schin else 11224887Schin pw->p_fgrp = 0; 11234887Schin pw->p_pgrp = pw->p_fgrp; 11244887Schin #ifdef DEBUG 11254887Schin 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, 11264887Schin pw->p_pid,pw->p_pgrp,job.savesig,join); 11274887Schin sfsync(sfstderr); 11284887Schin #endif /* DEBUG */ 11294887Schin #ifdef JOBS 11304887Schin if(hp && !sh_isstate(SH_PROFILE)) 11314887Schin pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1); 11324887Schin else 11334887Schin pw->p_name = -1; 11344887Schin #endif /* JOBS */ 1135*8462SApril.Chin@Sun.COM if ((val = job_chksave(pid)) >= 0) 11364887Schin { 1137*8462SApril.Chin@Sun.COM pw->p_exit = val; 11384887Schin if(pw->p_exit==SH_STOPSIG) 11394887Schin { 11404887Schin pw->p_flag |= (P_SIGNALLED|P_STOPPED); 11414887Schin pw->p_exit = 0; 11424887Schin } 11434887Schin else 11444887Schin pw->p_flag |= (P_DONE|P_NOTIFY); 11454887Schin } 11464887Schin lastpid = 0; 11474887Schin job_unlock(); 11484887Schin return(pw->p_job); 11494887Schin } 11504887Schin 11514887Schin /* 11524887Schin * Returns a process structure give a process id 11534887Schin */ 11544887Schin 11554887Schin static struct process *job_bypid(pid_t pid) 11564887Schin { 11574887Schin register struct process *pw, *px; 11584887Schin for(pw=job.pwlist; pw; pw=pw->p_nxtjob) 11594887Schin for(px=pw; px; px=px->p_nxtproc) 11604887Schin { 11614887Schin if(px->p_pid==pid) 11624887Schin return(px); 11634887Schin } 11644887Schin return(NIL(struct process*)); 11654887Schin } 11664887Schin 11674887Schin /* 11684887Schin * return a pointer to a job given the job id 11694887Schin */ 11704887Schin 11714887Schin static struct process *job_byjid(int jobid) 11724887Schin { 11734887Schin register struct process *pw; 11744887Schin for(pw=job.pwlist;pw; pw = pw->p_nxtjob) 11754887Schin { 11764887Schin if(pw->p_job==jobid) 11774887Schin break; 11784887Schin } 11794887Schin return(pw); 11804887Schin } 11814887Schin 11824887Schin /* 11834887Schin * print a signal message 11844887Schin */ 11854887Schin static void job_prmsg(register struct process *pw) 11864887Schin { 11874887Schin if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE) 11884887Schin { 11894887Schin register const char *msg, *dump; 11904887Schin msg = job_sigmsg((int)(pw->p_exit)); 11914887Schin msg = sh_translate(msg); 11924887Schin if(pw->p_flag&P_COREDUMP) 11934887Schin dump = sh_translate(e_coredump); 11944887Schin else 11954887Schin dump = ""; 11964887Schin if(sh_isstate(SH_INTERACTIVE)) 11974887Schin sfprintf(sfstderr,"%s%s\n",msg,dump); 11984887Schin else 11994887Schin errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump); 12004887Schin } 12014887Schin } 12024887Schin 12034887Schin /* 12044887Schin * Wait for process pid to complete 12054887Schin * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin) 12064887Schin * pid=0 to unpost all done processes 12074887Schin * pid=1 to wait for at least one process to complete 12084887Schin * pid=-1 to wait for all runing processes 12094887Schin */ 12104887Schin 1211*8462SApril.Chin@Sun.COM int job_wait(register pid_t pid) 12124887Schin { 12134887Schin register struct process *pw=0,*px; 12144887Schin register int jobid = 0; 1215*8462SApril.Chin@Sun.COM int nochild = 1; 12164887Schin char intr = 0; 12174887Schin if(pid <= 0) 12184887Schin { 12194887Schin if(pid==0) 12204887Schin goto done; 12214887Schin pid = -pid; 12224887Schin intr = 1; 12234887Schin } 12244887Schin job_lock(); 12254887Schin if(pid > 1) 12264887Schin { 1227*8462SApril.Chin@Sun.COM if(pid==sh.spid) 1228*8462SApril.Chin@Sun.COM sh.spid = 0; 12294887Schin if(!(pw=job_bypid(pid))) 12304887Schin { 12314887Schin /* check to see whether job status has been saved */ 12324887Schin if((sh.exitval = job_chksave(pid)) < 0) 12334887Schin sh.exitval = ERROR_NOENT; 12344887Schin exitset(); 12354887Schin job_unlock(); 1236*8462SApril.Chin@Sun.COM return(nochild); 12374887Schin } 12384887Schin else if(intr && pw->p_env!=sh.curenv) 12394887Schin { 12404887Schin sh.exitval = ERROR_NOENT; 12414887Schin job_unlock(); 1242*8462SApril.Chin@Sun.COM return(nochild); 12434887Schin } 12444887Schin jobid = pw->p_job; 12454887Schin if(!intr) 12464887Schin pw->p_flag &= ~P_EXITSAVE; 12474887Schin if(pw->p_pgrp && job.parent!= (pid_t)-1) 12484887Schin job_set(job_byjid(jobid)); 12494887Schin } 1250*8462SApril.Chin@Sun.COM pwfg = pw; 12514887Schin #ifdef DEBUG 12524887Schin sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid); 12534887Schin if(pw) 12544887Schin sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag); 12554887Schin #endif /* DEBUG*/ 12564887Schin errno = 0; 1257*8462SApril.Chin@Sun.COM if(sh.coutpipe>=0 && sh.cpid==lastpid) 1258*8462SApril.Chin@Sun.COM { 1259*8462SApril.Chin@Sun.COM sh_close(sh.coutpipe); 1260*8462SApril.Chin@Sun.COM sh_close(sh.cpipe[1]); 1261*8462SApril.Chin@Sun.COM sh.cpipe[1] = sh.coutpipe = -1; 1262*8462SApril.Chin@Sun.COM } 12634887Schin while(1) 12644887Schin { 12654887Schin if(job.waitsafe) 12664887Schin { 12674887Schin for(px=job.pwlist;px; px = px->p_nxtjob) 12684887Schin { 12694887Schin if(px!=pw && (px->p_flag&P_NOTIFY)) 12704887Schin { 12714887Schin if(sh_isoption(SH_NOTIFY)) 12724887Schin { 12734887Schin outfile = sfstderr; 12744887Schin job_list(px,JOB_NFLAG|JOB_NLFLAG); 12754887Schin sfsync(sfstderr); 12764887Schin } 12774887Schin else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED)) 12784887Schin { 12794887Schin job_prmsg(px); 12804887Schin px->p_flag &= ~P_NOTIFY; 12814887Schin } 12824887Schin } 12834887Schin } 12844887Schin } 12854887Schin if(pw && (pw->p_flag&(P_DONE|P_STOPPED))) 12864887Schin { 12874887Schin #ifdef SIGTSTP 12884887Schin if(pw->p_flag&P_STOPPED) 12894887Schin { 12904887Schin pw->p_flag |= P_EXITSAVE; 12914887Schin if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED)) 12924887Schin { 12934887Schin if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU) 12944887Schin break; 12954887Schin 12964887Schin killpg(pw->p_pgrp,SIGCONT); 12974887Schin } 12984887Schin else /* ignore stop when non-interactive */ 12994887Schin pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE); 13004887Schin } 13014887Schin else 13024887Schin #endif /* SIGTSTP */ 13034887Schin { 13044887Schin if(pw->p_flag&P_SIGNALLED) 13054887Schin { 13064887Schin pw->p_flag &= ~P_NOTIFY; 13074887Schin job_prmsg(pw); 13084887Schin } 13094887Schin else if(pw->p_flag&P_DONE) 13104887Schin pw->p_flag &= ~P_NOTIFY; 13114887Schin if(pw->p_job==jobid) 13124887Schin { 13134887Schin px = job_byjid(jobid); 13144887Schin /* last process in job */ 13154887Schin if(sh_isoption(SH_PIPEFAIL)) 13164887Schin { 13174887Schin /* last non-zero exit */ 13184887Schin for(;px;px=px->p_nxtproc) 13194887Schin { 13204887Schin if(px->p_exit) 13214887Schin break; 13224887Schin } 13234887Schin if(!px) 13244887Schin px = pw; 13254887Schin } 13264887Schin else if(px!=pw) 13274887Schin px = 0; 13284887Schin if(px) 13294887Schin { 13304887Schin sh.exitval=px->p_exit; 13314887Schin if(px->p_flag&P_SIGNALLED) 13324887Schin sh.exitval |= SH_EXITSIG; 13334887Schin if(intr) 13344887Schin px->p_flag &= ~P_EXITSAVE; 13354887Schin } 13364887Schin } 13374887Schin if(!job.waitall) 13384887Schin { 13394887Schin if(!sh_isoption(SH_PIPEFAIL)) 13404887Schin job_unpost(pw,1); 13414887Schin break; 13424887Schin } 13434887Schin else if(!(px=job_unpost(pw,1))) 13444887Schin break; 13454887Schin pw = px; 13464887Schin continue; 13474887Schin } 13484887Schin } 13494887Schin sfsync(sfstderr); 13504887Schin job.waitsafe = 0; 13514887Schin nochild = job_reap(job.savesig); 13524887Schin if(job.waitsafe) 13534887Schin continue; 13544887Schin if(nochild) 13554887Schin break; 13564887Schin if(sh.sigflag[SIGALRM]&SH_SIGTRAP) 13574887Schin sh_timetraps(); 13584887Schin if((intr && sh.trapnote) || (pid==1 && !intr)) 13594887Schin break; 13604887Schin } 1361*8462SApril.Chin@Sun.COM pwfg = 0; 13624887Schin job_unlock(); 13634887Schin if(pid==1) 1364*8462SApril.Chin@Sun.COM return(nochild); 13654887Schin exitset(); 13664887Schin if(pw->p_pgrp) 13674887Schin { 13684887Schin job_reset(pw); 13694887Schin /* propogate keyboard interrupts to parent */ 13704887Schin if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF)) 13714887Schin sh_fault(SIGINT); 13724887Schin #ifdef SIGTSTP 13734887Schin else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP) 13744887Schin { 13754887Schin job.parent = 0; 13764887Schin sh_fault(SIGTSTP); 13774887Schin } 13784887Schin #endif /* SIGTSTP */ 13794887Schin } 13804887Schin else 1381*8462SApril.Chin@Sun.COM { 1382*8462SApril.Chin@Sun.COM if(pw->p_pid == tcgetpgrp(JOBTTY)) 1383*8462SApril.Chin@Sun.COM { 1384*8462SApril.Chin@Sun.COM if(pw->p_pgrp==0) 1385*8462SApril.Chin@Sun.COM pw->p_pgrp = pw->p_pid; 1386*8462SApril.Chin@Sun.COM job_reset(pw); 1387*8462SApril.Chin@Sun.COM } 13884887Schin tty_set(-1, 0, NIL(struct termios*)); 1389*8462SApril.Chin@Sun.COM } 13904887Schin done: 13914887Schin if(!job.waitall && sh_isoption(SH_PIPEFAIL)) 1392*8462SApril.Chin@Sun.COM return(nochild); 13934887Schin if(!sh.intrap) 13944887Schin { 13954887Schin job_lock(); 13964887Schin for(pw=job.pwlist; pw; pw=px) 13974887Schin { 13984887Schin px = pw->p_nxtjob; 13994887Schin job_unpost(pw,0); 14004887Schin } 14014887Schin job_unlock(); 14024887Schin } 1403*8462SApril.Chin@Sun.COM return(nochild); 14044887Schin } 14054887Schin 14064887Schin /* 14074887Schin * move job to foreground if bgflag == 'f' 14084887Schin * move job to background if bgflag == 'b' 14094887Schin * disown job if bgflag == 'd' 14104887Schin */ 14114887Schin 14124887Schin int job_switch(register struct process *pw,int bgflag) 14134887Schin { 14144887Schin register const char *msg; 14154887Schin job_lock(); 14164887Schin if(!pw || !(pw=job_byjid((int)pw->p_job))) 14174887Schin { 14184887Schin job_unlock(); 14194887Schin return(1); 14204887Schin } 14214887Schin if(bgflag=='d') 14224887Schin { 14234887Schin for(; pw; pw=pw->p_nxtproc) 14244887Schin pw->p_flag |= P_DISOWN; 14254887Schin job_unlock(); 14264887Schin return(0); 14274887Schin } 14284887Schin #ifdef SIGTSTP 14294887Schin if(bgflag=='b') 14304887Schin { 14314887Schin sfprintf(outfile,"[%d]\t",(int)pw->p_job); 14324887Schin sh.bckpid = pw->p_pid; 14334887Schin msg = "&"; 14344887Schin } 14354887Schin else 14364887Schin { 14374887Schin job_unlink(pw); 14384887Schin pw->p_nxtjob = job.pwlist; 14394887Schin job.pwlist = pw; 14404887Schin msg = ""; 14414887Schin } 14424887Schin hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";"); 14434887Schin sfputr(outfile,msg,'\n'); 14444887Schin sfsync(outfile); 14454887Schin if(bgflag=='f') 14464887Schin { 14474887Schin if(!(pw=job_unpost(pw,1))) 14484887Schin { 14494887Schin job_unlock(); 14504887Schin return(1); 14514887Schin } 14524887Schin job.waitall = 1; 14534887Schin pw->p_flag |= P_FG; 14544887Schin job_wait(pw->p_pid); 14554887Schin job.waitall = 0; 14564887Schin } 14574887Schin else if(pw->p_flag&P_STOPPED) 14584887Schin job_unstop(pw); 14594887Schin #endif /* SIGTSTP */ 14604887Schin job_unlock(); 14614887Schin return(0); 14624887Schin } 14634887Schin 14644887Schin 14654887Schin #ifdef SIGTSTP 14664887Schin /* 14674887Schin * Set the foreground group associated with a job 14684887Schin */ 14694887Schin 14704887Schin static void job_fgrp(register struct process *pw, int newgrp) 14714887Schin { 14724887Schin for(; pw; pw=pw->p_nxtproc) 14734887Schin pw->p_fgrp = newgrp; 14744887Schin } 14754887Schin 14764887Schin /* 14774887Schin * turn off STOP state of a process group and send CONT signals 14784887Schin */ 14794887Schin 14804887Schin static void job_unstop(register struct process *px) 14814887Schin { 14824887Schin register struct process *pw; 14834887Schin register int num = 0; 14844887Schin for(pw=px ;pw ;pw=pw->p_nxtproc) 14854887Schin { 14864887Schin if(pw->p_flag&P_STOPPED) 14874887Schin { 14884887Schin num++; 14894887Schin pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY); 14904887Schin } 14914887Schin } 14924887Schin if(num!=0) 14934887Schin { 14944887Schin if(px->p_fgrp != px->p_pgrp) 14954887Schin killpg(px->p_fgrp,SIGCONT); 14964887Schin killpg(px->p_pgrp,SIGCONT); 14974887Schin } 14984887Schin } 14994887Schin #endif /* SIGTSTP */ 15004887Schin 15014887Schin /* 15024887Schin * remove a job from table 15034887Schin * If all the processes have not completed, unpost first non-completed process 15044887Schin * Otherwise the job is removed and job_unpost returns NULL. 15054887Schin * pwlist is reset if the first job is removed 15064887Schin * if <notify> is non-zero, then jobs with pending notifications are unposted 15074887Schin */ 15084887Schin 15094887Schin static struct process *job_unpost(register struct process *pwtop,int notify) 15104887Schin { 15114887Schin register struct process *pw; 15124887Schin /* make sure all processes are done */ 15134887Schin #ifdef DEBUG 15144887Schin 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); 15154887Schin sfsync(sfstderr); 15164887Schin #endif /* DEBUG */ 15174887Schin pwtop = pw = job_byjid((int)pwtop->p_job); 15184887Schin for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc); 15194887Schin if(pw) 15204887Schin return(pw); 15214887Schin /* all processes complete, unpost job */ 15224887Schin job_unlink(pwtop); 15234887Schin for(pw=pwtop; pw; pw=pw->p_nxtproc) 15244887Schin { 15254887Schin /* save the exit status for background jobs */ 1526*8462SApril.Chin@Sun.COM if((pw->p_flag&P_EXITSAVE) || pw->p_pid==sh.spid) 15274887Schin { 15284887Schin struct jobsave *jp; 15294887Schin /* save status for future wait */ 15304887Schin if(bck.count++ > sh.lim.child_max) 15314887Schin job_chksave(0); 15324887Schin if(jp = jobsave_create(pw->p_pid)) 15334887Schin { 15344887Schin jp->next = bck.list; 15354887Schin bck.list = jp; 15364887Schin jp->exitval = pw->p_exit; 15374887Schin if(pw->p_flag&P_SIGNALLED) 15384887Schin jp->exitval |= SH_EXITSIG; 15394887Schin } 15404887Schin pw->p_flag &= ~P_EXITSAVE; 15414887Schin } 15424887Schin pw->p_flag &= ~P_DONE; 15434887Schin job.numpost--; 15444887Schin pw->p_nxtjob = freelist; 15454887Schin freelist = pw; 15464887Schin } 15474887Schin #ifdef DEBUG 15484887Schin sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job); 15494887Schin sfsync(sfstderr); 15504887Schin #endif /* DEBUG */ 15514887Schin job_free((int)pwtop->p_job); 15524887Schin return((struct process*)0); 15534887Schin } 15544887Schin 15554887Schin /* 15564887Schin * unlink a job form the job list 15574887Schin */ 15584887Schin static void job_unlink(register struct process *pw) 15594887Schin { 15604887Schin register struct process *px; 15614887Schin if(pw==job.pwlist) 15624887Schin { 15634887Schin job.pwlist = pw->p_nxtjob; 15644887Schin job.curpgid = 0; 15654887Schin return; 15664887Schin } 15674887Schin for(px=job.pwlist;px;px=px->p_nxtjob) 15684887Schin if(px->p_nxtjob == pw) 15694887Schin { 15704887Schin px->p_nxtjob = pw->p_nxtjob; 15714887Schin return; 15724887Schin } 15734887Schin } 15744887Schin 15754887Schin /* 15764887Schin * get an unused job number 15774887Schin * freejobs is a bit vector, 0 is unused 15784887Schin */ 15794887Schin 15804887Schin static int job_alloc(void) 15814887Schin { 15824887Schin register int j=0; 15834887Schin register unsigned mask = 1; 15844887Schin register unsigned char *freeword; 15854887Schin register int jmax = BYTE(sh.lim.child_max); 15864887Schin /* skip to first word with a free slot */ 15874887Schin for(j=0;job.freejobs[j] == UCHAR_MAX; j++); 15884887Schin if(j >= jmax) 15894887Schin { 15904887Schin register struct process *pw; 15914887Schin for(j=1; j < sh.lim.child_max; j++) 15924887Schin { 15934887Schin if((pw=job_byjid(j))&& !job_unpost(pw,0)) 15944887Schin break; 15954887Schin } 15964887Schin j /= CHAR_BIT; 15974887Schin if(j >= jmax) 15984887Schin return(-1); 15994887Schin } 16004887Schin freeword = &job.freejobs[j]; 16014887Schin j *= CHAR_BIT; 16024887Schin for(j++;mask&(*freeword);j++,mask <<=1); 16034887Schin *freeword |= mask; 16044887Schin return(j); 16054887Schin } 16064887Schin 16074887Schin /* 16084887Schin * return a job number 16094887Schin */ 16104887Schin 16114887Schin static void job_free(register int n) 16124887Schin { 16134887Schin register int j = (--n)/CHAR_BIT; 16144887Schin register unsigned mask; 16154887Schin n -= j*CHAR_BIT; 16164887Schin mask = 1 << n; 16174887Schin job.freejobs[j] &= ~mask; 16184887Schin } 16194887Schin 16204887Schin static char *job_sigmsg(int sig) 16214887Schin { 16224887Schin static char signo[40]; 16234887Schin #ifdef apollo 16244887Schin /* 16254887Schin * This code handles the formatting for the apollo specific signal 16264887Schin * SIGAPOLLO. 16274887Schin */ 16284887Schin extern char *apollo_error(void); 16294887Schin 16304887Schin if ( sig == SIGAPOLLO ) 16314887Schin return( apollo_error() ); 16324887Schin #endif /* apollo */ 16334887Schin if(sig<sh.sigmax && sh.sigmsg[sig]) 16344887Schin return(sh.sigmsg[sig]); 16354887Schin #if defined(SIGRTMIN) && defined(SIGRTMAX) 1636*8462SApril.Chin@Sun.COM if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX]) 16374887Schin { 16384887Schin static char sigrt[20]; 1639*8462SApril.Chin@Sun.COM if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2) 1640*8462SApril.Chin@Sun.COM sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig); 1641*8462SApril.Chin@Sun.COM else 1642*8462SApril.Chin@Sun.COM sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]); 16434887Schin return(sigrt); 16444887Schin } 16454887Schin #endif 16464887Schin sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig); 16474887Schin return(signo); 16484887Schin } 16494887Schin 16504887Schin /* 16514887Schin * see whether exit status has been saved and delete it 16524887Schin * if pid==0, then oldest saved process is deleted 16534887Schin * If pid is not found a -1 is returned. 16544887Schin */ 16554887Schin static int job_chksave(register pid_t pid) 16564887Schin { 16574887Schin register struct jobsave *jp = bck.list, *jpold=0; 16584887Schin register int r= -1; 16594887Schin while(jp) 16604887Schin { 16614887Schin if(jp->pid==pid) 16624887Schin break; 16634887Schin if(pid==0 && !jp->next) 16644887Schin break; 16654887Schin jpold = jp; 16664887Schin jp = jp->next; 16674887Schin } 16684887Schin if(jp) 16694887Schin { 16704887Schin r = 0; 16714887Schin if(pid) 16724887Schin r = jp->exitval; 16734887Schin if(jpold) 16744887Schin jpold->next = jp->next; 16754887Schin else 16764887Schin bck.list = jp->next; 16774887Schin bck.count--; 16784887Schin if(njob_savelist < NJOB_SAVELIST) 16794887Schin { 16804887Schin njob_savelist++; 16814887Schin jp->next = job_savelist; 16824887Schin job_savelist = jp; 16834887Schin } 16844887Schin else 16854887Schin free((void*)jp); 16864887Schin } 16874887Schin return(r); 16884887Schin } 16894887Schin 16904887Schin void *job_subsave(void) 16914887Schin { 16924887Schin struct back_save *bp = new_of(struct back_save,0); 16934887Schin job_lock(); 16944887Schin *bp = bck; 16954887Schin bck.count = 0; 16964887Schin bck.list = 0; 16974887Schin job_unlock(); 16984887Schin return((void*)bp); 16994887Schin } 17004887Schin 17014887Schin void job_subrestore(void* ptr) 17024887Schin { 1703*8462SApril.Chin@Sun.COM register struct jobsave *jp; 17044887Schin register struct back_save *bp = (struct back_save*)ptr; 17054887Schin register struct process *pw, *px, *pwnext; 1706*8462SApril.Chin@Sun.COM struct jobsave *jpnext; 17074887Schin job_lock(); 1708*8462SApril.Chin@Sun.COM for(jp=bck.list; jp; jp=jpnext) 1709*8462SApril.Chin@Sun.COM { 1710*8462SApril.Chin@Sun.COM jpnext = jp->next; 1711*8462SApril.Chin@Sun.COM if(jp->pid==sh.spid) 1712*8462SApril.Chin@Sun.COM { 1713*8462SApril.Chin@Sun.COM jp->next = bp->list; 1714*8462SApril.Chin@Sun.COM bp->list = jp; 1715*8462SApril.Chin@Sun.COM } 1716*8462SApril.Chin@Sun.COM else 1717*8462SApril.Chin@Sun.COM job_chksave(jp->pid); 1718*8462SApril.Chin@Sun.COM } 17194887Schin for(pw=job.pwlist; pw; pw=pwnext) 17204887Schin { 17214887Schin pwnext = pw->p_nxtjob; 17224887Schin if(pw->p_env != sh.curenv) 17234887Schin continue; 17244887Schin for(px=pw; px; px=px->p_nxtproc) 17254887Schin px->p_flag |= P_DONE; 17264887Schin job_unpost(pw,0); 17274887Schin } 1728*8462SApril.Chin@Sun.COM 1729*8462SApril.Chin@Sun.COM /* 1730*8462SApril.Chin@Sun.COM * queue up old lists for disposal by job_reap() 1731*8462SApril.Chin@Sun.COM */ 1732*8462SApril.Chin@Sun.COM 1733*8462SApril.Chin@Sun.COM bck = *bp; 1734*8462SApril.Chin@Sun.COM free((void*)bp); 17354887Schin job_unlock(); 17364887Schin } 17374887Schin 17384887Schin int sh_waitsafe(void) 17394887Schin { 17404887Schin return(job.waitsafe); 17414887Schin } 17424887Schin 17434887Schin void job_fork(pid_t parent) 17444887Schin { 17454887Schin #ifdef DEBUG 17464887Schin sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent); 17474887Schin #endif /* DEBUG */ 17484887Schin switch (parent) 17494887Schin { 17504887Schin case -1: 17514887Schin job_lock(); 17524887Schin break; 17534887Schin case 0: 17544887Schin job_unlock(); 17554887Schin job.waitsafe = 0; 17564887Schin job.in_critical = 0; 17574887Schin break; 17584887Schin default: 17594887Schin job_unlock(); 17604887Schin break; 17614887Schin } 17624887Schin } 1763