home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / ksh48.zip / sh / jobs.c < prev    next >
C/C++ Source or Header  |  1993-01-12  |  22KB  |  972 lines

  1. /*
  2.  * Process and job control
  3.  */
  4. #ifndef lint
  5. static char *RCSid = "$Id: jobs.c,v 1.6 1992/12/05 13:15:43 sjg Exp $";
  6. #endif
  7.  
  8. /*
  9.  * based on version by Ron Natalie, BRL
  10.  * modified by Simon J. Gerraty <sjg@melb.bull.oz.au>
  11.  *
  12.  * TODO:
  13.  *    change Proc table to Job table, with array of pids.
  14.  *    make %+ be jobs, %- be jobs->next.
  15.  *    do not JFREE members of pipeline.
  16.  *    consider procs[] related critical sections.
  17.  */
  18.  
  19. #include "stdh.h"
  20. #include <errno.h>
  21. #include <signal.h>
  22. #include <setjmp.h>
  23. #ifdef OS2
  24. #include <time.h>
  25. #include <process.h>
  26. typedef int pid_t;
  27. #endif
  28. #include <unistd.h>
  29. #include <sys/times.h>
  30. #ifndef OS2
  31. #include <sys/wait.h>
  32. #endif
  33. #include "sh.h"
  34. #ifdef JOBS
  35. #ifdef _BSDI
  36. #define _BSD
  37. #define WIFCORED(x) WCOREDUMP(x)
  38. #endif
  39. #ifdef _BSD
  40. #include <sys/ioctl.h>
  41. #else
  42. #ifndef OS2
  43. #include "termios.h"
  44. #endif
  45. #endif
  46. #endif
  47.  
  48. #ifdef _BSD
  49. /*
  50.  * These macros are for the benefit of SunOS 4.0.2 and 4.0.3
  51.  * SunOS 4.1.1 already defines most of them.
  52.  * Clearly these are aimed at SunOS, they may work for other
  53.  * BSD systems but I can't promise.
  54.  */
  55. # ifndef WIFSTOPPED
  56. #   define WIFSTOPPED(x)    ((x).w_stopval == WSTOPPED)
  57. # endif
  58. # ifndef WIFSIGNALED
  59. #   define WIFSIGNALED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig != 0)
  60. # endif
  61. # ifndef WIFEXITED
  62. #   define WIFEXITED(x)    ((x).w_stopval != WSTOPPED && (x).w_termsig == 0)
  63. # endif
  64. # ifndef WSTOPSIG
  65. #   define WSTOPSIG(x)    ((x).w_stopsig)
  66. # endif
  67. # ifndef WTERMSIG
  68. #   define WTERMSIG(x)    ((x).w_termsig)
  69. # endif
  70. # ifndef WIFCORED
  71. #   define WIFCORED(x)    ((x).w_coredump)
  72. # endif
  73. # ifndef WEXITSTATUS
  74. #   define WEXITSTATUS(x)    ((x).w_retcode)
  75. # endif
  76. # ifndef HAVE_WAITPID
  77. #   define    waitpid(pid, sp, opts)    wait3(sp, opts, (void*)NULL)
  78. # endif
  79. #else                    /* not _BSD */
  80. # ifndef WIFSTOPPED
  81. #   define WIFSTOPPED(x)   (((x)&0xFF) == 0x7F)
  82. # endif
  83. # ifndef WIFSIGNALED
  84. #   define WIFSIGNALED(x)  (((x)&0xFF) != 0x7F && ((x)&0x7F) != 0)
  85. # endif
  86. # ifndef WIFEXITED
  87. #   define WIFEXITED(x)    (((x)&0xFF) != 0x7F && ((x)&0x7F) == 0)
  88. # endif
  89. # ifndef WIFCORED
  90. #   define    WIFCORED(x)    (!!((x)&0x80)) /* non-standard */
  91. # endif
  92. # ifndef WEXITSTATUS
  93. #   define WEXITSTATUS(x)  ((x)>>8&0xFF)
  94. # endif
  95. # ifndef WTERMSIG
  96. #   define WTERMSIG(x)     ((x)&0x7F)
  97. # endif
  98. # ifndef WSTOPSIG
  99. #   define WSTOPSIG(x)     ((x)>>8&0xFF)
  100. # endif
  101. #endif
  102.  
  103. /* as of P1003.1 Draft 12.3:
  104.  *    pid_t getpgrp(void);        // Get process group id
  105.  *    pid_t setsid(void);        // Create session and Set process group id
  106.  *    int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
  107.  */
  108.  
  109.  
  110. #ifdef JOBS
  111. #ifdef _BSD            /* _BSD 4.* */
  112. #define    setpgid(p, pg)    setpgrp(p, pg)
  113. #define    getpgid(p)    getpgrp(p)
  114. #define    tcsetpgrp(fd,p)    ioctl(fd, TIOCSPGRP, &(p))
  115. #else                /* POSIX-compatible */
  116. #define    getpgid(p)    getpgrp() /* 1003.1 stupidity */
  117. #define    killpg(p, s)    kill(-(p), s)
  118. #endif
  119. #endif
  120.  
  121.  
  122. #ifndef    SIGCHLD
  123. #define    SIGCHLD    SIGCLD
  124. #endif
  125. #ifndef WAIT_T
  126. #ifdef _BSD
  127. #define WAIT_T union wait
  128. #else
  129. #define WAIT_T int
  130. #endif
  131. #ifdef _BSDI
  132. #undef WAIT_T
  133. #define WAIT_T int
  134. #endif
  135. #endif
  136. #ifndef SA_RESTART
  137. #define SA_RESTART    0
  138. #endif
  139.  
  140. typedef struct Proc Proc;
  141. struct Proc {
  142.     Proc   *next;        /* `procs' list link */
  143.     int    job;        /* job number: %n */
  144.     short    volatile state;    /* proc state */
  145.     short    volatile notify; /* proc state has changed */
  146.     Proc   *prev;        /* prev member of pipeline */
  147.     pid_t    proc;        /* process id */
  148.     pid_t    pgrp;        /* process group if flag[FMONITOR] */
  149.     short    flags;        /* execute flags */
  150.     WAIT_T    status;        /* wait status */
  151.     clock_t    utime, stime;    /* user/system time when JDONE */
  152.     char    com [48];    /* command */
  153. };
  154.  
  155. /* proc states */
  156. #define    JFREE    0        /* unused proc */
  157. #define    JRUN    1        /* foreground */
  158. #define JEXIT    2        /* exit termination */
  159. #define    JSIGNAL    3        /* signal termination */
  160. #define    JSTOP    4        /* stopped */
  161.  
  162. static    Proc *procs = NULL;    /* job/process table */
  163.  
  164. clock_t    j_utime, j_stime;    /* user and system time for last job a-waited */
  165. #ifdef JOBS
  166. # ifdef USE_SIGACT
  167. sigset_t sm_default, sm_sigchld;    /* signal masks */
  168. # else
  169. static    int    sm_default, sm_sigchld;    /* signal masks */
  170. # endif
  171. static    int    our_pgrp;        /* shell's pgrp */
  172. #endif
  173. static    Proc   *j_lastj;        /* last proc created by exchild */
  174. static    int    j_lastjob = 0;        /* last created job */
  175. static    int    j_current = 0;        /* current job */
  176. static    int    j_previous = 0;        /* previous job */
  177.  
  178. static int      j_waitj     ARGS((Proc *aj, int intr));
  179. static void     j_print     ARGS((Proc *j));
  180. static int      j_newjob    ARGS((void));
  181. static Proc *   j_search    ARGS((int job));
  182. static void    j_sigchld   ARGS((int sig));
  183.  
  184. /* initialize job control */
  185. void
  186. j_init()
  187. {
  188. #ifdef JOBS
  189. # if defined(NTTYDISC) && defined(TIOCSETD)
  190.     int ldisc = NTTYDISC;    /* BSD brain damage */
  191.  
  192.     if (ttyfd >= 0)
  193.         ioctl(ttyfd, TIOCSETD, &ldisc);
  194. # endif
  195.     our_pgrp = getpgid(0);
  196.     sigchld_caught = 0;
  197. # ifdef USE_SIGACT
  198.     sigemptyset(&sm_default);
  199.     sigemptyset(&sm_sigchld);
  200.     sigaddset(&sm_sigchld, SIGCHLD);
  201. # else
  202.     sm_default = 0;
  203.     sm_sigchld = sigmask(SIGCHLD);
  204.     _TRACE(5, ("j_init: sm_sigchld == 0x%x", sm_sigchld));
  205. # endif
  206. #endif
  207. #ifndef JOBS
  208. # ifdef USE_SIGACT
  209.     sigaction(SIGCHLD, &Sigact_dfl, NULL);
  210. # else
  211. #   ifdef _SYSV
  212.     signal(SIGCHLD, SIG_DFL);    /* necessary ??? */
  213. #   endif
  214. # endif
  215. #endif
  216. }
  217.  
  218. /* job cleanup before shell exit */
  219. void
  220. j_exit()
  221. {
  222.     register Proc *j;
  223.     int killed = 0;
  224.  
  225. #ifdef JOBS
  226.     /* kill stopped jobs */
  227.     for (j = procs; j != NULL; j = j->next)
  228.         if (j->state == JSTOP) {
  229.             killed ++;
  230.             killpg(j->pgrp, SIGHUP);
  231.             killpg(j->pgrp, SIGCONT);
  232.         }
  233.     if (killed)
  234.         sleep(1);
  235. #endif
  236.     j_notify();
  237.  
  238. #ifdef JOBS
  239.     if (flag[FMONITOR]) {
  240.         flag[FMONITOR] = 0;
  241.         j_change();
  242.     }
  243. #endif
  244. }
  245.  
  246. #ifdef JOBS
  247. /* turn job control on or off according to flag[FMONITOR] */
  248. void
  249. j_change()
  250. {
  251. #ifdef USE_SIGACT
  252.     static struct sigaction old_tstp, old_ttin, old_ttou;
  253. #else
  254.     static handler_t old_tstp, old_ttin, old_ttou;
  255. #endif
  256.     if (flag[FMONITOR]) {
  257.         if (ttyfd < 0) {
  258.             flag[FMONITOR] = 0;
  259.             shellf("job control requires tty\n");
  260.             return;
  261.         }
  262. #ifdef USE_SIGACT
  263.         Sigact.sa_handler = j_sigchld;
  264.         sigemptyset(&Sigact.sa_mask);
  265.         Sigact.sa_flags = SA_RESTART;
  266.         sigaction(SIGCHLD, &Sigact, NULL);
  267.         Sigact.sa_flags = 0;
  268.         sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
  269.         sigaction(SIGTSTP, &Sigact_ign, &old_tstp);
  270.         sigtraps[SIGTSTP].sig_dfl = 1;
  271.         sigaction(SIGTTIN, &Sigact_ign, &old_ttin);
  272.         sigtraps[SIGTTIN].sig_dfl = 1;
  273.         sigaction(SIGTTOU, &Sigact_ign, &old_ttou);
  274.         sigtraps[SIGTTOU].sig_dfl = 1;
  275. #else
  276.         (void) signal(SIGCHLD, j_sigchld);
  277.         sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
  278.         old_tstp = signal(SIGTSTP, SIG_IGN);
  279.         sigtraps[SIGTSTP].sig_dfl = 1;
  280.         old_ttin = signal(SIGTTIN, SIG_IGN);
  281.         sigtraps[SIGTTIN].sig_dfl = 1;
  282.         old_ttou = signal(SIGTTOU, SIG_IGN);
  283.         sigtraps[SIGTTOU].sig_dfl = 1;
  284. #endif
  285. #ifdef USE_SIGACT
  286.         sigprocmask(SIG_SETMASK, &sm_default, NULL);
  287. #else
  288.         sigsetmask(sm_default);
  289. #endif
  290.         tcsetpgrp(ttyfd, our_pgrp);
  291.     } else {
  292. #ifdef USE_SIGACT
  293.         sigaction(SIGCHLD, &Sigact_dfl, NULL);
  294.         sigaction(SIGTSTP, &old_tstp, NULL);
  295.         sigtraps[SIGTSTP].sig_dfl = 0;
  296.         sigaction(SIGTTIN, &old_ttin, NULL);
  297.         sigtraps[SIGTTIN].sig_dfl = 0;
  298.         sigaction(SIGTTOU, &old_ttou, NULL);
  299.         sigtraps[SIGTTOU].sig_dfl = 0;
  300. #else
  301.         (void) signal(SIGCHLD, SIG_DFL);
  302.         (void) signal(SIGTSTP, old_tstp);
  303.         sigtraps[SIGTSTP].sig_dfl = 0;
  304.         (void) signal(SIGTTIN, old_ttin);
  305.         sigtraps[SIGTTIN].sig_dfl = 0;
  306.         (void) signal(SIGTTOU, old_ttou);
  307.         sigtraps[SIGTTOU].sig_dfl = 0;
  308. #endif
  309.     }
  310. }
  311. #endif
  312.  
  313. /* execute tree in child subprocess */
  314. int
  315. exchild(t, flags)
  316.     struct op *t;
  317.     int flags;
  318. {
  319.     register int i;
  320.     register Proc *j;
  321.     int rv = 0;
  322.     int forksleep;
  323.  
  324.     flags &= ~XFORK;
  325.     if ((flags&XEXEC))
  326.         return execute(t, flags);
  327.  
  328.     /* get free Proc entry */
  329.     for (j = procs; j != NULL; j = j->next)
  330.         if (j->state == JFREE)
  331.             goto Found;
  332.     j = (Proc*) alloc(sizeof(Proc), APERM);
  333.     j->next = procs;
  334.     j->state = JFREE;
  335.     procs = j;
  336.   Found:
  337.  
  338.     j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
  339.     j->proc = j->pgrp = 0;
  340.     j->flags = flags;
  341.     j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
  342.     snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
  343.     j->com[sizeof(j->com)-1] = '\0';
  344.     j->state = JRUN;
  345.  
  346.     /* stdio buffer must be flushed and invalidated */
  347.     for (i = (flags&XXWHL) ? 1 : 0; i < NUFILE; i++)
  348.         flushshf(i);
  349.  
  350. #ifdef JOBS
  351.     /* don't allow SIGCHLD until we are ready */
  352.  
  353. # ifdef USE_SIGACT
  354.     sigprocmask(SIG_SETMASK, &sm_sigchld, NULL);
  355. # else
  356.     sigsetmask(sm_sigchld);
  357. # endif
  358. #endif
  359.     /* create child process */
  360.     forksleep = 0;
  361.     while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
  362.         if (forksleep) {
  363.             sleep(forksleep);
  364.             forksleep <<= 1;
  365.         } else
  366.             forksleep = 1;
  367.     }
  368.     if (i < 0) {
  369.         j->state = JFREE;
  370.         errorf("cannot fork - try again\n");
  371.     }
  372.     j->proc = (i != 0) ? i : getpid();
  373.  
  374. #ifdef JOBS
  375.     /* job control set up */
  376.     if (flag[FMONITOR] && !(flags&XXCOM))
  377.     {
  378.       j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
  379.       /* do in both parent and child to avoid fork race condition */
  380.       if (!(flags&XBGND))
  381.         tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
  382.       setpgid(j->proc, j->pgrp);
  383.     }
  384. #endif
  385.     j_lastj = j;
  386.  
  387.     if (i == 0) {        /* child */
  388.         e.oenv = NULL;
  389.         if (flag[FTALKING])
  390.             restoresigs();
  391.         if ((flags&XBGND) && !flag[FMONITOR])
  392.         {
  393. #ifdef USE_SIGACT
  394.           sigaction(SIGINT, &Sigact_dfl, NULL);
  395.           sigaction(SIGQUIT, &Sigact_dfl, NULL);
  396.           if (flag[FTALKING])
  397.             sigaction(SIGTERM, &Sigact_dfl, NULL);
  398. #else
  399.           signal(SIGINT, SIG_IGN);
  400.           signal(SIGQUIT, SIG_IGN);
  401.           if (flag[FTALKING])
  402.             signal(SIGTERM, SIG_DFL);
  403. #endif
  404.             if (!(flags&XPIPEI)) {
  405.                 i = open("/dev/null", 0);
  406.                 (void) dup2(i, 0);
  407.                 close(i);
  408.             }
  409.         }
  410.         for (j = procs; j != NULL; j = j->next)
  411.             j->state = JFREE;
  412.         ttyfd = -1;
  413. #ifdef JOBS
  414.         /* is this needed in the child? */
  415. # ifdef USE_SIGACT
  416.         sigprocmask(SIG_SETMASK, &sm_default, NULL);
  417. # else
  418.         sigsetmask(sm_default);
  419. # endif
  420. #endif
  421.         flag[FMONITOR] = flag[FTALKING] = 0;
  422.         cleartraps();
  423.         execute(t, flags|XEXEC); /* no return */
  424.         /* NOTREACHED */
  425.     }
  426.  
  427.     /* shell (parent) stuff */
  428.     if ((flags&XBGND)) { /* async statement */
  429.         async = j->proc;
  430.         j_previous = j_current;
  431.         j_current = j->job;
  432.         if (flag[FTALKING])
  433.             j_print(j);
  434.     }
  435. #ifdef JOBS
  436. # ifdef USE_SIGACT
  437.     sigprocmask(SIG_SETMASK, &sm_default, NULL);
  438. # else
  439.     sigsetmask(sm_default);
  440. # endif
  441. #endif
  442.     if (!(flags&XBGND))
  443.     {         /* sync statement */
  444.         if (!(flags&XPIPE))
  445.             rv = j_waitj(j, 0);
  446.     }
  447.  
  448.     return rv;
  449. }
  450.  
  451. /* wait for last job: pipeline or $() sub-process */
  452. int
  453. waitlast()
  454. {
  455.     return j_waitj(j_lastj, 0);
  456. }
  457.  
  458. /* wait for job to complete or change state */
  459. static int
  460. j_waitj(aj, intr)
  461.     Proc *aj;
  462.     int intr;        /* interruptable */
  463. {
  464.     register Proc *j;
  465.     int rv = 1;
  466.     int ttysig = 0;
  467.  
  468. #ifdef JOBS
  469.     if (flag[FMONITOR])
  470.     {
  471. # ifdef USE_SIGACT
  472.       sigprocmask(SIG_SETMASK, &sm_sigchld, NULL);
  473. # else
  474.       _TRACE(5, ("j_waitj: sigsetmask(sm_sigchld==0x%x)", sm_sigchld));
  475.       sigsetmask(sm_sigchld);
  476. # endif
  477.     }
  478. #endif
  479.     /* wait for all members of pipeline */
  480.     for (j = aj; j != NULL; j = j->prev) {
  481.         /* wait for job to finish, stop, or ^C of built-in wait */
  482.         while (j->state == JRUN) {
  483. #ifdef JOBS
  484.             if (flag[FMONITOR])
  485.             {
  486.               /*
  487.                * 91-07-07 <sjg@sun0>
  488.                * we don't want to wait for a signal
  489.                * that has already arrived :-)
  490.                */
  491.               if (!sigchld_caught)
  492.               {
  493. # ifdef USE_SIGACT
  494.                 sigsuspend(&sm_default);
  495. # else
  496.                 _TRACE(4, ("j_waitj: sigpause(%d), sigchld_caught==%d", sm_default, sigchld_caught));
  497.                 sigpause(sm_default);
  498.                 _TRACE(4, ("j_waitj: sigpause() returned %d, sigchld_caught==%d", errno, sigchld_caught));
  499. # endif /* USE_SIGACT */
  500.               }
  501.             }
  502.             else
  503. #endif /* JOBS */
  504.                 j_sigchld(0);
  505.             /*
  506.              * Children to reap
  507.              */
  508.             if (sigchld_caught)
  509.               j_reapchld();
  510.             _TRACE(4, ("j_waitj: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  511.  
  512.             if (sigtraps[SIGINT].set && intr)
  513.                 goto Break;
  514.         }
  515.         if (j->state == JEXIT) { /* exit termination */
  516.             if (!(j->flags&XPIPEO))
  517.                 rv = WEXITSTATUS(j->status);
  518.             j->notify = 0;
  519.         } else
  520.         if (j->state == JSIGNAL) { /* signalled to death */
  521.             if (!(j->flags&XPIPEO))
  522.                 rv = 0x80 + WTERMSIG(j->status);
  523.             if (WTERMSIG(j->status) == SIGINT ||
  524.                 (WTERMSIG(j->status) == SIGPIPE &&
  525.                  (j->flags&XPIPEO)))
  526.                 j->notify = 0;
  527.             if (WTERMSIG(j->status) == SIGINT ||
  528.                 WTERMSIG(j->status) == SIGQUIT)
  529.                 ttysig = 1;
  530.         } else
  531. #ifdef JOBS
  532.         if (j->state == JSTOP)
  533.             if (WSTOPSIG(j->status) == SIGTSTP)
  534.                 ttysig = 1;
  535. #else
  536.         ;
  537. #endif
  538.     }
  539.  
  540.     /* compute total child time for time statement */
  541.     for (j = aj; j != NULL; j = j->prev)
  542.         j_utime += j->utime, j_stime += j->stime;
  543.  
  544.     /* find new current job */
  545. #ifdef JOBS
  546.     if (aj->state == JSTOP) {
  547.         j_previous = j_current;
  548.         j_current = aj->job;
  549.     } else {
  550. #else
  551.     if (1) {
  552. #endif
  553.         int hijob = 0;
  554.  
  555.         /* todo: this needs to be done in j_notify */
  556.         /* todo: figure out what to do with j_previous */
  557.         j_current = 0;
  558.         for (j = procs; j != NULL; j = j->next)
  559.             if ((j->state == JRUN || j->state == JSTOP)
  560.                 && j->job > hijob) {
  561.                 hijob = j->job;
  562.                 j_current = j->job;
  563.             }
  564.     }
  565.  
  566.   Break:
  567. #ifdef JOBS
  568.     if (flag[FMONITOR])
  569.     {
  570.       /* reset shell job control state */
  571. # ifdef USE_SIGACT
  572.       sigprocmask(SIG_SETMASK, &sm_default, NULL);
  573. # else
  574.       sigsetmask(sm_default);
  575. # endif
  576.       tcsetpgrp(ttyfd, our_pgrp);
  577.     }
  578. #endif
  579.     if (ttysig)
  580.         fputc('\n', shlout);
  581.     j_notify();
  582.  
  583.     return rv;
  584. }
  585.  
  586. /* SIGCHLD handler to reap children */
  587. /*
  588.  * 91-07-07 <sjg@sun0>
  589.  * On the Sun SS2 this appears to get called
  590.  * too quickly!
  591.  * So just record the event and process later.
  592.  */
  593. static void
  594. j_sigchld(sig)
  595.     int sig;
  596. {
  597.     sigchld_caught++;    /* acknowledge it */
  598. }
  599.  
  600. /*
  601.  * 91-07-07 <sjg@sun0>
  602.  * This now gets called when j_sigchld()
  603.  * has recorded some signals...
  604.  */
  605. j_reapchld()
  606. {
  607.     struct tms t0, t1;
  608. #if defined(JOBS)
  609. # ifdef USE_SIGACT
  610.     sigset_t    sm_old;
  611.  
  612.     sigprocmask(SIG_SETMASK, NULL, &sm_old);
  613. # else
  614.     int sm_old;
  615.  
  616.     sm_old = sigblock(0);    /* just get current mask */
  617.     _TRACE(5, ("j_reapchld: sm_old==0x%x, sigchld_caught==%d", sm_old, sigchld_caught));
  618. # endif
  619. #endif
  620.     (void) times(&t0);
  621.  
  622.     do {
  623.         register Proc *j;
  624.         int pid;
  625.         WAIT_T status;
  626. #ifdef JOBS
  627.         if (flag[FMONITOR])
  628.             pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
  629.         else
  630. #endif
  631.             pid = wait(&status);
  632.         if (pid < 0 && errno == ECHILD)
  633.         {
  634.           /* no children - what are we doing here? */
  635.           _TRACE(5, ("j_reapchld: no children"));
  636.           sigchld_caught = 0;
  637.           break;
  638.         }
  639.         if (pid <= 0)    /* return if would block (0) ... */
  640.             break;    /* ... or no children or interrupted (-1) */
  641.         (void) times(&t1);
  642.  
  643.         _TRACE(5, ("j_reapchld: looking for pid==%d", pid));
  644.  
  645.         for (j = procs; j != NULL; j = j->next)
  646.         {
  647.           _TRACE(6, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  648.           if (j->state != JFREE && j->proc == pid)
  649.             goto Found;
  650.         }
  651.         _TRACE(5, ("j_reapchld: did not find pid==%d", pid));
  652.         continue;
  653.       Found:
  654.         _TRACE(5, ("j_reapchld: found pid==%d", pid));
  655.         j->notify = 1;
  656.         j->status = status;
  657. #ifdef JOBS
  658.         if (WIFSTOPPED(status))
  659.             j->state = JSTOP;
  660.         else
  661. #endif
  662.         if (WIFEXITED(status))
  663.             j->state = JEXIT;
  664.         else
  665.         if (WIFSIGNALED(status))
  666.             j->state = JSIGNAL;
  667.  
  668.         /* compute child's time */
  669.         /* todo: what does a stopped job do? */
  670.         j->utime = t1.tms_cutime - t0.tms_cutime;
  671.         j->stime = t1.tms_cstime - t0.tms_cstime;
  672.         t0 = t1;
  673. #ifdef JOBS
  674. # ifdef USE_SIGACT
  675.         sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
  676. # else
  677.         sigblock(sm_sigchld);
  678. # endif
  679. #endif
  680.         if (--sigchld_caught < 0) /* reduce the count */
  681.           sigchld_caught = 0;
  682. #ifdef JOBS
  683. # ifdef USE_SIGACT
  684.         sigprocmask(SIG_SETMASK, &sm_old, NULL);
  685. # else
  686.         _TRACE(5, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  687.         sigsetmask(sm_old); /* restore old mask */
  688. # endif
  689. #endif
  690.         
  691. #ifdef JOBS
  692.     } while (flag[FMONITOR]);
  693. #else
  694.     } while (0);        /* only once if wait()ing */
  695. #endif
  696. /*
  697.  * this should be safe
  698.  */
  699. #if defined(_SYSV) && !defined(JOBS) && !defined(USE_SIGACT)
  700.     signal(SIGCHLD, j_sigchld);
  701. #if 0
  702.     /* why was this here??? */
  703.     signal(SIGCLD, SIG_DFL);
  704. #endif
  705. #endif
  706. }
  707.  
  708. j_reap()
  709. {
  710.   if (sigchld_caught)
  711.     j_reapchld();
  712. /*
  713.  * now done in j_reapchld()
  714.  */
  715. #if 0 && defined(_SYSV) && !defined(JOBS) && !defined(USE_SIGACT)
  716.     signal(SIGCHLD, j_sigchld);
  717.     signal(SIGCLD, SIG_DFL);
  718. #endif
  719.     return(0);
  720. }
  721.  
  722. /* wait for child, interruptable */
  723. int
  724. waitfor(job)
  725.     int job;
  726. {
  727.     register Proc *j;
  728.  
  729.     if (job == 0 && j_current == 0)
  730.         errorf("no current job\n");
  731.     j = j_search((job == 0) ? j_current : job);
  732.     if (j == NULL)
  733.         errorf("no such job: %d\n", job);
  734.     if (flag[FTALKING])
  735.         j_print(j);
  736.     if (e.interactive) {    /* flush stdout, shlout */
  737.         fflush(shf[1]);
  738.         fflush(shf[2]);
  739.     }
  740.     return j_waitj(j, 1);
  741. }
  742.  
  743. /* kill (built-in) a job */
  744. void
  745. j_kill(job, sig)
  746.     int job;
  747.     int sig;
  748. {
  749.     register Proc *j;
  750.  
  751.     j = j_search(job);
  752.     if (j == NULL)
  753.         errorf("cannot find job\n");
  754.     if (j->pgrp == 0) {    /* !flag[FMONITOR] */
  755.         if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
  756.             errorf("kill: %s\n", strerror(errno));
  757. #ifdef JOBS
  758.     } else {
  759.         if (sig == SIGTERM || sig == SIGHUP)
  760.             (void) killpg(j->pgrp, SIGCONT);
  761.         if (killpg(j->pgrp, sig) < 0)
  762.             errorf("killpg: %s\n", strerror(errno));
  763. #endif
  764.     }
  765. }
  766.  
  767. #ifdef JOBS
  768.  
  769. /* fg and bg built-ins */
  770. int
  771. j_resume(job, bg)
  772.     int job;
  773.     int bg;
  774. {
  775.     register Proc *j;
  776.  
  777.     j = j_search((job == 0) ? j_current : job);
  778.     if (j == NULL)
  779.         errorf("cannot find job\n", job);
  780.     if (j->pgrp == 0)
  781.         errorf("job not job-controlled\n");
  782.  
  783.     j->state = JRUN;
  784.     j_print(j);
  785.     flushshf(2);
  786.  
  787.     if (!bg)
  788.           tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
  789.     if (killpg(j->pgrp, SIGCONT) < 0)
  790.         errorf("cannot continue job %%%d\n", job);
  791.     if (!bg)
  792.         return j_waitj(j, 0);
  793.     return 0;
  794. }
  795.  
  796. #endif
  797.  
  798. /* list jobs for jobs built-in */
  799. void
  800. j_jobs()
  801. {
  802.     register Proc *j;
  803.  
  804.     for (j = procs; j != NULL; j = j->next)
  805.         if (j->state != JFREE)
  806.             j_print(j);
  807. }
  808.  
  809. /* list jobs for top-level notification */
  810. void
  811. j_notify()
  812. {
  813.     register Proc *j;
  814.  
  815.     /*
  816.      * since reaping is no longer done in the signal handler
  817.      * we had better try here...
  818.      */
  819.     if (sigchld_caught)
  820.       j_reapchld();
  821.  
  822.     for (j = procs; j != NULL; j = j->next) {
  823.         if (j->state == JEXIT && !flag[FTALKING])
  824.             j->notify = 0;
  825.         if (j->state != JFREE && j->notify)
  826.             j_print(j);
  827.         if (j->state == JEXIT || j->state == JSIGNAL)
  828.             j->state = JFREE;
  829.         j->notify = 0;
  830.     }
  831. }
  832.  
  833. static void
  834. j_print(j)
  835.     register Proc *j;
  836. {
  837.     char buf [64], *s = buf;
  838.  
  839.     switch (j->state) {
  840.       case JRUN:
  841.         s = "Running";
  842.         break;
  843.  
  844. #ifdef JOBS
  845.       case JSTOP:
  846.         strcpy(buf, "Stopped ");
  847.         s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
  848.         if (s != NULL)
  849.             strcat(buf, s);
  850.         s = buf;
  851.         break;
  852. #endif
  853.  
  854.       case JEXIT: {
  855.         int rv;
  856.         rv = WEXITSTATUS(j->status);
  857.         sprintf(buf, "Done (%d)", rv);
  858.         if (rv == 0)
  859.             *strchr(buf, '(') = 0;
  860.         j->state = JFREE;
  861.         } break;
  862.  
  863.       case JSIGNAL: {
  864.         int sig = WTERMSIG(j->status);
  865.         char *n = sigtraps[sig].mess;
  866.         if (n != NULL)
  867.             sprintf(buf, "%s", n);
  868.         else
  869.             sprintf(buf, "Signal %d", sig);
  870.         if (WIFCORED(j->status))
  871.             strcat(buf, " - core dumped");
  872.         j->state = JFREE;
  873.         } break;
  874.  
  875.       default:
  876.         s = "Hideous job state";
  877.         j->state = JFREE;
  878.         break;
  879.     }
  880.     shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
  881.            (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
  882.            j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
  883. }
  884.  
  885. /* convert % sequence to job number */
  886. int
  887. j_lookup(cp)
  888.     char *cp;
  889. {
  890.     register Proc *j;
  891.     int len, job = 0;
  892.  
  893.     if (*cp == '%')        /* leading % is optional */
  894.         cp++;
  895.     switch (*cp) {
  896.       case '\0':
  897.       case '+':
  898.         job = j_current;
  899.         break;
  900.  
  901.       case '-':
  902.         job = j_previous;
  903.         break;
  904.  
  905.       case '0': case '1': case '2': case '3': case '4':
  906.       case '5': case '6': case '7': case '8': case '9':
  907.         job = atoi(cp);
  908.         break;
  909.  
  910.       case '?':        /* %?string */
  911.         for (j = procs; j != NULL; j = j->next)
  912.             if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
  913.                 job = j->job;
  914.         break;
  915.  
  916.       default:        /* %string */
  917.         len = strlen(cp);
  918.         for (j = procs; j != NULL; j = j->next)
  919.             if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
  920.                 job = j->job;
  921.         break;
  922.     }
  923.     if (job == 0)
  924.         errorf("%s: no such job\n", cp);
  925.     return job;
  926. }
  927.  
  928. /* are any stopped jobs ? */
  929. #ifdef JOBS
  930. int
  931. j_stopped()
  932. {
  933.     register Proc *j;
  934.  
  935.     for (j = procs; j != NULL; j = j->next)
  936.         if (j->state == JSTOP)
  937.             return 1;
  938.     return 0;
  939. }
  940. #endif
  941.  
  942. /* create new job number */
  943. static int
  944. j_newjob()
  945. {
  946.     register Proc *j;
  947.     register int max = 0;
  948.  
  949.     j_lastjob ++;
  950.     for (j = procs; j != NULL; j = j->next)
  951.         if (j->state != JFREE && j->job)
  952.             if (j->job > max)
  953.                 max = j->job;
  954.     if (j_lastjob > max)
  955.         j_lastjob = max + 1;
  956.     return j_lastjob;
  957. }
  958.  
  959. /* search for job by job number */
  960. static Proc *
  961. j_search(job)
  962.     int job;
  963. {
  964.     register Proc *j;
  965.  
  966.     for (j = procs; j != NULL; j = j->next)
  967.         if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
  968.             return j;
  969.     return NULL;
  970. }
  971.  
  972.