home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / ap / ash / ash-linu.2 / ash-linu / ash-linux-0.2 / jobs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-04  |  22.2 KB  |  1,029 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.                 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
  278.                     scopy(sys_siglist[i & 0x7F], s);
  279.                 else
  280.                     fmtstr(s, 64, "Signal %d", i & 0x7F);
  281.                 if (i & 0x80)
  282.                     strcat(s, " (core dumped)");
  283.             }
  284.             out1str(s);
  285.             col += strlen(s);
  286.             do {
  287.                 out1c(' ');
  288.                 col++;
  289.             } while (col < 30);
  290.             out1str(ps->cmd);
  291.             out1c('\n');
  292.             if (--procno <= 0)
  293.                 break;
  294.         }
  295.         jp->changed = 0;
  296.         if (jp->state == JOBDONE) {
  297.             freejob(jp);
  298.         }
  299.     }
  300. }
  301.  
  302.  
  303. /*
  304.  * Mark a job structure as unused.
  305.  */
  306.  
  307. STATIC void
  308. freejob(jp)
  309.     struct job *jp;
  310.     {
  311.     struct procstat *ps;
  312.     int i;
  313.  
  314.     INTOFF;
  315.     for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
  316.         if (ps->cmd != nullstr)
  317.             ckfree(ps->cmd);
  318.     }
  319.     if (jp->ps != &jp->ps0)
  320.         ckfree(jp->ps);
  321.     jp->used = 0;
  322. #if JOBS
  323.     if (curjob == jp - jobtab + 1)
  324.         curjob = 0;
  325. #endif
  326.     INTON;
  327. }
  328.  
  329.  
  330.  
  331. int
  332. waitcmd(argc, argv)  char **argv; {
  333.     struct job *job;
  334.     int status;
  335.     struct job *jp;
  336.  
  337.     if (argc > 1) {
  338.         job = getjob(argv[1]);
  339.     } else {
  340.         job = NULL;
  341.     }
  342.     for (;;) {    /* loop until process terminated or stopped */
  343.         if (job != NULL) {
  344.             if (job->state) {
  345.                 status = job->ps[job->nprocs - 1].status;
  346.                 if ((status & 0xFF) == 0)
  347.                     status = status >> 8 & 0xFF;
  348. #if JOBS
  349.                 else if ((status & 0xFF) == 0177)
  350.                     status = (status >> 8 & 0x7F) + 128;
  351. #endif
  352.                 else
  353.                     status = (status & 0x7F) + 128;
  354.                 if (! iflag)
  355.                     freejob(job);
  356.                 return status;
  357.             }
  358.         } else {
  359.             for (jp = jobtab ; ; jp++) {
  360.                 if (jp >= jobtab + njobs) {    /* no running procs */
  361.                     return 0;
  362.                 }
  363.                 if (jp->used && jp->state == 0)
  364.                     break;
  365.             }
  366.         }
  367.         dowait(1, (struct job *)NULL);
  368.     }
  369. }
  370.  
  371.  
  372.  
  373. jobidcmd(argc, argv)  char **argv; {
  374.     struct job *jp;
  375.     int i;
  376.  
  377.     jp = getjob(argv[1]);
  378.     for (i = 0 ; i < jp->nprocs ; ) {
  379.         out1fmt("%d", jp->ps[i].pid);
  380.         out1c(++i < jp->nprocs? ' ' : '\n');
  381.     }
  382.     return 0;
  383. }
  384.  
  385.  
  386.  
  387. /*
  388.  * Convert a job name to a job structure.
  389.  */
  390.  
  391. STATIC struct job *
  392. getjob(name)
  393.     char *name;
  394.     {
  395.     int jobno;
  396.     register struct job *jp;
  397.     int pid;
  398.     int i;
  399.  
  400.     if (name == NULL) {
  401. #if JOBS
  402. currentjob:
  403.         if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
  404.             error("No current job");
  405.         return &jobtab[jobno - 1];
  406. #else
  407.         error("No current job");
  408. #endif
  409.     } else if (name[0] == '%') {
  410.         if (is_digit(name[1])) {
  411.             jobno = number(name + 1);
  412.             if (jobno > 0 && jobno <= njobs
  413.              && jobtab[jobno - 1].used != 0)
  414.                 return &jobtab[jobno - 1];
  415. #if JOBS
  416.         } else if (name[1] == '%' && name[2] == '\0') {
  417.             goto currentjob;
  418. #endif
  419.         } else {
  420.             register struct job *found = NULL;
  421.             for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  422.                 if (jp->used && jp->nprocs > 0
  423.                  && prefix(name + 1, jp->ps[0].cmd)) {
  424.                     if (found)
  425.                         error("%s: ambiguous", name);
  426.                     found = jp;
  427.                 }
  428.             }
  429.             if (found)
  430.                 return found;
  431.         }
  432.     } else if (is_number(name)) {
  433.         pid = number(name);
  434.         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
  435.             if (jp->used && jp->nprocs > 0
  436.              && jp->ps[jp->nprocs - 1].pid == pid)
  437.                 return jp;
  438.         }
  439.     }
  440.     error("No such job: %s", name);
  441. }
  442.  
  443.  
  444.  
  445. /*
  446.  * Return a new job structure,
  447.  */
  448.  
  449. struct job *
  450. makejob(node, nprocs)
  451.     union node *node;
  452.     {
  453.     int i;
  454.     struct job *jp;
  455.  
  456.     for (i = njobs, jp = jobtab ; ; jp++) {
  457.         if (--i < 0) {
  458.             INTOFF;
  459.             if (njobs == 0) {
  460.                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
  461.             } else {
  462.                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
  463.                 bcopy(jobtab, jp, njobs * sizeof jp[0]);
  464.                 ckfree(jobtab);
  465.                 jobtab = jp;
  466.             }
  467.             jp = jobtab + njobs;
  468.             for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
  469.             INTON;
  470.             break;
  471.         }
  472.         if (jp->used == 0)
  473.             break;
  474.     }
  475.     INTOFF;
  476.     jp->state = 0;
  477.     jp->used = 1;
  478.     jp->changed = 0;
  479.     jp->nprocs = 0;
  480. #if JOBS
  481.     jp->jobctl = jobctl;
  482. #endif
  483.     if (nprocs > 1) {
  484.         jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
  485.     } else {
  486.         jp->ps = &jp->ps0;
  487.     }
  488.     INTON;
  489.     TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
  490.     return jp;
  491. }    
  492.  
  493.  
  494. /*
  495.  * Fork of a subshell.  If we are doing job control, give the subshell its
  496.  * own process group.  Jp is a job structure that the job is to be added to.
  497.  * N is the command that will be evaluated by the child.  Both jp and n may
  498.  * be NULL.  The mode parameter can be one of the following:
  499.  *    FORK_FG - Fork off a foreground process.
  500.  *    FORK_BG - Fork off a background process.
  501.  *    FORK_NOJOB - Like FORK_FG, but don't give the process its own
  502.  *             process group even if job control is on.
  503.  *
  504.  * When job control is turned off, background processes have their standard
  505.  * input redirected to /dev/null (except for the second and later processes
  506.  * in a pipeline).
  507.  */
  508.  
  509. int
  510. forkshell(jp, n, mode)
  511.     union node *n;
  512.     struct job *jp;
  513.     {
  514.     int pid;
  515.     int pgrp;
  516.  
  517.     TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
  518.     INTOFF;
  519.     pid = fork();
  520.     if (pid == -1) {
  521.         TRACE(("Fork failed, errno=%d\n", errno));
  522.         INTON;
  523.         error("Cannot fork");
  524.     }
  525.     if (pid == 0) {
  526.         struct job *p;
  527.         int wasroot;
  528.         int i;
  529.  
  530.         TRACE(("Child shell %d\n", getpid()));
  531.         wasroot = rootshell;
  532.         rootshell = 0;
  533.         for (i = njobs, p = jobtab ; --i >= 0 ; p++)
  534.             if (p->used)
  535.                 freejob(p);
  536.         closescript();
  537.         INTON;
  538.         clear_traps();
  539. #if JOBS
  540.         jobctl = 0;        /* do job control only in root shell */
  541.         if (wasroot && mode != FORK_NOJOB && jflag) {
  542.             if (jp == NULL || jp->nprocs == 0)
  543.                 pgrp = getpid();
  544.             else
  545.                 pgrp = jp->ps[0].pid;
  546.             setpgrp(0, pgrp);
  547.             if (mode == FORK_FG) {
  548.                 /*** this causes superfluous TIOCSPGRPS ***/
  549.                 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
  550.                     error("TIOCSPGRP failed, errno=%d\n", errno);
  551.             }
  552.             setsignal(SIGTSTP);
  553.             setsignal(SIGTTOU);
  554.         } else if (mode == FORK_BG) {
  555.             ignoresig(SIGINT);
  556.             ignoresig(SIGQUIT);
  557.             if ((jp == NULL || jp->nprocs == 0)
  558.                 && ! fd0_redirected_p ()) {
  559.                 close(0);
  560.                 if (open("/dev/null", O_RDONLY) != 0)
  561.                     error("Can't open /dev/null");
  562.             }
  563.         }
  564. #else
  565.         if (mode == FORK_BG) {
  566.             ignoresig(SIGINT);
  567.             ignoresig(SIGQUIT);
  568.             if ((jp == NULL || jp->nprocs == 0)
  569.                 && ! fd0_redirected_p ()) {
  570.                 close(0);
  571.                 if (open("/dev/null", O_RDONLY) != 0)
  572.                     error("Can't open /dev/null");
  573.             }
  574.         }
  575. #endif
  576.         if (wasroot && iflag) {
  577.             setsignal(SIGINT);
  578.             setsignal(SIGQUIT);
  579.             setsignal(SIGTERM);
  580.         }
  581.         return pid;
  582.     }
  583. #if JOBS
  584.     if (rootshell && mode != FORK_NOJOB && jflag) {
  585.         if (jp == NULL || jp->nprocs == 0)
  586.             pgrp = pid;
  587.         else
  588.             pgrp = jp->ps[0].pid;
  589.         setpgrp(pid, pgrp);
  590.     }
  591. #endif
  592.     if (mode == FORK_BG)
  593.         backgndpid = pid;        /* set $! */
  594.     if (jp) {
  595.         struct procstat *ps = &jp->ps[jp->nprocs++];
  596.         ps->pid = pid;
  597.         ps->status = -1;
  598.         ps->cmd = nullstr;
  599.         if (iflag && rootshell && n)
  600.             ps->cmd = commandtext(n);
  601.     }
  602.     INTON;
  603.     TRACE(("In parent shell:  child = %d\n", pid));
  604.     return pid;
  605. }
  606.  
  607.  
  608.  
  609. /*
  610.  * Wait for job to finish.
  611.  *
  612.  * Under job control we have the problem that while a child process is
  613.  * running interrupts generated by the user are sent to the child but not
  614.  * to the shell.  This means that an infinite loop started by an inter-
  615.  * active user may be hard to kill.  With job control turned off, an
  616.  * interactive user may place an interactive program inside a loop.  If
  617.  * the interactive program catches interrupts, the user doesn't want
  618.  * these interrupts to also abort the loop.  The approach we take here
  619.  * is to have the shell ignore interrupt signals while waiting for a
  620.  * forground process to terminate, and then send itself an interrupt
  621.  * signal if the child process was terminated by an interrupt signal.
  622.  * Unfortunately, some programs want to do a bit of cleanup and then
  623.  * exit on interrupt; unless these processes terminate themselves by
  624.  * sending a signal to themselves (instead of calling exit) they will
  625.  * confuse this approach.
  626.  */
  627.  
  628. int
  629. waitforjob(jp)
  630.     register struct job *jp;
  631.     {
  632. #if JOBS
  633.     int mypgrp = getpgrp();
  634. #endif
  635.     int status;
  636.     int st;
  637.  
  638.     INTOFF;
  639.     TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
  640.     while (jp->state == 0) {
  641.         if (dowait(1, jp) == -1 && errno == ECHILD) {
  642.             error("waitforjob: no children");
  643.     }
  644.     }
  645. #if JOBS
  646.     if (jp->jobctl) {
  647.         if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
  648.             error("TIOCSPGRP failed, errno=%d\n", errno);
  649.     }
  650.     if (jp->state == JOBSTOPPED)
  651.         curjob = jp - jobtab + 1;
  652. #endif
  653.     status = jp->ps[jp->nprocs - 1].status;
  654.     /* convert to 8 bits */
  655.     if ((status & 0xFF) == 0)
  656.         st = status >> 8 & 0xFF;
  657. #if JOBS
  658.     else if ((status & 0xFF) == 0177)
  659.         st = (status >> 8 & 0x7F) + 128;
  660. #endif
  661.     else
  662.         st = (status & 0x7F) + 128;
  663.     if (! JOBS || jp->state == JOBDONE)
  664.         freejob(jp);
  665.     CLEAR_PENDING_INT;
  666. #if 0
  667.     if ((status & 0x7F) == SIGINT)
  668.         kill(getpid(), SIGINT);
  669. #endif
  670.     INTON;
  671.     return st;
  672. }
  673.  
  674.  
  675.  
  676. /*
  677.  * Wait for a process to terminate.
  678.  */
  679.  
  680. STATIC int
  681. dowait(block, job)
  682.     struct job *job;
  683.     {
  684.     int pid;
  685.     int status;
  686.     struct procstat *sp;
  687.     struct job *jp;
  688.     struct job *thisjob;
  689.     int done;
  690.     int stopped;
  691.     int core;
  692.  
  693.     TRACE(("dowait(%d) called\n", block));
  694.     do {
  695.         pid = waitproc(block, &status);
  696.         TRACE(("wait returns %d, status=%d\n", pid, status));
  697.     } while (pid == -1 && errno == EINTR);
  698.     if (pid <= 0)
  699.         return pid;
  700.     INTOFF;
  701.     thisjob = NULL;
  702.     for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
  703.         if (jp->used) {
  704.             done = 1;
  705.             stopped = 1;
  706.             for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
  707.                 if (sp->pid == -1)
  708.                     continue;
  709.                 if (sp->pid == pid) {
  710.                     TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
  711.                     sp->status = status;
  712.                     thisjob = jp;
  713.                 }
  714.                 if (sp->status == -1)
  715.                     stopped = 0;
  716.                 else if ((sp->status & 0377) == 0177)
  717.                     done = 0;
  718.             }
  719.             if (stopped) {        /* stopped or done */
  720.                 int state = done? JOBDONE : JOBSTOPPED;
  721.                 if (jp->state != state) {
  722.                     TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
  723.                     jp->state = state;
  724. #if JOBS
  725.                     if (done && curjob == jp - jobtab + 1)
  726.                         curjob = 0;        /* no current job */
  727. #endif
  728.                 }
  729.             }
  730.         }
  731.     }
  732.     INTON;
  733.     if (! rootshell || ! iflag || (job && thisjob == job)) {
  734. #if JOBS
  735.         if ((status & 0xFF) == 0177)
  736.             status >>= 8;
  737. #endif
  738.         core = status & 0x80;
  739.         status &= 0x7F;
  740.         if (status != 0 && status != SIGINT && status != SIGPIPE) {
  741.             if (thisjob != job)
  742.                 outfmt(out2, "%d: ", pid);
  743. #if JOBS
  744.             if (status == SIGTSTP && rootshell && iflag)
  745.                 outfmt(out2, "%%%d ", job - jobtab + 1);
  746. #endif
  747.             if (status < NSIG && sys_siglist[status])
  748.                 out2str(sys_siglist[status]);
  749.             else
  750.                 outfmt(out2, "Signal %d", status);
  751.             if (core)
  752.                 out2str(" - core dumped");
  753.             out2c('\n');
  754.             flushout(&errout);
  755.         } else {
  756.             TRACE(("Not printing status: status=%d\n", status));
  757.         }
  758.     } else {
  759.         TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
  760.         if (thisjob)
  761.             thisjob->changed = 1;
  762.     }
  763.     return pid;
  764. }
  765.  
  766.  
  767.  
  768. /*
  769.  * Do a wait system call.  If job control is compiled in, we accept
  770.  * stopped processes.  If block is zero, we return a value of zero
  771.  * rather than blocking.
  772.  *
  773.  * System V doesn't have a non-blocking wait system call.  It does
  774.  * have a SIGCLD signal that is sent to a process when one of it's
  775.  * children dies.  The obvious way to use SIGCLD would be to install
  776.  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
  777.  * was received, and have waitproc bump another counter when it got
  778.  * the status of a process.  Waitproc would then know that a wait
  779.  * system call would not block if the two counters were different.
  780.  * This approach doesn't work because if a process has children that
  781.  * have not been waited for, System V will send it a SIGCLD when it
  782.  * installs a signal handler for SIGCLD.  What this means is that when
  783.  * a child exits, the shell will be sent SIGCLD signals continuously
  784.  * until is runs out of stack space, unless it does a wait call before
  785.  * restoring the signal handler.  The code below takes advantage of
  786.  * this (mis)feature by installing a signal handler for SIGCLD and
  787.  * then checking to see whether it was called.  If there are any
  788.  * children to be waited for, it will be.
  789.  *
  790.  * If neither SYSV nor BSD is defined, we don't implement nonblocking
  791.  * waits at all.  In this case, the user will not be informed when
  792.  * a background process until the next time she runs a real program
  793.  * (as opposed to running a builtin command or just typing return),
  794.  * and the jobs command may give out of date information.
  795.  */
  796.  
  797. #ifdef SYSV
  798. STATIC int gotsigchild;
  799.  
  800. STATIC int onsigchild() {
  801.     gotsigchild = 1;
  802. }
  803. #endif
  804.  
  805.  
  806. STATIC int
  807. waitproc(block, status)
  808.     int *status;
  809.     {
  810. #ifdef BSD
  811.     int flags;
  812.  
  813. #if JOBS
  814.     flags = WUNTRACED;
  815. #else
  816.     flags = 0;
  817. #endif
  818.     if (block == 0)
  819.         flags |= WNOHANG;
  820.     return wait3((int *)status, flags, (struct rusage *)NULL);
  821. #else
  822. #ifdef SYSV
  823.     int (*save)();
  824.  
  825.     if (block == 0) {
  826.         gotsigchild = 0;
  827.         save = signal(SIGCLD, onsigchild);
  828.         signal(SIGCLD, save);
  829.         if (gotsigchild == 0)
  830.             return 0;
  831.     }
  832.     return wait(status);
  833. #else
  834.     if (block == 0)
  835.         return 0;
  836.     return wait(status);
  837. #endif
  838. #endif
  839. }
  840.  
  841.  
  842.  
  843. /*
  844.  * Return a string identifying a command (to be printed by the
  845.  * jobs command.
  846.  */
  847.  
  848. STATIC char *cmdnextc;
  849. STATIC int cmdnleft;
  850. STATIC void cmdtxt(), cmdputs();
  851.  
  852. STATIC char *
  853. commandtext(n)
  854.     union node *n;
  855.     {
  856.     char *name;
  857.  
  858.     cmdnextc = name = ckmalloc(50);
  859.     cmdnleft = 50 - 4;
  860.     cmdtxt(n);
  861.     *cmdnextc = '\0';
  862.     return name;
  863. }
  864.  
  865.  
  866. STATIC void
  867. cmdtxt(n)
  868.     union node *n;
  869.     {
  870.     union node *np;
  871.     struct nodelist *lp;
  872.     char *p;
  873.     int i;
  874.     char s[2];
  875.  
  876.     switch (n->type) {
  877.     case NSEMI:
  878.         cmdtxt(n->nbinary.ch1);
  879.         cmdputs("; ");
  880.         cmdtxt(n->nbinary.ch2);
  881.         break;
  882.     case NAND:
  883.         cmdtxt(n->nbinary.ch1);
  884.         cmdputs(" && ");
  885.         cmdtxt(n->nbinary.ch2);
  886.         break;
  887.     case NOR:
  888.         cmdtxt(n->nbinary.ch1);
  889.         cmdputs(" || ");
  890.         cmdtxt(n->nbinary.ch2);
  891.         break;
  892.     case NPIPE:
  893.         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
  894.             cmdtxt(lp->n);
  895.             if (lp->next)
  896.                 cmdputs(" | ");
  897.         }
  898.         break;
  899.     case NSUBSHELL:
  900.         cmdputs("(");
  901.         cmdtxt(n->nredir.n);
  902.         cmdputs(")");
  903.         break;
  904.     case NREDIR:
  905.     case NBACKGND:
  906.         cmdtxt(n->nredir.n);
  907.         break;
  908.     case NIF:
  909.         cmdputs("if ");
  910.         cmdtxt(n->nif.test);
  911.         cmdputs("; then ");
  912.         cmdtxt(n->nif.ifpart);
  913.         cmdputs("...");
  914.         break;
  915.     case NWHILE:
  916.         cmdputs("while ");
  917.         goto until;
  918.     case NUNTIL:
  919.         cmdputs("until ");
  920. until:
  921.         cmdtxt(n->nbinary.ch1);
  922.         cmdputs("; do ");
  923.         cmdtxt(n->nbinary.ch2);
  924.         cmdputs("; done");
  925.         break;
  926.     case NFOR:
  927.         cmdputs("for ");
  928.         cmdputs(n->nfor.var);
  929.         cmdputs(" in ...");
  930.         break;
  931.     case NCASE:
  932.         cmdputs("case ");
  933.         cmdputs(n->ncase.expr->narg.text);
  934.         cmdputs(" in ...");
  935.         break;
  936.     case NDEFUN:
  937.         cmdputs(n->narg.text);
  938.         cmdputs("() ...");
  939.         break;
  940.     case NCMD:
  941.         for (np = n->ncmd.args ; np ; np = np->narg.next) {
  942.             cmdtxt(np);
  943.             if (np->narg.next)
  944.                 cmdputs(" ");
  945.         }
  946.         for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
  947.             cmdputs(" ");
  948.             cmdtxt(np);
  949.         }
  950.         break;
  951.     case NARG:
  952.         cmdputs(n->narg.text);
  953.         break;
  954.     case NTO:
  955.         p = ">";  i = 1;  goto redir;
  956.     case NAPPEND:
  957.         p = ">>";  i = 1;  goto redir;
  958.     case NTOFD:
  959.         p = ">&";  i = 1;  goto redir;
  960.     case NFROM:
  961.         p = "<";  i = 0;  goto redir;
  962.     case NFROMFD:
  963.         p = "<&";  i = 0;  goto redir;
  964. redir:
  965.         if (n->nfile.fd != i) {
  966.             s[0] = n->nfile.fd + '0';
  967.             s[1] = '\0';
  968.             cmdputs(s);
  969.         }
  970.         cmdputs(p);
  971.         if (n->type == NTOFD || n->type == NFROMFD) {
  972.             s[0] = n->ndup.dupfd + '0';
  973.             s[1] = '\0';
  974.             cmdputs(s);
  975.         } else {
  976.             cmdtxt(n->nfile.fname);
  977.         }
  978.         break;
  979.     case NHERE:
  980.     case NXHERE:
  981.         cmdputs("<<...");
  982.         break;
  983.     default:
  984.         cmdputs("???");
  985.         break;
  986.     }
  987. }
  988.  
  989.  
  990.  
  991. STATIC void
  992. cmdputs(s)
  993.     char *s;
  994.     {
  995.     register char *p, *q;
  996.     register char c;
  997.     int subtype = 0;
  998.  
  999.     if (cmdnleft <= 0)
  1000.         return;
  1001.     p = s;
  1002.     q = cmdnextc;
  1003.     while ((c = *p++) != '\0') {
  1004.         if (c == CTLESC)
  1005.             *q++ = *p++;
  1006.         else if (c == CTLVAR) {
  1007.             *q++ = '$';
  1008.             if (--cmdnleft > 0)
  1009.                 *q++ = '{';
  1010.             subtype = *p++;
  1011.         } else if (c == '=' && subtype != 0) {
  1012.             *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
  1013.             subtype = 0;
  1014.         } else if (c == CTLENDVAR) {
  1015.             *q++ = '}';
  1016.         } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
  1017.             cmdnleft++;        /* ignore it */
  1018.         else
  1019.             *q++ = c;
  1020.         if (--cmdnleft <= 0) {
  1021.             *q++ = '.';
  1022.             *q++ = '.';
  1023.             *q++ = '.';
  1024.             break;
  1025.         }
  1026.     }
  1027.     cmdnextc = q;
  1028. }
  1029.