home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / jobs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  21.8 KB  |  1,017 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)jobs.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. #include "shell.h"
  42. #if JOBS
  43. #include "sgtty.h"
  44. #undef CEOF            /* syntax.h redefines this */
  45. #endif
  46. #include "main.h"
  47. #include "parser.h"
  48. #include "nodes.h"
  49. #include "jobs.h"
  50. #include "options.h"
  51. #include "trap.h"
  52. #include "signames.h"
  53. #include "syntax.h"
  54. #include "input.h"
  55. #include "output.h"
  56. #include "memalloc.h"
  57. #include "error.h"
  58. #include "mystring.h"
  59. #include <fcntl.h>
  60. #include <signal.h>
  61. #include <errno.h>
  62. #ifdef BSD
  63. #include <sys/types.h>
  64. #include <sys/wait.h>
  65. #include <sys/time.h>
  66. #include <sys/resource.h>
  67. #endif
  68.  
  69.  
  70.  
  71. struct job *jobtab;        /* array of jobs */
  72. int njobs;            /* size of array */
  73. MKINIT short backgndpid = -1;    /* pid of last background process */
  74. #if JOBS
  75. int initialpgrp;        /* pgrp of shell on invocation */
  76. short curjob;            /* current job */
  77. #endif
  78.  
  79. #ifdef __STDC__
  80. STATIC void restartjob(struct job *);
  81. STATIC struct job *getjob(char *);
  82. STATIC void freejob(struct job *);
  83. STATIC int procrunning(int);
  84. STATIC int dowait(int, struct job *);
  85. STATIC int waitproc(int, int *);
  86. STATIC char *commandtext(union node *);
  87. #else
  88. STATIC void restartjob();
  89. STATIC struct job *getjob();
  90. STATIC void freejob();
  91. STATIC int procrunning();
  92. STATIC int dowait();
  93. STATIC int waitproc();
  94. STATIC char *commandtext();
  95. #endif
  96.  
  97.  
  98.  
  99. #if JOBS
  100. /*
  101.  * Turn job control on and off.
  102.  *
  103.  * Note:  This code assumes that the third arg to ioctl is a character
  104.  * pointer, which is true on Berkeley systems but not System V.  Since
  105.  * System V doesn't have job control yet, this isn't a problem now.
  106.  */
  107.  
  108. MKINIT int jobctl;
  109.  
  110. void
  111. setjobctl(on) {
  112.     int ldisc;
  113.  
  114.     if (on == jobctl || rootshell == 0)
  115.         return;
  116.     if (on) {
  117.         do { /* while we are in the background */
  118.             if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
  119.                 out2str("ash: can't access tty; job control turned off\n");
  120.                 jflag = 0;
  121.                 return;
  122.             }
  123.             if (initialpgrp == -1)
  124.                 initialpgrp = getpgrp(0);
  125.             else if (initialpgrp != getpgrp(0)) {
  126.                 killpg(initialpgrp, SIGTTIN);
  127.                 continue;
  128.             }
  129.         } while (0);
  130.         if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
  131.             out2str("ash: need new tty driver to run job control; job control turned off\n");
  132.             jflag = 0;
  133.             return;
  134.         }
  135.         setsignal(SIGTSTP);
  136.         setsignal(SIGTTOU);
  137.         setpgrp(0, rootpid);
  138.         ioctl(2, TIOCSPGRP, (char *)&rootpid);
  139.     } else { /* turning job control off */
  140.         setpgrp(0, initialpgrp);
  141.         ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
  142.         setsignal(SIGTSTP);
  143.         setsignal(SIGTTOU);
  144.     }
  145.     jobctl = on;
  146. }
  147. #endif
  148.  
  149.  
  150. #ifdef mkinit
  151.  
  152. SHELLPROC {
  153.     backgndpid = -1;
  154. #if JOBS
  155.     jobctl = 0;
  156. #endif
  157. }
  158.  
  159. #endif
  160.  
  161.  
  162.  
  163. #if JOBS
  164. fgcmd(argc, argv)  char **argv; {
  165.     struct job *jp;
  166.     int pgrp;
  167.     int status;
  168.  
  169.     jp = getjob(argv[1]);
  170.     if (jp->jobctl == 0)
  171.         error("job not created under job control");
  172.     pgrp = jp->ps[0].pid;
  173.     ioctl(2, TIOCSPGRP, (char *)&pgrp);
  174.     restartjob(jp);
  175.     INTOFF;
  176.     status = waitforjob(jp);
  177.     INTON;
  178.     return status;
  179. }
  180.  
  181.  
  182. bgcmd(argc, argv)  char **argv; {
  183.     struct job *jp;
  184.  
  185.     do {
  186.         jp = getjob(*++argv);
  187.         if (jp->jobctl == 0)
  188.             error("job not created under job control");
  189.         restartjob(jp);
  190.     } while (--argc > 1);
  191.     return 0;
  192. }
  193.  
  194.  
  195. STATIC void
  196. restartjob(jp)
  197.     struct job *jp;
  198.     {
  199.     struct procstat *ps;
  200.     int i;
  201.  
  202.     if (jp->state == JOBDONE)
  203.         return;
  204.     INTOFF;
  205.     killpg(jp->ps[0].pid, SIGCONT);
  206.     for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
  207.         if ((ps->status & 0377) == 0177) {
  208.             ps->status = -1;
  209.             jp->state = 0;
  210.         }
  211.     }
  212.     INTON;
  213. }
  214. #endif
  215.  
  216.  
  217. int
  218. jobscmd(argc, argv)  char **argv; {
  219.     showjobs(0);
  220.     return 0;
  221. }
  222.  
  223.  
  224. /*
  225.  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
  226.  * statuses have changed since the last call to showjobs.
  227.  *
  228.  * If the shell is interrupted in the process of creating a job, the
  229.  * result may be a job structure containing zero processes.  Such structures
  230.  * will be freed here.
  231.  */
  232.  
  233. void
  234. showjobs(change) {
  235.     int jobno;
  236.     int procno;
  237.     int i;
  238.     struct job *jp;
  239.     struct procstat *ps;
  240.     int col;
  241.     char s[64];
  242.  
  243.     TRACE(("showjobs(%d) called\n", change));
  244.     while (dowait(0, (struct job *)NULL) > 0);
  245.     for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
  246.         if (! jp->used)
  247.             continue;
  248.         if (jp->nprocs == 0) {
  249.             freejob(jp);
  250.             continue;
  251.         }
  252.         if (change && ! jp->changed)
  253.             continue;
  254.         procno = jp->nprocs;
  255.         for (ps = jp->ps ; ; ps++) {    /* for each process */
  256.             if (ps == jp->ps)
  257.                 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
  258.             else
  259.                 fmtstr(s, 64, "    %d ", ps->pid);
  260.             out1str(s);
  261.             col = strlen(s);
  262.             s[0] = '\0';
  263.             if (ps->status == -1) {
  264.                 /* don't print anything */
  265.             } else if ((ps->status & 0xFF) == 0) {
  266.                 fmtstr(s, 64, "Exit %d", ps->status >> 8);
  267.             } else {
  268.                 i = ps->status;
  269. #if JOBS
  270.                 if ((i & 0xFF) == 0177)
  271.                     i >>= 8;
  272. #endif
  273.                 if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
  274.                     scopy(sigmesg[i & 0x7F], s);
  275.                 else
  276.                     fmtstr(s, 64, "Signal %d", i & 0x7F);
  277.                 if (i & 0x80)
  278.                     strcat(s, " (core dumped)");
  279.             }
  280.             out1str(s);
  281.             col += strlen(s);
  282.             do {
  283.                 out1c(' ');
  284.                 col++;
  285.             } while (col < 30);
  286.             out1str(ps->cmd);
  287.             out1c('\n');
  288.             if (--procno <= 0)
  289.                 break;
  290.         }
  291.         jp->changed = 0;
  292.         if (jp->state == JOBDONE) {
  293.             freejob(jp);
  294.         }
  295.     }
  296. }
  297.  
  298.  
  299. /*
  300.  * Mark a job structure as unused.
  301.  */
  302.  
  303. STATIC void
  304. freejob(jp)
  305.     struct job *jp;
  306.     {
  307.     struct procstat *ps;
  308.     int i;
  309.  
  310.     INTOFF;
  311.     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
  312.         if (ps->cmd != nullstr)
  313.             ckfree(ps->cmd);
  314.     }
  315.     if (jp->ps != &jp->ps0)
  316.         ckfree(jp->ps);
  317.     jp->used = 0;
  318. #if JOBS
  319.     if (curjob == jp - jobtab + 1)
  320.         curjob = 0;
  321. #endif
  322.     INTON;
  323. }
  324.  
  325.  
  326.  
  327. int
  328. waitcmd(argc, argv)  char **argv; {
  329.     struct job *job;
  330.     int status;
  331.     struct job *jp;
  332.  
  333.     if (argc > 1) {
  334.         job = getjob(argv[1]);
  335.     } else {
  336.         job = NULL;
  337.     }
  338.     for (;;) {    /* loop until process terminated or stopped */
  339.         if (job != NULL) {
  340.             if (job->state) {
  341.                 status = job->ps[job->nprocs - 1].status;
  342.                 if ((status & 0xFF) == 0)
  343.                     status = status >> 8 & 0xFF;
  344. #if JOBS
  345.                 else if ((status & 0xFF) == 0177)
  346.                     status = (status >> 8 & 0x7F) + 128;
  347. #endif
  348.                 else
  349.                     status = (status & 0x7F) + 128;
  350.                 if (! iflag)
  351.                     freejob(job);
  352.                 return status;
  353.             }
  354.         } else {
  355.             for (jp = jobtab ; ; jp++) {
  356.                 if (jp >= jobtab + njobs) {    /* no running procs */
  357.                     return 0;
  358.                 }
  359.                 if (jp->used && jp->state == 0)
  360.                     break;
  361.             }
  362.         }
  363.         dowait(1, (struct job *)NULL);
  364.     }
  365. }
  366.  
  367.  
  368.  
  369. jobidcmd(argc, argv)  char **argv; {
  370.     struct job *jp;
  371.     int i;
  372.  
  373.     jp = getjob(argv[1]);
  374.     for (i = 0 ; i < jp->nprocs ; ) {
  375.         out1fmt("%d", jp->ps[i].pid);
  376.         out1c(++i < jp->nprocs? ' ' : '\n');
  377.     }
  378.     return 0;
  379. }
  380.  
  381.  
  382.  
  383. /*
  384.  * Convert a job name to a job structure.
  385.  */
  386.  
  387. STATIC struct job *
  388. getjob(name)
  389.     char *name;
  390.     {
  391.     int jobno;
  392.     register struct job *jp;
  393.     int pid;
  394.     int i;
  395.  
  396.     if (name == NULL) {
  397. #if JOBS
  398. currentjob:
  399.         if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
  400.             error("No current job");
  401.         return &jobtab[jobno - 1];
  402. #else
  403.         error("No current job");
  404. #endif
  405.     } else if (name[0] == '%') {
  406.         if (is_digit(name[1])) {
  407.             jobno = number(name + 1);
  408.             if (jobno > 0 && jobno <= njobs
  409.              && jobtab[jobno - 1].used != 0)
  410.                 return &jobtab[jobno - 1];
  411. #if JOBS
  412.         } else if (name[1] == '%' && name[2] == '\0') {
  413.             goto currentjob;
  414. #endif
  415.         } else {
  416.             register struct job *found = NULL;
  417.             for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  418.                 if (jp->used && jp->nprocs > 0
  419.                  && prefix(name + 1, jp->ps[0].cmd)) {
  420.                     if (found)
  421.                         error("%s: ambiguous", name);
  422.                     found = jp;
  423.                 }
  424.             }
  425.             if (found)
  426.                 return found;
  427.         }
  428.     } else if (is_number(name)) {
  429.         pid = number(name);
  430.         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  431.             if (jp->used && jp->nprocs > 0
  432.              && jp->ps[jp->nprocs - 1].pid == pid)
  433.                 return jp;
  434.         }
  435.     }
  436.     error("No such job: %s", name);
  437. }
  438.  
  439.  
  440.  
  441. /*
  442.  * Return a new job structure,
  443.  */
  444.  
  445. struct job *
  446. makejob(node, nprocs)
  447.     union node *node;
  448.     {
  449.     int i;
  450.     struct job *jp;
  451.  
  452.     for (i = njobs, jp = jobtab ; ; jp++) {
  453.         if (--i < 0) {
  454.             INTOFF;
  455.             if (njobs == 0) {
  456.                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
  457.             } else {
  458.                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
  459.                 bcopy(jobtab, jp, njobs * sizeof jp[0]);
  460.                 ckfree(jobtab);
  461.                 jobtab = jp;
  462.             }
  463.             jp = jobtab + njobs;
  464.             for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
  465.             INTON;
  466.             break;
  467.         }
  468.         if (jp->used == 0)
  469.             break;
  470.     }
  471.     INTOFF;
  472.     jp->state = 0;
  473.     jp->used = 1;
  474.     jp->changed = 0;
  475.     jp->nprocs = 0;
  476. #if JOBS
  477.     jp->jobctl = jobctl;
  478. #endif
  479.     if (nprocs > 1) {
  480.         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
  481.     } else {
  482.         jp->ps = &jp->ps0;
  483.     }
  484.     INTON;
  485.     TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
  486.     return jp;
  487. }    
  488.  
  489.  
  490. /*
  491.  * Fork of a subshell.  If we are doing job control, give the subshell its
  492.  * own process group.  Jp is a job structure that the job is to be added to.
  493.  * N is the command that will be evaluated by the child.  Both jp and n may
  494.  * be NULL.  The mode parameter can be one of the following:
  495.  *    FORK_FG - Fork off a foreground process.
  496.  *    FORK_BG - Fork off a background process.
  497.  *    FORK_NOJOB - Like FORK_FG, but don't give the process its own
  498.  *             process group even if job control is on.
  499.  *
  500.  * When job control is turned off, background processes have their standard
  501.  * input redirected to /dev/null (except for the second and later processes
  502.  * in a pipeline).
  503.  */
  504.  
  505. int
  506. forkshell(jp, n, mode)
  507.     union node *n;
  508.     struct job *jp;
  509.     {
  510.     int pid;
  511.     int pgrp;
  512.  
  513.     TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
  514.     INTOFF;
  515.     pid = fork();
  516.     if (pid == -1) {
  517.         TRACE(("Fork failed, errno=%d\n", errno));
  518.         INTON;
  519.         error("Cannot fork");
  520.     }
  521.     if (pid == 0) {
  522.         struct job *p;
  523.         int wasroot;
  524.         int i;
  525.  
  526.         TRACE(("Child shell %d\n", getpid()));
  527.         wasroot = rootshell;
  528.         rootshell = 0;
  529.         for (i = njobs, p = jobtab ; --i >= 0 ; p++)
  530.             if (p->used)
  531.                 freejob(p);
  532.         closescript();
  533.         INTON;
  534.         clear_traps();
  535. #if JOBS
  536.         jobctl = 0;        /* do job control only in root shell */
  537.         if (wasroot && mode != FORK_NOJOB && jflag) {
  538.             if (jp == NULL || jp->nprocs == 0)
  539.                 pgrp = getpid();
  540.             else
  541.                 pgrp = jp->ps[0].pid;
  542.             setpgrp(0, pgrp);
  543.             if (mode == FORK_FG) {
  544.                 /*** this causes superfluous TIOCSPGRPS ***/
  545.                 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
  546.                     error("TIOCSPGRP failed, errno=%d\n", errno);
  547.             }
  548.             setsignal(SIGTSTP);
  549.             setsignal(SIGTTOU);
  550.         } else if (mode == FORK_BG) {
  551.             ignoresig(SIGINT);
  552.             ignoresig(SIGQUIT);
  553.             if (jp == NULL || jp->nprocs == 0) {
  554.                 close(0);
  555.                 if (open("/dev/null", O_RDONLY) != 0)
  556.                     error("Can't open /dev/null");
  557.             }
  558.         }
  559. #else
  560.         if (mode == FORK_BG) {
  561.             ignoresig(SIGINT);
  562.             ignoresig(SIGQUIT);
  563.             if (jp == NULL || jp->nprocs == 0) {
  564.                 close(0);
  565.                 if (open("/dev/null", O_RDONLY) != 0)
  566.                     error("Can't open /dev/null");
  567.             }
  568.         }
  569. #endif
  570.         if (wasroot && iflag) {
  571.             setsignal(SIGINT);
  572.             setsignal(SIGQUIT);
  573.             setsignal(SIGTERM);
  574.         }
  575.         return pid;
  576.     }
  577.     if (rootshell && mode != FORK_NOJOB && jflag) {
  578.         if (jp == NULL || jp->nprocs == 0)
  579.             pgrp = pid;
  580.         else
  581.             pgrp = jp->ps[0].pid;
  582.         setpgrp(pid, pgrp);
  583.     }
  584.     if (mode == FORK_BG)
  585.         backgndpid = pid;        /* set $! */
  586.     if (jp) {
  587.         struct procstat *ps = &jp->ps[jp->nprocs++];
  588.         ps->pid = pid;
  589.         ps->status = -1;
  590.         ps->cmd = nullstr;
  591.         if (iflag && rootshell && n)
  592.             ps->cmd = commandtext(n);
  593.     }
  594.     INTON;
  595.     TRACE(("In parent shell:  child = %d\n", pid));
  596.     return pid;
  597. }
  598.  
  599.  
  600.  
  601. /*
  602.  * Wait for job to finish.
  603.  *
  604.  * Under job control we have the problem that while a child process is
  605.  * running interrupts generated by the user are sent to the child but not
  606.  * to the shell.  This means that an infinite loop started by an inter-
  607.  * active user may be hard to kill.  With job control turned off, an
  608.  * interactive user may place an interactive program inside a loop.  If
  609.  * the interactive program catches interrupts, the user doesn't want
  610.  * these interrupts to also abort the loop.  The approach we take here
  611.  * is to have the shell ignore interrupt signals while waiting for a
  612.  * forground process to terminate, and then send itself an interrupt
  613.  * signal if the child process was terminated by an interrupt signal.
  614.  * Unfortunately, some programs want to do a bit of cleanup and then
  615.  * exit on interrupt; unless these processes terminate themselves by
  616.  * sending a signal to themselves (instead of calling exit) they will
  617.  * confuse this approach.
  618.  */
  619.  
  620. int
  621. waitforjob(jp)
  622.     register struct job *jp;
  623.     {
  624. #if JOBS
  625.     int mypgrp = getpgrp(0);
  626. #endif
  627.     int status;
  628.     int st;
  629.  
  630.     INTOFF;
  631.     TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
  632.     while (jp->state == 0) {
  633.         dowait(1, jp);
  634.     }
  635. #if JOBS
  636.     if (jp->jobctl) {
  637.         if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
  638.             error("TIOCSPGRP failed, errno=%d\n", errno);
  639.     }
  640.     if (jp->state == JOBSTOPPED)
  641.         curjob = jp - jobtab + 1;
  642. #endif
  643.     status = jp->ps[jp->nprocs - 1].status;
  644.     /* convert to 8 bits */
  645.     if ((status & 0xFF) == 0)
  646.         st = status >> 8 & 0xFF;
  647. #if JOBS
  648.     else if ((status & 0xFF) == 0177)
  649.         st = (status >> 8 & 0x7F) + 128;
  650. #endif
  651.     else
  652.         st = (status & 0x7F) + 128;
  653.     if (! JOBS || jp->state == JOBDONE)
  654.         freejob(jp);
  655.     CLEAR_PENDING_INT;
  656.     if ((status & 0x7F) == SIGINT)
  657.         kill(getpid(), SIGINT);
  658.     INTON;
  659.     return st;
  660. }
  661.  
  662.  
  663.  
  664. /*
  665.  * Wait for a process to terminate.
  666.  */
  667.  
  668. STATIC int
  669. dowait(block, job)
  670.     struct job *job;
  671.     {
  672.     int pid;
  673.     int status;
  674.     struct procstat *sp;
  675.     struct job *jp;
  676.     struct job *thisjob;
  677.     int done;
  678.     int stopped;
  679.     int core;
  680.  
  681.     TRACE(("dowait(%d) called\n", block));
  682.     do {
  683.         pid = waitproc(block, &status);
  684.         TRACE(("wait returns %d, status=%d\n", pid, status));
  685.     } while (pid == -1 && errno == EINTR);
  686.     if (pid <= 0)
  687.         return pid;
  688.     INTOFF;
  689.     thisjob = NULL;
  690.     for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
  691.         if (jp->used) {
  692.             done = 1;
  693.             stopped = 1;
  694.             for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
  695.                 if (sp->pid == -1)
  696.                     continue;
  697.                 if (sp->pid == pid) {
  698.                     TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
  699.                     sp->status = status;
  700.                     thisjob = jp;
  701.                 }
  702.                 if (sp->status == -1)
  703.                     stopped = 0;
  704.                 else if ((sp->status & 0377) == 0177)
  705.                     done = 0;
  706.             }
  707.             if (stopped) {        /* stopped or done */
  708.                 int state = done? JOBDONE : JOBSTOPPED;
  709.                 if (jp->state != state) {
  710.                     TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
  711.                     jp->state = state;
  712. #if JOBS
  713.                     if (done && curjob == jp - jobtab + 1)
  714.                         curjob = 0;        /* no current job */
  715. #endif
  716.                 }
  717.             }
  718.         }
  719.     }
  720.     INTON;
  721.     if (! rootshell || ! iflag || (job && thisjob == job)) {
  722. #if JOBS
  723.         if ((status & 0xFF) == 0177)
  724.             status >>= 8;
  725. #endif
  726.         core = status & 0x80;
  727.         status &= 0x7F;
  728.         if (status != 0 && status != SIGINT && status != SIGPIPE) {
  729.             if (thisjob != job)
  730.                 outfmt(out2, "%d: ", pid);
  731. #if JOBS
  732.             if (status == SIGTSTP && rootshell && iflag)
  733.                 outfmt(out2, "%%%d ", job - jobtab + 1);
  734. #endif
  735.             if (status <= MAXSIG && sigmesg[status])
  736.                 out2str(sigmesg[status]);
  737.             else
  738.                 outfmt(out2, "Signal %d", status);
  739.             if (core)
  740.                 out2str(" - core dumped");
  741.             out2c('\n');
  742.             flushout(&errout);
  743.         } else {
  744.             TRACE(("Not printing status: status=%d\n", status));
  745.         }
  746.     } else {
  747.         TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
  748.         if (thisjob)
  749.             thisjob->changed = 1;
  750.     }
  751.     return pid;
  752. }
  753.  
  754.  
  755.  
  756. /*
  757.  * Do a wait system call.  If job control is compiled in, we accept
  758.  * stopped processes.  If block is zero, we return a value of zero
  759.  * rather than blocking.
  760.  *
  761.  * System V doesn't have a non-blocking wait system call.  It does
  762.  * have a SIGCLD signal that is sent to a process when one of it's
  763.  * children dies.  The obvious way to use SIGCLD would be to install
  764.  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
  765.  * was received, and have waitproc bump another counter when it got
  766.  * the status of a process.  Waitproc would then know that a wait
  767.  * system call would not block if the two counters were different.
  768.  * This approach doesn't work because if a process has children that
  769.  * have not been waited for, System V will send it a SIGCLD when it
  770.  * installs a signal handler for SIGCLD.  What this means is that when
  771.  * a child exits, the shell will be sent SIGCLD signals continuously
  772.  * until is runs out of stack space, unless it does a wait call before
  773.  * restoring the signal handler.  The code below takes advantage of
  774.  * this (mis)feature by installing a signal handler for SIGCLD and
  775.  * then checking to see whether it was called.  If there are any
  776.  * children to be waited for, it will be.
  777.  *
  778.  * If neither SYSV nor BSD is defined, we don't implement nonblocking
  779.  * waits at all.  In this case, the user will not be informed when
  780.  * a background process until the next time she runs a real program
  781.  * (as opposed to running a builtin command or just typing return),
  782.  * and the jobs command may give out of date information.
  783.  */
  784.  
  785. #ifdef SYSV
  786. STATIC int gotsigchild;
  787.  
  788. STATIC int onsigchild() {
  789.     gotsigchild = 1;
  790. }
  791. #endif
  792.  
  793.  
  794. STATIC int
  795. waitproc(block, status)
  796.     int *status;
  797.     {
  798. #ifdef BSD
  799.     int flags;
  800.  
  801. #if JOBS
  802.     flags = WUNTRACED;
  803. #else
  804.     flags = 0;
  805. #endif
  806.     if (block == 0)
  807.         flags |= WNOHANG;
  808.     return wait3((union wait *)status, flags, (struct rusage *)NULL);
  809. #else
  810. #ifdef SYSV
  811.     int (*save)();
  812.  
  813.     if (block == 0) {
  814.         gotsigchild = 0;
  815.         save = signal(SIGCLD, onsigchild);
  816.         signal(SIGCLD, save);
  817.         if (gotsigchild == 0)
  818.             return 0;
  819.     }
  820.     return wait(status);
  821. #else
  822.     if (block == 0)
  823.         return 0;
  824.     return wait(status);
  825. #endif
  826. #endif
  827. }
  828.  
  829.  
  830.  
  831. /*
  832.  * Return a string identifying a command (to be printed by the
  833.  * jobs command.
  834.  */
  835.  
  836. STATIC char *cmdnextc;
  837. STATIC int cmdnleft;
  838. STATIC void cmdtxt(), cmdputs();
  839.  
  840. STATIC char *
  841. commandtext(n)
  842.     union node *n;
  843.     {
  844.     char *name;
  845.  
  846.     cmdnextc = name = ckmalloc(50);
  847.     cmdnleft = 50 - 4;
  848.     cmdtxt(n);
  849.     *cmdnextc = '\0';
  850.     return name;
  851. }
  852.  
  853.  
  854. STATIC void
  855. cmdtxt(n)
  856.     union node *n;
  857.     {
  858.     union node *np;
  859.     struct nodelist *lp;
  860.     char *p;
  861.     int i;
  862.     char s[2];
  863.  
  864.     switch (n->type) {
  865.     case NSEMI:
  866.         cmdtxt(n->nbinary.ch1);
  867.         cmdputs("; ");
  868.         cmdtxt(n->nbinary.ch2);
  869.         break;
  870.     case NAND:
  871.         cmdtxt(n->nbinary.ch1);
  872.         cmdputs(" && ");
  873.         cmdtxt(n->nbinary.ch2);
  874.         break;
  875.     case NOR:
  876.         cmdtxt(n->nbinary.ch1);
  877.         cmdputs(" || ");
  878.         cmdtxt(n->nbinary.ch2);
  879.         break;
  880.     case NPIPE:
  881.         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
  882.             cmdtxt(lp->n);
  883.             if (lp->next)
  884.                 cmdputs(" | ");
  885.         }
  886.         break;
  887.     case NSUBSHELL:
  888.         cmdputs("(");
  889.         cmdtxt(n->nredir.n);
  890.         cmdputs(")");
  891.         break;
  892.     case NREDIR:
  893.     case NBACKGND:
  894.         cmdtxt(n->nredir.n);
  895.         break;
  896.     case NIF:
  897.         cmdputs("if ");
  898.         cmdtxt(n->nif.test);
  899.         cmdputs("; then ");
  900.         cmdtxt(n->nif.ifpart);
  901.         cmdputs("...");
  902.         break;
  903.     case NWHILE:
  904.         cmdputs("while ");
  905.         goto until;
  906.     case NUNTIL:
  907.         cmdputs("until ");
  908. until:
  909.         cmdtxt(n->nbinary.ch1);
  910.         cmdputs("; do ");
  911.         cmdtxt(n->nbinary.ch2);
  912.         cmdputs("; done");
  913.         break;
  914.     case NFOR:
  915.         cmdputs("for ");
  916.         cmdputs(n->nfor.var);
  917.         cmdputs(" in ...");
  918.         break;
  919.     case NCASE:
  920.         cmdputs("case ");
  921.         cmdputs(n->ncase.expr->narg.text);
  922.         cmdputs(" in ...");
  923.         break;
  924.     case NDEFUN:
  925.         cmdputs(n->narg.text);
  926.         cmdputs("() ...");
  927.         break;
  928.     case NCMD:
  929.         for (np = n->ncmd.args ; np ; np = np->narg.next) {
  930.             cmdtxt(np);
  931.             if (np->narg.next)
  932.                 cmdputs(" ");
  933.         }
  934.         for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
  935.             cmdputs(" ");
  936.             cmdtxt(np);
  937.         }
  938.         break;
  939.     case NARG:
  940.         cmdputs(n->narg.text);
  941.         break;
  942.     case NTO:
  943.         p = ">";  i = 1;  goto redir;
  944.     case NAPPEND:
  945.         p = ">>";  i = 1;  goto redir;
  946.     case NTOFD:
  947.         p = ">&";  i = 1;  goto redir;
  948.     case NFROM:
  949.         p = "<";  i = 0;  goto redir;
  950.     case NFROMFD:
  951.         p = "<&";  i = 0;  goto redir;
  952. redir:
  953.         if (n->nfile.fd != i) {
  954.             s[0] = n->nfile.fd + '0';
  955.             s[1] = '\0';
  956.             cmdputs(s);
  957.         }
  958.         cmdputs(p);
  959.         if (n->type == NTOFD || n->type == NFROMFD) {
  960.             s[0] = n->ndup.dupfd + '0';
  961.             s[1] = '\0';
  962.             cmdputs(s);
  963.         } else {
  964.             cmdtxt(n->nfile.fname);
  965.         }
  966.         break;
  967.     case NHERE:
  968.     case NXHERE:
  969.         cmdputs("<<...");
  970.         break;
  971.     default:
  972.         cmdputs("???");
  973.         break;
  974.     }
  975. }
  976.  
  977.  
  978.  
  979. STATIC void
  980. cmdputs(s)
  981.     char *s;
  982.     {
  983.     register char *p, *q;
  984.     register char c;
  985.     int subtype = 0;
  986.  
  987.     if (cmdnleft <= 0)
  988.         return;
  989.     p = s;
  990.     q = cmdnextc;
  991.     while ((c = *p++) != '\0') {
  992.         if (c == CTLESC)
  993.             *q++ = *p++;
  994.         else if (c == CTLVAR) {
  995.             *q++ = '$';
  996.             if (--cmdnleft > 0)
  997.                 *q++ = '{';
  998.             subtype = *p++;
  999.         } else if (c == '=' && subtype != 0) {
  1000.             *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
  1001.             subtype = 0;
  1002.         } else if (c == CTLENDVAR) {
  1003.             *q++ = '}';
  1004.         } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
  1005.             cmdnleft++;        /* ignore it */
  1006.         else
  1007.             *q++ = c;
  1008.         if (--cmdnleft <= 0) {
  1009.             *q++ = '.';
  1010.             *q++ = '.';
  1011.             *q++ = '.';
  1012.             break;
  1013.         }
  1014.     }
  1015.     cmdnextc = q;
  1016. }
  1017.