home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / csh / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-06  |  30.7 KB  |  1,356 lines

  1. /*-
  2.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)proc.c    5.28 (Berkeley) 11/6/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/types.h>
  39. #include <sys/wait.h>
  40. #include <errno.h>
  41. #include <unistd.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #if __STDC__
  45. # include <stdarg.h>
  46. #else
  47. # include <varargs.h>
  48. #endif
  49.  
  50. #include "csh.h"
  51. #include "dir.h"
  52. #include "proc.h"
  53. #include "extern.h"
  54.  
  55. #define BIGINDEX    9    /* largest desirable job index */
  56.  
  57. static struct rusage zru;
  58.  
  59. static void     pflushall __P((void));
  60. static void     pflush __P((struct process *));
  61. static void     pclrcurr __P((struct process *));
  62. static void     padd __P((struct command *));
  63. static int     pprint __P((struct process *, int));
  64. static void     ptprint __P((struct process *));
  65. static void     pads __P((Char *));
  66. static void     pkill __P((Char **v, int));
  67. static struct    process
  68.         *pgetcurr __P((struct process *));
  69. static void     okpcntl __P((void));
  70.  
  71. /*
  72.  * pchild - called at interrupt level by the SIGCHLD signal
  73.  *    indicating that at least one child has terminated or stopped
  74.  *    thus at least one wait system call will definitely return a
  75.  *    childs status.  Top level routines (like pwait) must be sure
  76.  *    to mask interrupts when playing with the proclist data structures!
  77.  */
  78. /* ARGUSED */
  79. void
  80. pchild(notused)
  81.     int notused;
  82. {
  83.     register struct process *pp;
  84.     register struct process *fp;
  85.     register int pid;
  86.     extern int insource;
  87.     union wait w;
  88.     int     jobflags;
  89.     struct rusage ru;
  90.  
  91. loop:
  92.     errno = 0;            /* reset, just in case */
  93.     pid = wait3(&w.w_status,
  94.        (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
  95.  
  96.     if (pid <= 0) {
  97.     if (errno == EINTR) {
  98.         errno = 0;
  99.         goto loop;
  100.     }
  101.     pnoprocesses = pid == -1;
  102.     return;
  103.     }
  104.     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
  105.     if (pid == pp->p_pid)
  106.         goto found;
  107.     goto loop;
  108. found:
  109.     if (pid == atoi(short2str(value(STRchild))))
  110.     unsetv(STRchild);
  111.     pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
  112.     if (WIFSTOPPED(w)) {
  113.     pp->p_flags |= PSTOPPED;
  114.     pp->p_reason = w.w_stopsig;
  115.     }
  116.     else {
  117.     if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
  118.         (void) gettimeofday(&pp->p_etime, NULL);
  119.  
  120.     pp->p_rusage = ru;
  121.     if (WIFSIGNALED(w)) {
  122.         if (w.w_termsig == SIGINT)
  123.         pp->p_flags |= PINTERRUPTED;
  124.         else
  125.         pp->p_flags |= PSIGNALED;
  126.         if (w.w_coredump)
  127.         pp->p_flags |= PDUMPED;
  128.         pp->p_reason = w.w_termsig;
  129.     }
  130.     else {
  131.         pp->p_reason = w.w_retcode;
  132.         if (pp->p_reason != 0)
  133.         pp->p_flags |= PAEXITED;
  134.         else
  135.         pp->p_flags |= PNEXITED;
  136.     }
  137.     }
  138.     jobflags = 0;
  139.     fp = pp;
  140.     do {
  141.     if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
  142.         !child && adrof(STRtime) &&
  143.         fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
  144.         >= atoi(short2str(value(STRtime))))
  145.         fp->p_flags |= PTIME;
  146.     jobflags |= fp->p_flags;
  147.     } while ((fp = fp->p_friends) != pp);
  148.     pp->p_flags &= ~PFOREGND;
  149.     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
  150.     pp->p_flags &= ~PPTIME;
  151.     pp->p_flags |= PTIME;
  152.     }
  153.     if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
  154.     fp = pp;
  155.     do {
  156.         if (fp->p_flags & PSTOPPED)
  157.         fp->p_flags |= PREPORTED;
  158.     } while ((fp = fp->p_friends) != pp);
  159.     while (fp->p_pid != fp->p_jobid)
  160.         fp = fp->p_friends;
  161.     if (jobflags & PSTOPPED) {
  162.         if (pcurrent && pcurrent != fp)
  163.         pprevious = pcurrent;
  164.         pcurrent = fp;
  165.     }
  166.     else
  167.         pclrcurr(fp);
  168.     if (jobflags & PFOREGND) {
  169.         if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
  170. #ifdef IIASA
  171.         jobflags & PAEXITED ||
  172. #endif
  173.         !eq(dcwd->di_name, fp->p_cwd->di_name)) {
  174.         ;        /* print in pjwait */
  175.         }
  176.         /* PWP: print a newline after ^C */
  177.         else if (jobflags & PINTERRUPTED) {
  178.         (void) vis_fputc('\r' | QUOTE, cshout);
  179.         (void) fputc('\n', cshout);
  180.         }
  181.     }
  182.     else {
  183.         if (jobflags & PNOTIFY || adrof(STRnotify)) {
  184.         (void) vis_fputc('\r' | QUOTE, cshout);
  185.         (void) fputc('\n', cshout);
  186.         (void) pprint(pp, NUMBER | NAME | REASON);
  187.         if ((jobflags & PSTOPPED) == 0)
  188.             pflush(pp);
  189.         }
  190.         else {
  191.         fp->p_flags |= PNEEDNOTE;
  192.         neednote++;
  193.         }
  194.     }
  195.     }
  196.     goto loop;
  197. }
  198.  
  199. void
  200. pnote()
  201. {
  202.     register struct process *pp;
  203.     int     flags;
  204.     sigset_t omask;
  205.  
  206.     neednote = 0;
  207.     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
  208.     if (pp->p_flags & PNEEDNOTE) {
  209.         omask = sigblock(sigmask(SIGCHLD));
  210.         pp->p_flags &= ~PNEEDNOTE;
  211.         flags = pprint(pp, NUMBER | NAME | REASON);
  212.         if ((flags & (PRUNNING | PSTOPPED)) == 0)
  213.         pflush(pp);
  214.         (void) sigsetmask(omask);
  215.     }
  216.     }
  217. }
  218.  
  219. /*
  220.  * pwait - wait for current job to terminate, maintaining integrity
  221.  *    of current and previous job indicators.
  222.  */
  223. void
  224. pwait()
  225. {
  226.     register struct process *fp, *pp;
  227.     sigset_t omask;
  228.  
  229.     /*
  230.      * Here's where dead procs get flushed.
  231.      */
  232.     omask = sigblock(sigmask(SIGCHLD));
  233.     for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
  234.     if (pp->p_pid == 0) {
  235.         fp->p_next = pp->p_next;
  236.         xfree((ptr_t) pp->p_command);
  237.         if (pp->p_cwd && --pp->p_cwd->di_count == 0)
  238.         if (pp->p_cwd->di_next == 0)
  239.             dfree(pp->p_cwd);
  240.         xfree((ptr_t) pp);
  241.         pp = fp;
  242.     }
  243.     (void) sigsetmask(omask);
  244.     pjwait(pcurrjob);
  245. }
  246.  
  247.  
  248. /*
  249.  * pjwait - wait for a job to finish or become stopped
  250.  *    It is assumed to be in the foreground state (PFOREGND)
  251.  */
  252. void
  253. pjwait(pp)
  254.     register struct process *pp;
  255. {
  256.     register struct process *fp;
  257.     int     jobflags, reason;
  258.     sigset_t omask;
  259.  
  260.     while (pp->p_pid != pp->p_jobid)
  261.     pp = pp->p_friends;
  262.     fp = pp;
  263.  
  264.     do {
  265.     if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
  266.         (void) fprintf(csherr, "BUG: waiting for background job!\n");
  267.     } while ((fp = fp->p_friends) != pp);
  268.     /*
  269.      * Now keep pausing as long as we are not interrupted (SIGINT), and the
  270.      * target process, or any of its friends, are running
  271.      */
  272.     fp = pp;
  273.     omask = sigblock(sigmask(SIGCHLD));
  274.     for (;;) {
  275.     (void) sigblock(sigmask(SIGCHLD));
  276.     jobflags = 0;
  277.     do
  278.         jobflags |= fp->p_flags;
  279.     while ((fp = (fp->p_friends)) != pp);
  280.     if ((jobflags & PRUNNING) == 0)
  281.         break;
  282. #ifdef JOBDEBUG
  283.     (void) fprintf(csherr, "starting to sigpause for  SIGCHLD on %d\n",
  284.                fp->p_pid);
  285. #endif                /* JOBDEBUG */
  286.     (void) sigpause(omask & ~sigmask(SIGCHLD));
  287.     }
  288.     (void) sigsetmask(omask);
  289.     if (tpgrp > 0)        /* get tty back */
  290.     (void) tcsetpgrp(FSHTTY, tpgrp);
  291.     if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
  292.     !eq(dcwd->di_name, fp->p_cwd->di_name)) {
  293.     if (jobflags & PSTOPPED) {
  294.         (void) fputc('\n', cshout);
  295.         if (adrof(STRlistjobs)) {
  296.         Char   *jobcommand[3];
  297.  
  298.         jobcommand[0] = STRjobs;
  299.         if (eq(value(STRlistjobs), STRlong))
  300.             jobcommand[1] = STRml;
  301.         else
  302.             jobcommand[1] = NULL;
  303.         jobcommand[2] = NULL;
  304.  
  305.         dojobs(jobcommand, NULL);
  306.         (void) pprint(pp, SHELLDIR);
  307.         }
  308.         else
  309.         (void) pprint(pp, AREASON | SHELLDIR);
  310.     }
  311.     else
  312.         (void) pprint(pp, AREASON | SHELLDIR);
  313.     }
  314.     if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
  315.     (!gointr || !eq(gointr, STRminus))) {
  316.     if ((jobflags & PSTOPPED) == 0)
  317.         pflush(pp);
  318.     pintr1(0);
  319.     /* NOTREACHED */
  320.     }
  321.     reason = 0;
  322.     fp = pp;
  323.     do {
  324.     if (fp->p_reason)
  325.         reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
  326.         fp->p_reason | META : fp->p_reason;
  327.     } while ((fp = fp->p_friends) != pp);
  328.     if ((reason != 0) && (adrof(STRprintexitvalue))) {
  329.     (void) fprintf(cshout, "Exit %d\n", reason);
  330.     }
  331.     set(STRstatus, putn(reason));
  332.     if (reason && exiterr)
  333.     exitstat();
  334.     pflush(pp);
  335. }
  336.  
  337. /*
  338.  * dowait - wait for all processes to finish
  339.  */
  340. void
  341. /*ARGSUSED*/
  342. dowait(v, t)
  343.     Char **v;
  344.     struct command *t;
  345. {
  346.     register struct process *pp;
  347.     sigset_t omask;
  348.  
  349.     pjobs++;
  350.     omask = sigblock(sigmask(SIGCHLD));
  351. loop:
  352.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  353.     if (pp->p_pid &&    /* pp->p_pid == pp->p_jobid && */
  354.         pp->p_flags & PRUNNING) {
  355.         (void) sigpause((sigset_t) 0);
  356.         goto loop;
  357.     }
  358.     (void) sigsetmask(omask);
  359.     pjobs = 0;
  360. }
  361.  
  362. /*
  363.  * pflushall - flush all jobs from list (e.g. at fork())
  364.  */
  365. static void
  366. pflushall()
  367. {
  368.     register struct process *pp;
  369.  
  370.     for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
  371.     if (pp->p_pid)
  372.         pflush(pp);
  373. }
  374.  
  375. /*
  376.  * pflush - flag all process structures in the same job as the
  377.  *    the argument process for deletion.  The actual free of the
  378.  *    space is not done here since pflush is called at interrupt level.
  379.  */
  380. static void
  381. pflush(pp)
  382.     register struct process *pp;
  383. {
  384.     register struct process *np;
  385.     register int idx;
  386.  
  387.     if (pp->p_pid == 0) {
  388.     (void) fprintf(csherr, "BUG: process flushed twice");
  389.     return;
  390.     }
  391.     while (pp->p_pid != pp->p_jobid)
  392.     pp = pp->p_friends;
  393.     pclrcurr(pp);
  394.     if (pp == pcurrjob)
  395.     pcurrjob = 0;
  396.     idx = pp->p_index;
  397.     np = pp;
  398.     do {
  399.     np->p_index = np->p_pid = 0;
  400.     np->p_flags &= ~PNEEDNOTE;
  401.     } while ((np = np->p_friends) != pp);
  402.     if (idx == pmaxindex) {
  403.     for (np = proclist.p_next, idx = 0; np; np = np->p_next)
  404.         if (np->p_index > idx)
  405.         idx = np->p_index;
  406.     pmaxindex = idx;
  407.     }
  408. }
  409.  
  410. /*
  411.  * pclrcurr - make sure the given job is not the current or previous job;
  412.  *    pp MUST be the job leader
  413.  */
  414. static void
  415. pclrcurr(pp)
  416.     register struct process *pp;
  417. {
  418.  
  419.     if (pp == pcurrent)
  420.     if (pprevious != NULL) {
  421.         pcurrent = pprevious;
  422.         pprevious = pgetcurr(pp);
  423.     }
  424.     else {
  425.         pcurrent = pgetcurr(pp);
  426.         pprevious = pgetcurr(pp);
  427.     }
  428.     else if (pp == pprevious)
  429.     pprevious = pgetcurr(pp);
  430. }
  431.  
  432. /* +4 here is 1 for '\0', 1 ea for << >& >> */
  433. static Char command[PMAXLEN + 4];
  434. static int cmdlen;
  435. static Char *cmdp;
  436.  
  437. /*
  438.  * palloc - allocate a process structure and fill it up.
  439.  *    an important assumption is made that the process is running.
  440.  */
  441. void
  442. palloc(pid, t)
  443.     int     pid;
  444.     register struct command *t;
  445. {
  446.     register struct process *pp;
  447.     int     i;
  448.  
  449.     pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
  450.     pp->p_pid = pid;
  451.     pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND;
  452.     if (t->t_dflg & F_TIME)
  453.     pp->p_flags |= PPTIME;
  454.     cmdp = command;
  455.     cmdlen = 0;
  456.     padd(t);
  457.     *cmdp++ = 0;
  458.     if (t->t_dflg & F_PIPEOUT) {
  459.     pp->p_flags |= PPOU;
  460.     if (t->t_dflg & F_STDERR)
  461.         pp->p_flags |= PERR;
  462.     }
  463.     pp->p_command = Strsave(command);
  464.     if (pcurrjob) {
  465.     struct process *fp;
  466.  
  467.     /* careful here with interrupt level */
  468.     pp->p_cwd = 0;
  469.     pp->p_index = pcurrjob->p_index;
  470.     pp->p_friends = pcurrjob;
  471.     pp->p_jobid = pcurrjob->p_pid;
  472.     for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
  473.         continue;
  474.     fp->p_friends = pp;
  475.     }
  476.     else {
  477.     pcurrjob = pp;
  478.     pp->p_jobid = pid;
  479.     pp->p_friends = pp;
  480.     pp->p_cwd = dcwd;
  481.     dcwd->di_count++;
  482.     if (pmaxindex < BIGINDEX)
  483.         pp->p_index = ++pmaxindex;
  484.     else {
  485.         struct process *np;
  486.  
  487.         for (i = 1;; i++) {
  488.         for (np = proclist.p_next; np; np = np->p_next)
  489.             if (np->p_index == i)
  490.             goto tryagain;
  491.         pp->p_index = i;
  492.         if (i > pmaxindex)
  493.             pmaxindex = i;
  494.         break;
  495.     tryagain:;
  496.         }
  497.     }
  498.     if (pcurrent == NULL)
  499.         pcurrent = pp;
  500.     else if (pprevious == NULL)
  501.         pprevious = pp;
  502.     }
  503.     pp->p_next = proclist.p_next;
  504.     proclist.p_next = pp;
  505.     (void) gettimeofday(&pp->p_btime, NULL);
  506. }
  507.  
  508. static void
  509. padd(t)
  510.     register struct command *t;
  511. {
  512.     Char  **argp;
  513.  
  514.     if (t == 0)
  515.     return;
  516.     switch (t->t_dtyp) {
  517.  
  518.     case NODE_PAREN:
  519.     pads(STRLparensp);
  520.     padd(t->t_dspr);
  521.     pads(STRspRparen);
  522.     break;
  523.  
  524.     case NODE_COMMAND:
  525.     for (argp = t->t_dcom; *argp; argp++) {
  526.         pads(*argp);
  527.         if (argp[1])
  528.         pads(STRspace);
  529.     }
  530.     break;
  531.  
  532.     case NODE_OR:
  533.     case NODE_AND:
  534.     case NODE_PIPE:
  535.     case NODE_LIST:
  536.     padd(t->t_dcar);
  537.     switch (t->t_dtyp) {
  538.     case NODE_OR:
  539.         pads(STRspor2sp);
  540.         break;
  541.     case NODE_AND:
  542.         pads(STRspand2sp);
  543.         break;
  544.     case NODE_PIPE:
  545.         pads(STRsporsp);
  546.         break;
  547.     case NODE_LIST:
  548.         pads(STRsemisp);
  549.         break;
  550.     }
  551.     padd(t->t_dcdr);
  552.     return;
  553.     }
  554.     if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
  555.     pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
  556.     pads(t->t_dlef);
  557.     }
  558.     if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
  559.     pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
  560.     if (t->t_dflg & F_STDERR)
  561.         pads(STRand);
  562.     pads(STRspace);
  563.     pads(t->t_drit);
  564.     }
  565. }
  566.  
  567. static void
  568. pads(cp)
  569.     Char   *cp;
  570. {
  571.     register int i;
  572.  
  573.     /*
  574.      * Avoid the Quoted Space alias hack! Reported by:
  575.      * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
  576.      */
  577.     if (cp[0] == STRQNULL[0])
  578.     cp++;
  579.  
  580.     i = Strlen(cp);
  581.  
  582.     if (cmdlen >= PMAXLEN)
  583.     return;
  584.     if (cmdlen + i >= PMAXLEN) {
  585.     (void) Strcpy(cmdp, STRsp3dots);
  586.     cmdlen = PMAXLEN;
  587.     cmdp += 4;
  588.     return;
  589.     }
  590.     (void) Strcpy(cmdp, cp);
  591.     cmdp += i;
  592.     cmdlen += i;
  593. }
  594.  
  595. /*
  596.  * psavejob - temporarily save the current job on a one level stack
  597.  *    so another job can be created.  Used for { } in exp6
  598.  *    and `` in globbing.
  599.  */
  600. void
  601. psavejob()
  602. {
  603.  
  604.     pholdjob = pcurrjob;
  605.     pcurrjob = NULL;
  606. }
  607.  
  608. /*
  609.  * prestjob - opposite of psavejob.  This may be missed if we are interrupted
  610.  *    somewhere, but pendjob cleans up anyway.
  611.  */
  612. void
  613. prestjob()
  614. {
  615.  
  616.     pcurrjob = pholdjob;
  617.     pholdjob = NULL;
  618. }
  619.  
  620. /*
  621.  * pendjob - indicate that a job (set of commands) has been completed
  622.  *    or is about to begin.
  623.  */
  624. void
  625. pendjob()
  626. {
  627.     register struct process *pp, *tp;
  628.  
  629.     if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
  630.     pp = pcurrjob;
  631.     while (pp->p_pid != pp->p_jobid)
  632.         pp = pp->p_friends;
  633.     (void) fprintf(cshout, "[%d]", pp->p_index);
  634.     tp = pp;
  635.     do {
  636.         (void) fprintf(cshout, " %d", pp->p_pid);
  637.         pp = pp->p_friends;
  638.     } while (pp != tp);
  639.     (void) fputc('\n', cshout);
  640.     }
  641.     pholdjob = pcurrjob = 0;
  642. }
  643.  
  644. /*
  645.  * pprint - print a job
  646.  */
  647. static int
  648. pprint(pp, flag)
  649.     register struct process *pp;
  650.     bool    flag;
  651. {
  652.     register status, reason;
  653.     struct process *tp;
  654.     int     jobflags, pstatus;
  655.     bool hadnl = 1;    /* did we just have a newline */
  656.     char   *format;
  657.  
  658.     (void) fpurge(cshout);
  659.  
  660.     while (pp->p_pid != pp->p_jobid)
  661.     pp = pp->p_friends;
  662.     if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
  663.     pp->p_flags &= ~PPTIME;
  664.     pp->p_flags |= PTIME;
  665.     }
  666.     tp = pp;
  667.     status = reason = -1;
  668.     jobflags = 0;
  669.     do {
  670.     jobflags |= pp->p_flags;
  671.     pstatus = pp->p_flags & PALLSTATES;
  672.     if (tp != pp && !hadnl && !(flag & FANCY) &&
  673.         ((pstatus == status && pp->p_reason == reason) ||
  674.          !(flag & REASON))) {
  675.         (void) fputc(' ', cshout);
  676.         hadnl = 0;
  677.     }
  678.     else {
  679.         if (tp != pp && !hadnl) {
  680.         (void) fputc('\n', cshout);
  681.         hadnl = 1;
  682.         }
  683.         if (flag & NUMBER) {
  684.         if (pp == tp)
  685.             (void) fprintf(cshout, "[%d]%s %c ", pp->p_index,
  686.                 pp->p_index < 10 ? " " : "",
  687.                 pp == pcurrent ? '+' :
  688.                 (pp == pprevious ? '-' : ' '));
  689.         else
  690.             (void) fprintf(cshout, "       ");
  691.         hadnl = 0;
  692.         }
  693.         if (flag & FANCY) {
  694.         (void) fprintf(cshout, "%5d ", pp->p_pid);
  695.         hadnl = 0;
  696.         }
  697.         if (flag & (REASON | AREASON)) {
  698.         if (flag & NAME)
  699.             format = "%-23s";
  700.         else
  701.             format = "%s";
  702.         if (pstatus == status)
  703.             if (pp->p_reason == reason) {
  704.             (void) fprintf(cshout, format, "");
  705.             hadnl = 0;
  706.             goto prcomd;
  707.             }
  708.             else
  709.             reason = pp->p_reason;
  710.         else {
  711.             status = pstatus;
  712.             reason = pp->p_reason;
  713.         }
  714.         switch (status) {
  715.  
  716.         case PRUNNING:
  717.             (void) fprintf(cshout, format, "Running ");
  718.             hadnl = 0;
  719.             break;
  720.  
  721.         case PINTERRUPTED:
  722.         case PSTOPPED:
  723.         case PSIGNALED:
  724.                     /*
  725.                      * tell what happened to the background job
  726.                      * From: Michael Schroeder
  727.                      * <mlschroe@immd4.informatik.uni-erlangen.de>
  728.                      */
  729.                     if ((flag & REASON)
  730.                         || ((flag & AREASON)
  731.                             && reason != SIGINT
  732.                             && (reason != SIGPIPE
  733.                                 || (pp->p_flags & PPOU) == 0))) {
  734.             (void) fprintf(cshout, format,
  735.                        sys_siglist[pp->p_reason]);
  736.             hadnl = 0;
  737.             }
  738.             break;
  739.  
  740.         case PNEXITED:
  741.         case PAEXITED:
  742.             if (flag & REASON) {
  743.             if (pp->p_reason)
  744.                 (void) fprintf(cshout, "Exit %-18d", pp->p_reason);
  745.             else
  746.                 (void) fprintf(cshout, format, "Done");
  747.             hadnl = 0;
  748.             }
  749.             break;
  750.  
  751.         default:
  752.             (void) fprintf(csherr, "BUG: status=%-9o", status);
  753.         }
  754.         }
  755.     }
  756. prcomd:
  757.     if (flag & NAME) {
  758.         (void) fprintf(cshout, "%s", vis_str(pp->p_command));
  759.         if (pp->p_flags & PPOU)
  760.         (void) fprintf(cshout, " |");
  761.         if (pp->p_flags & PERR)
  762.         (void) fputc('&', cshout);
  763.         hadnl = 0;
  764.     }
  765.     if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) {
  766.         (void) fprintf(cshout, " (core dumped)");
  767.         hadnl = 0;
  768.     }
  769.     if (tp == pp->p_friends) {
  770.         if (flag & AMPERSAND) {
  771.         (void) fprintf(cshout, " &");
  772.         hadnl = 0;
  773.         }
  774.         if (flag & JOBDIR &&
  775.         !eq(tp->p_cwd->di_name, dcwd->di_name)) {
  776.         (void) fprintf(cshout, " (wd: ");
  777.         dtildepr(value(STRhome), tp->p_cwd->di_name);
  778.         (void) fputc(')', cshout);
  779.         hadnl = 0;
  780.         }
  781.     }
  782.     if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
  783.         if (!hadnl)
  784.         (void) fprintf(cshout, "\n\t");
  785.         prusage(&zru, &pp->p_rusage, &pp->p_etime,
  786.             &pp->p_btime);
  787.         hadnl = 1;
  788.     }
  789.     if (tp == pp->p_friends) {
  790.         if (!hadnl) {
  791.         (void) fputc('\n', cshout);
  792.         hadnl = 1;
  793.         }
  794.         if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
  795.         (void) fprintf(cshout, "(wd now: ");
  796.         dtildepr(value(STRhome), dcwd->di_name);
  797.         (void) fprintf(cshout, ")\n");
  798.         hadnl = 1;
  799.         }
  800.     }
  801.     } while ((pp = pp->p_friends) != tp);
  802.     if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
  803.     if (jobflags & NUMBER)
  804.         (void) fprintf(cshout, "       ");
  805.     ptprint(tp);
  806.     hadnl = 1;
  807.     }
  808.     (void) fflush(cshout);
  809.     return (jobflags);
  810. }
  811.  
  812. static void
  813. ptprint(tp)
  814.     register struct process *tp;
  815. {
  816.     struct timeval tetime, diff;
  817.     static struct timeval ztime;
  818.     struct rusage ru;
  819.     static struct rusage zru;
  820.     register struct process *pp = tp;
  821.  
  822.     ru = zru;
  823.     tetime = ztime;
  824.     do {
  825.     ruadd(&ru, &pp->p_rusage);
  826.     tvsub(&diff, &pp->p_etime, &pp->p_btime);
  827.     if (timercmp(&diff, &tetime, >))
  828.         tetime = diff;
  829.     } while ((pp = pp->p_friends) != tp);
  830.     prusage(&zru, &ru, &tetime, &ztime);
  831. }
  832.  
  833. /*
  834.  * dojobs - print all jobs
  835.  */
  836. void
  837. /*ARGSUSED*/
  838. dojobs(v, t)
  839.     Char **v;
  840.     struct command *t;
  841. {
  842.     register struct process *pp;
  843.     register int flag = NUMBER | NAME | REASON;
  844.     int     i;
  845.  
  846.     if (chkstop)
  847.     chkstop = 2;
  848.     if (*++v) {
  849.     if (v[1] || !eq(*v, STRml))
  850.         stderror(ERR_JOBS);
  851.     flag |= FANCY | JOBDIR;
  852.     }
  853.     for (i = 1; i <= pmaxindex; i++)
  854.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  855.         if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
  856.         pp->p_flags &= ~PNEEDNOTE;
  857.         if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
  858.             pflush(pp);
  859.         break;
  860.         }
  861. }
  862.  
  863. /*
  864.  * dofg - builtin - put the job into the foreground
  865.  */
  866. void
  867. /*ARGSUSED*/
  868. dofg(v, t)
  869.     Char **v;
  870.     struct command *t;
  871. {
  872.     register struct process *pp;
  873.  
  874.     okpcntl();
  875.     ++v;
  876.     do {
  877.     pp = pfind(*v);
  878.     pstart(pp, 1);
  879.     pjwait(pp);
  880.     } while (*v && *++v);
  881. }
  882.  
  883. /*
  884.  * %... - builtin - put the job into the foreground
  885.  */
  886. void
  887. /*ARGSUSED*/
  888. dofg1(v, t)
  889.     Char **v;
  890.     struct command *t;
  891. {
  892.     register struct process *pp;
  893.  
  894.     okpcntl();
  895.     pp = pfind(v[0]);
  896.     pstart(pp, 1);
  897.     pjwait(pp);
  898. }
  899.  
  900. /*
  901.  * dobg - builtin - put the job into the background
  902.  */
  903. void
  904. /*ARGSUSED*/
  905. dobg(v, t)
  906.     Char **v;
  907.     struct command *t;
  908. {
  909.     register struct process *pp;
  910.  
  911.     okpcntl();
  912.     ++v;
  913.     do {
  914.     pp = pfind(*v);
  915.     pstart(pp, 0);
  916.     } while (*v && *++v);
  917. }
  918.  
  919. /*
  920.  * %... & - builtin - put the job into the background
  921.  */
  922. void
  923. /*ARGSUSED*/
  924. dobg1(v, t)
  925.     Char **v;
  926.     struct command *t;
  927. {
  928.     register struct process *pp;
  929.  
  930.     pp = pfind(v[0]);
  931.     pstart(pp, 0);
  932. }
  933.  
  934. /*
  935.  * dostop - builtin - stop the job
  936.  */
  937. void
  938. /*ARGSUSED*/
  939. dostop(v, t)
  940.     Char **v;
  941.     struct command *t;
  942. {
  943.     pkill(++v, SIGSTOP);
  944. }
  945.  
  946. /*
  947.  * dokill - builtin - superset of kill (1)
  948.  */
  949. void
  950. /*ARGSUSED*/
  951. dokill(v, t)
  952.     Char **v;
  953.     struct command *t;
  954. {
  955.     register int signum = SIGTERM;
  956.     register char *name;
  957.  
  958.     v++;
  959.     if (v[0] && v[0][0] == '-') {
  960.     if (v[0][1] == 'l') {
  961.         for (signum = 1; signum < NSIG; signum++) {
  962.         (void) fprintf(cshout, "%s ", sys_signame[signum]);
  963.         if (signum == NSIG / 2)
  964.             (void) fputc('\n', cshout);
  965.         }
  966.         (void) fputc('\n', cshout);
  967.         return;
  968.     }
  969.     if (Isdigit(v[0][1])) {
  970.         signum = atoi(short2str(v[0] + 1));
  971.         if (signum < 0 || signum > NSIG)
  972.         stderror(ERR_NAME | ERR_BADSIG);
  973.     }
  974.     else {
  975.         name = short2str(&v[0][1]);
  976.         if (!strncasecmp(name, "sig", 3))
  977.         name += 3;
  978.  
  979.         for (signum = 1; signum < NSIG; signum++)
  980.         if (!strcasecmp(sys_signame[signum], name))
  981.             break;
  982.  
  983.         if (signum == NSIG) {
  984.         setname(vis_str(&v[0][1]));
  985.         stderror(ERR_NAME | ERR_UNKSIG);
  986.         }
  987.     }
  988.     v++;
  989.     }
  990.     pkill(v, signum);
  991. }
  992.  
  993. static void
  994. pkill(v, signum)
  995.     Char  **v;
  996.     int     signum;
  997. {
  998.     register struct process *pp, *np;
  999.     register int jobflags = 0;
  1000.     int     pid, err1 = 0;
  1001.     sigset_t omask;
  1002.     Char   *cp;
  1003.  
  1004.     omask = sigmask(SIGCHLD);
  1005.     if (setintr)
  1006.     omask |= sigmask(SIGINT);
  1007.     omask = sigblock(omask) & ~omask;
  1008.     gflag = 0, tglob(v);
  1009.     if (gflag) {
  1010.     v = globall(v);
  1011.     if (v == 0)
  1012.         stderror(ERR_NAME | ERR_NOMATCH);
  1013.     }
  1014.     else {
  1015.     v = gargv = saveblk(v);
  1016.     trim(v);
  1017.     }
  1018.  
  1019.     while (v && (cp = *v)) {
  1020.     if (*cp == '%') {
  1021.         np = pp = pfind(cp);
  1022.         do
  1023.         jobflags |= np->p_flags;
  1024.         while ((np = np->p_friends) != pp);
  1025.         switch (signum) {
  1026.  
  1027.         case SIGSTOP:
  1028.         case SIGTSTP:
  1029.         case SIGTTIN:
  1030.         case SIGTTOU:
  1031.         if ((jobflags & PRUNNING) == 0) {
  1032.             (void) fprintf(csherr, "%s: Already suspended\n",
  1033.                    vis_str(cp));
  1034.             err1++;
  1035.             goto cont;
  1036.         }
  1037.         break;
  1038.         /*
  1039.          * suspend a process, kill -CONT %, then type jobs; the shell
  1040.          * says it is suspended, but it is running; thanks jaap..
  1041.          */
  1042.         case SIGCONT:
  1043.         pstart(pp, 0);
  1044.         goto cont;
  1045.         }
  1046.         if (killpg((pid_t) pp->p_jobid, signum) < 0) {
  1047.         (void) fprintf(csherr, "%s: %s\n", vis_str(cp),
  1048.                    strerror(errno));
  1049.         err1++;
  1050.         }
  1051.         if (signum == SIGTERM || signum == SIGHUP)
  1052.         (void) killpg((pid_t) pp->p_jobid, SIGCONT);
  1053.     }
  1054.     else if (!(Isdigit(*cp) || *cp == '-'))
  1055.         stderror(ERR_NAME | ERR_JOBARGS);
  1056.     else {
  1057.         pid = atoi(short2str(cp));
  1058.         if (kill((pid_t) pid, signum) < 0) {
  1059.         (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno));
  1060.         err1++;
  1061.         goto cont;
  1062.         }
  1063.         if (signum == SIGTERM || signum == SIGHUP)
  1064.         (void) kill((pid_t) pid, SIGCONT);
  1065.     }
  1066. cont:
  1067.     v++;
  1068.     }
  1069.     if (gargv)
  1070.     blkfree(gargv), gargv = 0;
  1071.     (void) sigsetmask(omask);
  1072.     if (err1)
  1073.     stderror(ERR_SILENT);
  1074. }
  1075.  
  1076. /*
  1077.  * pstart - start the job in foreground/background
  1078.  */
  1079. void
  1080. pstart(pp, foregnd)
  1081.     register struct process *pp;
  1082.     int     foregnd;
  1083. {
  1084.     register struct process *np;
  1085.     sigset_t omask;
  1086.     long    jobflags = 0;
  1087.  
  1088.     omask = sigblock(sigmask(SIGCHLD));
  1089.     np = pp;
  1090.     do {
  1091.     jobflags |= np->p_flags;
  1092.     if (np->p_flags & (PRUNNING | PSTOPPED)) {
  1093.         np->p_flags |= PRUNNING;
  1094.         np->p_flags &= ~PSTOPPED;
  1095.         if (foregnd)
  1096.         np->p_flags |= PFOREGND;
  1097.         else
  1098.         np->p_flags &= ~PFOREGND;
  1099.     }
  1100.     } while ((np = np->p_friends) != pp);
  1101.     if (!foregnd)
  1102.     pclrcurr(pp);
  1103.     (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
  1104.     if (foregnd)
  1105.     (void) tcsetpgrp(FSHTTY, pp->p_jobid);
  1106.     if (jobflags & PSTOPPED)
  1107.     (void) killpg((pid_t) pp->p_jobid, SIGCONT);
  1108.     (void) sigsetmask(omask);
  1109. }
  1110.  
  1111. void
  1112. panystop(neednl)
  1113.     bool    neednl;
  1114. {
  1115.     register struct process *pp;
  1116.  
  1117.     chkstop = 2;
  1118.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  1119.     if (pp->p_flags & PSTOPPED)
  1120.         stderror(ERR_STOPPED, neednl ? "\n" : "");
  1121. }
  1122.  
  1123. struct process *
  1124. pfind(cp)
  1125.     Char   *cp;
  1126. {
  1127.     register struct process *pp, *np;
  1128.  
  1129.     if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
  1130.     if (pcurrent == NULL)
  1131.         stderror(ERR_NAME | ERR_JOBCUR);
  1132.     return (pcurrent);
  1133.     }
  1134.     if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
  1135.     if (pprevious == NULL)
  1136.         stderror(ERR_NAME | ERR_JOBPREV);
  1137.     return (pprevious);
  1138.     }
  1139.     if (Isdigit(cp[1])) {
  1140.     int     idx = atoi(short2str(cp + 1));
  1141.  
  1142.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  1143.         if (pp->p_index == idx && pp->p_pid == pp->p_jobid)
  1144.         return (pp);
  1145.     stderror(ERR_NAME | ERR_NOSUCHJOB);
  1146.     }
  1147.     np = NULL;
  1148.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  1149.     if (pp->p_pid == pp->p_jobid) {
  1150.         if (cp[1] == '?') {
  1151.         register Char *dp;
  1152.  
  1153.         for (dp = pp->p_command; *dp; dp++) {
  1154.             if (*dp != cp[2])
  1155.             continue;
  1156.             if (prefix(cp + 2, dp))
  1157.             goto match;
  1158.         }
  1159.         }
  1160.         else if (prefix(cp + 1, pp->p_command)) {
  1161.     match:
  1162.         if (np)
  1163.             stderror(ERR_NAME | ERR_AMBIG);
  1164.         np = pp;
  1165.         }
  1166.     }
  1167.     if (np)
  1168.     return (np);
  1169.     stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB);
  1170.     /* NOTREACHED */
  1171.     return (0);
  1172. }
  1173.  
  1174.  
  1175. /*
  1176.  * pgetcurr - find most recent job that is not pp, preferably stopped
  1177.  */
  1178. static struct process *
  1179. pgetcurr(pp)
  1180.     register struct process *pp;
  1181. {
  1182.     register struct process *np;
  1183.     register struct process *xp = NULL;
  1184.  
  1185.     for (np = proclist.p_next; np; np = np->p_next)
  1186.     if (np != pcurrent && np != pp && np->p_pid &&
  1187.         np->p_pid == np->p_jobid) {
  1188.         if (np->p_flags & PSTOPPED)
  1189.         return (np);
  1190.         if (xp == NULL)
  1191.         xp = np;
  1192.     }
  1193.     return (xp);
  1194. }
  1195.  
  1196. /*
  1197.  * donotify - flag the job so as to report termination asynchronously
  1198.  */
  1199. void
  1200. /*ARGSUSED*/
  1201. donotify(v, t)
  1202.     Char **v;
  1203.     struct command *t;
  1204. {
  1205.     register struct process *pp;
  1206.  
  1207.     pp = pfind(*++v);
  1208.     pp->p_flags |= PNOTIFY;
  1209. }
  1210.  
  1211. /*
  1212.  * Do the fork and whatever should be done in the child side that
  1213.  * should not be done if we are not forking at all (like for simple builtin's)
  1214.  * Also do everything that needs any signals fiddled with in the parent side
  1215.  *
  1216.  * Wanttty tells whether process and/or tty pgrps are to be manipulated:
  1217.  *    -1:    leave tty alone; inherit pgrp from parent
  1218.  *     0:    already have tty; manipulate process pgrps only
  1219.  *     1:    want to claim tty; manipulate process and tty pgrps
  1220.  * It is usually just the value of tpgrp.
  1221.  */
  1222.  
  1223. int
  1224. pfork(t, wanttty)
  1225.     struct command *t;        /* command we are forking for */
  1226.     int     wanttty;
  1227. {
  1228.     register int pid;
  1229.     bool    ignint = 0;
  1230.     int     pgrp;
  1231.     sigset_t omask;
  1232.  
  1233.     /*
  1234.      * A child will be uninterruptible only under very special conditions.
  1235.      * Remember that the semantics of '&' is implemented by disconnecting the
  1236.      * process from the tty so signals do not need to ignored just for '&'.
  1237.      * Thus signals are set to default action for children unless: we have had
  1238.      * an "onintr -" (then specifically ignored) we are not playing with
  1239.      * signals (inherit action)
  1240.      */
  1241.     if (setintr)
  1242.     ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
  1243.         || (gointr && eq(gointr, STRminus));
  1244.     /*
  1245.      * Check for maximum nesting of 16 processes to avoid Forking loops
  1246.      */
  1247.     if (child == 16)
  1248.     stderror(ERR_NESTING, 16);
  1249.     /*
  1250.      * Hold SIGCHLD until we have the process installed in our table.
  1251.      */
  1252.     omask = sigblock(sigmask(SIGCHLD));
  1253.     while ((pid = fork()) < 0)
  1254.     if (setintr == 0)
  1255.         (void) sleep(FORKSLEEP);
  1256.     else {
  1257.         (void) sigsetmask(omask);
  1258.         stderror(ERR_NOPROC);
  1259.     }
  1260.     if (pid == 0) {
  1261.     settimes();
  1262.     pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
  1263.     pflushall();
  1264.     pcurrjob = NULL;
  1265.     child++;
  1266.     if (setintr) {
  1267.         setintr = 0;    /* until I think otherwise */
  1268.         /*
  1269.          * Children just get blown away on SIGINT, SIGQUIT unless "onintr
  1270.          * -" seen.
  1271.          */
  1272.         (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
  1273.         (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
  1274.         if (wanttty >= 0) {
  1275.         /* make stoppable */
  1276.         (void) signal(SIGTSTP, SIG_DFL);
  1277.         (void) signal(SIGTTIN, SIG_DFL);
  1278.         (void) signal(SIGTTOU, SIG_DFL);
  1279.         }
  1280.         (void) signal(SIGTERM, parterm);
  1281.     }
  1282.     else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
  1283.         (void) signal(SIGINT, SIG_IGN);
  1284.         (void) signal(SIGQUIT, SIG_IGN);
  1285.     }
  1286.     pgetty(wanttty, pgrp);
  1287.     /*
  1288.      * Nohup and nice apply only to NODE_COMMAND's but it would be nice
  1289.      * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
  1290.      * to know about nice/nohup/time
  1291.      */
  1292.     if (t->t_dflg & F_NOHUP)
  1293.         (void) signal(SIGHUP, SIG_IGN);
  1294.     if (t->t_dflg & F_NICE)
  1295.         (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
  1296.     }
  1297.     else {
  1298.     if (wanttty >= 0)
  1299.         (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid);
  1300.     palloc(pid, t);
  1301.     (void) sigsetmask(omask);
  1302.     }
  1303.  
  1304.     return (pid);
  1305. }
  1306.  
  1307. static void
  1308. okpcntl()
  1309. {
  1310.     if (tpgrp == -1)
  1311.     stderror(ERR_JOBCONTROL);
  1312.     if (tpgrp == 0)
  1313.     stderror(ERR_JOBCTRLSUB);
  1314. }
  1315.  
  1316. /*
  1317.  * if we don't have vfork(), things can still go in the wrong order
  1318.  * resulting in the famous 'Stopped (tty output)'. But some systems
  1319.  * don't permit the setpgid() call, (these are more recent secure
  1320.  * systems such as ibm's aix). Then we'd rather print an error message
  1321.  * than hang the shell!
  1322.  * I am open to suggestions how to fix that.
  1323.  */
  1324. void
  1325. pgetty(wanttty, pgrp)
  1326.     int     wanttty, pgrp;
  1327. {
  1328.     sigset_t omask = 0;
  1329.  
  1330.     /*
  1331.      * christos: I am blocking the tty signals till I've set things
  1332.      * correctly....
  1333.      */
  1334.     if (wanttty > 0)
  1335.     omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
  1336.     /*
  1337.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  1338.      * Don't check for tpgrp >= 0 so even non-interactive shells give
  1339.      * background jobs process groups Same for the comparison in the other part
  1340.      * of the #ifdef
  1341.      */
  1342.     if (wanttty >= 0)
  1343.     if (setpgid(0, pgrp) == -1) {
  1344.         (void) fprintf(csherr, "csh: setpgid error.\n");
  1345.         xexit(0);
  1346.     }
  1347.  
  1348.     if (wanttty > 0) {
  1349.     (void) tcsetpgrp(FSHTTY, pgrp);
  1350.     (void) sigsetmask(omask);
  1351.     }
  1352.  
  1353.     if (tpgrp > 0)
  1354.     tpgrp = 0;        /* gave tty away */
  1355. }
  1356.