home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / pdksh-4.9-src.tgz / tar.out / contrib / pdksh / sh / jobs.c < prev    next >
C/C++ Source or Header  |  1996-10-05  |  24KB  |  1,066 lines

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