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*50040Schristos static char sccsid[] = "@(#)proc.c 5.21 (Berkeley) 06/09/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)); 4150024Schristos 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 } 78*50040Schristos 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 */ 15149992Sbostic else if (jobflags & PINTERRUPTED) 15249992Sbostic xputchar('\r' | QUOTE), xputchar('\n'); 1531302Sbill } 15449992Sbostic else { 15549992Sbostic if (jobflags & PNOTIFY || adrof(STRnotify)) { 15649992Sbostic xputchar('\r' | QUOTE), xputchar('\n'); 15749992Sbostic (void) pprint(pp, NUMBER | NAME | REASON); 15849992Sbostic if ((jobflags & PSTOPPED) == 0) 15949992Sbostic pflush(pp); 16049992Sbostic } 16149992Sbostic else { 16249992Sbostic fp->p_flags |= PNEEDNOTE; 16349992Sbostic neednote++; 16449992Sbostic } 16549992Sbostic } 16649992Sbostic } 16749992Sbostic goto loop; 1681302Sbill } 1691302Sbill 17049992Sbostic void 1711302Sbill pnote() 1721302Sbill { 17349992Sbostic register struct process *pp; 17449992Sbostic int flags; 17550028Sbostic sigset_t omask; 1761302Sbill 17749992Sbostic neednote = 0; 178*50040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 17949992Sbostic if (pp->p_flags & PNEEDNOTE) { 18049992Sbostic omask = sigblock(sigmask(SIGCHLD)); 18149992Sbostic pp->p_flags &= ~PNEEDNOTE; 18249992Sbostic flags = pprint(pp, NUMBER | NAME | REASON); 18349992Sbostic if ((flags & (PRUNNING | PSTOPPED)) == 0) 18449992Sbostic pflush(pp); 18549992Sbostic (void) sigsetmask(omask); 1861302Sbill } 18749992Sbostic } 1881302Sbill } 1891302Sbill 1901302Sbill /* 1911302Sbill * pwait - wait for current job to terminate, maintaining integrity 1921302Sbill * of current and previous job indicators. 1931302Sbill */ 19449992Sbostic void 1951302Sbill pwait() 1961302Sbill { 19749992Sbostic register struct process *fp, *pp; 19850028Sbostic sigset_t omask; 1991302Sbill 20049992Sbostic /* 20149992Sbostic * Here's where dead procs get flushed. 20249992Sbostic */ 20349992Sbostic omask = sigblock(sigmask(SIGCHLD)); 204*50040Schristos for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 20549992Sbostic if (pp->p_pid == 0) { 20649992Sbostic fp->p_next = pp->p_next; 20749992Sbostic xfree((ptr_t) pp->p_command); 20849992Sbostic if (pp->p_cwd && --pp->p_cwd->di_count == 0) 20949992Sbostic if (pp->p_cwd->di_next == 0) 21049992Sbostic dfree(pp->p_cwd); 21149992Sbostic xfree((ptr_t) pp); 21249992Sbostic pp = fp; 21349992Sbostic } 21449992Sbostic (void) sigsetmask(omask); 21549992Sbostic pjwait(pcurrjob); 2161302Sbill } 2171302Sbill 21849992Sbostic 2191302Sbill /* 2201302Sbill * pjwait - wait for a job to finish or become stopped 2211302Sbill * It is assumed to be in the foreground state (PFOREGND) 2221302Sbill */ 22349992Sbostic void 2241302Sbill pjwait(pp) 22549992Sbostic register struct process *pp; 2261302Sbill { 22749992Sbostic register struct process *fp; 22849992Sbostic int jobflags, reason; 22950028Sbostic sigset_t omask; 2301302Sbill 23149992Sbostic while (pp->p_pid != pp->p_jobid) 23249992Sbostic pp = pp->p_friends; 23349992Sbostic fp = pp; 23449992Sbostic 23549992Sbostic do { 23649992Sbostic if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 23749992Sbostic xprintf("BUG: waiting for background job!\n"); 23849992Sbostic } while ((fp = fp->p_friends) != pp); 23949992Sbostic /* 24049992Sbostic * Now keep pausing as long as we are not interrupted (SIGINT), and the 24149992Sbostic * target process, or any of its friends, are running 24249992Sbostic */ 24349992Sbostic fp = pp; 24449992Sbostic omask = sigblock(sigmask(SIGCHLD)); 24549992Sbostic for (;;) { 24649992Sbostic (void) sigblock(sigmask(SIGCHLD)); 24749992Sbostic jobflags = 0; 24849992Sbostic do 24949992Sbostic jobflags |= fp->p_flags; 25049992Sbostic while ((fp = (fp->p_friends)) != pp); 25149992Sbostic if ((jobflags & PRUNNING) == 0) 25249992Sbostic break; 25349992Sbostic #ifdef JOBDEBUG 25449992Sbostic xprintf("starting to sigpause for SIGCHLD on %d\n", fp->p_pid); 25549992Sbostic #endif /* JOBDEBUG */ 25649992Sbostic (void) sigpause(omask & ~sigmask(SIGCHLD)); 25749992Sbostic } 25849992Sbostic (void) sigsetmask(omask); 25949992Sbostic if (tpgrp > 0) /* get tty back */ 26049992Sbostic (void) tcsetpgrp(FSHTTY, tpgrp); 26149992Sbostic if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 26249992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) { 26349992Sbostic if (jobflags & PSTOPPED) { 26449992Sbostic xprintf("\n"); 26549992Sbostic if (adrof(STRlistjobs)) { 26649992Sbostic Char *jobcommand[3]; 26749992Sbostic 26849992Sbostic jobcommand[0] = STRjobs; 26949992Sbostic if (eq(value(STRlistjobs), STRlong)) 27049992Sbostic jobcommand[1] = STRml; 27149992Sbostic else 27249992Sbostic jobcommand[1] = NULL; 27349992Sbostic jobcommand[2] = NULL; 27449992Sbostic 27549992Sbostic dojobs(jobcommand); 27649992Sbostic (void) pprint(pp, SHELLDIR); 27749992Sbostic } 27849992Sbostic else 27949992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 2801302Sbill } 28149992Sbostic else 28249992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 28349992Sbostic } 28449992Sbostic if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 28549992Sbostic (!gointr || !eq(gointr, STRminus))) { 28649992Sbostic if ((jobflags & PSTOPPED) == 0) 28749992Sbostic pflush(pp); 28849992Sbostic pintr1(0); 28949992Sbostic /* NOTREACHED */ 29049992Sbostic } 29149992Sbostic reason = 0; 29249992Sbostic fp = pp; 29349992Sbostic do { 29449992Sbostic if (fp->p_reason) 29549992Sbostic reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 29649992Sbostic fp->p_reason | META : fp->p_reason; 29749992Sbostic } while ((fp = fp->p_friends) != pp); 29849992Sbostic if ((reason != 0) && (adrof(STRprintexitvalue))) 29949992Sbostic xprintf("Exit %d\n", reason); 30049992Sbostic set(STRstatus, putn(reason)); 30149992Sbostic if (reason && exiterr) 30249992Sbostic exitstat(); 30349992Sbostic pflush(pp); 3041302Sbill } 3051302Sbill 3061302Sbill /* 3071302Sbill * dowait - wait for all processes to finish 3081302Sbill */ 30949992Sbostic void 3101302Sbill dowait() 3111302Sbill { 31249992Sbostic register struct process *pp; 31350028Sbostic sigset_t omask; 3141302Sbill 31549992Sbostic pjobs++; 31649992Sbostic omask = sigblock(sigmask(SIGCHLD)); 3171302Sbill loop: 31849992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 31949992Sbostic if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 32049992Sbostic pp->p_flags & PRUNNING) { 32150028Sbostic (void) sigpause((sigset_t) 0); 32249992Sbostic goto loop; 32349992Sbostic } 32449992Sbostic (void) sigsetmask(omask); 32549992Sbostic pjobs = 0; 3261302Sbill } 3271302Sbill 3281302Sbill /* 3291302Sbill * pflushall - flush all jobs from list (e.g. at fork()) 3301302Sbill */ 33149992Sbostic static void 3321302Sbill pflushall() 3331302Sbill { 33449992Sbostic register struct process *pp; 3351302Sbill 336*50040Schristos for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 33749992Sbostic if (pp->p_pid) 33849992Sbostic pflush(pp); 3391302Sbill } 3401302Sbill 3411302Sbill /* 3421302Sbill * pflush - flag all process structures in the same job as the 3431302Sbill * the argument process for deletion. The actual free of the 3441302Sbill * space is not done here since pflush is called at interrupt level. 3451302Sbill */ 34649992Sbostic static void 3471302Sbill pflush(pp) 34849992Sbostic register struct process *pp; 3491302Sbill { 35049992Sbostic register struct process *np; 35149992Sbostic register int idx; 3521302Sbill 35349992Sbostic if (pp->p_pid == 0) { 35449992Sbostic xprintf("BUG: process flushed twice"); 35549992Sbostic return; 35649992Sbostic } 35749992Sbostic while (pp->p_pid != pp->p_jobid) 35849992Sbostic pp = pp->p_friends; 35949992Sbostic pclrcurr(pp); 36049992Sbostic if (pp == pcurrjob) 36149992Sbostic pcurrjob = 0; 36249992Sbostic idx = pp->p_index; 36349992Sbostic np = pp; 36449992Sbostic do { 36549992Sbostic np->p_index = np->p_pid = 0; 36649992Sbostic np->p_flags &= ~PNEEDNOTE; 36749992Sbostic } while ((np = np->p_friends) != pp); 36849992Sbostic if (idx == pmaxindex) { 36949992Sbostic for (np = proclist.p_next, idx = 0; np; np = np->p_next) 37049992Sbostic if (np->p_index > idx) 37149992Sbostic idx = np->p_index; 37249992Sbostic pmaxindex = idx; 37349992Sbostic } 3741302Sbill } 3751302Sbill 3761302Sbill /* 3771302Sbill * pclrcurr - make sure the given job is not the current or previous job; 3781302Sbill * pp MUST be the job leader 3791302Sbill */ 38049992Sbostic static void 3811302Sbill pclrcurr(pp) 38249992Sbostic register struct process *pp; 3831302Sbill { 3841302Sbill 38549992Sbostic if (pp == pcurrent) 386*50040Schristos if (pprevious != NULL) { 38749992Sbostic pcurrent = pprevious; 38849992Sbostic pprevious = pgetcurr(pp); 38949992Sbostic } 39049992Sbostic else { 39149992Sbostic pcurrent = pgetcurr(pp); 39249992Sbostic pprevious = pgetcurr(pp); 39349992Sbostic } 39449992Sbostic else if (pp == pprevious) 39549992Sbostic pprevious = pgetcurr(pp); 3961302Sbill } 3971302Sbill 3981302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */ 39949992Sbostic static Char command[PMAXLEN + 4]; 40049992Sbostic static int cmdlen; 40149992Sbostic static Char *cmdp; 40249992Sbostic 4031302Sbill /* 4041302Sbill * palloc - allocate a process structure and fill it up. 4051302Sbill * an important assumption is made that the process is running. 4061302Sbill */ 40749992Sbostic void 4081302Sbill palloc(pid, t) 40949992Sbostic int pid; 41049992Sbostic register struct command *t; 4111302Sbill { 41249992Sbostic register struct process *pp; 41349992Sbostic int i; 4141302Sbill 41549992Sbostic pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 41649992Sbostic pp->p_pid = pid; 41749992Sbostic pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 41849992Sbostic if (t->t_dflg & F_TIME) 41949992Sbostic pp->p_flags |= PPTIME; 42049992Sbostic cmdp = command; 42149992Sbostic cmdlen = 0; 42249992Sbostic padd(t); 42349992Sbostic *cmdp++ = 0; 42449992Sbostic if (t->t_dflg & F_PIPEOUT) { 42549992Sbostic pp->p_flags |= PPOU; 42649992Sbostic if (t->t_dflg & F_STDERR) 42749992Sbostic pp->p_flags |= PDIAG; 42849992Sbostic } 42949992Sbostic pp->p_command = Strsave(command); 43049992Sbostic if (pcurrjob) { 43149992Sbostic struct process *fp; 4321302Sbill 43349992Sbostic /* careful here with interrupt level */ 43449992Sbostic pp->p_cwd = 0; 43549992Sbostic pp->p_index = pcurrjob->p_index; 43649992Sbostic pp->p_friends = pcurrjob; 43749992Sbostic pp->p_jobid = pcurrjob->p_pid; 43849992Sbostic for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends); 43949992Sbostic fp->p_friends = pp; 44049992Sbostic } 44149992Sbostic else { 44249992Sbostic pcurrjob = pp; 44349992Sbostic pp->p_jobid = pid; 44449992Sbostic pp->p_friends = pp; 44549992Sbostic pp->p_cwd = dcwd; 44649992Sbostic dcwd->di_count++; 44749992Sbostic if (pmaxindex < BIGINDEX) 44849992Sbostic pp->p_index = ++pmaxindex; 44949992Sbostic else { 45049992Sbostic struct process *np; 45149992Sbostic 45249992Sbostic for (i = 1;; i++) { 45349992Sbostic for (np = proclist.p_next; np; np = np->p_next) 45449992Sbostic if (np->p_index == i) 45549992Sbostic goto tryagain; 45649992Sbostic pp->p_index = i; 45749992Sbostic if (i > pmaxindex) 45849992Sbostic pmaxindex = i; 45949992Sbostic break; 46049992Sbostic tryagain:; 46149992Sbostic } 4621302Sbill } 463*50040Schristos if (pcurrent == NULL) 46449992Sbostic pcurrent = pp; 465*50040Schristos else if (pprevious == NULL) 46649992Sbostic pprevious = pp; 46749992Sbostic } 46849992Sbostic pp->p_next = proclist.p_next; 46949992Sbostic proclist.p_next = pp; 47050028Sbostic (void) gettimeofday(&pp->p_btime, NULL); 4711302Sbill } 4721302Sbill 47349992Sbostic static void 4741302Sbill padd(t) 47549992Sbostic register struct command *t; 4761302Sbill { 47749992Sbostic Char **argp; 4781302Sbill 47949992Sbostic if (t == 0) 48049992Sbostic return; 48149992Sbostic switch (t->t_dtyp) { 4821302Sbill 48349992Sbostic case NODE_PAREN: 48449992Sbostic pads(STRLparensp); 48549992Sbostic padd(t->t_dspr); 48649992Sbostic pads(STRspRparen); 48749992Sbostic break; 4881302Sbill 48949992Sbostic case NODE_COMMAND: 49049992Sbostic for (argp = t->t_dcom; *argp; argp++) { 49149992Sbostic pads(*argp); 49249992Sbostic if (argp[1]) 49349992Sbostic pads(STRspace); 49449992Sbostic } 49549992Sbostic break; 4961302Sbill 49749992Sbostic case NODE_OR: 49849992Sbostic case NODE_AND: 49949992Sbostic case NODE_PIPE: 50049992Sbostic case NODE_LIST: 50149992Sbostic padd(t->t_dcar); 50249992Sbostic switch (t->t_dtyp) { 50347724Sbostic case NODE_OR: 50449992Sbostic pads(STRspor2sp); 50549992Sbostic break; 50647724Sbostic case NODE_AND: 50749992Sbostic pads(STRspand2sp); 50849992Sbostic break; 50947724Sbostic case NODE_PIPE: 51049992Sbostic pads(STRsporsp); 51149992Sbostic break; 51247724Sbostic case NODE_LIST: 51349992Sbostic pads(STRsemisp); 51449992Sbostic break; 5151302Sbill } 51649992Sbostic padd(t->t_dcdr); 51749992Sbostic return; 51849992Sbostic } 51949992Sbostic if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 52049992Sbostic pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 52149992Sbostic pads(t->t_dlef); 52249992Sbostic } 52349992Sbostic if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 52449992Sbostic pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 52549992Sbostic if (t->t_dflg & F_STDERR) 52649992Sbostic pads(STRand); 52749992Sbostic pads(STRspace); 52849992Sbostic pads(t->t_drit); 52949992Sbostic } 5301302Sbill } 5311302Sbill 53249992Sbostic static void 5331302Sbill pads(cp) 53449992Sbostic Char *cp; 5351302Sbill { 53649992Sbostic register int i; 5371302Sbill 53849992Sbostic /* 53949992Sbostic * Avoid the Quoted Space alias hack! Reported by: 54049992Sbostic * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 54149992Sbostic */ 54249992Sbostic if (cp[0] == STRQNULL[0]) 54349992Sbostic cp++; 54449992Sbostic 54549992Sbostic i = Strlen(cp); 54649992Sbostic 54749992Sbostic if (cmdlen >= PMAXLEN) 54849992Sbostic return; 54949992Sbostic if (cmdlen + i >= PMAXLEN) { 55049992Sbostic (void) Strcpy(cmdp, STRsp3dots); 55149992Sbostic cmdlen = PMAXLEN; 55249992Sbostic cmdp += 4; 55349992Sbostic return; 55449992Sbostic } 55549992Sbostic (void) Strcpy(cmdp, cp); 55649992Sbostic cmdp += i; 55749992Sbostic cmdlen += i; 5581302Sbill } 5591302Sbill 5601302Sbill /* 5611302Sbill * psavejob - temporarily save the current job on a one level stack 5621302Sbill * so another job can be created. Used for { } in exp6 5631302Sbill * and `` in globbing. 5641302Sbill */ 56549992Sbostic void 5661302Sbill psavejob() 5671302Sbill { 5681302Sbill 56949992Sbostic pholdjob = pcurrjob; 570*50040Schristos pcurrjob = NULL; 5711302Sbill } 5721302Sbill 5731302Sbill /* 5741302Sbill * prestjob - opposite of psavejob. This may be missed if we are interrupted 5751302Sbill * somewhere, but pendjob cleans up anyway. 5761302Sbill */ 57749992Sbostic void 5781302Sbill prestjob() 5791302Sbill { 5801302Sbill 58149992Sbostic pcurrjob = pholdjob; 582*50040Schristos pholdjob = NULL; 5831302Sbill } 5841302Sbill 5851302Sbill /* 5861302Sbill * pendjob - indicate that a job (set of commands) has been completed 5871302Sbill * or is about to begin. 5881302Sbill */ 58949992Sbostic void 5901302Sbill pendjob() 5911302Sbill { 59249992Sbostic register struct process *pp, *tp; 5931302Sbill 59449992Sbostic if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 59549992Sbostic pp = pcurrjob; 59649992Sbostic while (pp->p_pid != pp->p_jobid) 59749992Sbostic pp = pp->p_friends; 59849992Sbostic xprintf("[%d]", pp->p_index); 59949992Sbostic tp = pp; 60049992Sbostic do { 60149992Sbostic xprintf(" %d", pp->p_pid); 60249992Sbostic pp = pp->p_friends; 60349992Sbostic } while (pp != tp); 60449992Sbostic xprintf("\n"); 60549992Sbostic } 60649992Sbostic pholdjob = pcurrjob = 0; 6071302Sbill } 6081302Sbill 6091302Sbill /* 6101302Sbill * pprint - print a job 6111302Sbill */ 61249992Sbostic static int 6131302Sbill pprint(pp, flag) 61449992Sbostic register struct process *pp; 61549992Sbostic bool flag; 6161302Sbill { 61749992Sbostic register status, reason; 61849992Sbostic struct process *tp; 61949992Sbostic extern char *linp, linbuf[]; 62049992Sbostic int jobflags, pstatus; 62149992Sbostic char *format; 6221302Sbill 62349992Sbostic while (pp->p_pid != pp->p_jobid) 62449992Sbostic pp = pp->p_friends; 62549992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 62649992Sbostic pp->p_flags &= ~PPTIME; 62749992Sbostic pp->p_flags |= PTIME; 62849992Sbostic } 62949992Sbostic tp = pp; 63049992Sbostic status = reason = -1; 63149992Sbostic jobflags = 0; 63249992Sbostic do { 63349992Sbostic jobflags |= pp->p_flags; 63449992Sbostic pstatus = pp->p_flags & PALLSTATES; 63549992Sbostic if (tp != pp && linp != linbuf && !(flag & FANCY) && 63649992Sbostic (pstatus == status && pp->p_reason == reason || 63749992Sbostic !(flag & REASON))) 63849992Sbostic xprintf(" "); 63949992Sbostic else { 64049992Sbostic if (tp != pp && linp != linbuf) 64149992Sbostic xprintf("\n"); 64249992Sbostic if (flag & NUMBER) 64349992Sbostic if (pp == tp) 64449992Sbostic xprintf("[%d]%s %c ", pp->p_index, 64549992Sbostic pp->p_index < 10 ? " " : "", 64649992Sbostic pp == pcurrent ? '+' : 64749992Sbostic (pp == pprevious ? '-' : ' ')); 64849992Sbostic else 64949992Sbostic xprintf(" "); 65049992Sbostic if (flag & FANCY) { 65149992Sbostic xprintf("%5d ", pp->p_pid); 65249992Sbostic } 65349992Sbostic if (flag & (REASON | AREASON)) { 65449992Sbostic if (flag & NAME) 65549992Sbostic format = "%-23s"; 65649992Sbostic else 65749992Sbostic format = "%s"; 65849992Sbostic if (pstatus == status) 65949992Sbostic if (pp->p_reason == reason) { 66049992Sbostic xprintf(format, ""); 66149992Sbostic goto prcomd; 66249992Sbostic } 66349992Sbostic else 66449992Sbostic reason = pp->p_reason; 6651302Sbill else { 66649992Sbostic status = pstatus; 66749992Sbostic reason = pp->p_reason; 66849992Sbostic } 66949992Sbostic switch (status) { 6701302Sbill 67149992Sbostic case PRUNNING: 67249992Sbostic xprintf(format, "Running "); 67349992Sbostic break; 6741302Sbill 67549992Sbostic case PINTERRUPTED: 67649992Sbostic case PSTOPPED: 67749992Sbostic case PSIGNALED: 67849992Sbostic if ((flag & (REASON | AREASON)) && reason != SIGINT 67949992Sbostic && reason != SIGPIPE) 68049992Sbostic xprintf(format, mesg[pp->p_reason].pname); 68149992Sbostic break; 6821302Sbill 68349992Sbostic case PNEXITED: 68449992Sbostic case PAEXITED: 68549992Sbostic if (flag & REASON) 68649992Sbostic if (pp->p_reason) 68749992Sbostic xprintf("Exit %-16d", pp->p_reason); 68849992Sbostic else 68949992Sbostic xprintf(format, "Done"); 69049992Sbostic break; 6911302Sbill 69249992Sbostic default: 69349992Sbostic xprintf("BUG: status=%-9o", status); 6941302Sbill } 69549992Sbostic } 69649992Sbostic } 6971302Sbill prcomd: 69849992Sbostic if (flag & NAME) { 69949992Sbostic xprintf("%s", short2str(pp->p_command)); 70049992Sbostic if (pp->p_flags & PPOU) 70149992Sbostic xprintf(" |"); 70249992Sbostic if (pp->p_flags & PDIAG) 70349992Sbostic xprintf("&"); 7041302Sbill } 70549992Sbostic if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 70649992Sbostic xprintf(" (core dumped)"); 70749992Sbostic if (tp == pp->p_friends) { 70849992Sbostic if (flag & AMPERSAND) 70949992Sbostic xprintf(" &"); 71049992Sbostic if (flag & JOBDIR && 71149992Sbostic !eq(tp->p_cwd->di_name, dcwd->di_name)) { 71249992Sbostic xprintf(" (wd: "); 71349992Sbostic dtildepr(value(STRhome), tp->p_cwd->di_name); 71449992Sbostic xprintf(")"); 71549992Sbostic } 71649992Sbostic } 71749992Sbostic if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 71849992Sbostic if (linp != linbuf) 71949992Sbostic xprintf("\n\t"); 72049992Sbostic prusage(&zru, &pp->p_rusage, &pp->p_etime, 72149992Sbostic &pp->p_btime); 72249992Sbostic } 72349992Sbostic if (tp == pp->p_friends) { 72449992Sbostic if (linp != linbuf) 72549992Sbostic xprintf("\n"); 72649992Sbostic if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 72749992Sbostic xprintf("(wd now: "); 72849992Sbostic dtildepr(value(STRhome), dcwd->di_name); 72949992Sbostic xprintf(")\n"); 73049992Sbostic } 73149992Sbostic } 73249992Sbostic } while ((pp = pp->p_friends) != tp); 73349992Sbostic if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 73449992Sbostic if (jobflags & NUMBER) 73549992Sbostic xprintf(" "); 73649992Sbostic ptprint(tp); 73749992Sbostic } 73849992Sbostic return (jobflags); 7391302Sbill } 7401302Sbill 74149992Sbostic static void 7421302Sbill ptprint(tp) 74349992Sbostic register struct process *tp; 7441302Sbill { 74549992Sbostic struct timeval tetime, diff; 74649992Sbostic static struct timeval ztime; 74749992Sbostic struct rusage ru; 74849992Sbostic static struct rusage zru; 74949992Sbostic register struct process *pp = tp; 7501302Sbill 75149992Sbostic ru = zru; 75249992Sbostic tetime = ztime; 75349992Sbostic do { 75449992Sbostic ruadd(&ru, &pp->p_rusage); 75549992Sbostic tvsub(&diff, &pp->p_etime, &pp->p_btime); 75649992Sbostic if (timercmp(&diff, &tetime, >)) 75749992Sbostic tetime = diff; 75849992Sbostic } while ((pp = pp->p_friends) != tp); 75949992Sbostic prusage(&zru, &ru, &tetime, &ztime); 7601302Sbill } 7611302Sbill 7621302Sbill /* 7631302Sbill * dojobs - print all jobs 7641302Sbill */ 76549992Sbostic void 7661302Sbill dojobs(v) 76749992Sbostic Char **v; 7681302Sbill { 76949992Sbostic register struct process *pp; 77049992Sbostic register int flag = NUMBER | NAME | REASON; 77149992Sbostic int i; 7721302Sbill 77349992Sbostic if (chkstop) 77449992Sbostic chkstop = 2; 77549992Sbostic if (*++v) { 77649992Sbostic if (v[1] || !eq(*v, STRml)) 77749992Sbostic stderror(ERR_JOBS); 77849992Sbostic flag |= FANCY | JOBDIR; 77949992Sbostic } 78049992Sbostic for (i = 1; i <= pmaxindex; i++) 78149992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 78249992Sbostic if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 78349992Sbostic pp->p_flags &= ~PNEEDNOTE; 78449992Sbostic if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 78549992Sbostic pflush(pp); 78649992Sbostic break; 78749992Sbostic } 7881302Sbill } 7891302Sbill 7901302Sbill /* 7911302Sbill * dofg - builtin - put the job into the foreground 7921302Sbill */ 79349992Sbostic void 7941302Sbill dofg(v) 79549992Sbostic Char **v; 7961302Sbill { 79749992Sbostic register struct process *pp; 7981302Sbill 79949992Sbostic okpcntl(); 80049992Sbostic ++v; 80149992Sbostic do { 80249992Sbostic pp = pfind(*v); 80349992Sbostic pstart(pp, 1); 80449992Sbostic pjwait(pp); 80549992Sbostic } while (*v && *++v); 8061302Sbill } 8071302Sbill 8081302Sbill /* 8091302Sbill * %... - builtin - put the job into the foreground 8101302Sbill */ 81149992Sbostic void 8121302Sbill dofg1(v) 81349992Sbostic Char **v; 8141302Sbill { 81549992Sbostic register struct process *pp; 8161302Sbill 81749992Sbostic okpcntl(); 81849992Sbostic pp = pfind(v[0]); 81949992Sbostic pstart(pp, 1); 82049992Sbostic pjwait(pp); 8211302Sbill } 8221302Sbill 8231302Sbill /* 8241302Sbill * dobg - builtin - put the job into the background 8251302Sbill */ 82649992Sbostic void 8271302Sbill dobg(v) 82849992Sbostic Char **v; 8291302Sbill { 83049992Sbostic register struct process *pp; 8311302Sbill 83249992Sbostic okpcntl(); 83349992Sbostic ++v; 83449992Sbostic do { 83549992Sbostic pp = pfind(*v); 83649992Sbostic pstart(pp, 0); 83749992Sbostic } while (*v && *++v); 8381302Sbill } 8391302Sbill 8401302Sbill /* 8411302Sbill * %... & - builtin - put the job into the background 8421302Sbill */ 84349992Sbostic void 8441302Sbill dobg1(v) 84549992Sbostic Char **v; 8461302Sbill { 84749992Sbostic register struct process *pp; 8481302Sbill 84949992Sbostic pp = pfind(v[0]); 85049992Sbostic pstart(pp, 0); 8511302Sbill } 8521302Sbill 8531302Sbill /* 8541302Sbill * dostop - builtin - stop the job 8551302Sbill */ 85649992Sbostic void 8571302Sbill dostop(v) 85849992Sbostic Char **v; 8591302Sbill { 86049992Sbostic pkill(++v, SIGSTOP); 8611302Sbill } 8621302Sbill 8631302Sbill /* 8641302Sbill * dokill - builtin - superset of kill (1) 8651302Sbill */ 86649992Sbostic void 8671302Sbill dokill(v) 86849992Sbostic Char **v; 8691302Sbill { 87049992Sbostic register int signum, len = 0; 87149992Sbostic register char *name; 8721302Sbill 87349992Sbostic v++; 87449992Sbostic if (v[0] && v[0][0] == '-') { 87549992Sbostic if (v[0][1] == 'l') { 87649992Sbostic for (signum = 1; signum <= NSIG; signum++) { 87749992Sbostic if ((name = mesg[signum].iname) != NULL) { 87849992Sbostic len += strlen(name) + 1; 87949992Sbostic if (len >= 80 - 1) { 88049992Sbostic xprintf("\n"); 88149992Sbostic len = strlen(name) + 1; 88249992Sbostic } 88349992Sbostic xprintf("%s ", name); 8841302Sbill } 88549992Sbostic } 88649992Sbostic xprintf("\n"); 88749992Sbostic return; 88849992Sbostic } 88949992Sbostic if (Isdigit(v[0][1])) { 89049992Sbostic signum = atoi(short2str(v[0] + 1)); 89149992Sbostic if (signum < 0 || signum > NSIG) 89249992Sbostic stderror(ERR_NAME | ERR_BADSIG); 89349992Sbostic } 89449992Sbostic else { 89549992Sbostic for (signum = 1; signum <= NSIG; signum++) 89649992Sbostic if (mesg[signum].iname && 89749992Sbostic eq(&v[0][1], str2short(mesg[signum].iname))) 89849992Sbostic goto gotsig; 89949992Sbostic setname(short2str(&v[0][1])); 90049992Sbostic stderror(ERR_NAME | ERR_UNKSIG); 90149992Sbostic } 9021302Sbill gotsig: 90349992Sbostic v++; 90449992Sbostic } 90549992Sbostic else 90649992Sbostic signum = SIGTERM; 90749992Sbostic pkill(v, signum); 9081302Sbill } 9091302Sbill 91049992Sbostic static void 9111302Sbill pkill(v, signum) 91249992Sbostic Char **v; 91349992Sbostic int signum; 9141302Sbill { 91549992Sbostic register struct process *pp, *np; 91649992Sbostic register int jobflags = 0; 91749992Sbostic int pid, err1 = 0; 91850028Sbostic sigset_t omask; 91949992Sbostic Char *cp; 9201302Sbill 92149992Sbostic omask = sigmask(SIGCHLD); 92249992Sbostic if (setintr) 92349992Sbostic omask |= sigmask(SIGINT); 92449992Sbostic omask = sigblock(omask) & ~omask; 92549992Sbostic gflag = 0, tglob(v); 92649992Sbostic if (gflag) { 92749992Sbostic v = globall(v); 92849992Sbostic if (v == 0) 92949992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 93049992Sbostic } 93149992Sbostic else { 93249992Sbostic v = gargv = saveblk(v); 93349992Sbostic trim(v); 93449992Sbostic } 9351302Sbill 93649992Sbostic while (v && (cp = *v)) { 93749992Sbostic if (*cp == '%') { 93849992Sbostic np = pp = pfind(cp); 93949992Sbostic do 94049992Sbostic jobflags |= np->p_flags; 94149992Sbostic while ((np = np->p_friends) != pp); 94249992Sbostic switch (signum) { 94349992Sbostic 94449992Sbostic case SIGSTOP: 94549992Sbostic case SIGTSTP: 94649992Sbostic case SIGTTIN: 94749992Sbostic case SIGTTOU: 94849992Sbostic if ((jobflags & PRUNNING) == 0) { 94949992Sbostic xprintf("%s: Already suspended\n", short2str(cp)); 95049992Sbostic err1++; 95149992Sbostic goto cont; 9521302Sbill } 95349992Sbostic break; 95449992Sbostic /* 95549992Sbostic * suspend a process, kill -CONT %, then type jobs; the shell 95649992Sbostic * says it is suspended, but it is running; thanks jaap.. 95749992Sbostic */ 95849992Sbostic case SIGCONT: 95949992Sbostic pstart(pp, 0); 96049992Sbostic goto cont; 96149992Sbostic } 96249992Sbostic if (killpg((pid_t) pp->p_jobid, signum) < 0) { 96349992Sbostic xprintf("%s: %s\n", short2str(cp), strerror(errno)); 96449992Sbostic err1++; 96549992Sbostic } 96649992Sbostic if (signum == SIGTERM || signum == SIGHUP) 96749992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 96849992Sbostic } 96949992Sbostic else if (!(Isdigit(*cp) || *cp == '-')) 97049992Sbostic stderror(ERR_NAME | ERR_JOBARGS); 97149992Sbostic else { 97249992Sbostic pid = atoi(short2str(cp)); 97349992Sbostic if (kill((pid_t) pid, signum) < 0) { 97449992Sbostic xprintf("%d: %s\n", pid, strerror(errno)); 97549992Sbostic err1++; 97649992Sbostic goto cont; 97749992Sbostic } 97849992Sbostic if (signum == SIGTERM || signum == SIGHUP) 97949992Sbostic (void) kill((pid_t) pid, SIGCONT); 98049992Sbostic } 9811302Sbill cont: 98249992Sbostic v++; 98349992Sbostic } 98449992Sbostic if (gargv) 98549992Sbostic blkfree(gargv), gargv = 0; 98649992Sbostic (void) sigsetmask(omask); 98749992Sbostic if (err1) 98849992Sbostic stderror(ERR_SILENT); 9891302Sbill } 9901302Sbill 9911302Sbill /* 9921302Sbill * pstart - start the job in foreground/background 9931302Sbill */ 99449992Sbostic void 9951302Sbill pstart(pp, foregnd) 99649992Sbostic register struct process *pp; 99749992Sbostic int foregnd; 9981302Sbill { 99949992Sbostic register struct process *np; 100050028Sbostic sigset_t omask; 100149992Sbostic long jobflags = 0; 10021302Sbill 100349992Sbostic omask = sigblock(sigmask(SIGCHLD)); 100449992Sbostic np = pp; 100549992Sbostic do { 100649992Sbostic jobflags |= np->p_flags; 100749992Sbostic if (np->p_flags & (PRUNNING | PSTOPPED)) { 100849992Sbostic np->p_flags |= PRUNNING; 100949992Sbostic np->p_flags &= ~PSTOPPED; 101049992Sbostic if (foregnd) 101149992Sbostic np->p_flags |= PFOREGND; 101249992Sbostic else 101349992Sbostic np->p_flags &= ~PFOREGND; 101449992Sbostic } 101549992Sbostic } while ((np = np->p_friends) != pp); 101649992Sbostic if (!foregnd) 101749992Sbostic pclrcurr(pp); 101849992Sbostic (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 101949992Sbostic if (foregnd) 102049992Sbostic (void) tcsetpgrp(FSHTTY, pp->p_jobid); 102149992Sbostic if (jobflags & PSTOPPED) 102249992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 102349992Sbostic (void) sigsetmask(omask); 10241302Sbill } 10251302Sbill 102649992Sbostic void 10271302Sbill panystop(neednl) 102849992Sbostic bool neednl; 10291302Sbill { 103049992Sbostic register struct process *pp; 10311302Sbill 103249992Sbostic chkstop = 2; 103349992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 103449992Sbostic if (pp->p_flags & PSTOPPED) 103549992Sbostic stderror(ERR_STOPPED, neednl ? "\n" : ""); 10361302Sbill } 10371302Sbill 10381302Sbill struct process * 10391302Sbill pfind(cp) 104049992Sbostic Char *cp; 10411302Sbill { 104249992Sbostic register struct process *pp, *np; 10431302Sbill 104449992Sbostic if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 1045*50040Schristos if (pcurrent == NULL) 104649992Sbostic stderror(ERR_NAME | ERR_JOBCUR); 104749992Sbostic return (pcurrent); 104849992Sbostic } 104949992Sbostic if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 1050*50040Schristos if (pprevious == NULL) 105149992Sbostic stderror(ERR_NAME | ERR_JOBPREV); 105249992Sbostic return (pprevious); 105349992Sbostic } 105449992Sbostic if (Isdigit(cp[1])) { 105549992Sbostic int idx = atoi(short2str(cp + 1)); 105649992Sbostic 10571302Sbill for (pp = proclist.p_next; pp; pp = pp->p_next) 105849992Sbostic if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 105949992Sbostic return (pp); 106049992Sbostic stderror(ERR_NAME | ERR_NOSUCHJOB); 106149992Sbostic } 1062*50040Schristos np = NULL; 106349992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 106449992Sbostic if (pp->p_pid == pp->p_jobid) { 106549992Sbostic if (cp[1] == '?') { 106649992Sbostic register Char *dp; 106749992Sbostic 106849992Sbostic for (dp = pp->p_command; *dp; dp++) { 106949992Sbostic if (*dp != cp[2]) 107049992Sbostic continue; 107149992Sbostic if (prefix(cp + 2, dp)) 107249992Sbostic goto match; 10731302Sbill } 107449992Sbostic } 107549992Sbostic else if (prefix(cp + 1, pp->p_command)) { 107649992Sbostic match: 107749992Sbostic if (np) 107849992Sbostic stderror(ERR_NAME | ERR_AMBIG); 107949992Sbostic np = pp; 108049992Sbostic } 108149992Sbostic } 108249992Sbostic if (np) 108349992Sbostic return (np); 108449992Sbostic stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB); 108549992Sbostic /* NOTREACHED */ 108649992Sbostic return (0); 10871302Sbill } 10881302Sbill 108949992Sbostic 10901302Sbill /* 10912357Swnj * pgetcurr - find most recent job that is not pp, preferably stopped 10921302Sbill */ 109349992Sbostic static struct process * 10941302Sbill pgetcurr(pp) 109549992Sbostic register struct process *pp; 10961302Sbill { 109749992Sbostic register struct process *np; 1098*50040Schristos register struct process *xp = NULL; 10991302Sbill 110049992Sbostic for (np = proclist.p_next; np; np = np->p_next) 110149992Sbostic if (np != pcurrent && np != pp && np->p_pid && 110249992Sbostic np->p_pid == np->p_jobid) { 110349992Sbostic if (np->p_flags & PSTOPPED) 110449992Sbostic return (np); 1105*50040Schristos if (xp == NULL) 110649992Sbostic xp = np; 110749992Sbostic } 110849992Sbostic return (xp); 11091302Sbill } 11101302Sbill 11111302Sbill /* 11121302Sbill * donotify - flag the job so as to report termination asynchronously 11131302Sbill */ 111449992Sbostic void 11151302Sbill donotify(v) 111649992Sbostic Char **v; 11171302Sbill { 111849992Sbostic register struct process *pp; 11191302Sbill 112049992Sbostic pp = pfind(*++v); 112149992Sbostic pp->p_flags |= PNOTIFY; 11221302Sbill } 11231302Sbill 11241302Sbill /* 11251302Sbill * Do the fork and whatever should be done in the child side that 11261302Sbill * should not be done if we are not forking at all (like for simple builtin's) 11271302Sbill * Also do everything that needs any signals fiddled with in the parent side 11281302Sbill * 11291302Sbill * Wanttty tells whether process and/or tty pgrps are to be manipulated: 11301302Sbill * -1: leave tty alone; inherit pgrp from parent 11311302Sbill * 0: already have tty; manipulate process pgrps only 11321302Sbill * 1: want to claim tty; manipulate process and tty pgrps 11331302Sbill * It is usually just the value of tpgrp. 11341302Sbill */ 113549992Sbostic 113649992Sbostic int 11371302Sbill pfork(t, wanttty) 113849992Sbostic struct command *t; /* command we are forking for */ 113949992Sbostic int wanttty; 11401302Sbill { 114149992Sbostic register int pid; 114249992Sbostic bool ignint = 0; 114349992Sbostic int pgrp; 114450028Sbostic sigset_t omask; 11451302Sbill 114649992Sbostic /* 114749992Sbostic * A child will be uninterruptible only under very special conditions. 114849992Sbostic * Remember that the semantics of '&' is implemented by disconnecting the 114949992Sbostic * process from the tty so signals do not need to ignored just for '&'. 115049992Sbostic * Thus signals are set to default action for children unless: we have had 115149992Sbostic * an "onintr -" (then specifically ignored) we are not playing with 115249992Sbostic * signals (inherit action) 115349992Sbostic */ 115449992Sbostic if (setintr) 115549992Sbostic ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 115649992Sbostic || (gointr && eq(gointr, STRminus)); 115749992Sbostic /* 115849992Sbostic * Check for maximum nesting of 16 processes to avoid Forking loops 115949992Sbostic */ 116049992Sbostic if (child == 16) 116149992Sbostic stderror(ERR_NESTING, 16); 116249992Sbostic /* 116349992Sbostic * Hold SIGCHLD until we have the process installed in our table. 116449992Sbostic */ 116549992Sbostic omask = sigblock(sigmask(SIGCHLD)); 116649992Sbostic while ((pid = fork()) < 0) 116749992Sbostic if (setintr == 0) 116849992Sbostic (void) sleep(FORKSLEEP); 116949992Sbostic else { 117049992Sbostic (void) sigsetmask(omask); 117149992Sbostic stderror(ERR_NOPROC); 117249992Sbostic } 117349992Sbostic if (pid == 0) { 117449992Sbostic settimes(); 117549992Sbostic pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 117649992Sbostic pflushall(); 1177*50040Schristos pcurrjob = NULL; 117849992Sbostic child++; 117949992Sbostic if (setintr) { 118049992Sbostic setintr = 0; /* until I think otherwise */ 118149992Sbostic /* 118249992Sbostic * Children just get blown away on SIGINT, SIGQUIT unless "onintr 118349992Sbostic * -" seen. 118449992Sbostic */ 118549992Sbostic (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 118649992Sbostic (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 118749992Sbostic if (wanttty >= 0) { 118849992Sbostic /* make stoppable */ 118949992Sbostic (void) signal(SIGTSTP, SIG_DFL); 119049992Sbostic (void) signal(SIGTTIN, SIG_DFL); 119149992Sbostic (void) signal(SIGTTOU, SIG_DFL); 119249992Sbostic } 119349992Sbostic (void) signal(SIGTERM, parterm); 119449992Sbostic } 119549992Sbostic else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 119649992Sbostic (void) signal(SIGINT, SIG_IGN); 119749992Sbostic (void) signal(SIGQUIT, SIG_IGN); 119849992Sbostic } 119949992Sbostic pgetty(wanttty, pgrp); 12001302Sbill /* 120149992Sbostic * Nohup and nice apply only to NODE_COMMAND's but it would be nice 120249992Sbostic * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 120349992Sbostic * to know about nice/nohup/time 12041302Sbill */ 120549992Sbostic if (t->t_dflg & F_NOHUP) 120649992Sbostic (void) signal(SIGHUP, SIG_IGN); 120749992Sbostic if (t->t_dflg & F_NICE) 120849992Sbostic (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 120949992Sbostic } 121049992Sbostic else { 121149992Sbostic if (wanttty >= 0) 121249992Sbostic (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 121349992Sbostic palloc(pid, t); 121449992Sbostic (void) sigsetmask(omask); 121549992Sbostic } 12161302Sbill 121749992Sbostic return (pid); 12181302Sbill } 12191302Sbill 122049992Sbostic static void 12211302Sbill okpcntl() 12221302Sbill { 122349992Sbostic if (tpgrp == -1) 122449992Sbostic stderror(ERR_JOBCONTROL); 122549992Sbostic if (tpgrp == 0) 122649992Sbostic stderror(ERR_JOBCTRLSUB); 122749992Sbostic } 12281302Sbill 122949992Sbostic /* 123049992Sbostic * if we don't have vfork(), things can still go in the wrong order 123149992Sbostic * resulting in the famous 'Stopped (tty output)'. But some systems 123249992Sbostic * don't permit the setpgid() call, (these are more recent secure 123349992Sbostic * systems such as ibm's aix). Then we'd rather print an error message 123449992Sbostic * than hang the shell! 123549992Sbostic * I am open to suggestions how to fix that. 123649992Sbostic */ 123749992Sbostic void 123849992Sbostic pgetty(wanttty, pgrp) 123949992Sbostic int wanttty, pgrp; 124049992Sbostic { 124150028Sbostic sigset_t omask = 0; 124249992Sbostic 124349992Sbostic /* 124449992Sbostic * christos: I am blocking the tty signals till I've set things 124549992Sbostic * correctly.... 124649992Sbostic */ 124749992Sbostic if (wanttty > 0) 124849992Sbostic omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); 124949992Sbostic /* 125049992Sbostic * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 125149992Sbostic * Don't check for tpgrp >= 0 so even non-interactive shells give 125249992Sbostic * background jobs process groups Same for the comparison in the other part 125349992Sbostic * of the #ifdef 125449992Sbostic */ 125549992Sbostic if (wanttty >= 0) 125649992Sbostic if (setpgid(0, pgrp) == -1) { 125749992Sbostic xprintf("csh: setpgid error.\n"); 125849992Sbostic xexit(0); 125949992Sbostic } 126049992Sbostic 126149992Sbostic if (wanttty > 0) { 126249992Sbostic (void) tcsetpgrp(FSHTTY, pgrp); 126349992Sbostic (void) sigsetmask(omask); 126449992Sbostic } 126549992Sbostic 126649992Sbostic if (tpgrp > 0) 126749992Sbostic tpgrp = 0; /* gave tty away */ 12681302Sbill } 1269