home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / pdksh-src.lha / src / amiga / pdksh / sh / jobs.c < prev    next >
C/C++ Source or Header  |  1993-12-01  |  24KB  |  1,071 lines

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