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*50023Sbostic static char sccsid[] = "@(#)proc.c 5.17 (Berkeley) 06/07/91"; 1047823Sbostic #endif /* not lint */ 111302Sbill 12*50023Sbostic #include "csh.h" 13*50023Sbostic #include "dir.h" 14*50023Sbostic #include "proc.h" 15*50023Sbostic #include "extern.h" 1613590Swnj #include <sys/wait.h> 171302Sbill 181302Sbill #define BIGINDEX 9 /* largest desirable job index */ 191302Sbill 2049992Sbostic static struct rusage zru; 2149992Sbostic 2249992Sbostic static void pflushall(); 2349992Sbostic static void pflush(); 2449992Sbostic static void pclrcurr(); 2549992Sbostic static void padd(); 2649992Sbostic static int pprint(); 2749992Sbostic static void ptprint(); 2849992Sbostic static void pads(); 2949992Sbostic static void pkill(); 3049992Sbostic static struct process *pgetcurr(); 3149992Sbostic static void okpcntl(); 3249992Sbostic 331302Sbill /* 341302Sbill * pchild - called at interrupt level by the SIGCHLD signal 351302Sbill * indicating that at least one child has terminated or stopped 361302Sbill * thus at least one wait system call will definitely return a 371302Sbill * childs status. Top level routines (like pwait) must be sure 381302Sbill * to mask interrupts when playing with the proclist data structures! 391302Sbill */ 40*50023Sbostic /* ARGUSED */ 4146657Sbostic void 42*50023Sbostic pchild(notused) 43*50023Sbostic int notused; 441302Sbill { 4549992Sbostic register struct process *pp; 4649992Sbostic register struct process *fp; 4749992Sbostic register int pid; 4849992Sbostic extern int insource; 4949992Sbostic union wait w; 5049992Sbostic int jobflags; 5149992Sbostic struct rusage ru; 521302Sbill 531302Sbill loop: 5449992Sbostic errno = 0; /* reset, just in case */ 5549992Sbostic pid = wait3(&w.w_status, 5649992Sbostic (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 5749992Sbostic 5849992Sbostic if (pid <= 0) { 5949992Sbostic if (errno == EINTR) { 6049992Sbostic errno = 0; 6149992Sbostic goto loop; 621302Sbill } 6349992Sbostic pnoprocesses = pid == -1; 6449992Sbostic return; 6549992Sbostic } 6649992Sbostic for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 6749992Sbostic if (pid == pp->p_pid) 6849992Sbostic goto found; 6949992Sbostic goto loop; 701302Sbill found: 7149992Sbostic if (pid == atoi(short2str(value(STRchild)))) 7249992Sbostic unsetv(STRchild); 7349992Sbostic pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 7449992Sbostic if (WIFSTOPPED(w)) { 7549992Sbostic pp->p_flags |= PSTOPPED; 7649992Sbostic pp->p_reason = w.w_stopsig; 7749992Sbostic } 7849992Sbostic else { 7949992Sbostic if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 8049992Sbostic (void) gettimeofday(&pp->p_etime, (struct timezone *) 0); 8149992Sbostic 8249992Sbostic pp->p_rusage = ru; 8349992Sbostic if (WIFSIGNALED(w)) { 8449992Sbostic if (w.w_termsig == SIGINT) 8549992Sbostic pp->p_flags |= PINTERRUPTED; 8649992Sbostic else 8749992Sbostic pp->p_flags |= PSIGNALED; 8849992Sbostic if (w.w_coredump) 8949992Sbostic pp->p_flags |= PDUMPED; 9049992Sbostic pp->p_reason = w.w_termsig; 911302Sbill } 9249992Sbostic else { 9349992Sbostic pp->p_reason = w.w_retcode; 9449992Sbostic if (pp->p_reason != 0) 9549992Sbostic pp->p_flags |= PAEXITED; 9649992Sbostic else 9749992Sbostic pp->p_flags |= PNEXITED; 9849992Sbostic } 9949992Sbostic } 10049992Sbostic jobflags = 0; 10149992Sbostic fp = pp; 10249992Sbostic do { 10349992Sbostic if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 10449992Sbostic !child && adrof(STRtime) && 10549992Sbostic fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 10649992Sbostic >= atoi(short2str(value(STRtime)))) 10749992Sbostic fp->p_flags |= PTIME; 10849992Sbostic jobflags |= fp->p_flags; 10949992Sbostic } while ((fp = fp->p_friends) != pp); 11049992Sbostic pp->p_flags &= ~PFOREGND; 11149992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 11249992Sbostic pp->p_flags &= ~PPTIME; 11349992Sbostic pp->p_flags |= PTIME; 11449992Sbostic } 11549992Sbostic if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 1161302Sbill fp = pp; 1171302Sbill do { 11849992Sbostic if (fp->p_flags & PSTOPPED) 11949992Sbostic fp->p_flags |= PREPORTED; 1201302Sbill } while ((fp = fp->p_friends) != pp); 12149992Sbostic while (fp->p_pid != fp->p_jobid) 12249992Sbostic fp = fp->p_friends; 12349992Sbostic if (jobflags & PSTOPPED) { 12449992Sbostic if (pcurrent && pcurrent != fp) 12549992Sbostic pprevious = pcurrent; 12649992Sbostic pcurrent = fp; 1271302Sbill } 12849992Sbostic else 12949992Sbostic pclrcurr(fp); 13049992Sbostic if (jobflags & PFOREGND) { 13149992Sbostic if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 13249992Sbostic #ifdef IIASA 13349992Sbostic jobflags & PAEXITED || 13449992Sbostic #endif 13549992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) { 13649992Sbostic ; /* print in pjwait */ 13749992Sbostic } 13849992Sbostic /* PWP: print a newline after ^C */ 13949992Sbostic else if (jobflags & PINTERRUPTED) 14049992Sbostic xputchar('\r' | QUOTE), xputchar('\n'); 1411302Sbill } 14249992Sbostic else { 14349992Sbostic if (jobflags & PNOTIFY || adrof(STRnotify)) { 14449992Sbostic xputchar('\r' | QUOTE), xputchar('\n'); 14549992Sbostic (void) pprint(pp, NUMBER | NAME | REASON); 14649992Sbostic if ((jobflags & PSTOPPED) == 0) 14749992Sbostic pflush(pp); 14849992Sbostic } 14949992Sbostic else { 15049992Sbostic fp->p_flags |= PNEEDNOTE; 15149992Sbostic neednote++; 15249992Sbostic } 15349992Sbostic } 15449992Sbostic } 15549992Sbostic goto loop; 1561302Sbill } 1571302Sbill 15849992Sbostic void 1591302Sbill pnote() 1601302Sbill { 16149992Sbostic register struct process *pp; 16249992Sbostic int flags; 16349992Sbostic sigmask_t omask; 1641302Sbill 16549992Sbostic neednote = 0; 16649992Sbostic for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) { 16749992Sbostic if (pp->p_flags & PNEEDNOTE) { 16849992Sbostic omask = sigblock(sigmask(SIGCHLD)); 16949992Sbostic pp->p_flags &= ~PNEEDNOTE; 17049992Sbostic flags = pprint(pp, NUMBER | NAME | REASON); 17149992Sbostic if ((flags & (PRUNNING | PSTOPPED)) == 0) 17249992Sbostic pflush(pp); 17349992Sbostic (void) sigsetmask(omask); 1741302Sbill } 17549992Sbostic } 1761302Sbill } 1771302Sbill 1781302Sbill /* 1791302Sbill * pwait - wait for current job to terminate, maintaining integrity 1801302Sbill * of current and previous job indicators. 1811302Sbill */ 18249992Sbostic void 1831302Sbill pwait() 1841302Sbill { 18549992Sbostic register struct process *fp, *pp; 18649992Sbostic sigmask_t omask; 1871302Sbill 18849992Sbostic /* 18949992Sbostic * Here's where dead procs get flushed. 19049992Sbostic */ 19149992Sbostic omask = sigblock(sigmask(SIGCHLD)); 19249992Sbostic for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next) 19349992Sbostic if (pp->p_pid == 0) { 19449992Sbostic fp->p_next = pp->p_next; 19549992Sbostic xfree((ptr_t) pp->p_command); 19649992Sbostic if (pp->p_cwd && --pp->p_cwd->di_count == 0) 19749992Sbostic if (pp->p_cwd->di_next == 0) 19849992Sbostic dfree(pp->p_cwd); 19949992Sbostic xfree((ptr_t) pp); 20049992Sbostic pp = fp; 20149992Sbostic } 20249992Sbostic (void) sigsetmask(omask); 20349992Sbostic pjwait(pcurrjob); 2041302Sbill } 2051302Sbill 20649992Sbostic 2071302Sbill /* 2081302Sbill * pjwait - wait for a job to finish or become stopped 2091302Sbill * It is assumed to be in the foreground state (PFOREGND) 2101302Sbill */ 21149992Sbostic void 2121302Sbill pjwait(pp) 21349992Sbostic register struct process *pp; 2141302Sbill { 21549992Sbostic register struct process *fp; 21649992Sbostic int jobflags, reason; 21749992Sbostic sigmask_t omask; 2181302Sbill 21949992Sbostic while (pp->p_pid != pp->p_jobid) 22049992Sbostic pp = pp->p_friends; 22149992Sbostic fp = pp; 22249992Sbostic 22349992Sbostic do { 22449992Sbostic if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 22549992Sbostic xprintf("BUG: waiting for background job!\n"); 22649992Sbostic } while ((fp = fp->p_friends) != pp); 22749992Sbostic /* 22849992Sbostic * Now keep pausing as long as we are not interrupted (SIGINT), and the 22949992Sbostic * target process, or any of its friends, are running 23049992Sbostic */ 23149992Sbostic fp = pp; 23249992Sbostic omask = sigblock(sigmask(SIGCHLD)); 23349992Sbostic for (;;) { 23449992Sbostic (void) sigblock(sigmask(SIGCHLD)); 23549992Sbostic jobflags = 0; 23649992Sbostic do 23749992Sbostic jobflags |= fp->p_flags; 23849992Sbostic while ((fp = (fp->p_friends)) != pp); 23949992Sbostic if ((jobflags & PRUNNING) == 0) 24049992Sbostic break; 24149992Sbostic #ifdef JOBDEBUG 24249992Sbostic xprintf("starting to sigpause for SIGCHLD on %d\n", fp->p_pid); 24349992Sbostic #endif /* JOBDEBUG */ 24449992Sbostic (void) sigpause(omask & ~sigmask(SIGCHLD)); 24549992Sbostic } 24649992Sbostic (void) sigsetmask(omask); 24749992Sbostic if (tpgrp > 0) /* get tty back */ 24849992Sbostic (void) tcsetpgrp(FSHTTY, tpgrp); 24949992Sbostic if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 25049992Sbostic !eq(dcwd->di_name, fp->p_cwd->di_name)) { 25149992Sbostic if (jobflags & PSTOPPED) { 25249992Sbostic xprintf("\n"); 25349992Sbostic if (adrof(STRlistjobs)) { 25449992Sbostic Char *jobcommand[3]; 25549992Sbostic 25649992Sbostic jobcommand[0] = STRjobs; 25749992Sbostic if (eq(value(STRlistjobs), STRlong)) 25849992Sbostic jobcommand[1] = STRml; 25949992Sbostic else 26049992Sbostic jobcommand[1] = NULL; 26149992Sbostic jobcommand[2] = NULL; 26249992Sbostic 26349992Sbostic dojobs(jobcommand); 26449992Sbostic (void) pprint(pp, SHELLDIR); 26549992Sbostic } 26649992Sbostic else 26749992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 2681302Sbill } 26949992Sbostic else 27049992Sbostic (void) pprint(pp, AREASON | SHELLDIR); 27149992Sbostic } 27249992Sbostic if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 27349992Sbostic (!gointr || !eq(gointr, STRminus))) { 27449992Sbostic if ((jobflags & PSTOPPED) == 0) 27549992Sbostic pflush(pp); 27649992Sbostic pintr1(0); 27749992Sbostic /* NOTREACHED */ 27849992Sbostic } 27949992Sbostic reason = 0; 28049992Sbostic fp = pp; 28149992Sbostic do { 28249992Sbostic if (fp->p_reason) 28349992Sbostic reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 28449992Sbostic fp->p_reason | META : fp->p_reason; 28549992Sbostic } while ((fp = fp->p_friends) != pp); 28649992Sbostic if ((reason != 0) && (adrof(STRprintexitvalue))) 28749992Sbostic xprintf("Exit %d\n", reason); 28849992Sbostic set(STRstatus, putn(reason)); 28949992Sbostic if (reason && exiterr) 29049992Sbostic exitstat(); 29149992Sbostic pflush(pp); 2921302Sbill } 2931302Sbill 2941302Sbill /* 2951302Sbill * dowait - wait for all processes to finish 2961302Sbill */ 29749992Sbostic void 2981302Sbill dowait() 2991302Sbill { 30049992Sbostic register struct process *pp; 30149992Sbostic sigmask_t omask; 3021302Sbill 30349992Sbostic pjobs++; 30449992Sbostic omask = sigblock(sigmask(SIGCHLD)); 3051302Sbill loop: 30649992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 30749992Sbostic if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 30849992Sbostic pp->p_flags & PRUNNING) { 30949992Sbostic (void) sigpause((sigmask_t) 0); 31049992Sbostic goto loop; 31149992Sbostic } 31249992Sbostic (void) sigsetmask(omask); 31349992Sbostic pjobs = 0; 3141302Sbill } 3151302Sbill 3161302Sbill /* 3171302Sbill * pflushall - flush all jobs from list (e.g. at fork()) 3181302Sbill */ 31949992Sbostic static void 3201302Sbill pflushall() 3211302Sbill { 32249992Sbostic register struct process *pp; 3231302Sbill 32449992Sbostic for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 32549992Sbostic if (pp->p_pid) 32649992Sbostic pflush(pp); 3271302Sbill } 3281302Sbill 3291302Sbill /* 3301302Sbill * pflush - flag all process structures in the same job as the 3311302Sbill * the argument process for deletion. The actual free of the 3321302Sbill * space is not done here since pflush is called at interrupt level. 3331302Sbill */ 33449992Sbostic static void 3351302Sbill pflush(pp) 33649992Sbostic register struct process *pp; 3371302Sbill { 33849992Sbostic register struct process *np; 33949992Sbostic register int idx; 3401302Sbill 34149992Sbostic if (pp->p_pid == 0) { 34249992Sbostic xprintf("BUG: process flushed twice"); 34349992Sbostic return; 34449992Sbostic } 34549992Sbostic while (pp->p_pid != pp->p_jobid) 34649992Sbostic pp = pp->p_friends; 34749992Sbostic pclrcurr(pp); 34849992Sbostic if (pp == pcurrjob) 34949992Sbostic pcurrjob = 0; 35049992Sbostic idx = pp->p_index; 35149992Sbostic np = pp; 35249992Sbostic do { 35349992Sbostic np->p_index = np->p_pid = 0; 35449992Sbostic np->p_flags &= ~PNEEDNOTE; 35549992Sbostic } while ((np = np->p_friends) != pp); 35649992Sbostic if (idx == pmaxindex) { 35749992Sbostic for (np = proclist.p_next, idx = 0; np; np = np->p_next) 35849992Sbostic if (np->p_index > idx) 35949992Sbostic idx = np->p_index; 36049992Sbostic pmaxindex = idx; 36149992Sbostic } 3621302Sbill } 3631302Sbill 3641302Sbill /* 3651302Sbill * pclrcurr - make sure the given job is not the current or previous job; 3661302Sbill * pp MUST be the job leader 3671302Sbill */ 36849992Sbostic static void 3691302Sbill pclrcurr(pp) 37049992Sbostic register struct process *pp; 3711302Sbill { 3721302Sbill 37349992Sbostic if (pp == pcurrent) 37449992Sbostic if (pprevious != PNULL) { 37549992Sbostic pcurrent = pprevious; 37649992Sbostic pprevious = pgetcurr(pp); 37749992Sbostic } 37849992Sbostic else { 37949992Sbostic pcurrent = pgetcurr(pp); 38049992Sbostic pprevious = pgetcurr(pp); 38149992Sbostic } 38249992Sbostic else if (pp == pprevious) 38349992Sbostic pprevious = pgetcurr(pp); 3841302Sbill } 3851302Sbill 3861302Sbill /* +4 here is 1 for '\0', 1 ea for << >& >> */ 38749992Sbostic static Char command[PMAXLEN + 4]; 38849992Sbostic static int cmdlen; 38949992Sbostic static Char *cmdp; 39049992Sbostic 3911302Sbill /* 3921302Sbill * palloc - allocate a process structure and fill it up. 3931302Sbill * an important assumption is made that the process is running. 3941302Sbill */ 39549992Sbostic void 3961302Sbill palloc(pid, t) 39749992Sbostic int pid; 39849992Sbostic register struct command *t; 3991302Sbill { 40049992Sbostic register struct process *pp; 40149992Sbostic int i; 4021302Sbill 40349992Sbostic pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 40449992Sbostic pp->p_pid = pid; 40549992Sbostic pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 40649992Sbostic if (t->t_dflg & F_TIME) 40749992Sbostic pp->p_flags |= PPTIME; 40849992Sbostic cmdp = command; 40949992Sbostic cmdlen = 0; 41049992Sbostic padd(t); 41149992Sbostic *cmdp++ = 0; 41249992Sbostic if (t->t_dflg & F_PIPEOUT) { 41349992Sbostic pp->p_flags |= PPOU; 41449992Sbostic if (t->t_dflg & F_STDERR) 41549992Sbostic pp->p_flags |= PDIAG; 41649992Sbostic } 41749992Sbostic pp->p_command = Strsave(command); 41849992Sbostic if (pcurrjob) { 41949992Sbostic struct process *fp; 4201302Sbill 42149992Sbostic /* careful here with interrupt level */ 42249992Sbostic pp->p_cwd = 0; 42349992Sbostic pp->p_index = pcurrjob->p_index; 42449992Sbostic pp->p_friends = pcurrjob; 42549992Sbostic pp->p_jobid = pcurrjob->p_pid; 42649992Sbostic for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends); 42749992Sbostic fp->p_friends = pp; 42849992Sbostic } 42949992Sbostic else { 43049992Sbostic pcurrjob = pp; 43149992Sbostic pp->p_jobid = pid; 43249992Sbostic pp->p_friends = pp; 43349992Sbostic pp->p_cwd = dcwd; 43449992Sbostic dcwd->di_count++; 43549992Sbostic if (pmaxindex < BIGINDEX) 43649992Sbostic pp->p_index = ++pmaxindex; 43749992Sbostic else { 43849992Sbostic struct process *np; 43949992Sbostic 44049992Sbostic for (i = 1;; i++) { 44149992Sbostic for (np = proclist.p_next; np; np = np->p_next) 44249992Sbostic if (np->p_index == i) 44349992Sbostic goto tryagain; 44449992Sbostic pp->p_index = i; 44549992Sbostic if (i > pmaxindex) 44649992Sbostic pmaxindex = i; 44749992Sbostic break; 44849992Sbostic tryagain:; 44949992Sbostic } 4501302Sbill } 45149992Sbostic if (pcurrent == PNULL) 45249992Sbostic pcurrent = pp; 45349992Sbostic else if (pprevious == PNULL) 45449992Sbostic pprevious = pp; 45549992Sbostic } 45649992Sbostic pp->p_next = proclist.p_next; 45749992Sbostic proclist.p_next = pp; 45849992Sbostic (void) gettimeofday(&pp->p_btime, (struct timezone *) 0); 4591302Sbill } 4601302Sbill 46149992Sbostic static void 4621302Sbill padd(t) 46349992Sbostic register struct command *t; 4641302Sbill { 46549992Sbostic Char **argp; 4661302Sbill 46749992Sbostic if (t == 0) 46849992Sbostic return; 46949992Sbostic switch (t->t_dtyp) { 4701302Sbill 47149992Sbostic case NODE_PAREN: 47249992Sbostic pads(STRLparensp); 47349992Sbostic padd(t->t_dspr); 47449992Sbostic pads(STRspRparen); 47549992Sbostic break; 4761302Sbill 47749992Sbostic case NODE_COMMAND: 47849992Sbostic for (argp = t->t_dcom; *argp; argp++) { 47949992Sbostic pads(*argp); 48049992Sbostic if (argp[1]) 48149992Sbostic pads(STRspace); 48249992Sbostic } 48349992Sbostic break; 4841302Sbill 48549992Sbostic case NODE_OR: 48649992Sbostic case NODE_AND: 48749992Sbostic case NODE_PIPE: 48849992Sbostic case NODE_LIST: 48949992Sbostic padd(t->t_dcar); 49049992Sbostic switch (t->t_dtyp) { 49147724Sbostic case NODE_OR: 49249992Sbostic pads(STRspor2sp); 49349992Sbostic break; 49447724Sbostic case NODE_AND: 49549992Sbostic pads(STRspand2sp); 49649992Sbostic break; 49747724Sbostic case NODE_PIPE: 49849992Sbostic pads(STRsporsp); 49949992Sbostic break; 50047724Sbostic case NODE_LIST: 50149992Sbostic pads(STRsemisp); 50249992Sbostic break; 5031302Sbill } 50449992Sbostic padd(t->t_dcdr); 50549992Sbostic return; 50649992Sbostic } 50749992Sbostic if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 50849992Sbostic pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 50949992Sbostic pads(t->t_dlef); 51049992Sbostic } 51149992Sbostic if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 51249992Sbostic pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 51349992Sbostic if (t->t_dflg & F_STDERR) 51449992Sbostic pads(STRand); 51549992Sbostic pads(STRspace); 51649992Sbostic pads(t->t_drit); 51749992Sbostic } 5181302Sbill } 5191302Sbill 52049992Sbostic static void 5211302Sbill pads(cp) 52249992Sbostic Char *cp; 5231302Sbill { 52449992Sbostic register int i; 5251302Sbill 52649992Sbostic /* 52749992Sbostic * Avoid the Quoted Space alias hack! Reported by: 52849992Sbostic * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 52949992Sbostic */ 53049992Sbostic if (cp[0] == STRQNULL[0]) 53149992Sbostic cp++; 53249992Sbostic 53349992Sbostic i = Strlen(cp); 53449992Sbostic 53549992Sbostic if (cmdlen >= PMAXLEN) 53649992Sbostic return; 53749992Sbostic if (cmdlen + i >= PMAXLEN) { 53849992Sbostic (void) Strcpy(cmdp, STRsp3dots); 53949992Sbostic cmdlen = PMAXLEN; 54049992Sbostic cmdp += 4; 54149992Sbostic return; 54249992Sbostic } 54349992Sbostic (void) Strcpy(cmdp, cp); 54449992Sbostic cmdp += i; 54549992Sbostic cmdlen += i; 5461302Sbill } 5471302Sbill 5481302Sbill /* 5491302Sbill * psavejob - temporarily save the current job on a one level stack 5501302Sbill * so another job can be created. Used for { } in exp6 5511302Sbill * and `` in globbing. 5521302Sbill */ 55349992Sbostic void 5541302Sbill psavejob() 5551302Sbill { 5561302Sbill 55749992Sbostic pholdjob = pcurrjob; 55849992Sbostic pcurrjob = PNULL; 5591302Sbill } 5601302Sbill 5611302Sbill /* 5621302Sbill * prestjob - opposite of psavejob. This may be missed if we are interrupted 5631302Sbill * somewhere, but pendjob cleans up anyway. 5641302Sbill */ 56549992Sbostic void 5661302Sbill prestjob() 5671302Sbill { 5681302Sbill 56949992Sbostic pcurrjob = pholdjob; 57049992Sbostic pholdjob = PNULL; 5711302Sbill } 5721302Sbill 5731302Sbill /* 5741302Sbill * pendjob - indicate that a job (set of commands) has been completed 5751302Sbill * or is about to begin. 5761302Sbill */ 57749992Sbostic void 5781302Sbill pendjob() 5791302Sbill { 58049992Sbostic register struct process *pp, *tp; 5811302Sbill 58249992Sbostic if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 58349992Sbostic pp = pcurrjob; 58449992Sbostic while (pp->p_pid != pp->p_jobid) 58549992Sbostic pp = pp->p_friends; 58649992Sbostic xprintf("[%d]", pp->p_index); 58749992Sbostic tp = pp; 58849992Sbostic do { 58949992Sbostic xprintf(" %d", pp->p_pid); 59049992Sbostic pp = pp->p_friends; 59149992Sbostic } while (pp != tp); 59249992Sbostic xprintf("\n"); 59349992Sbostic } 59449992Sbostic pholdjob = pcurrjob = 0; 5951302Sbill } 5961302Sbill 5971302Sbill /* 5981302Sbill * pprint - print a job 5991302Sbill */ 60049992Sbostic static int 6011302Sbill pprint(pp, flag) 60249992Sbostic register struct process *pp; 60349992Sbostic bool flag; 6041302Sbill { 60549992Sbostic register status, reason; 60649992Sbostic struct process *tp; 60749992Sbostic extern char *linp, linbuf[]; 60849992Sbostic int jobflags, pstatus; 60949992Sbostic char *format; 6101302Sbill 61149992Sbostic while (pp->p_pid != pp->p_jobid) 61249992Sbostic pp = pp->p_friends; 61349992Sbostic if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 61449992Sbostic pp->p_flags &= ~PPTIME; 61549992Sbostic pp->p_flags |= PTIME; 61649992Sbostic } 61749992Sbostic tp = pp; 61849992Sbostic status = reason = -1; 61949992Sbostic jobflags = 0; 62049992Sbostic do { 62149992Sbostic jobflags |= pp->p_flags; 62249992Sbostic pstatus = pp->p_flags & PALLSTATES; 62349992Sbostic if (tp != pp && linp != linbuf && !(flag & FANCY) && 62449992Sbostic (pstatus == status && pp->p_reason == reason || 62549992Sbostic !(flag & REASON))) 62649992Sbostic xprintf(" "); 62749992Sbostic else { 62849992Sbostic if (tp != pp && linp != linbuf) 62949992Sbostic xprintf("\n"); 63049992Sbostic if (flag & NUMBER) 63149992Sbostic if (pp == tp) 63249992Sbostic xprintf("[%d]%s %c ", pp->p_index, 63349992Sbostic pp->p_index < 10 ? " " : "", 63449992Sbostic pp == pcurrent ? '+' : 63549992Sbostic (pp == pprevious ? '-' : ' ')); 63649992Sbostic else 63749992Sbostic xprintf(" "); 63849992Sbostic if (flag & FANCY) { 63949992Sbostic xprintf("%5d ", pp->p_pid); 64049992Sbostic } 64149992Sbostic if (flag & (REASON | AREASON)) { 64249992Sbostic if (flag & NAME) 64349992Sbostic format = "%-23s"; 64449992Sbostic else 64549992Sbostic format = "%s"; 64649992Sbostic if (pstatus == status) 64749992Sbostic if (pp->p_reason == reason) { 64849992Sbostic xprintf(format, ""); 64949992Sbostic goto prcomd; 65049992Sbostic } 65149992Sbostic else 65249992Sbostic reason = pp->p_reason; 6531302Sbill else { 65449992Sbostic status = pstatus; 65549992Sbostic reason = pp->p_reason; 65649992Sbostic } 65749992Sbostic switch (status) { 6581302Sbill 65949992Sbostic case PRUNNING: 66049992Sbostic xprintf(format, "Running "); 66149992Sbostic break; 6621302Sbill 66349992Sbostic case PINTERRUPTED: 66449992Sbostic case PSTOPPED: 66549992Sbostic case PSIGNALED: 66649992Sbostic if ((flag & (REASON | AREASON)) && reason != SIGINT 66749992Sbostic && reason != SIGPIPE) 66849992Sbostic xprintf(format, mesg[pp->p_reason].pname); 66949992Sbostic break; 6701302Sbill 67149992Sbostic case PNEXITED: 67249992Sbostic case PAEXITED: 67349992Sbostic if (flag & REASON) 67449992Sbostic if (pp->p_reason) 67549992Sbostic xprintf("Exit %-16d", pp->p_reason); 67649992Sbostic else 67749992Sbostic xprintf(format, "Done"); 67849992Sbostic break; 6791302Sbill 68049992Sbostic default: 68149992Sbostic xprintf("BUG: status=%-9o", status); 6821302Sbill } 68349992Sbostic } 68449992Sbostic } 6851302Sbill prcomd: 68649992Sbostic if (flag & NAME) { 68749992Sbostic xprintf("%s", short2str(pp->p_command)); 68849992Sbostic if (pp->p_flags & PPOU) 68949992Sbostic xprintf(" |"); 69049992Sbostic if (pp->p_flags & PDIAG) 69149992Sbostic xprintf("&"); 6921302Sbill } 69349992Sbostic if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 69449992Sbostic xprintf(" (core dumped)"); 69549992Sbostic if (tp == pp->p_friends) { 69649992Sbostic if (flag & AMPERSAND) 69749992Sbostic xprintf(" &"); 69849992Sbostic if (flag & JOBDIR && 69949992Sbostic !eq(tp->p_cwd->di_name, dcwd->di_name)) { 70049992Sbostic xprintf(" (wd: "); 70149992Sbostic dtildepr(value(STRhome), tp->p_cwd->di_name); 70249992Sbostic xprintf(")"); 70349992Sbostic } 70449992Sbostic } 70549992Sbostic if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 70649992Sbostic if (linp != linbuf) 70749992Sbostic xprintf("\n\t"); 70849992Sbostic prusage(&zru, &pp->p_rusage, &pp->p_etime, 70949992Sbostic &pp->p_btime); 71049992Sbostic } 71149992Sbostic if (tp == pp->p_friends) { 71249992Sbostic if (linp != linbuf) 71349992Sbostic xprintf("\n"); 71449992Sbostic if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 71549992Sbostic xprintf("(wd now: "); 71649992Sbostic dtildepr(value(STRhome), dcwd->di_name); 71749992Sbostic xprintf(")\n"); 71849992Sbostic } 71949992Sbostic } 72049992Sbostic } while ((pp = pp->p_friends) != tp); 72149992Sbostic if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 72249992Sbostic if (jobflags & NUMBER) 72349992Sbostic xprintf(" "); 72449992Sbostic ptprint(tp); 72549992Sbostic } 72649992Sbostic return (jobflags); 7271302Sbill } 7281302Sbill 72949992Sbostic static void 7301302Sbill ptprint(tp) 73149992Sbostic register struct process *tp; 7321302Sbill { 73349992Sbostic struct timeval tetime, diff; 73449992Sbostic static struct timeval ztime; 73549992Sbostic struct rusage ru; 73649992Sbostic static struct rusage zru; 73749992Sbostic register struct process *pp = tp; 7381302Sbill 73949992Sbostic ru = zru; 74049992Sbostic tetime = ztime; 74149992Sbostic do { 74249992Sbostic ruadd(&ru, &pp->p_rusage); 74349992Sbostic tvsub(&diff, &pp->p_etime, &pp->p_btime); 74449992Sbostic if (timercmp(&diff, &tetime, >)) 74549992Sbostic tetime = diff; 74649992Sbostic } while ((pp = pp->p_friends) != tp); 74749992Sbostic prusage(&zru, &ru, &tetime, &ztime); 7481302Sbill } 7491302Sbill 7501302Sbill /* 7511302Sbill * dojobs - print all jobs 7521302Sbill */ 75349992Sbostic void 7541302Sbill dojobs(v) 75549992Sbostic Char **v; 7561302Sbill { 75749992Sbostic register struct process *pp; 75849992Sbostic register int flag = NUMBER | NAME | REASON; 75949992Sbostic int i; 7601302Sbill 76149992Sbostic if (chkstop) 76249992Sbostic chkstop = 2; 76349992Sbostic if (*++v) { 76449992Sbostic if (v[1] || !eq(*v, STRml)) 76549992Sbostic stderror(ERR_JOBS); 76649992Sbostic flag |= FANCY | JOBDIR; 76749992Sbostic } 76849992Sbostic for (i = 1; i <= pmaxindex; i++) 76949992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 77049992Sbostic if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 77149992Sbostic pp->p_flags &= ~PNEEDNOTE; 77249992Sbostic if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 77349992Sbostic pflush(pp); 77449992Sbostic break; 77549992Sbostic } 7761302Sbill } 7771302Sbill 7781302Sbill /* 7791302Sbill * dofg - builtin - put the job into the foreground 7801302Sbill */ 78149992Sbostic void 7821302Sbill dofg(v) 78349992Sbostic Char **v; 7841302Sbill { 78549992Sbostic register struct process *pp; 7861302Sbill 78749992Sbostic okpcntl(); 78849992Sbostic ++v; 78949992Sbostic do { 79049992Sbostic pp = pfind(*v); 79149992Sbostic pstart(pp, 1); 79249992Sbostic pjwait(pp); 79349992Sbostic } while (*v && *++v); 7941302Sbill } 7951302Sbill 7961302Sbill /* 7971302Sbill * %... - builtin - put the job into the foreground 7981302Sbill */ 79949992Sbostic void 8001302Sbill dofg1(v) 80149992Sbostic Char **v; 8021302Sbill { 80349992Sbostic register struct process *pp; 8041302Sbill 80549992Sbostic okpcntl(); 80649992Sbostic pp = pfind(v[0]); 80749992Sbostic pstart(pp, 1); 80849992Sbostic pjwait(pp); 8091302Sbill } 8101302Sbill 8111302Sbill /* 8121302Sbill * dobg - builtin - put the job into the background 8131302Sbill */ 81449992Sbostic void 8151302Sbill dobg(v) 81649992Sbostic Char **v; 8171302Sbill { 81849992Sbostic register struct process *pp; 8191302Sbill 82049992Sbostic okpcntl(); 82149992Sbostic ++v; 82249992Sbostic do { 82349992Sbostic pp = pfind(*v); 82449992Sbostic pstart(pp, 0); 82549992Sbostic } while (*v && *++v); 8261302Sbill } 8271302Sbill 8281302Sbill /* 8291302Sbill * %... & - builtin - put the job into the background 8301302Sbill */ 83149992Sbostic void 8321302Sbill dobg1(v) 83349992Sbostic Char **v; 8341302Sbill { 83549992Sbostic register struct process *pp; 8361302Sbill 83749992Sbostic pp = pfind(v[0]); 83849992Sbostic pstart(pp, 0); 8391302Sbill } 8401302Sbill 8411302Sbill /* 8421302Sbill * dostop - builtin - stop the job 8431302Sbill */ 84449992Sbostic void 8451302Sbill dostop(v) 84649992Sbostic Char **v; 8471302Sbill { 84849992Sbostic pkill(++v, SIGSTOP); 8491302Sbill } 8501302Sbill 8511302Sbill /* 8521302Sbill * dokill - builtin - superset of kill (1) 8531302Sbill */ 85449992Sbostic void 8551302Sbill dokill(v) 85649992Sbostic Char **v; 8571302Sbill { 85849992Sbostic register int signum, len = 0; 85949992Sbostic register char *name; 8601302Sbill 86149992Sbostic v++; 86249992Sbostic if (v[0] && v[0][0] == '-') { 86349992Sbostic if (v[0][1] == 'l') { 86449992Sbostic for (signum = 1; signum <= NSIG; signum++) { 86549992Sbostic if ((name = mesg[signum].iname) != NULL) { 86649992Sbostic len += strlen(name) + 1; 86749992Sbostic if (len >= 80 - 1) { 86849992Sbostic xprintf("\n"); 86949992Sbostic len = strlen(name) + 1; 87049992Sbostic } 87149992Sbostic xprintf("%s ", name); 8721302Sbill } 87349992Sbostic } 87449992Sbostic xprintf("\n"); 87549992Sbostic return; 87649992Sbostic } 87749992Sbostic if (Isdigit(v[0][1])) { 87849992Sbostic signum = atoi(short2str(v[0] + 1)); 87949992Sbostic if (signum < 0 || signum > NSIG) 88049992Sbostic stderror(ERR_NAME | ERR_BADSIG); 88149992Sbostic } 88249992Sbostic else { 88349992Sbostic for (signum = 1; signum <= NSIG; signum++) 88449992Sbostic if (mesg[signum].iname && 88549992Sbostic eq(&v[0][1], str2short(mesg[signum].iname))) 88649992Sbostic goto gotsig; 88749992Sbostic setname(short2str(&v[0][1])); 88849992Sbostic stderror(ERR_NAME | ERR_UNKSIG); 88949992Sbostic } 8901302Sbill gotsig: 89149992Sbostic v++; 89249992Sbostic } 89349992Sbostic else 89449992Sbostic signum = SIGTERM; 89549992Sbostic pkill(v, signum); 8961302Sbill } 8971302Sbill 89849992Sbostic static void 8991302Sbill pkill(v, signum) 90049992Sbostic Char **v; 90149992Sbostic int signum; 9021302Sbill { 90349992Sbostic register struct process *pp, *np; 90449992Sbostic register int jobflags = 0; 90549992Sbostic int pid, err1 = 0; 90649992Sbostic sigmask_t omask; 90749992Sbostic Char *cp; 9081302Sbill 90949992Sbostic omask = sigmask(SIGCHLD); 91049992Sbostic if (setintr) 91149992Sbostic omask |= sigmask(SIGINT); 91249992Sbostic omask = sigblock(omask) & ~omask; 91349992Sbostic gflag = 0, tglob(v); 91449992Sbostic if (gflag) { 91549992Sbostic v = globall(v); 91649992Sbostic if (v == 0) 91749992Sbostic stderror(ERR_NAME | ERR_NOMATCH); 91849992Sbostic } 91949992Sbostic else { 92049992Sbostic v = gargv = saveblk(v); 92149992Sbostic trim(v); 92249992Sbostic } 9231302Sbill 92449992Sbostic while (v && (cp = *v)) { 92549992Sbostic if (*cp == '%') { 92649992Sbostic np = pp = pfind(cp); 92749992Sbostic do 92849992Sbostic jobflags |= np->p_flags; 92949992Sbostic while ((np = np->p_friends) != pp); 93049992Sbostic switch (signum) { 93149992Sbostic 93249992Sbostic case SIGSTOP: 93349992Sbostic case SIGTSTP: 93449992Sbostic case SIGTTIN: 93549992Sbostic case SIGTTOU: 93649992Sbostic if ((jobflags & PRUNNING) == 0) { 93749992Sbostic xprintf("%s: Already suspended\n", short2str(cp)); 93849992Sbostic err1++; 93949992Sbostic goto cont; 9401302Sbill } 94149992Sbostic break; 94249992Sbostic /* 94349992Sbostic * suspend a process, kill -CONT %, then type jobs; the shell 94449992Sbostic * says it is suspended, but it is running; thanks jaap.. 94549992Sbostic */ 94649992Sbostic case SIGCONT: 94749992Sbostic pstart(pp, 0); 94849992Sbostic goto cont; 94949992Sbostic } 95049992Sbostic if (killpg((pid_t) pp->p_jobid, signum) < 0) { 95149992Sbostic xprintf("%s: %s\n", short2str(cp), strerror(errno)); 95249992Sbostic err1++; 95349992Sbostic } 95449992Sbostic if (signum == SIGTERM || signum == SIGHUP) 95549992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 95649992Sbostic } 95749992Sbostic else if (!(Isdigit(*cp) || *cp == '-')) 95849992Sbostic stderror(ERR_NAME | ERR_JOBARGS); 95949992Sbostic else { 96049992Sbostic pid = atoi(short2str(cp)); 96149992Sbostic if (kill((pid_t) pid, signum) < 0) { 96249992Sbostic xprintf("%d: %s\n", pid, strerror(errno)); 96349992Sbostic err1++; 96449992Sbostic goto cont; 96549992Sbostic } 96649992Sbostic if (signum == SIGTERM || signum == SIGHUP) 96749992Sbostic (void) kill((pid_t) pid, SIGCONT); 96849992Sbostic } 9691302Sbill cont: 97049992Sbostic v++; 97149992Sbostic } 97249992Sbostic if (gargv) 97349992Sbostic blkfree(gargv), gargv = 0; 97449992Sbostic (void) sigsetmask(omask); 97549992Sbostic if (err1) 97649992Sbostic stderror(ERR_SILENT); 9771302Sbill } 9781302Sbill 9791302Sbill /* 9801302Sbill * pstart - start the job in foreground/background 9811302Sbill */ 98249992Sbostic void 9831302Sbill pstart(pp, foregnd) 98449992Sbostic register struct process *pp; 98549992Sbostic int foregnd; 9861302Sbill { 98749992Sbostic register struct process *np; 98849992Sbostic sigmask_t omask; 98949992Sbostic long jobflags = 0; 9901302Sbill 99149992Sbostic omask = sigblock(sigmask(SIGCHLD)); 99249992Sbostic np = pp; 99349992Sbostic do { 99449992Sbostic jobflags |= np->p_flags; 99549992Sbostic if (np->p_flags & (PRUNNING | PSTOPPED)) { 99649992Sbostic np->p_flags |= PRUNNING; 99749992Sbostic np->p_flags &= ~PSTOPPED; 99849992Sbostic if (foregnd) 99949992Sbostic np->p_flags |= PFOREGND; 100049992Sbostic else 100149992Sbostic np->p_flags &= ~PFOREGND; 100249992Sbostic } 100349992Sbostic } while ((np = np->p_friends) != pp); 100449992Sbostic if (!foregnd) 100549992Sbostic pclrcurr(pp); 100649992Sbostic (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 100749992Sbostic if (foregnd) 100849992Sbostic (void) tcsetpgrp(FSHTTY, pp->p_jobid); 100949992Sbostic if (jobflags & PSTOPPED) 101049992Sbostic (void) killpg((pid_t) pp->p_jobid, SIGCONT); 101149992Sbostic (void) sigsetmask(omask); 10121302Sbill } 10131302Sbill 101449992Sbostic void 10151302Sbill panystop(neednl) 101649992Sbostic bool neednl; 10171302Sbill { 101849992Sbostic register struct process *pp; 10191302Sbill 102049992Sbostic chkstop = 2; 102149992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 102249992Sbostic if (pp->p_flags & PSTOPPED) 102349992Sbostic stderror(ERR_STOPPED, neednl ? "\n" : ""); 10241302Sbill } 10251302Sbill 10261302Sbill struct process * 10271302Sbill pfind(cp) 102849992Sbostic Char *cp; 10291302Sbill { 103049992Sbostic register struct process *pp, *np; 10311302Sbill 103249992Sbostic if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 103349992Sbostic if (pcurrent == PNULL) 103449992Sbostic stderror(ERR_NAME | ERR_JOBCUR); 103549992Sbostic return (pcurrent); 103649992Sbostic } 103749992Sbostic if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 103849992Sbostic if (pprevious == PNULL) 103949992Sbostic stderror(ERR_NAME | ERR_JOBPREV); 104049992Sbostic return (pprevious); 104149992Sbostic } 104249992Sbostic if (Isdigit(cp[1])) { 104349992Sbostic int idx = atoi(short2str(cp + 1)); 104449992Sbostic 10451302Sbill for (pp = proclist.p_next; pp; pp = pp->p_next) 104649992Sbostic if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 104749992Sbostic return (pp); 104849992Sbostic stderror(ERR_NAME | ERR_NOSUCHJOB); 104949992Sbostic } 105049992Sbostic np = PNULL; 105149992Sbostic for (pp = proclist.p_next; pp; pp = pp->p_next) 105249992Sbostic if (pp->p_pid == pp->p_jobid) { 105349992Sbostic if (cp[1] == '?') { 105449992Sbostic register Char *dp; 105549992Sbostic 105649992Sbostic for (dp = pp->p_command; *dp; dp++) { 105749992Sbostic if (*dp != cp[2]) 105849992Sbostic continue; 105949992Sbostic if (prefix(cp + 2, dp)) 106049992Sbostic goto match; 10611302Sbill } 106249992Sbostic } 106349992Sbostic else if (prefix(cp + 1, pp->p_command)) { 106449992Sbostic match: 106549992Sbostic if (np) 106649992Sbostic stderror(ERR_NAME | ERR_AMBIG); 106749992Sbostic np = pp; 106849992Sbostic } 106949992Sbostic } 107049992Sbostic if (np) 107149992Sbostic return (np); 107249992Sbostic stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB); 107349992Sbostic /* NOTREACHED */ 107449992Sbostic return (0); 10751302Sbill } 10761302Sbill 107749992Sbostic 10781302Sbill /* 10792357Swnj * pgetcurr - find most recent job that is not pp, preferably stopped 10801302Sbill */ 108149992Sbostic static struct process * 10821302Sbill pgetcurr(pp) 108349992Sbostic register struct process *pp; 10841302Sbill { 108549992Sbostic register struct process *np; 108649992Sbostic register struct process *xp = PNULL; 10871302Sbill 108849992Sbostic for (np = proclist.p_next; np; np = np->p_next) 108949992Sbostic if (np != pcurrent && np != pp && np->p_pid && 109049992Sbostic np->p_pid == np->p_jobid) { 109149992Sbostic if (np->p_flags & PSTOPPED) 109249992Sbostic return (np); 109349992Sbostic if (xp == PNULL) 109449992Sbostic xp = np; 109549992Sbostic } 109649992Sbostic return (xp); 10971302Sbill } 10981302Sbill 10991302Sbill /* 11001302Sbill * donotify - flag the job so as to report termination asynchronously 11011302Sbill */ 110249992Sbostic void 11031302Sbill donotify(v) 110449992Sbostic Char **v; 11051302Sbill { 110649992Sbostic register struct process *pp; 11071302Sbill 110849992Sbostic pp = pfind(*++v); 110949992Sbostic pp->p_flags |= PNOTIFY; 11101302Sbill } 11111302Sbill 11121302Sbill /* 11131302Sbill * Do the fork and whatever should be done in the child side that 11141302Sbill * should not be done if we are not forking at all (like for simple builtin's) 11151302Sbill * Also do everything that needs any signals fiddled with in the parent side 11161302Sbill * 11171302Sbill * Wanttty tells whether process and/or tty pgrps are to be manipulated: 11181302Sbill * -1: leave tty alone; inherit pgrp from parent 11191302Sbill * 0: already have tty; manipulate process pgrps only 11201302Sbill * 1: want to claim tty; manipulate process and tty pgrps 11211302Sbill * It is usually just the value of tpgrp. 11221302Sbill */ 112349992Sbostic 112449992Sbostic int 11251302Sbill pfork(t, wanttty) 112649992Sbostic struct command *t; /* command we are forking for */ 112749992Sbostic int wanttty; 11281302Sbill { 112949992Sbostic register int pid; 113049992Sbostic bool ignint = 0; 113149992Sbostic int pgrp; 113249992Sbostic sigmask_t omask; 11331302Sbill 113449992Sbostic /* 113549992Sbostic * A child will be uninterruptible only under very special conditions. 113649992Sbostic * Remember that the semantics of '&' is implemented by disconnecting the 113749992Sbostic * process from the tty so signals do not need to ignored just for '&'. 113849992Sbostic * Thus signals are set to default action for children unless: we have had 113949992Sbostic * an "onintr -" (then specifically ignored) we are not playing with 114049992Sbostic * signals (inherit action) 114149992Sbostic */ 114249992Sbostic if (setintr) 114349992Sbostic ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 114449992Sbostic || (gointr && eq(gointr, STRminus)); 114549992Sbostic /* 114649992Sbostic * Check for maximum nesting of 16 processes to avoid Forking loops 114749992Sbostic */ 114849992Sbostic if (child == 16) 114949992Sbostic stderror(ERR_NESTING, 16); 115049992Sbostic /* 115149992Sbostic * Hold SIGCHLD until we have the process installed in our table. 115249992Sbostic */ 115349992Sbostic omask = sigblock(sigmask(SIGCHLD)); 115449992Sbostic while ((pid = fork()) < 0) 115549992Sbostic if (setintr == 0) 115649992Sbostic (void) sleep(FORKSLEEP); 115749992Sbostic else { 115849992Sbostic (void) sigsetmask(omask); 115949992Sbostic stderror(ERR_NOPROC); 116049992Sbostic } 116149992Sbostic if (pid == 0) { 116249992Sbostic settimes(); 116349992Sbostic pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 116449992Sbostic pflushall(); 116549992Sbostic pcurrjob = PNULL; 116649992Sbostic child++; 116749992Sbostic if (setintr) { 116849992Sbostic setintr = 0; /* until I think otherwise */ 116949992Sbostic /* 117049992Sbostic * Children just get blown away on SIGINT, SIGQUIT unless "onintr 117149992Sbostic * -" seen. 117249992Sbostic */ 117349992Sbostic (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 117449992Sbostic (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 117549992Sbostic if (wanttty >= 0) { 117649992Sbostic /* make stoppable */ 117749992Sbostic (void) signal(SIGTSTP, SIG_DFL); 117849992Sbostic (void) signal(SIGTTIN, SIG_DFL); 117949992Sbostic (void) signal(SIGTTOU, SIG_DFL); 118049992Sbostic } 118149992Sbostic (void) signal(SIGTERM, parterm); 118249992Sbostic } 118349992Sbostic else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 118449992Sbostic (void) signal(SIGINT, SIG_IGN); 118549992Sbostic (void) signal(SIGQUIT, SIG_IGN); 118649992Sbostic } 118749992Sbostic pgetty(wanttty, pgrp); 11881302Sbill /* 118949992Sbostic * Nohup and nice apply only to NODE_COMMAND's but it would be nice 119049992Sbostic * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 119149992Sbostic * to know about nice/nohup/time 11921302Sbill */ 119349992Sbostic if (t->t_dflg & F_NOHUP) 119449992Sbostic (void) signal(SIGHUP, SIG_IGN); 119549992Sbostic if (t->t_dflg & F_NICE) 119649992Sbostic (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 119749992Sbostic } 119849992Sbostic else { 119949992Sbostic if (wanttty >= 0) 120049992Sbostic (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 120149992Sbostic palloc(pid, t); 120249992Sbostic (void) sigsetmask(omask); 120349992Sbostic } 12041302Sbill 120549992Sbostic return (pid); 12061302Sbill } 12071302Sbill 120849992Sbostic static void 12091302Sbill okpcntl() 12101302Sbill { 121149992Sbostic if (tpgrp == -1) 121249992Sbostic stderror(ERR_JOBCONTROL); 121349992Sbostic if (tpgrp == 0) 121449992Sbostic stderror(ERR_JOBCTRLSUB); 121549992Sbostic } 12161302Sbill 121749992Sbostic /* 121849992Sbostic * if we don't have vfork(), things can still go in the wrong order 121949992Sbostic * resulting in the famous 'Stopped (tty output)'. But some systems 122049992Sbostic * don't permit the setpgid() call, (these are more recent secure 122149992Sbostic * systems such as ibm's aix). Then we'd rather print an error message 122249992Sbostic * than hang the shell! 122349992Sbostic * I am open to suggestions how to fix that. 122449992Sbostic */ 122549992Sbostic void 122649992Sbostic pgetty(wanttty, pgrp) 122749992Sbostic int wanttty, pgrp; 122849992Sbostic { 122949992Sbostic sigmask_t omask = 0; 123049992Sbostic 123149992Sbostic /* 123249992Sbostic * christos: I am blocking the tty signals till I've set things 123349992Sbostic * correctly.... 123449992Sbostic */ 123549992Sbostic if (wanttty > 0) 123649992Sbostic omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); 123749992Sbostic /* 123849992Sbostic * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 123949992Sbostic * Don't check for tpgrp >= 0 so even non-interactive shells give 124049992Sbostic * background jobs process groups Same for the comparison in the other part 124149992Sbostic * of the #ifdef 124249992Sbostic */ 124349992Sbostic if (wanttty >= 0) 124449992Sbostic if (setpgid(0, pgrp) == -1) { 124549992Sbostic xprintf("csh: setpgid error.\n"); 124649992Sbostic xexit(0); 124749992Sbostic } 124849992Sbostic 124949992Sbostic if (wanttty > 0) { 125049992Sbostic (void) tcsetpgrp(FSHTTY, pgrp); 125149992Sbostic (void) sigsetmask(omask); 125249992Sbostic } 125349992Sbostic 125449992Sbostic if (tpgrp > 0) 125549992Sbostic tpgrp = 0; /* gave tty away */ 12561302Sbill } 1257