147823Sbostic /*- 247823Sbostic * Copyright (c) 1980, 1991 The Regents of the University of California. 347823Sbostic * All rights reserved. 447823Sbostic * 547823Sbostic * %sccs.include.redist.c% 621940Sdist */ 721940Sdist 817509Sedward #ifndef lint 9*51589Schristos static char sccsid[] = "@(#)proc.c 5.28 (Berkeley) 11/06/91"; 1047823Sbostic #endif /* not lint */ 111302Sbill 1250028Sbostic #include <sys/types.h> 1350028Sbostic #include <sys/wait.h> 1450028Sbostic #include <errno.h> 1550028Sbostic #include <unistd.h> 1650028Sbostic #include <stdlib.h> 1750028Sbostic #include <string.h> 1850033Schristos #if __STDC__ 1950033Schristos # include <stdarg.h> 2050033Schristos #else 2150033Schristos # include <varargs.h> 2250033Schristos #endif 2350033Schristos 2450023Sbostic #include "csh.h" 2550023Sbostic #include "dir.h" 2650023Sbostic #include "proc.h" 2750023Sbostic #include "extern.h" 281302Sbill 291302Sbill #define BIGINDEX 9 /* largest desirable job index */ 301302Sbill 3149992Sbostic static struct rusage zru; 3249992Sbostic 3350024Schristos static void pflushall __P((void)); 3450024Schristos static void pflush __P((struct process *)); 3550024Schristos static void pclrcurr __P((struct process *)); 3650024Schristos static void padd __P((struct command *)); 3750024Schristos static int pprint __P((struct process *, int)); 3850024Schristos static void ptprint __P((struct process *)); 3950024Schristos static void pads __P((Char *)); 4050024Schristos static void pkill __P((Char **v, int)); 4151437Sleres static struct process 4250024Schristos *pgetcurr __P((struct process *)); 4350024Schristos static void okpcntl __P((void)); 4449992Sbostic 451302Sbill /* 461302Sbill * pchild - called at interrupt level by the SIGCHLD signal 471302Sbill * indicating that at least one child has terminated or stopped 481302Sbill * thus at least one wait system call will definitely return a 491302Sbill * childs status. Top level routines (like pwait) must be sure 501302Sbill * to mask interrupts when playing with the proclist data structures! 511302Sbill */ 5250023Sbostic /* ARGUSED */ 5346657Sbostic void 5450023Sbostic pchild(notused) 5550023Sbostic int notused; 561302Sbill { 5749992Sbostic register struct process *pp; 5849992Sbostic register struct process *fp; 5949992Sbostic register int pid; 6049992Sbostic extern int insource; 6149992Sbostic union wait w; 6249992Sbostic int jobflags; 6349992Sbostic struct rusage ru; 641302Sbill 651302Sbill loop: 6649992Sbostic errno = 0; /* reset, just in case */ 6749992Sbostic pid = wait3(&w.w_status, 6849992Sbostic (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 6949992Sbostic 7049992Sbostic if (pid <= 0) { 7149992Sbostic if (errno == EINTR) { 7249992Sbostic errno = 0; 7349992Sbostic goto loop; 741302Sbill } 7549992Sbostic pnoprocesses = pid == -1; 7649992Sbostic return; 7749992Sbostic } 7850040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 7949992Sbostic if (pid == pp->p_pid) 8049992Sbostic goto found; 8149992Sbostic goto loop; 821302Sbill found: 8349992Sbostic if (pid == atoi(short2str(value(STRchild)))) 8449992Sbostic unsetv(STRchild); 8549992Sbostic pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 8649992Sbostic if (WIFSTOPPED(w)) { 8749992Sbostic pp->p_flags |= PSTOPPED; 8849992Sbostic pp->p_reason = w.w_stopsig; 8949992Sbostic } 9049992Sbostic else { 9149992Sbostic if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 9250028Sbostic (void) gettimeofday(&pp->p_etime, NULL); 9349992Sbostic 9449992Sbostic pp->p_rusage = ru; 9549992Sbostic if (WIFSIGNALED(w)) { 9649992Sbostic if (w.w_termsig == SIGINT) 9749992Sbostic pp->p_flags |= PINTERRUPTED; 9849992Sbostic else 9949992Sbostic pp->p_flags |= PSIGNALED; 10049992Sbostic if (w.w_coredump) 10149992Sbostic pp->p_flags |= PDUMPED; 10249992Sbostic pp->p_reason = w.w_termsig; 1031302Sbill } 10449992Sbostic else { 10549992Sbostic pp->p_reason = w.w_retcode; 10649992Sbostic if (pp->p_reason != 0) 10749992Sbostic pp->p_flags |= PAEXITED; 10849992Sbostic else 10949992Sbostic pp->p_flags |= PNEXITED; 11049992Sbostic } 11149992Sbostic } 11249992Sbostic jobflags = 0; 11349992Sbostic fp = pp; 11449992Sbostic do { 11549992Sbostic if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 11649992Sbostic !child && adrof(STRtime) && 11749992Sbostic fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 11849992Sbostic >= atoi(short2str(value(STRtime)))) 11949992Sbostic fp->p_flags |= PTIME; 12049992Sbostic jobflags |= fp->p_flags; 12149992Sbostic } while ((fp = fp->p_friends) != pp); 12249992Sbostic pp->p_flags &= ~PFOREGND; 12349992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 12449992Sbostic pp->p_flags &= ~PPTIME; 12549992Sbostic pp->p_flags |= PTIME; 12649992Sbostic } 12749992Sbostic if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 1281302Sbill fp = pp; 1291302Sbill do { 13049992Sbostic if (fp->p_flags & PSTOPPED) 13149992Sbostic fp->p_flags |= PREPORTED; 1321302Sbill } while ((fp = fp->p_friends) != pp); 13349992Sbostic while (fp->p_pid != fp->p_jobid) 13449992Sbostic fp = fp->p_friends; 13549992Sbostic if (jobflags & PSTOPPED) { 13649992Sbostic if (pcurrent && pcurrent != fp) 13749992Sbostic pprevious = pcurrent; 13849992Sbostic pcurrent = fp; 1391302Sbill } 14049992Sbostic else 14149992Sbostic pclrcurr(fp); 14249992Sbostic if (jobflags & PFOREGND) { 14349992Sbostic if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 14449992Sbostic #ifdef IIASA 14549992Sbostic jobflags & PAEXITED || 14649992Sbostic #endif 14749992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) { 14849992Sbostic ; /* print in pjwait */ 14949992Sbostic } 15049992Sbostic /* PWP: print a newline after ^C */ 15150445Schristos else if (jobflags & PINTERRUPTED) { 152*51589Schristos (void) vis_fputc('\r' | QUOTE, cshout); 15350445Schristos (void) fputc('\n', cshout); 15450445Schristos } 1551302Sbill } 15649992Sbostic else { 15749992Sbostic if (jobflags & PNOTIFY || adrof(STRnotify)) { 158*51589Schristos (void) vis_fputc('\r' | QUOTE, cshout); 15950445Schristos (void) fputc('\n', cshout); 16049992Sbostic (void) pprint(pp, NUMBER | NAME | REASON); 16149992Sbostic if ((jobflags & PSTOPPED) == 0) 16249992Sbostic pflush(pp); 16349992Sbostic } 16449992Sbostic else { 16549992Sbostic fp->p_flags |= PNEEDNOTE; 16649992Sbostic neednote++; 16749992Sbostic } 16849992Sbostic } 16949992Sbostic } 17049992Sbostic goto loop; 1711302Sbill } 1721302Sbill 17349992Sbostic void 1741302Sbill pnote() 1751302Sbill { 17649992Sbostic register struct process *pp; 17749992Sbostic int flags; 17850028Sbostic sigset_t omask; 1791302Sbill 18049992Sbostic neednote = 0; 18150040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 18249992Sbostic if (pp->p_flags & PNEEDNOTE) { 18349992Sbostic omask = sigblock(sigmask(SIGCHLD)); 18449992Sbostic pp->p_flags &= ~PNEEDNOTE; 18549992Sbostic flags = pprint(pp, NUMBER | NAME | REASON); 18649992Sbostic if ((flags & (PRUNNING | PSTOPPED)) == 0) 18749992Sbostic pflush(pp); 18849992Sbostic (void) sigsetmask(omask); 1891302Sbill } 19049992Sbostic } 1911302Sbill } 1921302Sbill 1931302Sbill /* 1941302Sbill * pwait - wait for current job to terminate, maintaining integrity 1951302Sbill * of current and previous job indicators. 1961302Sbill */ 19749992Sbostic void 1981302Sbill pwait() 1991302Sbill { 20049992Sbostic register struct process *fp, *pp; 20150028Sbostic sigset_t omask; 2021302Sbill 20349992Sbostic /* 20449992Sbostic * Here's where dead procs get flushed. 20549992Sbostic */ 20649992Sbostic omask = sigblock(sigmask(SIGCHLD)); 20750040Schristos for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 20849992Sbostic if (pp->p_pid == 0) { 20949992Sbostic fp->p_next = pp->p_next; 21049992Sbostic xfree((ptr_t) pp->p_command); 21149992Sbostic if (pp->p_cwd && --pp->p_cwd->di_count == 0) 21249992Sbostic if (pp->p_cwd->di_next == 0) 21349992Sbostic dfree(pp->p_cwd); 21449992Sbostic xfree((ptr_t) pp); 21549992Sbostic pp = fp; 21649992Sbostic } 21749992Sbostic (void) sigsetmask(omask); 21849992Sbostic pjwait(pcurrjob); 2191302Sbill } 2201302Sbill 22149992Sbostic 2221302Sbill /* 2231302Sbill * pjwait - wait for a job to finish or become stopped 2241302Sbill * It is assumed to be in the foreground state (PFOREGND) 2251302Sbill */ 22649992Sbostic void 2271302Sbill pjwait(pp) 22849992Sbostic register struct process *pp; 2291302Sbill { 23049992Sbostic register struct process *fp; 23149992Sbostic int jobflags, reason; 23250028Sbostic sigset_t omask; 2331302Sbill 23449992Sbostic while (pp->p_pid != pp->p_jobid) 23549992Sbostic pp = pp->p_friends; 23649992Sbostic fp = pp; 23749992Sbostic 23849992Sbostic do { 23949992Sbostic if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 24050439Schristos (void) fprintf(csherr, "BUG: waiting for background job!\n"); 24149992Sbostic } while ((fp = fp->p_friends) != pp); 24249992Sbostic /* 24349992Sbostic * Now keep pausing as long as we are not interrupted (SIGINT), and the 24449992Sbostic * target process, or any of its friends, are running 24549992Sbostic */ 24649992Sbostic fp = pp; 24749992Sbostic omask = sigblock(sigmask(SIGCHLD)); 24849992Sbostic for (;;) { 24949992Sbostic (void) sigblock(sigmask(SIGCHLD)); 25049992Sbostic jobflags = 0; 25149992Sbostic do 25249992Sbostic jobflags |= fp->p_flags; 25349992Sbostic while ((fp = (fp->p_friends)) != pp); 25449992Sbostic if ((jobflags & PRUNNING) == 0) 25549992Sbostic break; 25649992Sbostic #ifdef JOBDEBUG 25751437Sleres (void) fprintf(csherr, "starting to sigpause for SIGCHLD on %d\n", 25850439Schristos fp->p_pid); 25949992Sbostic #endif /* JOBDEBUG */ 26049992Sbostic (void) sigpause(omask & ~sigmask(SIGCHLD)); 26149992Sbostic } 26249992Sbostic (void) sigsetmask(omask); 26349992Sbostic if (tpgrp > 0) /* get tty back */ 26449992Sbostic (void) tcsetpgrp(FSHTTY, tpgrp); 26549992Sbostic if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 26649992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) { 26749992Sbostic if (jobflags & PSTOPPED) { 26850445Schristos (void) fputc('\n', cshout); 26949992Sbostic if (adrof(STRlistjobs)) { 27049992Sbostic Char *jobcommand[3]; 27149992Sbostic 27249992Sbostic jobcommand[0] = STRjobs; 27349992Sbostic if (eq(value(STRlistjobs), STRlong)) 27449992Sbostic jobcommand[1] = STRml; 27549992Sbostic else 27649992Sbostic jobcommand[1] = NULL; 27749992Sbostic jobcommand[2] = NULL; 27849992Sbostic 27950439Schristos dojobs(jobcommand, NULL); 28049992Sbostic (void) pprint(pp, SHELLDIR); 28149992Sbostic } 28249992Sbostic else 28349992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 2841302Sbill } 28549992Sbostic else 28649992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 28749992Sbostic } 28849992Sbostic if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 28949992Sbostic (!gointr || !eq(gointr, STRminus))) { 29049992Sbostic if ((jobflags & PSTOPPED) == 0) 29149992Sbostic pflush(pp); 29249992Sbostic pintr1(0); 29349992Sbostic /* NOTREACHED */ 29449992Sbostic } 29549992Sbostic reason = 0; 29649992Sbostic fp = pp; 29749992Sbostic do { 29849992Sbostic if (fp->p_reason) 29949992Sbostic reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 30049992Sbostic fp->p_reason | META : fp->p_reason; 30149992Sbostic } while ((fp = fp->p_friends) != pp); 30250445Schristos if ((reason != 0) && (adrof(STRprintexitvalue))) { 30350439Schristos (void) fprintf(cshout, "Exit %d\n", reason); 30450445Schristos } 30549992Sbostic set(STRstatus, putn(reason)); 30649992Sbostic if (reason && exiterr) 30749992Sbostic exitstat(); 30849992Sbostic pflush(pp); 3091302Sbill } 3101302Sbill 3111302Sbill /* 3121302Sbill * dowait - wait for all processes to finish 3131302Sbill */ 31449992Sbostic void 31550439Schristos /*ARGSUSED*/ 31650439Schristos dowait(v, t) 31750439Schristos Char **v; 31850439Schristos struct command *t; 3191302Sbill { 32049992Sbostic register struct process *pp; 32150028Sbostic sigset_t omask; 3221302Sbill 32349992Sbostic pjobs++; 32449992Sbostic omask = sigblock(sigmask(SIGCHLD)); 3251302Sbill loop: 32649992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 32749992Sbostic if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 32849992Sbostic pp->p_flags & PRUNNING) { 32950028Sbostic (void) sigpause((sigset_t) 0); 33049992Sbostic goto loop; 33149992Sbostic } 33249992Sbostic (void) sigsetmask(omask); 33349992Sbostic pjobs = 0; 3341302Sbill } 3351302Sbill 3361302Sbill /* 3371302Sbill * pflushall - flush all jobs from list (e.g. at fork()) 3381302Sbill */ 33949992Sbostic static void 3401302Sbill pflushall() 3411302Sbill { 34249992Sbostic register struct process *pp; 3431302Sbill 34450040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 34549992Sbostic if (pp->p_pid) 34649992Sbostic pflush(pp); 3471302Sbill } 3481302Sbill 3491302Sbill /* 3501302Sbill * pflush - flag all process structures in the same job as the 3511302Sbill * the argument process for deletion. The actual free of the 3521302Sbill * space is not done here since pflush is called at interrupt level. 3531302Sbill */ 35449992Sbostic static void 3551302Sbill pflush(pp) 35649992Sbostic register struct process *pp; 3571302Sbill { 35849992Sbostic register struct process *np; 35949992Sbostic register int idx; 3601302Sbill 36149992Sbostic if (pp->p_pid == 0) { 36250439Schristos (void) fprintf(csherr, "BUG: process flushed twice"); 36349992Sbostic return; 36449992Sbostic } 36549992Sbostic while (pp->p_pid != pp->p_jobid) 36649992Sbostic pp = pp->p_friends; 36749992Sbostic pclrcurr(pp); 36849992Sbostic if (pp == pcurrjob) 36949992Sbostic pcurrjob = 0; 37049992Sbostic idx = pp->p_index; 37149992Sbostic np = pp; 37249992Sbostic do { 37349992Sbostic np->p_index = np->p_pid = 0; 37449992Sbostic np->p_flags &= ~PNEEDNOTE; 37549992Sbostic } while ((np = np->p_friends) != pp); 37649992Sbostic if (idx == pmaxindex) { 37749992Sbostic for (np = proclist.p_next, idx = 0; np; np = np->p_next) 37849992Sbostic if (np->p_index > idx) 37949992Sbostic idx = np->p_index; 38049992Sbostic pmaxindex = idx; 38149992Sbostic } 3821302Sbill } 3831302Sbill 3841302Sbill /* 3851302Sbill * pclrcurr - make sure the given job is not the current or previous job; 3861302Sbill * pp MUST be the job leader 3871302Sbill */ 38849992Sbostic static void 3891302Sbill pclrcurr(pp) 39049992Sbostic register struct process *pp; 3911302Sbill { 3921302Sbill 39349992Sbostic if (pp == pcurrent) 39450040Schristos if (pprevious != NULL) { 39549992Sbostic pcurrent = pprevious; 39649992Sbostic pprevious = pgetcurr(pp); 39749992Sbostic } 39849992Sbostic else { 39949992Sbostic pcurrent = pgetcurr(pp); 40049992Sbostic pprevious = pgetcurr(pp); 40149992Sbostic } 40249992Sbostic else if (pp == pprevious) 40349992Sbostic pprevious = pgetcurr(pp); 4041302Sbill } 4051302Sbill 4061302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */ 40749992Sbostic static Char command[PMAXLEN + 4]; 40849992Sbostic static int cmdlen; 40949992Sbostic static Char *cmdp; 41049992Sbostic 4111302Sbill /* 4121302Sbill * palloc - allocate a process structure and fill it up. 4131302Sbill * an important assumption is made that the process is running. 4141302Sbill */ 41549992Sbostic void 4161302Sbill palloc(pid, t) 41749992Sbostic int pid; 41849992Sbostic register struct command *t; 4191302Sbill { 42049992Sbostic register struct process *pp; 42149992Sbostic int i; 4221302Sbill 42349992Sbostic pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 42449992Sbostic pp->p_pid = pid; 42549992Sbostic pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 42649992Sbostic if (t->t_dflg & F_TIME) 42749992Sbostic pp->p_flags |= PPTIME; 42849992Sbostic cmdp = command; 42949992Sbostic cmdlen = 0; 43049992Sbostic padd(t); 43149992Sbostic *cmdp++ = 0; 43249992Sbostic if (t->t_dflg & F_PIPEOUT) { 43349992Sbostic pp->p_flags |= PPOU; 43449992Sbostic if (t->t_dflg & F_STDERR) 43550439Schristos pp->p_flags |= PERR; 43649992Sbostic } 43749992Sbostic pp->p_command = Strsave(command); 43849992Sbostic if (pcurrjob) { 43949992Sbostic struct process *fp; 4401302Sbill 44149992Sbostic /* careful here with interrupt level */ 44249992Sbostic pp->p_cwd = 0; 44349992Sbostic pp->p_index = pcurrjob->p_index; 44449992Sbostic pp->p_friends = pcurrjob; 44549992Sbostic pp->p_jobid = pcurrjob->p_pid; 44651437Sleres for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 44751437Sleres continue; 44849992Sbostic fp->p_friends = pp; 44949992Sbostic } 45049992Sbostic else { 45149992Sbostic pcurrjob = pp; 45249992Sbostic pp->p_jobid = pid; 45349992Sbostic pp->p_friends = pp; 45449992Sbostic pp->p_cwd = dcwd; 45549992Sbostic dcwd->di_count++; 45649992Sbostic if (pmaxindex < BIGINDEX) 45749992Sbostic pp->p_index = ++pmaxindex; 45849992Sbostic else { 45949992Sbostic struct process *np; 46049992Sbostic 46149992Sbostic for (i = 1;; i++) { 46249992Sbostic for (np = proclist.p_next; np; np = np->p_next) 46349992Sbostic if (np->p_index == i) 46449992Sbostic goto tryagain; 46549992Sbostic pp->p_index = i; 46649992Sbostic if (i > pmaxindex) 46749992Sbostic pmaxindex = i; 46849992Sbostic break; 46949992Sbostic tryagain:; 47049992Sbostic } 4711302Sbill } 47250040Schristos if (pcurrent == NULL) 47349992Sbostic pcurrent = pp; 47450040Schristos else if (pprevious == NULL) 47549992Sbostic pprevious = pp; 47649992Sbostic } 47749992Sbostic pp->p_next = proclist.p_next; 47849992Sbostic proclist.p_next = pp; 47950028Sbostic (void) gettimeofday(&pp->p_btime, NULL); 4801302Sbill } 4811302Sbill 48249992Sbostic static void 4831302Sbill padd(t) 48449992Sbostic register struct command *t; 4851302Sbill { 48649992Sbostic Char **argp; 4871302Sbill 48849992Sbostic if (t == 0) 48949992Sbostic return; 49049992Sbostic switch (t->t_dtyp) { 4911302Sbill 49249992Sbostic case NODE_PAREN: 49349992Sbostic pads(STRLparensp); 49449992Sbostic padd(t->t_dspr); 49549992Sbostic pads(STRspRparen); 49649992Sbostic break; 4971302Sbill 49849992Sbostic case NODE_COMMAND: 49949992Sbostic for (argp = t->t_dcom; *argp; argp++) { 50049992Sbostic pads(*argp); 50149992Sbostic if (argp[1]) 50249992Sbostic pads(STRspace); 50349992Sbostic } 50449992Sbostic break; 5051302Sbill 50649992Sbostic case NODE_OR: 50749992Sbostic case NODE_AND: 50849992Sbostic case NODE_PIPE: 50949992Sbostic case NODE_LIST: 51049992Sbostic padd(t->t_dcar); 51149992Sbostic switch (t->t_dtyp) { 51247724Sbostic case NODE_OR: 51349992Sbostic pads(STRspor2sp); 51449992Sbostic break; 51547724Sbostic case NODE_AND: 51649992Sbostic pads(STRspand2sp); 51749992Sbostic break; 51847724Sbostic case NODE_PIPE: 51949992Sbostic pads(STRsporsp); 52049992Sbostic break; 52147724Sbostic case NODE_LIST: 52249992Sbostic pads(STRsemisp); 52349992Sbostic break; 5241302Sbill } 52549992Sbostic padd(t->t_dcdr); 52649992Sbostic return; 52749992Sbostic } 52849992Sbostic if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 52949992Sbostic pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 53049992Sbostic pads(t->t_dlef); 53149992Sbostic } 53249992Sbostic if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 53349992Sbostic pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 53449992Sbostic if (t->t_dflg & F_STDERR) 53549992Sbostic pads(STRand); 53649992Sbostic pads(STRspace); 53749992Sbostic pads(t->t_drit); 53849992Sbostic } 5391302Sbill } 5401302Sbill 54149992Sbostic static void 5421302Sbill pads(cp) 54349992Sbostic Char *cp; 5441302Sbill { 54549992Sbostic register int i; 5461302Sbill 54749992Sbostic /* 54849992Sbostic * Avoid the Quoted Space alias hack! Reported by: 54949992Sbostic * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 55049992Sbostic */ 55149992Sbostic if (cp[0] == STRQNULL[0]) 55249992Sbostic cp++; 55349992Sbostic 55449992Sbostic i = Strlen(cp); 55549992Sbostic 55649992Sbostic if (cmdlen >= PMAXLEN) 55749992Sbostic return; 55849992Sbostic if (cmdlen + i >= PMAXLEN) { 55949992Sbostic (void) Strcpy(cmdp, STRsp3dots); 56049992Sbostic cmdlen = PMAXLEN; 56149992Sbostic cmdp += 4; 56249992Sbostic return; 56349992Sbostic } 56449992Sbostic (void) Strcpy(cmdp, cp); 56549992Sbostic cmdp += i; 56649992Sbostic cmdlen += i; 5671302Sbill } 5681302Sbill 5691302Sbill /* 5701302Sbill * psavejob - temporarily save the current job on a one level stack 5711302Sbill * so another job can be created. Used for { } in exp6 5721302Sbill * and `` in globbing. 5731302Sbill */ 57449992Sbostic void 5751302Sbill psavejob() 5761302Sbill { 5771302Sbill 57849992Sbostic pholdjob = pcurrjob; 57950040Schristos pcurrjob = NULL; 5801302Sbill } 5811302Sbill 5821302Sbill /* 5831302Sbill * prestjob - opposite of psavejob. This may be missed if we are interrupted 5841302Sbill * somewhere, but pendjob cleans up anyway. 5851302Sbill */ 58649992Sbostic void 5871302Sbill prestjob() 5881302Sbill { 5891302Sbill 59049992Sbostic pcurrjob = pholdjob; 59150040Schristos pholdjob = NULL; 5921302Sbill } 5931302Sbill 5941302Sbill /* 5951302Sbill * pendjob - indicate that a job (set of commands) has been completed 5961302Sbill * or is about to begin. 5971302Sbill */ 59849992Sbostic void 5991302Sbill pendjob() 6001302Sbill { 60149992Sbostic register struct process *pp, *tp; 6021302Sbill 60349992Sbostic if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 60449992Sbostic pp = pcurrjob; 60549992Sbostic while (pp->p_pid != pp->p_jobid) 60649992Sbostic pp = pp->p_friends; 60750439Schristos (void) fprintf(cshout, "[%d]", pp->p_index); 60849992Sbostic tp = pp; 60949992Sbostic do { 61050439Schristos (void) fprintf(cshout, " %d", pp->p_pid); 61149992Sbostic pp = pp->p_friends; 61249992Sbostic } while (pp != tp); 61350439Schristos (void) fputc('\n', cshout); 61449992Sbostic } 61549992Sbostic pholdjob = pcurrjob = 0; 6161302Sbill } 6171302Sbill 6181302Sbill /* 6191302Sbill * pprint - print a job 6201302Sbill */ 62149992Sbostic static int 6221302Sbill pprint(pp, flag) 62349992Sbostic register struct process *pp; 62449992Sbostic bool flag; 6251302Sbill { 62649992Sbostic register status, reason; 62749992Sbostic struct process *tp; 62849992Sbostic int jobflags, pstatus; 62950445Schristos bool hadnl = 1; /* did we just have a newline */ 63049992Sbostic char *format; 6311302Sbill 63250439Schristos (void) fpurge(cshout); 63350439Schristos 63449992Sbostic while (pp->p_pid != pp->p_jobid) 63549992Sbostic pp = pp->p_friends; 63649992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 63749992Sbostic pp->p_flags &= ~PPTIME; 63849992Sbostic pp->p_flags |= PTIME; 63949992Sbostic } 64049992Sbostic tp = pp; 64149992Sbostic status = reason = -1; 64249992Sbostic jobflags = 0; 64349992Sbostic do { 64449992Sbostic jobflags |= pp->p_flags; 64549992Sbostic pstatus = pp->p_flags & PALLSTATES; 64651437Sleres if (tp != pp && !hadnl && !(flag & FANCY) && 64750445Schristos ((pstatus == status && pp->p_reason == reason) || 64850445Schristos !(flag & REASON))) { 64950439Schristos (void) fputc(' ', cshout); 65050445Schristos hadnl = 0; 65150445Schristos } 65249992Sbostic else { 65350445Schristos if (tp != pp && !hadnl) { 65450439Schristos (void) fputc('\n', cshout); 65550445Schristos hadnl = 1; 65650445Schristos } 65750445Schristos if (flag & NUMBER) { 65849992Sbostic if (pp == tp) 65950439Schristos (void) fprintf(cshout, "[%d]%s %c ", pp->p_index, 66049992Sbostic pp->p_index < 10 ? " " : "", 66149992Sbostic pp == pcurrent ? '+' : 66249992Sbostic (pp == pprevious ? '-' : ' ')); 66349992Sbostic else 66450439Schristos (void) fprintf(cshout, " "); 66550445Schristos hadnl = 0; 66650445Schristos } 66749992Sbostic if (flag & FANCY) { 66850439Schristos (void) fprintf(cshout, "%5d ", pp->p_pid); 66950445Schristos hadnl = 0; 67049992Sbostic } 67149992Sbostic if (flag & (REASON | AREASON)) { 67249992Sbostic if (flag & NAME) 67349992Sbostic format = "%-23s"; 67449992Sbostic else 67549992Sbostic format = "%s"; 67649992Sbostic if (pstatus == status) 67749992Sbostic if (pp->p_reason == reason) { 67850439Schristos (void) fprintf(cshout, format, ""); 67950445Schristos hadnl = 0; 68049992Sbostic goto prcomd; 68149992Sbostic } 68249992Sbostic else 68349992Sbostic reason = pp->p_reason; 6841302Sbill else { 68549992Sbostic status = pstatus; 68649992Sbostic reason = pp->p_reason; 68749992Sbostic } 68849992Sbostic switch (status) { 6891302Sbill 69049992Sbostic case PRUNNING: 69150439Schristos (void) fprintf(cshout, format, "Running "); 69250445Schristos hadnl = 0; 69349992Sbostic break; 6941302Sbill 69549992Sbostic case PINTERRUPTED: 69649992Sbostic case PSTOPPED: 69749992Sbostic case PSIGNALED: 69850445Schristos /* 69950445Schristos * tell what happened to the background job 70050445Schristos * From: Michael Schroeder 70150445Schristos * <mlschroe@immd4.informatik.uni-erlangen.de> 70250445Schristos */ 70350445Schristos if ((flag & REASON) 70450445Schristos || ((flag & AREASON) 70550445Schristos && reason != SIGINT 70650445Schristos && (reason != SIGPIPE 70750445Schristos || (pp->p_flags & PPOU) == 0))) { 70851437Sleres (void) fprintf(cshout, format, 70950947Schristos sys_siglist[pp->p_reason]); 71050445Schristos hadnl = 0; 71150445Schristos } 71249992Sbostic break; 7131302Sbill 71449992Sbostic case PNEXITED: 71549992Sbostic case PAEXITED: 71650445Schristos if (flag & REASON) { 71749992Sbostic if (pp->p_reason) 71850439Schristos (void) fprintf(cshout, "Exit %-18d", pp->p_reason); 71949992Sbostic else 72050439Schristos (void) fprintf(cshout, format, "Done"); 72150445Schristos hadnl = 0; 72250445Schristos } 72349992Sbostic break; 7241302Sbill 72549992Sbostic default: 72650439Schristos (void) fprintf(csherr, "BUG: status=%-9o", status); 7271302Sbill } 72849992Sbostic } 72949992Sbostic } 7301302Sbill prcomd: 73149992Sbostic if (flag & NAME) { 732*51589Schristos (void) fprintf(cshout, "%s", vis_str(pp->p_command)); 73349992Sbostic if (pp->p_flags & PPOU) 73450439Schristos (void) fprintf(cshout, " |"); 73550439Schristos if (pp->p_flags & PERR) 73650439Schristos (void) fputc('&', cshout); 73750445Schristos hadnl = 0; 7381302Sbill } 73950445Schristos if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) { 74050439Schristos (void) fprintf(cshout, " (core dumped)"); 74150445Schristos hadnl = 0; 74250445Schristos } 74349992Sbostic if (tp == pp->p_friends) { 74450445Schristos if (flag & AMPERSAND) { 74550439Schristos (void) fprintf(cshout, " &"); 74650445Schristos hadnl = 0; 74750445Schristos } 74849992Sbostic if (flag & JOBDIR && 74949992Sbostic !eq(tp->p_cwd->di_name, dcwd->di_name)) { 75050439Schristos (void) fprintf(cshout, " (wd: "); 75149992Sbostic dtildepr(value(STRhome), tp->p_cwd->di_name); 75250439Schristos (void) fputc(')', cshout); 75350445Schristos hadnl = 0; 75449992Sbostic } 75549992Sbostic } 75649992Sbostic if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 75750445Schristos if (!hadnl) 75850445Schristos (void) fprintf(cshout, "\n\t"); 75949992Sbostic prusage(&zru, &pp->p_rusage, &pp->p_etime, 76049992Sbostic &pp->p_btime); 76150445Schristos hadnl = 1; 76249992Sbostic } 76349992Sbostic if (tp == pp->p_friends) { 76450445Schristos if (!hadnl) { 76550439Schristos (void) fputc('\n', cshout); 76650445Schristos hadnl = 1; 76750445Schristos } 76849992Sbostic if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 76950439Schristos (void) fprintf(cshout, "(wd now: "); 77049992Sbostic dtildepr(value(STRhome), dcwd->di_name); 77150439Schristos (void) fprintf(cshout, ")\n"); 77250445Schristos hadnl = 1; 77349992Sbostic } 77449992Sbostic } 77549992Sbostic } while ((pp = pp->p_friends) != tp); 77649992Sbostic if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 77749992Sbostic if (jobflags & NUMBER) 77850439Schristos (void) fprintf(cshout, " "); 77949992Sbostic ptprint(tp); 78050445Schristos hadnl = 1; 78149992Sbostic } 78250439Schristos (void) fflush(cshout); 78349992Sbostic return (jobflags); 7841302Sbill } 7851302Sbill 78649992Sbostic static void 7871302Sbill ptprint(tp) 78849992Sbostic register struct process *tp; 7891302Sbill { 79049992Sbostic struct timeval tetime, diff; 79149992Sbostic static struct timeval ztime; 79249992Sbostic struct rusage ru; 79349992Sbostic static struct rusage zru; 79449992Sbostic register struct process *pp = tp; 7951302Sbill 79649992Sbostic ru = zru; 79749992Sbostic tetime = ztime; 79849992Sbostic do { 79949992Sbostic ruadd(&ru, &pp->p_rusage); 80049992Sbostic tvsub(&diff, &pp->p_etime, &pp->p_btime); 80149992Sbostic if (timercmp(&diff, &tetime, >)) 80249992Sbostic tetime = diff; 80349992Sbostic } while ((pp = pp->p_friends) != tp); 80449992Sbostic prusage(&zru, &ru, &tetime, &ztime); 8051302Sbill } 8061302Sbill 8071302Sbill /* 8081302Sbill * dojobs - print all jobs 8091302Sbill */ 81049992Sbostic void 81150439Schristos /*ARGSUSED*/ 81250439Schristos dojobs(v, t) 81350439Schristos Char **v; 81450439Schristos struct command *t; 8151302Sbill { 81649992Sbostic register struct process *pp; 81749992Sbostic register int flag = NUMBER | NAME | REASON; 81849992Sbostic int i; 8191302Sbill 82049992Sbostic if (chkstop) 82149992Sbostic chkstop = 2; 82249992Sbostic if (*++v) { 82349992Sbostic if (v[1] || !eq(*v, STRml)) 82449992Sbostic stderror(ERR_JOBS); 82549992Sbostic flag |= FANCY | JOBDIR; 82649992Sbostic } 82749992Sbostic for (i = 1; i <= pmaxindex; i++) 82849992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 82949992Sbostic if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 83049992Sbostic pp->p_flags &= ~PNEEDNOTE; 83149992Sbostic if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 83249992Sbostic pflush(pp); 83349992Sbostic break; 83449992Sbostic } 8351302Sbill } 8361302Sbill 8371302Sbill /* 8381302Sbill * dofg - builtin - put the job into the foreground 8391302Sbill */ 84049992Sbostic void 84150439Schristos /*ARGSUSED*/ 84250439Schristos dofg(v, t) 84350439Schristos Char **v; 84450439Schristos struct command *t; 8451302Sbill { 84649992Sbostic register struct process *pp; 8471302Sbill 84849992Sbostic okpcntl(); 84949992Sbostic ++v; 85049992Sbostic do { 85149992Sbostic pp = pfind(*v); 85249992Sbostic pstart(pp, 1); 85349992Sbostic pjwait(pp); 85449992Sbostic } while (*v && *++v); 8551302Sbill } 8561302Sbill 8571302Sbill /* 8581302Sbill * %... - builtin - put the job into the foreground 8591302Sbill */ 86049992Sbostic void 86150439Schristos /*ARGSUSED*/ 86250439Schristos dofg1(v, t) 86350439Schristos Char **v; 86450439Schristos struct command *t; 8651302Sbill { 86649992Sbostic register struct process *pp; 8671302Sbill 86849992Sbostic okpcntl(); 86949992Sbostic pp = pfind(v[0]); 87049992Sbostic pstart(pp, 1); 87149992Sbostic pjwait(pp); 8721302Sbill } 8731302Sbill 8741302Sbill /* 8751302Sbill * dobg - builtin - put the job into the background 8761302Sbill */ 87749992Sbostic void 87850439Schristos /*ARGSUSED*/ 87950439Schristos dobg(v, t) 88050439Schristos Char **v; 88150439Schristos struct command *t; 8821302Sbill { 88349992Sbostic register struct process *pp; 8841302Sbill 88549992Sbostic okpcntl(); 88649992Sbostic ++v; 88749992Sbostic do { 88849992Sbostic pp = pfind(*v); 88949992Sbostic pstart(pp, 0); 89049992Sbostic } while (*v && *++v); 8911302Sbill } 8921302Sbill 8931302Sbill /* 8941302Sbill * %... & - builtin - put the job into the background 8951302Sbill */ 89649992Sbostic void 89750439Schristos /*ARGSUSED*/ 89850439Schristos dobg1(v, t) 89950439Schristos Char **v; 90050439Schristos struct command *t; 9011302Sbill { 90249992Sbostic register struct process *pp; 9031302Sbill 90449992Sbostic pp = pfind(v[0]); 90549992Sbostic pstart(pp, 0); 9061302Sbill } 9071302Sbill 9081302Sbill /* 9091302Sbill * dostop - builtin - stop the job 9101302Sbill */ 91149992Sbostic void 91250439Schristos /*ARGSUSED*/ 91350439Schristos dostop(v, t) 91450439Schristos Char **v; 91550439Schristos struct command *t; 9161302Sbill { 91749992Sbostic pkill(++v, SIGSTOP); 9181302Sbill } 9191302Sbill 9201302Sbill /* 9211302Sbill * dokill - builtin - superset of kill (1) 9221302Sbill */ 92349992Sbostic void 92450439Schristos /*ARGSUSED*/ 92550439Schristos dokill(v, t) 92650439Schristos Char **v; 92750439Schristos struct command *t; 9281302Sbill { 92950761Schristos register int signum = SIGTERM; 93049992Sbostic register char *name; 9311302Sbill 93249992Sbostic v++; 93349992Sbostic if (v[0] && v[0][0] == '-') { 93449992Sbostic if (v[0][1] == 'l') { 93550761Schristos for (signum = 1; signum < NSIG; signum++) { 93650761Schristos (void) fprintf(cshout, "%s ", sys_signame[signum]); 93750761Schristos if (signum == NSIG / 2) 93850761Schristos (void) fputc('\n', cshout); 93949992Sbostic } 94050439Schristos (void) fputc('\n', cshout); 94149992Sbostic return; 94249992Sbostic } 94349992Sbostic if (Isdigit(v[0][1])) { 94449992Sbostic signum = atoi(short2str(v[0] + 1)); 94549992Sbostic if (signum < 0 || signum > NSIG) 94649992Sbostic stderror(ERR_NAME | ERR_BADSIG); 94749992Sbostic } 94849992Sbostic else { 94950761Schristos name = short2str(&v[0][1]); 95050761Schristos if (!strncasecmp(name, "sig", 3)) 95150761Schristos name += 3; 95250761Schristos 95351437Sleres for (signum = 1; signum < NSIG; signum++) 95450761Schristos if (!strcasecmp(sys_signame[signum], name)) 95550761Schristos break; 95650761Schristos 95750761Schristos if (signum == NSIG) { 958*51589Schristos setname(vis_str(&v[0][1])); 95950761Schristos stderror(ERR_NAME | ERR_UNKSIG); 96050761Schristos } 96149992Sbostic } 96249992Sbostic v++; 96349992Sbostic } 96449992Sbostic pkill(v, signum); 9651302Sbill } 9661302Sbill 96749992Sbostic static void 9681302Sbill pkill(v, signum) 96949992Sbostic Char **v; 97049992Sbostic int signum; 9711302Sbill { 97249992Sbostic register struct process *pp, *np; 97349992Sbostic register int jobflags = 0; 97449992Sbostic int pid, err1 = 0; 97550028Sbostic sigset_t omask; 97649992Sbostic Char *cp; 9771302Sbill 97849992Sbostic omask = sigmask(SIGCHLD); 97949992Sbostic if (setintr) 98049992Sbostic omask |= sigmask(SIGINT); 98149992Sbostic omask = sigblock(omask) & ~omask; 98249992Sbostic gflag = 0, tglob(v); 98349992Sbostic if (gflag) { 98449992Sbostic v = globall(v); 98549992Sbostic if (v == 0) 98649992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 98749992Sbostic } 98849992Sbostic else { 98949992Sbostic v = gargv = saveblk(v); 99049992Sbostic trim(v); 99149992Sbostic } 9921302Sbill 99349992Sbostic while (v && (cp = *v)) { 99449992Sbostic if (*cp == '%') { 99549992Sbostic np = pp = pfind(cp); 99649992Sbostic do 99749992Sbostic jobflags |= np->p_flags; 99849992Sbostic while ((np = np->p_friends) != pp); 99949992Sbostic switch (signum) { 100049992Sbostic 100149992Sbostic case SIGSTOP: 100249992Sbostic case SIGTSTP: 100349992Sbostic case SIGTTIN: 100449992Sbostic case SIGTTOU: 100549992Sbostic if ((jobflags & PRUNNING) == 0) { 100651437Sleres (void) fprintf(csherr, "%s: Already suspended\n", 1007*51589Schristos vis_str(cp)); 100849992Sbostic err1++; 100949992Sbostic goto cont; 10101302Sbill } 101149992Sbostic break; 101249992Sbostic /* 101349992Sbostic * suspend a process, kill -CONT %, then type jobs; the shell 101449992Sbostic * says it is suspended, but it is running; thanks jaap.. 101549992Sbostic */ 101649992Sbostic case SIGCONT: 101749992Sbostic pstart(pp, 0); 101849992Sbostic goto cont; 101949992Sbostic } 102049992Sbostic if (killpg((pid_t) pp->p_jobid, signum) < 0) { 1021*51589Schristos (void) fprintf(csherr, "%s: %s\n", vis_str(cp), 102250439Schristos strerror(errno)); 102349992Sbostic err1++; 102449992Sbostic } 102549992Sbostic if (signum == SIGTERM || signum == SIGHUP) 102649992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 102749992Sbostic } 102849992Sbostic else if (!(Isdigit(*cp) || *cp == '-')) 102949992Sbostic stderror(ERR_NAME | ERR_JOBARGS); 103049992Sbostic else { 103149992Sbostic pid = atoi(short2str(cp)); 103249992Sbostic if (kill((pid_t) pid, signum) < 0) { 103350439Schristos (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno)); 103449992Sbostic err1++; 103549992Sbostic goto cont; 103649992Sbostic } 103749992Sbostic if (signum == SIGTERM || signum == SIGHUP) 103849992Sbostic (void) kill((pid_t) pid, SIGCONT); 103949992Sbostic } 10401302Sbill cont: 104149992Sbostic v++; 104249992Sbostic } 104349992Sbostic if (gargv) 104449992Sbostic blkfree(gargv), gargv = 0; 104549992Sbostic (void) sigsetmask(omask); 104649992Sbostic if (err1) 104749992Sbostic stderror(ERR_SILENT); 10481302Sbill } 10491302Sbill 10501302Sbill /* 10511302Sbill * pstart - start the job in foreground/background 10521302Sbill */ 105349992Sbostic void 10541302Sbill pstart(pp, foregnd) 105549992Sbostic register struct process *pp; 105649992Sbostic int foregnd; 10571302Sbill { 105849992Sbostic register struct process *np; 105950028Sbostic sigset_t omask; 106049992Sbostic long jobflags = 0; 10611302Sbill 106249992Sbostic omask = sigblock(sigmask(SIGCHLD)); 106349992Sbostic np = pp; 106449992Sbostic do { 106549992Sbostic jobflags |= np->p_flags; 106649992Sbostic if (np->p_flags & (PRUNNING | PSTOPPED)) { 106749992Sbostic np->p_flags |= PRUNNING; 106849992Sbostic np->p_flags &= ~PSTOPPED; 106949992Sbostic if (foregnd) 107049992Sbostic np->p_flags |= PFOREGND; 107149992Sbostic else 107249992Sbostic np->p_flags &= ~PFOREGND; 107349992Sbostic } 107449992Sbostic } while ((np = np->p_friends) != pp); 107549992Sbostic if (!foregnd) 107649992Sbostic pclrcurr(pp); 107749992Sbostic (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 107849992Sbostic if (foregnd) 107949992Sbostic (void) tcsetpgrp(FSHTTY, pp->p_jobid); 108049992Sbostic if (jobflags & PSTOPPED) 108149992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 108249992Sbostic (void) sigsetmask(omask); 10831302Sbill } 10841302Sbill 108549992Sbostic void 10861302Sbill panystop(neednl) 108749992Sbostic bool neednl; 10881302Sbill { 108949992Sbostic register struct process *pp; 10901302Sbill 109149992Sbostic chkstop = 2; 109249992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 109349992Sbostic if (pp->p_flags & PSTOPPED) 109449992Sbostic stderror(ERR_STOPPED, neednl ? "\n" : ""); 10951302Sbill } 10961302Sbill 10971302Sbill struct process * 10981302Sbill pfind(cp) 109949992Sbostic Char *cp; 11001302Sbill { 110149992Sbostic register struct process *pp, *np; 11021302Sbill 110349992Sbostic if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 110450040Schristos if (pcurrent == NULL) 110549992Sbostic stderror(ERR_NAME | ERR_JOBCUR); 110649992Sbostic return (pcurrent); 110749992Sbostic } 110849992Sbostic if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 110950040Schristos if (pprevious == NULL) 111049992Sbostic stderror(ERR_NAME | ERR_JOBPREV); 111149992Sbostic return (pprevious); 111249992Sbostic } 111349992Sbostic if (Isdigit(cp[1])) { 111449992Sbostic int idx = atoi(short2str(cp + 1)); 111549992Sbostic 11161302Sbill for (pp = proclist.p_next; pp; pp = pp->p_next) 111749992Sbostic if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 111849992Sbostic return (pp); 111949992Sbostic stderror(ERR_NAME | ERR_NOSUCHJOB); 112049992Sbostic } 112150040Schristos np = NULL; 112249992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 112349992Sbostic if (pp->p_pid == pp->p_jobid) { 112449992Sbostic if (cp[1] == '?') { 112549992Sbostic register Char *dp; 112649992Sbostic 112749992Sbostic for (dp = pp->p_command; *dp; dp++) { 112849992Sbostic if (*dp != cp[2]) 112949992Sbostic continue; 113049992Sbostic if (prefix(cp + 2, dp)) 113149992Sbostic goto match; 11321302Sbill } 113349992Sbostic } 113449992Sbostic else if (prefix(cp + 1, pp->p_command)) { 113549992Sbostic match: 113649992Sbostic if (np) 113749992Sbostic stderror(ERR_NAME | ERR_AMBIG); 113849992Sbostic np = pp; 113949992Sbostic } 114049992Sbostic } 114149992Sbostic if (np) 114249992Sbostic return (np); 114349992Sbostic stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB); 114449992Sbostic /* NOTREACHED */ 114549992Sbostic return (0); 11461302Sbill } 11471302Sbill 114849992Sbostic 11491302Sbill /* 11502357Swnj * pgetcurr - find most recent job that is not pp, preferably stopped 11511302Sbill */ 115249992Sbostic static struct process * 11531302Sbill pgetcurr(pp) 115449992Sbostic register struct process *pp; 11551302Sbill { 115649992Sbostic register struct process *np; 115750040Schristos register struct process *xp = NULL; 11581302Sbill 115949992Sbostic for (np = proclist.p_next; np; np = np->p_next) 116049992Sbostic if (np != pcurrent && np != pp && np->p_pid && 116149992Sbostic np->p_pid == np->p_jobid) { 116249992Sbostic if (np->p_flags & PSTOPPED) 116349992Sbostic return (np); 116450040Schristos if (xp == NULL) 116549992Sbostic xp = np; 116649992Sbostic } 116749992Sbostic return (xp); 11681302Sbill } 11691302Sbill 11701302Sbill /* 11711302Sbill * donotify - flag the job so as to report termination asynchronously 11721302Sbill */ 117349992Sbostic void 117450439Schristos /*ARGSUSED*/ 117550439Schristos donotify(v, t) 117650439Schristos Char **v; 117750439Schristos struct command *t; 11781302Sbill { 117949992Sbostic register struct process *pp; 11801302Sbill 118149992Sbostic pp = pfind(*++v); 118249992Sbostic pp->p_flags |= PNOTIFY; 11831302Sbill } 11841302Sbill 11851302Sbill /* 11861302Sbill * Do the fork and whatever should be done in the child side that 11871302Sbill * should not be done if we are not forking at all (like for simple builtin's) 11881302Sbill * Also do everything that needs any signals fiddled with in the parent side 11891302Sbill * 11901302Sbill * Wanttty tells whether process and/or tty pgrps are to be manipulated: 11911302Sbill * -1: leave tty alone; inherit pgrp from parent 11921302Sbill * 0: already have tty; manipulate process pgrps only 11931302Sbill * 1: want to claim tty; manipulate process and tty pgrps 11941302Sbill * It is usually just the value of tpgrp. 11951302Sbill */ 119649992Sbostic 119749992Sbostic int 11981302Sbill pfork(t, wanttty) 119949992Sbostic struct command *t; /* command we are forking for */ 120049992Sbostic int wanttty; 12011302Sbill { 120249992Sbostic register int pid; 120349992Sbostic bool ignint = 0; 120449992Sbostic int pgrp; 120550028Sbostic sigset_t omask; 12061302Sbill 120749992Sbostic /* 120849992Sbostic * A child will be uninterruptible only under very special conditions. 120949992Sbostic * Remember that the semantics of '&' is implemented by disconnecting the 121049992Sbostic * process from the tty so signals do not need to ignored just for '&'. 121149992Sbostic * Thus signals are set to default action for children unless: we have had 121249992Sbostic * an "onintr -" (then specifically ignored) we are not playing with 121349992Sbostic * signals (inherit action) 121449992Sbostic */ 121549992Sbostic if (setintr) 121649992Sbostic ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 121749992Sbostic || (gointr && eq(gointr, STRminus)); 121849992Sbostic /* 121949992Sbostic * Check for maximum nesting of 16 processes to avoid Forking loops 122049992Sbostic */ 122149992Sbostic if (child == 16) 122249992Sbostic stderror(ERR_NESTING, 16); 122349992Sbostic /* 122449992Sbostic * Hold SIGCHLD until we have the process installed in our table. 122549992Sbostic */ 122649992Sbostic omask = sigblock(sigmask(SIGCHLD)); 122749992Sbostic while ((pid = fork()) < 0) 122849992Sbostic if (setintr == 0) 122949992Sbostic (void) sleep(FORKSLEEP); 123049992Sbostic else { 123149992Sbostic (void) sigsetmask(omask); 123249992Sbostic stderror(ERR_NOPROC); 123349992Sbostic } 123449992Sbostic if (pid == 0) { 123549992Sbostic settimes(); 123649992Sbostic pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 123749992Sbostic pflushall(); 123850040Schristos pcurrjob = NULL; 123949992Sbostic child++; 124049992Sbostic if (setintr) { 124149992Sbostic setintr = 0; /* until I think otherwise */ 124249992Sbostic /* 124349992Sbostic * Children just get blown away on SIGINT, SIGQUIT unless "onintr 124449992Sbostic * -" seen. 124549992Sbostic */ 124649992Sbostic (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 124749992Sbostic (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 124849992Sbostic if (wanttty >= 0) { 124949992Sbostic /* make stoppable */ 125049992Sbostic (void) signal(SIGTSTP, SIG_DFL); 125149992Sbostic (void) signal(SIGTTIN, SIG_DFL); 125249992Sbostic (void) signal(SIGTTOU, SIG_DFL); 125349992Sbostic } 125449992Sbostic (void) signal(SIGTERM, parterm); 125549992Sbostic } 125649992Sbostic else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 125749992Sbostic (void) signal(SIGINT, SIG_IGN); 125849992Sbostic (void) signal(SIGQUIT, SIG_IGN); 125949992Sbostic } 126049992Sbostic pgetty(wanttty, pgrp); 12611302Sbill /* 126249992Sbostic * Nohup and nice apply only to NODE_COMMAND's but it would be nice 126349992Sbostic * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 126449992Sbostic * to know about nice/nohup/time 12651302Sbill */ 126649992Sbostic if (t->t_dflg & F_NOHUP) 126749992Sbostic (void) signal(SIGHUP, SIG_IGN); 126849992Sbostic if (t->t_dflg & F_NICE) 126949992Sbostic (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 127049992Sbostic } 127149992Sbostic else { 127249992Sbostic if (wanttty >= 0) 127349992Sbostic (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 127449992Sbostic palloc(pid, t); 127549992Sbostic (void) sigsetmask(omask); 127649992Sbostic } 12771302Sbill 127849992Sbostic return (pid); 12791302Sbill } 12801302Sbill 128149992Sbostic static void 12821302Sbill okpcntl() 12831302Sbill { 128449992Sbostic if (tpgrp == -1) 128549992Sbostic stderror(ERR_JOBCONTROL); 128649992Sbostic if (tpgrp == 0) 128749992Sbostic stderror(ERR_JOBCTRLSUB); 128849992Sbostic } 12891302Sbill 129049992Sbostic /* 129149992Sbostic * if we don't have vfork(), things can still go in the wrong order 129249992Sbostic * resulting in the famous 'Stopped (tty output)'. But some systems 129349992Sbostic * don't permit the setpgid() call, (these are more recent secure 129449992Sbostic * systems such as ibm's aix). Then we'd rather print an error message 129549992Sbostic * than hang the shell! 129649992Sbostic * I am open to suggestions how to fix that. 129749992Sbostic */ 129849992Sbostic void 129949992Sbostic pgetty(wanttty, pgrp) 130049992Sbostic int wanttty, pgrp; 130149992Sbostic { 130250028Sbostic sigset_t omask = 0; 130349992Sbostic 130449992Sbostic /* 130549992Sbostic * christos: I am blocking the tty signals till I've set things 130649992Sbostic * correctly.... 130749992Sbostic */ 130849992Sbostic if (wanttty > 0) 130949992Sbostic omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); 131049992Sbostic /* 131149992Sbostic * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 131249992Sbostic * Don't check for tpgrp >= 0 so even non-interactive shells give 131349992Sbostic * background jobs process groups Same for the comparison in the other part 131449992Sbostic * of the #ifdef 131549992Sbostic */ 131649992Sbostic if (wanttty >= 0) 131749992Sbostic if (setpgid(0, pgrp) == -1) { 131850439Schristos (void) fprintf(csherr, "csh: setpgid error.\n"); 131949992Sbostic xexit(0); 132049992Sbostic } 132149992Sbostic 132249992Sbostic if (wanttty > 0) { 132349992Sbostic (void) tcsetpgrp(FSHTTY, pgrp); 132449992Sbostic (void) sigsetmask(omask); 132549992Sbostic } 132649992Sbostic 132749992Sbostic if (tpgrp > 0) 132849992Sbostic tpgrp = 0; /* gave tty away */ 13291302Sbill } 1330