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