Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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