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