[BACK]Return to job.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/job.c between version 1.1 and 1.2

version 1.1, 1995/10/18 08:45:42 version 1.2, 1995/12/14 03:23:31
Line 1 
Line 1 
 /*      $NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $     */  /*      $NetBSD: job.c,v 1.13 1995/11/22 17:40:09 christos Exp $        */
   
 /*  /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.   * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
Line 42 
Line 42 
 #if 0  #if 0
 static char sccsid[] = "@(#)job.c       5.15 (Berkeley) 3/1/91";  static char sccsid[] = "@(#)job.c       5.15 (Berkeley) 3/1/91";
 #else  #else
 static char rcsid[] = "$NetBSD: job.c,v 1.11 1995/09/27 18:44:40 jtc Exp $";  static char rcsid[] = "$NetBSD: job.c,v 1.13 1995/11/22 17:40:09 christos Exp $";
 #endif  #endif
 #endif /* not lint */  #endif /* not lint */
   
Line 118 
Line 118 
 #include "dir.h"  #include "dir.h"
 #include "job.h"  #include "job.h"
 #include "pathnames.h"  #include "pathnames.h"
   #ifdef REMOTE
   #include "rmt.h"
   # define STATIC
   #else
   # define STATIC static
   #endif
   
 extern int  errno;  extern int  errno;
   
Line 130 
Line 136 
 #define ABORT_INTERRUPT 2           /* Because it was interrupted */  #define ABORT_INTERRUPT 2           /* Because it was interrupted */
 #define ABORT_WAIT      3           /* Waiting for jobs to finish */  #define ABORT_WAIT      3           /* Waiting for jobs to finish */
   
   /*
    * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file
    * is a char! So when we go above 127 we turn negative!
    */
   #define FILENO(a) ((unsigned) fileno(a))
   
 /*  /*
  * post-make command processing. The node postCommands is really just the   * post-make command processing. The node postCommands is really just the
Line 142 
Line 153 
                                      * for a target. Should this number be                                       * for a target. Should this number be
                                      * 0, no shell will be executed. */                                       * 0, no shell will be executed. */
   
   
 /*  /*
  * Return values from JobStart.   * Return values from JobStart.
  */   */
Line 182 
Line 192 
 {  {
     "sh",      "sh",
     TRUE, "set -", "set -v", "set -", 5,      TRUE, "set -", "set -v", "set -", 5,
       TRUE, "set -e", "set +e",
   #ifdef OLDBOURNESHELL
     FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",      FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",
   #endif
     "v", "e",      "v", "e",
 },  },
     /*      /*
      * UNKNOWN.       * UNKNOWN.
      */       */
 {  {
     (char *)0,      (char *) 0,
     FALSE, (char *)0, (char *)0, (char *)0, 0,      FALSE, (char *) 0, (char *) 0, (char *) 0, 0,
     FALSE, (char *)0, (char *)0,      FALSE, (char *) 0, (char *) 0,
     (char *)0, (char *)0,      (char *) 0, (char *) 0,
 }  }
 };  };
 static Shell    *commandShell = &shells[DEFSHELL];/* this is the shell to  static Shell    *commandShell = &shells[DEFSHELL];/* this is the shell to
Line 200 
Line 213 
                                                    * commands in the Makefile.                                                     * commands in the Makefile.
                                                    * It is set by the                                                     * It is set by the
                                                    * Job_ParseShell function */                                                     * Job_ParseShell function */
 static char     *shellPath = (char *) NULL,       /* full pathname of  static char     *shellPath = NULL,                /* full pathname of
                                                    * executable image */                                                     * executable image */
                 *shellName;                       /* last component of shell */                  *shellName;                       /* last component of shell */
   
   
 static int      maxJobs;        /* The most children we can run at once */  static int      maxJobs;        /* The most children we can run at once */
 static int      maxLocal;       /* The most local ones we can have */  static int      maxLocal;       /* The most local ones we can have */
 int             nJobs;          /* The number of children currently running */  STATIC int      nJobs;          /* The number of children currently running */
 int             nLocal;         /* The number of local children */  STATIC int      nLocal;         /* The number of local children */
 Lst             jobs;           /* The structures that describe them */  STATIC Lst      jobs;           /* The structures that describe them */
 Boolean         jobFull;        /* Flag to tell when the job table is full. It  STATIC Boolean  jobFull;        /* Flag to tell when the job table is full. It
                                  * is set TRUE when (1) the total number of                                   * is set TRUE when (1) the total number of
                                  * running jobs equals the maximum allowed or                                   * running jobs equals the maximum allowed or
                                  * (2) a job can only be run locally, but                                   * (2) a job can only be run locally, but
Line 220 
Line 233 
                                  * the output channels of children */                                   * the output channels of children */
 #endif  #endif
   
 GNode           *lastNode;      /* The node for which output was most recently  STATIC GNode    *lastNode;      /* The node for which output was most recently
                                  * produced. */                                   * produced. */
 char            *targFmt;       /* Format string to use to head output from a  STATIC char     *targFmt;       /* Format string to use to head output from a
                                  * job when it's not the most-recent job heard                                   * job when it's not the most-recent job heard
                                  * from */                                   * from */
 #define TARG_FMT  "--- %s ---\n" /* Default format */  
   
   #ifdef REMOTE
   # define TARG_FMT  "--- %s at %s ---\n" /* Default format */
   # define MESSAGE(fp, gn) \
           (void) fprintf(fp, targFmt, gn->name, gn->rem.hname);
   #else
   # define TARG_FMT  "--- %s ---\n" /* Default format */
   # define MESSAGE(fp, gn) \
           (void) fprintf(fp, targFmt, gn->name);
   #endif
   
 /*  /*
  * When JobStart attempts to run a job remotely but can't, and isn't allowed   * When JobStart attempts to run a job remotely but can't, and isn't allowed
  * to run the job locally, or when Job_CatchChildren detects a job that has   * to run the job locally, or when Job_CatchChildren detects a job that has
  * been migrated home, the job is placed on the stoppedJobs queue to be run   * been migrated home, the job is placed on the stoppedJobs queue to be run
  * when the next job finishes.   * when the next job finishes.
  */   */
 Lst             stoppedJobs;    /* Lst of Job structures describing  STATIC Lst      stoppedJobs;    /* Lst of Job structures describing
                                  * jobs that were stopped due to concurrency                                   * jobs that were stopped due to concurrency
                                  * limits or migration home */                                   * limits or migration home */
   
   
 #if defined(USE_PGRP) && defined(SYSV)  #if defined(USE_PGRP) && defined(SYSV)
 #define KILL(pid,sig)   killpg (-(pid),(sig))  # define KILL(pid, sig)         killpg(-(pid), (sig))
 #else  #else
 # if defined(USE_PGRP)  # if defined(USE_PGRP)
 #define KILL(pid,sig)   killpg ((pid),(sig))  #  define KILL(pid, sig)        killpg((pid), (sig))
 # else  # else
 #define KILL(pid,sig)   kill ((pid),(sig))  #  define KILL(pid, sig)        kill((pid), (sig))
 # endif  # endif
 #endif  #endif
   
   /*
    * Grmpf... There is no way to set bits of the wait structure
    * anymore with the stupid W*() macros. I liked the union wait
    * stuff much more. So, we devise our own macros... This is
    * really ugly, use dramamine sparingly. You have been warned.
    */
   #define W_SETMASKED(st, val, fun)                               \
           {                                                       \
                   int sh = (int) ~0;                              \
                   int mask = fun(sh);                             \
                                                                   \
                   for (sh = 0; ((mask >> sh) & 1) == 0; sh++)     \
                           continue;                               \
                   *(st) = (*(st) & ~mask) | ((val) << sh);        \
           }
   
   #define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG)
   #define W_SETEXITSTATUS(st, val) W_SETMASKED(st, val, WEXITSTATUS)
   
   
 static int JobCondPassSig __P((ClientData, ClientData));  static int JobCondPassSig __P((ClientData, ClientData));
 static void JobPassSig __P((int));  static void JobPassSig __P((int));
 static int JobCmpPid __P((ClientData, ClientData));  static int JobCmpPid __P((ClientData, ClientData));
 static int JobPrintCommand __P((ClientData, ClientData));  static int JobPrintCommand __P((ClientData, ClientData));
 static int JobSaveCommand __P((ClientData, ClientData));  static int JobSaveCommand __P((ClientData, ClientData));
 static void JobFinish __P((Job *, union wait));  static void JobClose __P((Job *));
   #ifdef REMOTE
   static int JobCmpRmtID __P((Job *, int));
   # ifdef RMT_WILL_WATCH
   static void JobLocalInput __P((int, Job *));
   # endif
   #else
   static void JobFinish __P((Job *, int *));
 static void JobExec __P((Job *, char **));  static void JobExec __P((Job *, char **));
   #endif
 static void JobMakeArgv __P((Job *, char **));  static void JobMakeArgv __P((Job *, char **));
 static void JobRestart __P((Job *));  static void JobRestart __P((Job *));
 static int JobStart __P((GNode *, int, Job *));  static int JobStart __P((GNode *, int, Job *));
 static void JobDoOutput __P((Job *, Boolean));  static void JobDoOutput __P((Job *, Boolean));
 static Shell *JobMatchShell __P((char *));  static Shell *JobMatchShell __P((char *));
 static void JobInterrupt __P((int));  static void JobInterrupt __P((int, int));
   static void JobRestartJobs __P((void));
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
Line 285 
Line 336 
     int signo = *(int *) signop;      int signo = *(int *) signop;
 #ifdef RMT_WANTS_SIGNALS  #ifdef RMT_WANTS_SIGNALS
     if (job->flags & JOB_REMOTE) {      if (job->flags & JOB_REMOTE) {
         (void)Rmt_Signal(job, signo);          (void) Rmt_Signal(job, signo);
     } else {      } else {
         KILL(job->pid, signo);          KILL(job->pid, signo);
     }      }
Line 294 
Line 345 
      * Assume that sending the signal to job->pid will signal any remote       * Assume that sending the signal to job->pid will signal any remote
      * job as well.       * job as well.
      */       */
       if (DEBUG(JOB)) {
           (void) fprintf(stdout,
                          "JobCondPassSig passing signal %d to child %d.\n",
                          signo, job->pid);
           (void) fflush(stdout);
       }
     KILL(job->pid, signo);      KILL(job->pid, signo);
 #endif  #endif
     return(0);      return 0;
 }  }
   
 /*-  /*-
Line 317 
Line 374 
 JobPassSig(signo)  JobPassSig(signo)
     int     signo;      /* The signal number we've received */      int     signo;      /* The signal number we've received */
 {  {
     int     mask;      sigset_t nmask, omask;
   
     Lst_ForEach(jobs, JobCondPassSig, (ClientData)(long)signo);      if (DEBUG(JOB)) {
           (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo);
           (void) fflush(stdout);
       }
       Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
   
     /*      /*
      * Deal with proper cleanup based on the signal received. We only run       * Deal with proper cleanup based on the signal received. We only run
Line 327 
Line 388 
      * three termination signals are more of a "get out *now*" command.       * three termination signals are more of a "get out *now*" command.
      */       */
     if (signo == SIGINT) {      if (signo == SIGINT) {
         JobInterrupt(TRUE);          JobInterrupt(TRUE, signo);
     } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {      } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {
         JobInterrupt(FALSE);          JobInterrupt(FALSE, signo);
     }      }
   
     /*      /*
Line 345 
Line 406 
      * This ensures that all our jobs get continued when we wake up before       * This ensures that all our jobs get continued when we wake up before
      * we take any other signal.       * we take any other signal.
      */       */
     mask = sigblock(0);      sigfillset(&nmask);
     (void) sigsetmask(~0 & ~(1 << (signo-1)));      (void) sigprocmask(SIG_BLOCK, &nmask, &omask);
     signal(signo, SIG_DFL);  
   
     kill(getpid(), signo);      if (DEBUG(JOB)) {
           (void) fprintf(stdout,
                          "JobPassSig passing signal to self, mask = %x.\n",
                          ~0 & ~(1 << (signo-1)));
           (void) fflush(stdout);
       }
       (void) signal(signo, SIG_DFL);
   
       (void) KILL(getpid(), signo);
   
     signo = SIGCONT;      signo = SIGCONT;
     Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);      Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo);
   
     sigsetmask(mask);      (void) sigprocmask(SIG_SETMASK, &omask, NULL);
     signal(signo, JobPassSig);      (void) signal(signo, JobPassSig);
   
 }  }
   
Line 374 
Line 442 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobCmpPid (job, pid)  JobCmpPid(job, pid)
     ClientData        job;      /* job to examine */      ClientData        job;      /* job to examine */
     ClientData        pid;      /* process id desired */      ClientData        pid;      /* process id desired */
 {  {
     return ( *(int *) pid - ((Job *) job)->pid);      return( *(int *) pid - ((Job *) job)->pid);
 }  }
   
   #ifdef REMOTE
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
    * JobCmpRmtID  --
    *      Compare the rmtID of the job with the given rmtID and return 0 if they
    *      are equal.
    *
    * Results:
    *      0 if the rmtID's match
    *
    * Side Effects:
    *      None.
    *-----------------------------------------------------------------------
    */
   static int
   JobCmpRmtID(job, rmtID)
       ClientData      job;        /* job to examine */
       ClientData      rmtID;      /* remote id desired */
   {
       return(*(int *) rmtID - *(int *) job->rmtID);
   }
   #endif
   
   /*-
    *-----------------------------------------------------------------------
  * JobPrintCommand  --   * JobPrintCommand  --
  *      Put out another command for the given job. If the command starts   *      Put out another command for the given job. If the command starts
  *      with an @ or a - we process it specially. In the former case,   *      with an @ or a - we process it specially. In the former case,
Line 409 
Line 500 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobPrintCommand (cmdp, jobp)  JobPrintCommand(cmdp, jobp)
     ClientData    cmdp;             /* command string to print */      ClientData    cmdp;             /* command string to print */
     ClientData    jobp;             /* job for which to print it */      ClientData    jobp;             /* job for which to print it */
 {  {
Line 428 
Line 519 
     char          *cmd = (char *) cmdp;      char          *cmd = (char *) cmdp;
     Job           *job = (Job *) jobp;      Job           *job = (Job *) jobp;
   
     noSpecials = (noExecute && ! (job->node->type & OP_MAKE));      noSpecials = (noExecute && !(job->node->type & OP_MAKE));
   
     if (strcmp (cmd, "...") == 0) {      if (strcmp(cmd, "...") == 0) {
         job->node->type |= OP_SAVE_CMDS;          job->node->type |= OP_SAVE_CMDS;
         if ((job->flags & JOB_IGNDOTS) == 0) {          if ((job->flags & JOB_IGNDOTS) == 0) {
             job->tailCmds = Lst_Succ (Lst_Member (job->node->commands,              job->tailCmds = Lst_Succ(Lst_Member(job->node->commands,
                                                   (ClientData)cmd));                                                  (ClientData)cmd));
             return (1);              return(1);
         }          }
         return (0);          return(0);
     }      }
   
 #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg)  #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) {    \
           (void) fprintf(stdout, fmt, arg);       \
           (void) fflush(stdout);                  \
       }                                           \
      (void) fprintf(job->cmdFILE, fmt, arg);      \
      (void) fflush(job->cmdFILE);
   
     numCommands += 1;      numCommands += 1;
   
Line 448 
Line 544 
      * For debugging, we replace each command with the result of expanding       * For debugging, we replace each command with the result of expanding
      * the variables in the command.       * the variables in the command.
      */       */
     cmdNode = Lst_Member (job->node->commands, (ClientData)cmd);      cmdNode = Lst_Member(job->node->commands, (ClientData)cmd);
     cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE);      cmdStart = cmd = Var_Subst(NULL, cmd, job->node, FALSE);
     Lst_Replace (cmdNode, (ClientData)cmdStart);      Lst_Replace(cmdNode, (ClientData)cmdStart);
   
     cmdTemplate = "%s\n";      cmdTemplate = "%s\n";
   
Line 470 
Line 566 
         cmd++;          cmd++;
   
     if (shutUp) {      if (shutUp) {
         if (! (job->flags & JOB_SILENT) && !noSpecials &&          if (!(job->flags & JOB_SILENT) && !noSpecials &&
             commandShell->hasEchoCtl) {              commandShell->hasEchoCtl) {
                 DBPRINTF ("%s\n", commandShell->echoOff);                  DBPRINTF("%s\n", commandShell->echoOff);
         } else {          } else {
             shutUp = FALSE;              shutUp = FALSE;
         }          }
     }      }
   
     if (errOff) {      if (errOff) {
         if ( ! (job->flags & JOB_IGNERR) && !noSpecials) {          if ( !(job->flags & JOB_IGNERR) && !noSpecials) {
             if (commandShell->hasErrCtl) {              if (commandShell->hasErrCtl) {
                 /*                  /*
                  * we don't want the error-control commands showing                   * we don't want the error-control commands showing
Line 489 
Line 585 
                  * string too, but why make it any more complex than                   * string too, but why make it any more complex than
                  * it already is?                   * it already is?
                  */                   */
                 if (! (job->flags & JOB_SILENT) && !shutUp &&                  if (!(job->flags & JOB_SILENT) && !shutUp &&
                     commandShell->hasEchoCtl) {                      commandShell->hasEchoCtl) {
                         DBPRINTF ("%s\n", commandShell->echoOff);                          DBPRINTF("%s\n", commandShell->echoOff);
                         DBPRINTF ("%s\n", commandShell->ignErr);                          DBPRINTF("%s\n", commandShell->ignErr);
                         DBPRINTF ("%s\n", commandShell->echoOn);                          DBPRINTF("%s\n", commandShell->echoOn);
                 } else {                  } else {
                     DBPRINTF ("%s\n", commandShell->ignErr);                      DBPRINTF("%s\n", commandShell->ignErr);
                 }                  }
             } else if (commandShell->ignErr &&              } else if (commandShell->ignErr &&
                        (*commandShell->ignErr != '\0'))                        (*commandShell->ignErr != '\0'))
             {              {
                 /*                  /*
                  * The shell has no error control, so we need to be                   * The shell has no error control, so we need to be
Line 509 
Line 605 
                  * to ignore errors. Set cmdTemplate to use the weirdness                   * to ignore errors. Set cmdTemplate to use the weirdness
                  * instead of the simple "%s\n" template.                   * instead of the simple "%s\n" template.
                  */                   */
                 if (! (job->flags & JOB_SILENT) && !shutUp &&                  if (!(job->flags & JOB_SILENT) && !shutUp &&
                     commandShell->hasEchoCtl) {                      commandShell->hasEchoCtl) {
                         DBPRINTF ("%s\n", commandShell->echoOff);                          DBPRINTF("%s\n", commandShell->echoOff);
                         DBPRINTF (commandShell->errCheck, cmd);                          DBPRINTF(commandShell->errCheck, cmd);
                         shutUp = TRUE;                          shutUp = TRUE;
                 }                  }
                 cmdTemplate = commandShell->ignErr;                  cmdTemplate = commandShell->ignErr;
                 /*                  /*
                  * The error ignoration (hee hee) is already taken care                   * The error ignoration(hee hee) is already taken care
                  * of by the ignErr template, so pretend error checking                   * of by the ignErr template, so pretend error checking
                  * is still on.                   * is still on.
                  */                   */
Line 530 
Line 626 
         }          }
     }      }
   
     DBPRINTF (cmdTemplate, cmd);      DBPRINTF(cmdTemplate, cmd);
   
     if (errOff) {      if (errOff) {
         /*          /*
Line 539 
Line 635 
          * for the whole command...           * for the whole command...
          */           */
         if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){          if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){
             DBPRINTF ("%s\n", commandShell->echoOff);              DBPRINTF("%s\n", commandShell->echoOff);
             shutUp = TRUE;              shutUp = TRUE;
         }          }
         DBPRINTF ("%s\n", commandShell->errCheck);          DBPRINTF("%s\n", commandShell->errCheck);
     }      }
     if (shutUp) {      if (shutUp) {
         DBPRINTF ("%s\n", commandShell->echoOn);          DBPRINTF("%s\n", commandShell->echoOn);
     }      }
     return (0);      return 0;
 }  }
   
 /*-  /*-
Line 565 
Line 661 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobSaveCommand (cmd, gn)  JobSaveCommand(cmd, gn)
     ClientData   cmd;      ClientData   cmd;
     ClientData   gn;      ClientData   gn;
 {  {
     cmd = (ClientData) Var_Subst (NULL, (char *) cmd, (GNode *) gn, FALSE);      cmd = (ClientData) Var_Subst(NULL, (char *) cmd, (GNode *) gn, FALSE);
     (void)Lst_AtEnd (postCommands->commands, cmd);      (void) Lst_AtEnd(postCommands->commands, cmd);
     return (0);      return(0);
 }  }
   
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
    * JobClose --
    *      Called to close both input and output pipes when a job is finished.
    *
    * Results:
    *      Nada
    *
    * Side Effects:
    *      The file descriptors associated with the job are closed.
    *
    *-----------------------------------------------------------------------
    */
   static void
   JobClose(job)
       Job *job;
   {
       if (usePipes) {
   #ifdef RMT_WILL_WATCH
           Rmt_Ignore(job->inPipe);
   #else
           FD_CLR(job->inPipe, &outputs);
   #endif
           if (job->outPipe != job->inPipe) {
              (void) close(job->outPipe);
           }
           JobDoOutput(job, TRUE);
           (void) close(job->inPipe);
       } else {
           (void) close(job->outFd);
           JobDoOutput(job, TRUE);
       }
   }
   
   /*-
    *-----------------------------------------------------------------------
  * JobFinish  --   * JobFinish  --
  *      Do final processing for the given job including updating   *      Do final processing for the given job including updating
  *      parents and starting new jobs as available/necessary. Note   *      parents and starting new jobs as available/necessary. Note
Line 591 
Line 722 
  *      Some nodes may be put on the toBeMade queue.   *      Some nodes may be put on the toBeMade queue.
  *      Final commands for the job are placed on postCommands.   *      Final commands for the job are placed on postCommands.
  *   *
  *      If we got an error and are aborting (aborting == ABORT_ERROR) and   *      If we got an error and are aborting(aborting == ABORT_ERROR) and
  *      the job list is now empty, we are done for the day.   *      the job list is now empty, we are done for the day.
  *      If we recognized an error (errors !=0), we set the aborting flag   *      If we recognized an error(errors !=0), we set the aborting flag
  *      to ABORT_ERROR so no more jobs will be started.   *      to ABORT_ERROR so no more jobs will be started.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 /*ARGSUSED*/  /*ARGSUSED*/
 static void  static void
 JobFinish (job, status)  JobFinish(job, status)
     Job           *job;           /* job to finish */      Job         *job;             /* job to finish */
     union wait    status;         /* sub-why job went away */      int         *status;          /* sub-why job went away */
 {  {
     Boolean       done;      Boolean      done;
   
     if ((WIFEXITED(status) &&      if ((WIFEXITED(*status) &&
           (((status.w_retcode != 0) && !(job->flags & JOB_IGNERR)))) ||           (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) ||
         (WIFSIGNALED(status) && (status.w_termsig != SIGCONT)))          (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT)))
     {      {
         /*          /*
          * If it exited non-zero and either we're doing things our           * If it exited non-zero and either we're doing things our
Line 617 
Line 748 
          * cases, finish out the job's output before printing the exit           * cases, finish out the job's output before printing the exit
          * status...           * status...
          */           */
         if (usePipes) {  #ifdef REMOTE
 #ifdef RMT_WILL_WATCH          KILL(job->pid, SIGCONT);
             Rmt_Ignore(job->inPipe);  #endif
 #else          JobClose(job);
             FD_CLR(job->inPipe, &outputs);  
 #endif /* RMT_WILL_WATCH */  
             if (job->outPipe != job->inPipe) {  
                 (void)close (job->outPipe);  
             }  
             JobDoOutput (job, TRUE);  
             (void)close (job->inPipe);  
         } else {  
             (void)close (job->outFd);  
             JobDoOutput (job, TRUE);  
         }  
   
         if (job->cmdFILE != NULL && job->cmdFILE != stdout) {          if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
             fclose(job->cmdFILE);             (void) fclose(job->cmdFILE);
         }          }
         done = TRUE;          done = TRUE;
     } else if (WIFEXITED(status) && status.w_retcode != 0) {  #ifdef REMOTE
           if (job->flags & JOB_REMOTE)
               Rmt_Done(job->rmtID, job->node);
   #endif
       } else if (WIFEXITED(*status)) {
         /*          /*
          * Deal with ignored errors in -B mode. We need to print a message           * Deal with ignored errors in -B mode. We need to print a message
          * telling of the ignored error as well as setting status.w_status           * telling of the ignored error as well as setting status.w_status
          * to 0 so the next command gets run. To do this, we set done to be           * to 0 so the next command gets run. To do this, we set done to be
          * TRUE if in -B mode and the job exited non-zero. Note we don't           * TRUE if in -B mode and the job exited non-zero.
            */
           done = WEXITSTATUS(*status) != 0;
           /*
            * Old comment said: "Note we don't
          * want to close down any of the streams until we know we're at the           * want to close down any of the streams until we know we're at the
          * end.           * end."
            * But we do. Otherwise when are we going to print the rest of the
            * stuff?
          */           */
         done = TRUE;          JobClose(job);
   #ifdef REMOTE
           if (job->flags & JOB_REMOTE)
               Rmt_Done(job->rmtID, job->node);
   #endif /* REMOTE */
     } else {      } else {
         /*          /*
          * No need to close things down or anything.           * No need to close things down or anything.
Line 655 
Line 788 
     }      }
   
     if (done ||      if (done ||
         WIFSTOPPED(status) ||          WIFSTOPPED(*status) ||
         (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) ||          (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) ||
         DEBUG(JOB))          DEBUG(JOB))
     {      {
         FILE      *out;          FILE      *out;
   
         if (!usePipes && (job->flags & JOB_IGNERR)) {          if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) {
             /*              /*
              * If output is going to a file and this job is ignoring               * If output is going to a file and this job is ignoring
              * errors, arrange to have the exit status sent to the               * errors, arrange to have the exit status sent to the
              * output file as well.               * output file as well.
              */               */
             out = fdopen (job->outFd, "w");              out = fdopen(job->outFd, "w");
         } else {          } else {
             out = stdout;              out = stdout;
         }          }
   
         if (WIFEXITED(status)) {          if (WIFEXITED(*status)) {
             if (status.w_retcode != 0) {              if (DEBUG(JOB)) {
                   (void) fprintf(stdout, "Process %d exited.\n", job->pid);
                   (void) fflush(stdout);
               }
               if (WEXITSTATUS(*status) != 0) {
                 if (usePipes && job->node != lastNode) {                  if (usePipes && job->node != lastNode) {
                     fprintf (out, targFmt, job->node->name);                      MESSAGE(out, job->node);
                     lastNode = job->node;                      lastNode = job->node;
                 }                  }
                 fprintf (out, "*** Error code %d%s\n", status.w_retcode,                  (void) fprintf(out, "*** Error code %d%s\n",
                          (job->flags & JOB_IGNERR) ? " (ignored)" : "");                                 WEXITSTATUS(*status),
                                  (job->flags & JOB_IGNERR) ? "(ignored)" : "");
   
                 if (job->flags & JOB_IGNERR) {                  if (job->flags & JOB_IGNERR) {
                     status.w_status = 0;                      *status = 0;
                 }                  }
             } else if (DEBUG(JOB)) {              } else if (DEBUG(JOB)) {
                 if (usePipes && job->node != lastNode) {                  if (usePipes && job->node != lastNode) {
                     fprintf (out, targFmt, job->node->name);                      MESSAGE(out, job->node);
                     lastNode = job->node;                      lastNode = job->node;
                 }                  }
                 fprintf (out, "*** Completed successfully\n");                  (void) fprintf(out, "*** Completed successfully\n");
             }              }
         } else if (WIFSTOPPED(status)) {          } else if (WIFSTOPPED(*status)) {
               if (DEBUG(JOB)) {
                   (void) fprintf(stdout, "Process %d stopped.\n", job->pid);
                   (void) fflush(stdout);
               }
             if (usePipes && job->node != lastNode) {              if (usePipes && job->node != lastNode) {
                 fprintf (out, targFmt, job->node->name);                  MESSAGE(out, job->node);
                 lastNode = job->node;                  lastNode = job->node;
             }              }
             if (! (job->flags & JOB_REMIGRATE)) {              if (!(job->flags & JOB_REMIGRATE)) {
                 fprintf (out, "*** Stopped -- signal %d\n", status.w_stopsig);                  fprintf(out, "*** Stopped -- signal %d\n", WSTOPSIG(*status));
             }              }
             job->flags |= JOB_RESUME;              job->flags |= JOB_RESUME;
             (void)Lst_AtEnd(stoppedJobs, (ClientData)job);              (void)Lst_AtEnd(stoppedJobs, (ClientData)job);
             fflush(out);  #ifdef REMOTE
               if (job->flags & JOB_REMIGRATE)
                   JobRestart(job);
   #endif
               (void) fflush(out);
             return;              return;
         } else if (status.w_termsig == SIGCONT) {          } else if (WTERMSIG(*status) == SIGCONT) {
             /*              /*
              * If the beastie has continued, shift the Job from the stopped               * If the beastie has continued, shift the Job from the stopped
              * list to the running one (or re-stop it if concurrency is               * list to the running one(or re-stop it if concurrency is
              * exceeded) and go and get another child.               * exceeded) and go and get another child.
              */               */
             if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {              if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) {
                 if (usePipes && job->node != lastNode) {                  if (usePipes && job->node != lastNode) {
                     fprintf (out, targFmt, job->node->name);                      MESSAGE(out, job->node);
                     lastNode = job->node;                      lastNode = job->node;
                 }                  }
                 fprintf (out, "*** Continued\n");                  (void) fprintf(out, "*** Continued\n");
             }              }
             if (! (job->flags & JOB_CONTINUING)) {              if (!(job->flags & JOB_CONTINUING)) {
                 JobRestart(job);                  if (DEBUG(JOB)) {
             } else {                      (void) fprintf(stdout,
                 Lst_AtEnd(jobs, (ClientData)job);                                     "Warning: process %d was not continuing.\n",
                 nJobs += 1;                                     job->pid);
                 if (! (job->flags & JOB_REMOTE)) {                      (void) fflush(stdout);
                     nLocal += 1;  
                 }                  }
                 if (nJobs == maxJobs) {  #ifdef notdef
                     jobFull = TRUE;                  /*
                     if (DEBUG(JOB)) {                   * We don't really want to restart a job from scratch just
                         printf("Job queue is full.\n");                   * because it continued, especially not without killing the
                     }                   * continuing process!  That's why this is ifdef'ed out.
                 }                   * FD - 9/17/90
                    */
                   JobRestart(job);
   #endif
             }              }
             fflush(out);              job->flags &= ~JOB_CONTINUING;
             return;              Lst_AtEnd(jobs, (ClientData)job);
               nJobs += 1;
               if (!(job->flags & JOB_REMOTE)) {
                   if (DEBUG(JOB)) {
                       (void) fprintf(stdout,
                                      "Process %d is continuing locally.\n",
                                      job->pid);
                       (void) fflush(stdout);
                   }
                   nLocal += 1;
               }
               if (nJobs == maxJobs) {
                   jobFull = TRUE;
                   if (DEBUG(JOB)) {
                       (void) fprintf(stdout, "Job queue is full.\n");
                       (void) fflush(stdout);
                   }
               }
               (void) fflush(out);
               return;
         } else {          } else {
             if (usePipes && job->node != lastNode) {              if (usePipes && job->node != lastNode) {
                 fprintf (out, targFmt, job->node->name);                  MESSAGE(out, job->node);
                 lastNode = job->node;                  lastNode = job->node;
             }              }
             fprintf (out, "*** Signal %d\n", status.w_termsig);              (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status));
         }          }
   
         fflush (out);          (void) fflush(out);
     }      }
   
     /*      /*
Line 749 
Line 916 
      * try and restart the job on the next command. If JobStart says it's       * try and restart the job on the next command. If JobStart says it's
      * ok, it's ok. If there's an error, this puppy is done.       * ok, it's ok. If there's an error, this puppy is done.
      */       */
     if ((status.w_status == 0) &&      if (compatMake && (WIFEXITED(*status) &&
         !Lst_IsAtEnd (job->node->commands))          !Lst_IsAtEnd(job->node->commands))) {
     {          switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) {
         switch (JobStart (job->node,          case JOB_RUNNING:
                           job->flags & JOB_IGNDOTS,              done = FALSE;
                           job))              break;
         {          case JOB_ERROR:
             case JOB_RUNNING:              done = TRUE;
                 done = FALSE;              W_SETEXITSTATUS(status, 1);
                 break;              break;
             case JOB_ERROR:          case JOB_FINISHED:
                 done = TRUE;              /*
                 status.w_retcode = 1;               * If we got back a JOB_FINISHED code, JobStart has already
                 break;               * called Make_Update and freed the job descriptor. We set
             case JOB_FINISHED:               * done to false here to avoid fake cycles and double frees.
                 /*               * JobStart needs to do the update so we can proceed up the
                  * If we got back a JOB_FINISHED code, JobStart has already               * graph when given the -n flag..
                  * called Make_Update and freed the job descriptor. We set               */
                  * done to false here to avoid fake cycles and double frees.              done = FALSE;
                  * JobStart needs to do the update so we can proceed up the              break;
                  * graph when given the -n flag..  
                  */  
                 done = FALSE;  
                 break;  
         }          }
     } else {      } else {
         done = TRUE;          done = TRUE;
Line 782 
Line 945 
     if (done &&      if (done &&
         (aborting != ABORT_ERROR) &&          (aborting != ABORT_ERROR) &&
         (aborting != ABORT_INTERRUPT) &&          (aborting != ABORT_INTERRUPT) &&
         (status.w_status == 0))          (*status == 0))
     {      {
         /*          /*
          * As long as we aren't aborting and the job didn't return a non-zero           * As long as we aren't aborting and the job didn't return a non-zero
Line 791 
Line 954 
          * on the .END target.           * on the .END target.
          */           */
         if (job->tailCmds != NILLNODE) {          if (job->tailCmds != NILLNODE) {
             Lst_ForEachFrom (job->node->commands, job->tailCmds,              Lst_ForEachFrom(job->node->commands, job->tailCmds,
                              JobSaveCommand,                               JobSaveCommand,
                              (ClientData)job->node);                              (ClientData)job->node);
         }          }
         job->node->made = MADE;          job->node->made = MADE;
         Make_Update (job->node);          Make_Update(job->node);
         free((Address)job);          free((Address)job);
     } else if (status.w_status) {      } else if (*status == 0) {
         errors += 1;          errors += 1;
         free((Address)job);          free((Address)job);
     }      }
   
     while (!errors && !jobFull && !Lst_IsEmpty(stoppedJobs)) {      JobRestartJobs();
         JobRestart((Job *)Lst_DeQueue(stoppedJobs));  
     }  
   
     /*      /*
      * Set aborting if any error.       * Set aborting if any error.
Line 823 
Line 984 
         /*          /*
          * If we are aborting and the job table is now empty, we finish.           * If we are aborting and the job table is now empty, we finish.
          */           */
         (void) unlink (tfile);          (void) eunlink(tfile);
         Finish (errors);          Finish(errors);
     }      }
 }  }
   
Line 843 
Line 1004 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_Touch (gn, silent)  Job_Touch(gn, silent)
     GNode         *gn;          /* the node of the file to touch */      GNode         *gn;          /* the node of the file to touch */
     Boolean       silent;       /* TRUE if should not print messages */      Boolean       silent;       /* TRUE if should not print messages */
 {  {
Line 859 
Line 1020 
     }      }
   
     if (!silent) {      if (!silent) {
         printf ("touch %s\n", gn->name);          (void) fprintf(stdout, "touch %s\n", gn->name);
           (void) fflush(stdout);
     }      }
   
     if (noExecute) {      if (noExecute) {
Line 867 
Line 1029 
     }      }
   
     if (gn->type & OP_ARCHV) {      if (gn->type & OP_ARCHV) {
         Arch_Touch (gn);          Arch_Touch(gn);
     } else if (gn->type & OP_LIB) {      } else if (gn->type & OP_LIB) {
         Arch_TouchLib (gn);          Arch_TouchLib(gn);
     } else {      } else {
         char    *file = gn->path ? gn->path : gn->name;          char    *file = gn->path ? gn->path : gn->name;
   
         times[0].tv_sec = times[1].tv_sec = now;          times[0].tv_sec = times[1].tv_sec = now;
         times[0].tv_usec = times[1].tv_usec = 0;          times[0].tv_usec = times[1].tv_usec = 0;
         if (utimes(file, times) < 0){          if (utimes(file, times) < 0){
             streamID = open (file, O_RDWR | O_CREAT, 0666);              streamID = open(file, O_RDWR | O_CREAT, 0666);
   
             if (streamID >= 0) {              if (streamID >= 0) {
                 char    c;                  char    c;
Line 886 
Line 1048 
                  * modification time, then close the file.                   * modification time, then close the file.
                  */                   */
                 if (read(streamID, &c, 1) == 1) {                  if (read(streamID, &c, 1) == 1) {
                     lseek(streamID, (off_t) 0, SEEK_SET);                      (void) lseek(streamID, 0L, L_SET);
                     write(streamID, &c, 1);                      (void) write(streamID, &c, 1);
                 }                  }
   
                 (void)close (streamID);                  (void) close(streamID);
             } else              } else {
                 printf("*** couldn't touch %s: %s", file, strerror(errno));                  (void) fprintf(stdout, "*** couldn't touch %s: %s",
                                  file, strerror(errno));
                   (void) fflush(stdout);
               }
         }          }
     }      }
 }  }
Line 911 
Line 1076 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 Boolean  Boolean
 Job_CheckCommands (gn, abortProc)  Job_CheckCommands(gn, abortProc)
     GNode          *gn;             /* The target whose commands need      GNode          *gn;             /* The target whose commands need
                                      * verifying */                                       * verifying */
     void          (*abortProc) __P((char *, ...));      void         (*abortProc) __P((char *, ...));
                         /* Function to abort with message */                          /* Function to abort with message */
 {  {
     if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) &&      if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) &&
         (gn->type & OP_LIB) == 0) {          (gn->type & OP_LIB) == 0) {
         /*          /*
          * No commands. Look for .DEFAULT rule from which we might infer           * No commands. Look for .DEFAULT rule from which we might infer
Line 935 
Line 1100 
              * .DEFAULT itself.               * .DEFAULT itself.
              */               */
             Make_HandleUse(DEFAULT, gn);              Make_HandleUse(DEFAULT, gn);
             Var_Set (IMPSRC, Var_Value (TARGET, gn, &p1), gn);              Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn);
             if (p1)              if (p1)
                 free(p1);                  free(p1);
         } else if (Dir_MTime (gn) == 0) {          } else if (Dir_MTime(gn) == 0) {
             /*              /*
              * The node wasn't the target of an operator we have no .DEFAULT               * The node wasn't the target of an operator we have no .DEFAULT
              * rule to go on and the target doesn't already exist. There's               * rule to go on and the target doesn't already exist. There's
Line 946 
Line 1111 
              * given, we stop in our tracks, otherwise we just don't update               * given, we stop in our tracks, otherwise we just don't update
              * this node's parents so they never get examined.               * this node's parents so they never get examined.
              */               */
               static const char msg[] = "make: don't know how to make";
   
             if (gn->type & OP_OPTIONAL) {              if (gn->type & OP_OPTIONAL) {
                 printf ("make: don't know how to make %s (ignored)\n",                  (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name);
                         gn->name);                  (void) fflush(stdout);
             } else if (keepgoing) {              } else if (keepgoing) {
                 printf ("make: don't know how to make %s (continuing)\n",                  (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name);
                         gn->name);                  (void) fflush(stdout);
                 return (FALSE);                  return FALSE;
             } else {              } else {
                 (*abortProc) ("make: don't know how to make %s. Stop",                  (*abortProc)("%s %s. Stop", msg, gn->name);
                              gn->name);                  return FALSE;
                 return(FALSE);  
             }              }
         }          }
     }      }
     return (TRUE);      return TRUE;
 }  }
 #ifdef RMT_WILL_WATCH  #ifdef RMT_WILL_WATCH
 /*-  /*-
Line 979 
Line 1145 
 /*ARGSUSED*/  /*ARGSUSED*/
 static void  static void
 JobLocalInput(stream, job)  JobLocalInput(stream, job)
     int     stream;     /* Stream that's ready (ignored) */      int     stream;     /* Stream that's ready(ignored) */
     Job     *job;       /* Job to which the stream belongs */      Job     *job;       /* Job to which the stream belongs */
 {  {
     JobDoOutput(job, FALSE);      JobDoOutput(job, FALSE);
Line 1011 
Line 1177 
     if (DEBUG(JOB)) {      if (DEBUG(JOB)) {
         int       i;          int       i;
   
         printf("Running %s %sly\n", job->node->name,          (void) fprintf(stdout, "Running %s %sly\n", job->node->name,
                job->flags&JOB_REMOTE?"remote":"local");                         job->flags&JOB_REMOTE?"remote":"local");
         printf("\tCommand: ");          (void) fprintf(stdout, "\tCommand: ");
         for (i = 0; argv[i] != (char *)NULL; i++) {          for (i = 0; argv[i] != NULL; i++) {
             printf("%s ", argv[i]);              (void) fprintf(stdout, "%s ", argv[i]);
         }          }
         printf("\n");          (void) fprintf(stdout, "\n");
           (void) fflush(stdout);
     }      }
   
     /*      /*
      * Some jobs produce no output and it's disconcerting to have       * Some jobs produce no output and it's disconcerting to have
      * no feedback of their running (since they produce no output, the       * no feedback of their running(since they produce no output, the
      * banner with their name in it never appears). This is an attempt to       * banner with their name in it never appears). This is an attempt to
      * provide that feedback, even if nothing follows it.       * provide that feedback, even if nothing follows it.
      */       */
     if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&      if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&
         !(job->flags & JOB_SILENT))          !(job->flags & JOB_SILENT)) {
     {          MESSAGE(stdout, job->node);
         printf(targFmt, job->node->name);  
         lastNode = job->node;          lastNode = job->node;
     }      }
   
Line 1039 
Line 1205 
     }      }
 #endif /* RMT_NO_EXEC */  #endif /* RMT_NO_EXEC */
   
     if ((cpid =  vfork()) == -1) {      if ((cpid = vfork()) == -1) {
         Punt ("Cannot fork");          Punt("Cannot fork");
     } else if (cpid == 0) {      } else if (cpid == 0) {
   
         /*          /*
          * Must duplicate the input stream down to the child's input and           * Must duplicate the input stream down to the child's input and
          * reset it to the beginning (again). Since the stream was marked           * reset it to the beginning(again). Since the stream was marked
          * close-on-exec, we must clear that bit in the new input.           * close-on-exec, we must clear that bit in the new input.
          */           */
         (void) dup2(fileno(job->cmdFILE), 0);          if (dup2(FILENO(job->cmdFILE), 0) == -1)
         fcntl(0, F_SETFD, 0);              Punt("Cannot dup2: %s", strerror(errno));
         lseek(0, (off_t) 0, SEEK_SET);          (void) fcntl(0, F_SETFD, 0);
           (void) lseek(0, 0, L_SET);
   
         if (usePipes) {          if (usePipes) {
             /*              /*
              * Set up the child's output to be routed through the pipe               * Set up the child's output to be routed through the pipe
              * we've created for it.               * we've created for it.
              */               */
             (void) dup2 (job->outPipe, 1);              if (dup2(job->outPipe, 1) == -1)
                   Punt("Cannot dup2: %s", strerror(errno));
         } else {          } else {
             /*              /*
              * We're capturing output in a file, so we duplicate the               * We're capturing output in a file, so we duplicate the
              * descriptor to the temporary file into the standard               * descriptor to the temporary file into the standard
              * output.               * output.
              */               */
             (void) dup2 (job->outFd, 1);              if (dup2(job->outFd, 1) == -1)
                   Punt("Cannot dup2: %s", strerror(errno));
         }          }
         /*          /*
          * The output channels are marked close on exec. This bit was           * The output channels are marked close on exec. This bit was
          * duplicated by the dup2 (on some systems), so we have to clear           * duplicated by the dup2(on some systems), so we have to clear
          * it before routing the shell's error output to the same place as           * it before routing the shell's error output to the same place as
          * its standard output.           * its standard output.
          */           */
         fcntl(1, F_SETFD, 0);          (void) fcntl(1, F_SETFD, 0);
         (void) dup2 (1, 2);          if (dup2(1, 2) == -1)
               Punt("Cannot dup2: %s", strerror(errno));
   
 #ifdef USE_PGRP  #ifdef USE_PGRP
         /*          /*
Line 1081 
Line 1251 
          * we can kill it and all its descendants in one fell swoop,           * we can kill it and all its descendants in one fell swoop,
          * by killing its process family, but not commit suicide.           * by killing its process family, but not commit suicide.
          */           */
   # if defined(SYSV)
         (void) setpgrp(0, getpid());          (void) setsid();
 #endif USE_PGRP  # else
           (void) setpgid(0, getpid());
   # endif
   #endif /* USE_PGRP */
   
         (void) execv (shellPath, argv);  #ifdef REMOTE
         (void) write (2, "Could not execute shell\n",          if (job->flags & JOB_REMOTE) {
                  sizeof ("Could not execute shell"));              Rmt_Exec(shellPath, argv, FALSE);
         _exit (1);          } else
   #endif /* REMOTE */
              (void) execv(shellPath, argv);
   
           (void) write(2, "Could not execute shell\n",
                        sizeof("Could not execute shell"));
           _exit(1);
     } else {      } else {
   #ifdef REMOTE
           long omask = sigblock(sigmask(SIGCHLD));
   #endif
         job->pid = cpid;          job->pid = cpid;
   
         if (usePipes && (job->flags & JOB_FIRST) ) {          if (usePipes && (job->flags & JOB_FIRST) ) {
Line 1108 
Line 1290 
         }          }
   
         if (job->flags & JOB_REMOTE) {          if (job->flags & JOB_REMOTE) {
   #ifndef REMOTE
             job->rmtID = 0;              job->rmtID = 0;
   #else
               job->rmtID = Rmt_LastID(job->pid);
   #endif /* REMOTE */
         } else {          } else {
             nLocal += 1;              nLocal += 1;
             /*              /*
              * XXX: Used to not happen if CUSTOMS. Why?               * XXX: Used to not happen if REMOTE. Why?
              */               */
             if (job->cmdFILE != stdout) {              if (job->cmdFILE != NULL && job->cmdFILE != stdout) {
                 fclose(job->cmdFILE);                  (void) fclose(job->cmdFILE);
                 job->cmdFILE = NULL;                  job->cmdFILE = NULL;
             }              }
         }          }
   #ifdef REMOTE
           (void) sigsetmask(omask);
   #endif
     }      }
   
 #ifdef RMT_NO_EXEC  #ifdef RMT_NO_EXEC
Line 1128 
Line 1317 
      * Now the job is actually running, add it to the table.       * Now the job is actually running, add it to the table.
      */       */
     nJobs += 1;      nJobs += 1;
     (void)Lst_AtEnd (jobs, (ClientData)job);      (void) Lst_AtEnd(jobs, (ClientData)job);
     if (nJobs == maxJobs) {      if (nJobs == maxJobs) {
         jobFull = TRUE;          jobFull = TRUE;
     }      }
Line 1186 
Line 1375 
             argc++;              argc++;
         }          }
     }      }
     argv[argc] = (char *)NULL;      argv[argc] = NULL;
 }  }
   
 /*-  /*-
Line 1206 
Line 1395 
 JobRestart(job)  JobRestart(job)
     Job           *job;         /* Job to restart */      Job           *job;         /* Job to restart */
 {  {
   #ifdef REMOTE
       int host;
   #endif
   
     if (job->flags & JOB_REMIGRATE) {      if (job->flags & JOB_REMIGRATE) {
         if (DEBUG(JOB)) {          if (
             printf("Remigrating %x\n", job->pid);  #ifdef REMOTE
               verboseRemigrates ||
   #endif
               DEBUG(JOB)) {
              (void) fprintf(stdout, "*** remigrating %x(%s)\n",
                              job->pid, job->node->name);
              (void) fflush(stdout);
         }          }
         if (nLocal != maxLocal) {  
   #ifdef REMOTE
           if (!Rmt_ReExport(job->pid, job->node, &host)) {
               if (verboseRemigrates || DEBUG(JOB)) {
                   (void) fprintf(stdout, "*** couldn't migrate...\n");
                   (void) fflush(stdout);
               }
   #endif
               if (nLocal != maxLocal) {
                 /*                  /*
                  * Job cannot be remigrated, but there's room on the local                   * Job cannot be remigrated, but there's room on the local
                  * machine, so resume the job and note that another                   * machine, so resume the job and note that another
                  * local job has started.                   * local job has started.
                  */                   */
                 if (DEBUG(JOB)) {                  if (
                     printf("resuming on local machine\n");  #ifdef REMOTE
                 }                      verboseRemigrates ||
   #endif
                       DEBUG(JOB)) {
                       (void) fprintf(stdout, "*** resuming on local machine\n");
                       (void) fflush(stdout);
                   }
                 KILL(job->pid, SIGCONT);                  KILL(job->pid, SIGCONT);
                 nLocal +=1;                  nLocal +=1;
   #ifdef REMOTE
                   job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE);
                   job->flags |= JOB_CONTINUING;
   #else
                 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);                  job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
   #endif
         } else {          } else {
                 /*                  /*
                  * Job cannot be restarted. Mark the table as full and                   * Job cannot be restarted. Mark the table as full and
                  * place the job back on the list of stopped jobs.                   * place the job back on the list of stopped jobs.
                  */                   */
                 if (DEBUG(JOB)) {                  if (
                     printf("holding\n");  #ifdef REMOTE
                 }                      verboseRemigrates ||
   #endif
                       DEBUG(JOB)) {
                      (void) fprintf(stdout, "*** holding\n");
                      (void) fflush(stdout);
                   }
                 (void)Lst_AtFront(stoppedJobs, (ClientData)job);                  (void)Lst_AtFront(stoppedJobs, (ClientData)job);
                 jobFull = TRUE;                  jobFull = TRUE;
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                     printf("Job queue is full.\n");                     (void) fprintf(stdout, "Job queue is full.\n");
                      (void) fflush(stdout);
                 }                  }
                 return;                  return;
               }
   #ifdef REMOTE
           } else {
               /*
                * Clear out the remigrate and resume flags. Set the continuing
                * flag so we know later on that the process isn't exiting just
                * because of a signal.
                */
               job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);
               job->flags |= JOB_CONTINUING;
               job->rmtID = host;
         }          }
   #endif
   
         (void)Lst_AtEnd(jobs, (ClientData)job);          (void)Lst_AtEnd(jobs, (ClientData)job);
         nJobs += 1;          nJobs += 1;
         if (nJobs == maxJobs) {          if (nJobs == maxJobs) {
             jobFull = TRUE;              jobFull = TRUE;
             if (DEBUG(JOB)) {              if (DEBUG(JOB)) {
                 printf("Job queue is full.\n");                  (void) fprintf(stdout, "Job queue is full.\n");
                   (void) fflush(stdout);
             }              }
         }          }
     } else if (job->flags & JOB_RESTART) {      } else if (job->flags & JOB_RESTART) {
Line 1258 
Line 1494 
         char      *argv[4];          char      *argv[4];
   
         JobMakeArgv(job, argv);          JobMakeArgv(job, argv);
   
         if (DEBUG(JOB)) {          if (DEBUG(JOB)) {
             printf("Restarting %s...", job->node->name);              (void) fprintf(stdout, "Restarting %s...", job->node->name);
               (void) fflush(stdout);
         }          }
         if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) {  #ifdef REMOTE
           if ((job->node->type&OP_NOEXPORT) ||
               (nLocal < maxLocal && runLocalFirst)
   # ifdef RMT_NO_EXEC
               || !Rmt_Export(shellPath, argv, job)
   # else
               || !Rmt_Begin(shellPath, argv, job->node)
   # endif
   #endif
           {
               if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) {
                 /*                  /*
                  * Can't be exported and not allowed to run locally -- put it                   * Can't be exported and not allowed to run locally -- put it
                  * back on the hold queue and mark the table full                   * back on the hold queue and mark the table full
                  */                   */
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                     printf("holding\n");                      (void) fprintf(stdout, "holding\n");
                       (void) fflush(stdout);
                 }                  }
                 (void)Lst_AtFront(stoppedJobs, (ClientData)job);                  (void)Lst_AtFront(stoppedJobs, (ClientData)job);
                 jobFull = TRUE;                  jobFull = TRUE;
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                     printf("Job queue is full.\n");                      (void) fprintf(stdout, "Job queue is full.\n");
                       (void) fflush(stdout);
                 }                  }
                 return;                  return;
         } else {              } else {
                 /*                  /*
                  * Job may be run locally.                   * Job may be run locally.
                  */                   */
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                     printf("running locally\n");                      (void) fprintf(stdout, "running locally\n");
                       (void) fflush(stdout);
                 }                  }
                 job->flags &= ~JOB_REMOTE;                  job->flags &= ~JOB_REMOTE;
               }
         }          }
   #ifdef REMOTE
           else {
               /*
                * Can be exported. Hooray!
                */
               if (DEBUG(JOB)) {
                   (void) fprintf(stdout, "exporting\n");
                   (void) fflush(stdout);
               }
               job->flags |= JOB_REMOTE;
           }
   #endif
         JobExec(job, argv);          JobExec(job, argv);
     } else {      } else {
         /*          /*
Line 1292 
Line 1555 
          * we don't know...           * we don't know...
          */           */
         if (DEBUG(JOB)) {          if (DEBUG(JOB)) {
             printf("Resuming %s...", job->node->name);             (void) fprintf(stdout, "Resuming %s...", job->node->name);
              (void) fflush(stdout);
         }          }
         if (((job->flags & JOB_REMOTE) ||          if (((job->flags & JOB_REMOTE) ||
              (nLocal < maxLocal) ||              (nLocal < maxLocal) ||
              (((job->flags & JOB_SPECIAL)) &&  #ifdef REMOTE
               (maxLocal == 0))) &&              (((job->flags & JOB_SPECIAL) &&
             (nJobs != maxJobs))                (job->node->type & OP_NOEXPORT)) &&
                (maxLocal == 0))) &&
   #else
               ((job->flags & JOB_SPECIAL) &&
                (maxLocal == 0))) &&
   #endif
              (nJobs != maxJobs))
         {          {
             /*              /*
              * If the job is remote, it's ok to resume it as long as the               * If the job is remote, it's ok to resume it as long as the
              * maximum concurrency won't be exceeded. If it's local and               * maximum concurrency won't be exceeded. If it's local and
              * we haven't reached the local concurrency limit already (or the               * we haven't reached the local concurrency limit already(or the
              * job must be run locally and maxLocal is 0), it's also ok to               * job must be run locally and maxLocal is 0), it's also ok to
              * resume it.               * resume it.
              */               */
             Boolean error;              Boolean error;
             extern int errno;              extern int errno;
             union wait status;              int status;
   
 #ifdef RMT_WANTS_SIGNALS  #ifdef RMT_WANTS_SIGNALS
             if (job->flags & JOB_REMOTE) {              if (job->flags & JOB_REMOTE) {
Line 1324 
Line 1594 
                  * actually put the thing in the job table.                   * actually put the thing in the job table.
                  */                   */
                 job->flags |= JOB_CONTINUING;                  job->flags |= JOB_CONTINUING;
                 status.w_termsig = SIGCONT;                  W_SETTERMSIG(&status, SIGCONT);
                 JobFinish(job, status);                  JobFinish(job, &status);
   
                 job->flags &= ~(JOB_RESUME|JOB_CONTINUING);                  job->flags &= ~(JOB_RESUME|JOB_CONTINUING);
                 if (DEBUG(JOB)) {                  if (DEBUG(JOB)) {
                     printf("done\n");                     (void) fprintf(stdout, "done\n");
                      (void) fflush(stdout);
                 }                  }
             } else {              } else {
                 Error("couldn't resume %s: %s",                  Error("couldn't resume %s: %s",
                     job->node->name, strerror(errno));                      job->node->name, strerror(errno));
                 status.w_status = 0;                  status = 0;
                 status.w_retcode = 1;                  W_SETEXITSTATUS(&status, 1);
                 JobFinish(job, status);                  JobFinish(job, &status);
             }              }
         } else {          } else {
             /*              /*
Line 1344 
Line 1615 
              * place the job back on the list of stopped jobs.               * place the job back on the list of stopped jobs.
              */               */
             if (DEBUG(JOB)) {              if (DEBUG(JOB)) {
                 printf("table full\n");                  (void) fprintf(stdout, "table full\n");
                   (void) fflush(stdout);
             }              }
             (void)Lst_AtFront(stoppedJobs, (ClientData)job);              (void) Lst_AtFront(stoppedJobs, (ClientData)job);
             jobFull = TRUE;              jobFull = TRUE;
             if (DEBUG(JOB)) {              if (DEBUG(JOB)) {
                 printf("Job queue is full.\n");                  (void) fprintf(stdout, "Job queue is full.\n");
                   (void) fflush(stdout);
             }              }
         }          }
     }      }
Line 1372 
Line 1645 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 JobStart (gn, flags, previous)  JobStart(gn, flags, previous)
     GNode         *gn;        /* target to create */      GNode         *gn;        /* target to create */
     int            flags;      /* flags for the job to override normal ones.      int            flags;      /* flags for the job to override normal ones.
                                * e.g. JOB_SPECIAL or JOB_IGNDOTS */                                 * e.g. JOB_SPECIAL or JOB_IGNDOTS */
Line 1386 
Line 1659 
     Boolean       local;      /* Set true if the job was run locally */      Boolean       local;      /* Set true if the job was run locally */
     Boolean       noExec;     /* Set true if we decide not to run the job */      Boolean       noExec;     /* Set true if we decide not to run the job */
   
     if (previous != (Job *)NULL) {      if (previous != NULL) {
         previous->flags &= ~ (JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);          previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
         job = previous;          job = previous;
     } else {      } else {
         job = (Job *) emalloc (sizeof (Job));          job = (Job *) emalloc(sizeof(Job));
         if (job == (Job *)NULL) {          if (job == NULL) {
             Punt("JobStart out of memory");              Punt("JobStart out of memory");
         }          }
         flags |= JOB_FIRST;          flags |= JOB_FIRST;
Line 1406 
Line 1679 
      * are also added to the field.       * are also added to the field.
      */       */
     job->flags = 0;      job->flags = 0;
     if (Targ_Ignore (gn)) {      if (Targ_Ignore(gn)) {
         job->flags |= JOB_IGNERR;          job->flags |= JOB_IGNERR;
     }      }
     if (Targ_Silent (gn)) {      if (Targ_Silent(gn)) {
         job->flags |= JOB_SILENT;          job->flags |= JOB_SILENT;
     }      }
     job->flags |= flags;      job->flags |= flags;
Line 1418 
Line 1691 
      * Check the commands now so any attributes from .DEFAULT have a chance       * Check the commands now so any attributes from .DEFAULT have a chance
      * to migrate to the node       * to migrate to the node
      */       */
     if (job->flags & JOB_FIRST) {      if (!compatMake && job->flags & JOB_FIRST) {
         cmdsOK = Job_CheckCommands(gn, Error);          cmdsOK = Job_CheckCommands(gn, Error);
     } else {      } else {
         cmdsOK = TRUE;          cmdsOK = TRUE;
     }      }
   
     /*      /*
      * If the -n flag wasn't given, we open up OUR (not the child's)       * If the -n flag wasn't given, we open up OUR(not the child's)
      * temporary file to stuff commands in it. The thing is rd/wr so we don't       * temporary file to stuff commands in it. The thing is rd/wr so we don't
      * need to reopen it to feed it to the shell. If the -n flag *was* given,       * need to reopen it to feed it to the shell. If the -n flag *was* given,
      * we just set the file to be stdout. Cute, huh?       * we just set the file to be stdout. Cute, huh?
Line 1439 
Line 1712 
             DieHorribly();              DieHorribly();
         }          }
   
         job->cmdFILE = fopen (tfile, "w+");          job->cmdFILE = fopen(tfile, "w+");
         if (job->cmdFILE == (FILE *) NULL) {          if (job->cmdFILE == NULL) {
             Punt ("Could not open %s", tfile);              Punt("Could not open %s", tfile);
         }          }
         fcntl(fileno(job->cmdFILE), F_SETFD, 1);          (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1);
         /*          /*
          * Send the commands to the command file, flush all its buffers then           * Send the commands to the command file, flush all its buffers then
          * rewind and remove the thing.           * rewind and remove the thing.
Line 1466 
Line 1739 
             if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){              if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){
                 cmdsOK = FALSE;                  cmdsOK = FALSE;
             } else {              } else {
                 LstNode ln = Lst_Next (gn->commands);                  LstNode ln = Lst_Next(gn->commands);
   
                 if ((ln == NILLNODE) ||                  if ((ln == NILLNODE) ||
                     JobPrintCommand ((char *)Lst_Datum (ln), job))                      JobPrintCommand((ClientData) Lst_Datum(ln),
                                       (ClientData) job))
                 {                  {
                     noExec = TRUE;                      noExec = TRUE;
                     Lst_Close (gn->commands);                      Lst_Close(gn->commands);
                 }                  }
                 if (noExec && !(job->flags & JOB_FIRST)) {                  if (noExec && !(job->flags & JOB_FIRST)) {
                     /*                      /*
Line 1486 
Line 1760 
                      * Job_CatchChildren b/c it wasn't clear if there were                       * Job_CatchChildren b/c it wasn't clear if there were
                      * more commands to execute or not...                       * more commands to execute or not...
                      */                       */
                     if (usePipes) {                      JobClose(job);
 #ifdef RMT_WILL_WATCH  
                         Rmt_Ignore(job->inPipe);  
 #else  
                         FD_CLR(job->inPipe, &outputs);  
 #endif  
                         if (job->outPipe != job->inPipe) {  
                             (void)close (job->outPipe);  
                         }  
                         JobDoOutput (job, TRUE);  
                         (void)close (job->inPipe);  
                     } else {  
                         (void)close (job->outFd);  
                         JobDoOutput (job, TRUE);  
                     }  
                 }                  }
             }              }
         } else {          } else {
Line 1508 
Line 1768 
              * We can do all the commands at once. hooray for sanity               * We can do all the commands at once. hooray for sanity
              */               */
             numCommands = 0;              numCommands = 0;
             Lst_ForEach (gn->commands, JobPrintCommand, (ClientData)job);              Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);
   
             /*              /*
              * If we didn't print out any commands to the shell script,               * If we didn't print out any commands to the shell script,
Line 1524 
Line 1784 
          * in one fell swoop. This will still set up job->tailCmds correctly.           * in one fell swoop. This will still set up job->tailCmds correctly.
          */           */
         if (lastNode != gn) {          if (lastNode != gn) {
             printf (targFmt, gn->name);              MESSAGE(stdout, gn);
             lastNode = gn;              lastNode = gn;
         }          }
         job->cmdFILE = stdout;          job->cmdFILE = stdout;
Line 1548 
Line 1808 
          * up the graph.           * up the graph.
          */           */
         job->cmdFILE = stdout;          job->cmdFILE = stdout;
         Job_Touch (gn, job->flags&JOB_SILENT);          Job_Touch(gn, job->flags&JOB_SILENT);
         noExec = TRUE;          noExec = TRUE;
     }      }
   
Line 1560 
Line 1820 
          * Unlink and close the command file if we opened one           * Unlink and close the command file if we opened one
          */           */
         if (job->cmdFILE != stdout) {          if (job->cmdFILE != stdout) {
             (void) unlink (tfile);              (void) eunlink(tfile);
             fclose(job->cmdFILE);              if (job->cmdFILE != NULL)
                   (void) fclose(job->cmdFILE);
         } else {          } else {
             fflush (stdout);               (void) fflush(stdout);
         }          }
   
         /*          /*
Line 1575 
Line 1836 
                 if (job->tailCmds != NILLNODE) {                  if (job->tailCmds != NILLNODE) {
                     Lst_ForEachFrom(job->node->commands, job->tailCmds,                      Lst_ForEachFrom(job->node->commands, job->tailCmds,
                                     JobSaveCommand,                                      JobSaveCommand,
                                     (ClientData)job->node);                                     (ClientData)job->node);
                 }                  }
                 Make_Update(job->node);                  Make_Update(job->node);
             }              }
Line 1586 
Line 1847 
             return(JOB_ERROR);              return(JOB_ERROR);
         }          }
     } else {      } else {
         fflush (job->cmdFILE);          (void) fflush(job->cmdFILE);
         (void) unlink (tfile);          (void) eunlink(tfile);
     }      }
   
     /*      /*
Line 1602 
Line 1863 
      * starting a job and then set up its temporary-file name. This is just       * starting a job and then set up its temporary-file name. This is just
      * tfile with two extra digits tacked on -- jobno.       * tfile with two extra digits tacked on -- jobno.
      */       */
     if (job->flags & JOB_FIRST) {      if (!compatMake || (job->flags & JOB_FIRST)) {
         if (usePipes) {          if (usePipes) {
             int fd[2];              int fd[2];
             (void) pipe(fd);              if (pipe(fd) == -1)
                   Punt("Cannot create pipe: %s", strerror(errno));
             job->inPipe = fd[0];              job->inPipe = fd[0];
             job->outPipe = fd[1];              job->outPipe = fd[1];
             (void)fcntl (job->inPipe, F_SETFD, 1);              (void) fcntl(job->inPipe, F_SETFD, 1);
             (void)fcntl (job->outPipe, F_SETFD, 1);              (void) fcntl(job->outPipe, F_SETFD, 1);
         } else {          } else {
             printf ("Remaking `%s'\n", gn->name);              (void) fprintf(stdout, "Remaking `%s'\n", gn->name);
             fflush (stdout);              (void) fflush(stdout);
             sprintf (job->outFile, "%s%02d", tfile, jobno);              sprintf(job->outFile, "%s%02d", tfile, jobno);
             jobno = (jobno + 1) % 100;              jobno = (jobno + 1) % 100;
             job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);              job->outFd = open(job->outFile,O_WRONLY|O_CREAT|O_APPEND,0600);
             (void)fcntl (job->outFd, F_SETFD, 1);              (void) fcntl(job->outFd, F_SETFD, 1);
         }          }
     }      }
   
     local = TRUE;  #ifdef REMOTE
       if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) {
   #ifdef RMT_NO_EXEC
           local = !Rmt_Export(shellPath, argv, job);
   #else
           local = !Rmt_Begin(shellPath, argv, job->node);
   #endif /* RMT_NO_EXEC */
           if (!local) {
               job->flags |= JOB_REMOTE;
           }
       } else
   #endif
           local = TRUE;
   
     if (local && (((nLocal >= maxLocal) &&      if (local && (((nLocal >= maxLocal) &&
          !(job->flags & JOB_SPECIAL) &&          !(job->flags & JOB_SPECIAL) &&
          (maxLocal != 0))))  #ifdef REMOTE
           (!(gn->type & OP_NOEXPORT) || (maxLocal != 0))
   #else
           (maxLocal != 0)
   #endif
           )))
     {      {
         /*          /*
          * The job can only be run locally, but we've hit the limit of           * The job can only be run locally, but we've hit the limit of
          * local concurrency, so put the job on hold until some other job           * local concurrency, so put the job on hold until some other job
          * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)           * finishes. Note that the special jobs(.BEGIN, .INTERRUPT and .END)
          * may be run locally even when the local limit has been reached           * may be run locally even when the local limit has been reached
          * (e.g. when maxLocal == 0), though they will be exported if at           *(e.g. when maxLocal == 0), though they will be exported if at
          * all possible.           * all possible. In addition, any target marked with .NOEXPORT will
            * be run locally if maxLocal is 0.
          */           */
         jobFull = TRUE;          jobFull = TRUE;
   
         if (DEBUG(JOB)) {          if (DEBUG(JOB)) {
             printf("Can only run job locally.\n");             (void) fprintf(stdout, "Can only run job locally.\n");
              (void) fflush(stdout);
         }          }
         job->flags |= JOB_RESTART;          job->flags |= JOB_RESTART;
         (void)Lst_AtEnd(stoppedJobs, (ClientData)job);          (void) Lst_AtEnd(stoppedJobs, (ClientData)job);
     } else {      } else {
         if ((nLocal >= maxLocal) && local) {          if ((nLocal >= maxLocal) && local) {
             /*              /*
              * If we're running this job locally as a special case (see above),               * If we're running this job locally as a special case(see above),
              * at least say the table is full.               * at least say the table is full.
              */               */
             jobFull = TRUE;              jobFull = TRUE;
             if (DEBUG(JOB)) {              if (DEBUG(JOB)) {
                 printf("Local job queue is full.\n");                  (void) fprintf(stdout, "Local job queue is full.\n");
                   (void) fflush(stdout);
             }              }
         }          }
         JobExec(job, argv);          JobExec(job, argv);
Line 1657 
Line 1939 
     return(JOB_RUNNING);      return(JOB_RUNNING);
 }  }
   
   static char *
   JobOutput(job, cp, endp, msg)
       register Job *job;
       register char *cp, *endp;
       int msg;
   {
       register char *ecp;
   
       if (commandShell->noPrint) {
           ecp = Str_FindSubstring(cp, commandShell->noPrint);
           while (ecp != NULL) {
               if (cp != ecp) {
                   *ecp = '\0';
                   if (msg && job->node != lastNode) {
                       MESSAGE(stdout, job->node);
                       lastNode = job->node;
                   }
                   /*
                    * The only way there wouldn't be a newline after
                    * this line is if it were the last in the buffer.
                    * however, since the non-printable comes after it,
                    * there must be a newline, so we don't print one.
                    */
                   (void) fprintf(stdout, "%s", cp);
                   (void) fflush(stdout);
               }
               cp = ecp + commandShell->noPLen;
               if (cp != endp) {
                   /*
                    * Still more to print, look again after skipping
                    * the whitespace following the non-printable
                    * command....
                    */
                   cp++;
                   while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
                       cp++;
                   }
                   ecp = Str_FindSubstring(cp, commandShell->noPrint);
               } else {
                   return cp;
               }
           }
       }
       return cp;
   }
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  * JobDoOutput  --   * JobDoOutput  --
Line 1674 
Line 2002 
  *      In both cases, however, we keep our figurative eye out for the   *      In both cases, however, we keep our figurative eye out for the
  *      'noPrint' line for the shell from which the output came. If   *      'noPrint' line for the shell from which the output came. If
  *      we recognize a line, we don't print it. If the command is not   *      we recognize a line, we don't print it. If the command is not
  *      alone on the line (the character after it is not \0 or \n), we   *      alone on the line(the character after it is not \0 or \n), we
  *      do print whatever follows it.   *      do print whatever follows it.
  *   *
  * Results:   * Results:
Line 1684 
Line 2012 
  *      curPos may be shifted as may the contents of outBuf.   *      curPos may be shifted as may the contents of outBuf.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  STATIC void
 JobDoOutput (job, finish)  JobDoOutput(job, finish)
     register Job   *job;          /* the job whose output needs printing */      register Job   *job;          /* the job whose output needs printing */
     Boolean        finish;        /* TRUE if this is the last time we'll be      Boolean        finish;        /* TRUE if this is the last time we'll be
                                    * called for this job */                                     * called for this job */
 {  {
     Boolean       gotNL = FALSE;  /* true if got a newline */      Boolean       gotNL = FALSE;  /* true if got a newline */
       Boolean       fbuf;           /* true if our buffer filled up */
     register int  nr;             /* number of bytes read */      register int  nr;             /* number of bytes read */
     register int  i;              /* auxiliary index into outBuf */      register int  i;              /* auxiliary index into outBuf */
     register int  max;            /* limit for i (end of current data) */      register int  max;            /* limit for i(end of current data) */
     int           nRead;          /* (Temporary) number of bytes read */      int           nRead;          /*(Temporary) number of bytes read */
   
     FILE          *oFILE;         /* Stream pointer to shell's output file */      FILE          *oFILE;         /* Stream pointer to shell's output file */
     char          inLine[132];      char          inLine[132];
Line 1705 
Line 2034 
          * Read as many bytes as will fit in the buffer.           * Read as many bytes as will fit in the buffer.
          */           */
 end_loop:  end_loop:
           gotNL = FALSE;
           fbuf = FALSE;
   
         nRead = read (job->inPipe, &job->outBuf[job->curPos],          nRead = read(job->inPipe, &job->outBuf[job->curPos],
                          JOB_BUFSIZE - job->curPos);                           JOB_BUFSIZE - job->curPos);
         if (nRead < 0) {          if (nRead < 0) {
             if (DEBUG(JOB)) {              if (DEBUG(JOB)) {
Line 1718 
Line 2049 
         }          }
   
         /*          /*
          * If we hit the end-of-file (the job is dead), we must flush its           * If we hit the end-of-file(the job is dead), we must flush its
          * remaining output, so pretend we read a newline if there's any           * remaining output, so pretend we read a newline if there's any
          * output remaining in the buffer.           * output remaining in the buffer.
          * Also clear the 'finish' flag so we stop looping.           * Also clear the 'finish' flag so we stop looping.
Line 1756 
Line 2087 
                  * If we've run out of buffer space, we have no choice                   * If we've run out of buffer space, we have no choice
                  * but to print the stuff. sigh.                   * but to print the stuff. sigh.
                  */                   */
                 gotNL = TRUE;                  fbuf = TRUE;
                 i = job->curPos;                  i = job->curPos;
             }              }
         }          }
         if (gotNL) {          if (gotNL || fbuf) {
             /*              /*
              * Need to send the output to the screen. Null terminate it               * Need to send the output to the screen. Null terminate it
              * first, overwriting the newline character if there was one.               * first, overwriting the newline character if there was one.
              * So long as the line isn't one we should filter (according               * So long as the line isn't one we should filter(according
              * to the shell description), we print the line, preceeded               * to the shell description), we print the line, preceeded
              * by a target banner if this target isn't the same as the               * by a target banner if this target isn't the same as the
              * one for which we last printed something.               * one for which we last printed something.
Line 1773 
Line 2104 
              */               */
             job->outBuf[i] = '\0';              job->outBuf[i] = '\0';
             if (i >= job->curPos) {              if (i >= job->curPos) {
                 register char   *cp, *ecp;                  char *cp;
   
                   cp = JobOutput(job, job->outBuf, &job->outBuf[i]);
   
                 cp = job->outBuf;  
                 if (commandShell->noPrint) {  
                     ecp = Str_FindSubstring(job->outBuf,  
                                             commandShell->noPrint);  
                     while (ecp != (char *)NULL) {  
                         if (cp != ecp) {  
                             *ecp = '\0';  
                             if (job->node != lastNode) {  
                                 printf (targFmt, job->node->name);  
                                 lastNode = job->node;  
                             }  
                             /*  
                              * The only way there wouldn't be a newline after  
                              * this line is if it were the last in the buffer.  
                              * however, since the non-printable comes after it,  
                              * there must be a newline, so we don't print one.  
                              */  
                             printf ("%s", cp);  
                         }  
                         cp = ecp + commandShell->noPLen;  
                         if (cp != &job->outBuf[i]) {  
                             /*  
                              * Still more to print, look again after skipping  
                              * the whitespace following the non-printable  
                              * command....  
                              */  
                             cp++;  
                             while (*cp == ' ' || *cp == '\t' || *cp == '\n') {  
                                 cp++;  
                             }  
                             ecp = Str_FindSubstring (cp,  
                                                      commandShell->noPrint);  
                         } else {  
                             break;  
                         }  
                     }  
                 }  
   
                 /*                  /*
                  * There's still more in that thar buffer. This time, though,                   * There's still more in that thar buffer. This time, though,
                  * we know there's no newline at the end, so we add one of                   * we know there's no newline at the end, so we add one of
Line 1820 
Line 2115 
                  */                   */
                 if (*cp != '\0') {                  if (*cp != '\0') {
                     if (job->node != lastNode) {                      if (job->node != lastNode) {
                         printf (targFmt, job->node->name);                          MESSAGE(stdout, job->node);
                         lastNode = job->node;                          lastNode = job->node;
                     }                      }
                     printf ("%s\n", cp);                      (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : "");
                       (void) fflush(stdout);
                 }                  }
   
                 fflush (stdout);  
             }              }
             if (i < max - 1) {              if (i < max - 1) {
                 /* shift the remaining characters down */                  /* shift the remaining characters down */
                 memcpy ( job->outBuf, &job->outBuf[i + 1], max - (i + 1));                  (void) memcpy(job->outBuf, &job->outBuf[i + 1], max -(i + 1));
                 job->curPos = max - (i + 1);                  job->curPos = max -(i + 1);
   
             } else {              } else {
                 /*                  /*
Line 1845 
Line 2139 
             /*              /*
              * If the finish flag is true, we must loop until we hit               * If the finish flag is true, we must loop until we hit
              * end-of-file on the pipe. This is guaranteed to happen eventually               * end-of-file on the pipe. This is guaranteed to happen eventually
              * since the other end of the pipe is now closed (we closed it               * since the other end of the pipe is now closed(we closed it
              * explicitly and the child has exited). When we do get an EOF,               * explicitly and the child has exited). When we do get an EOF,
              * finish will be set FALSE and we'll fall through and out.               * finish will be set FALSE and we'll fall through and out.
              */               */
Line 1862 
Line 2156 
          * Change to read in blocks and do FindSubString type things as for           * Change to read in blocks and do FindSubString type things as for
          * pipes? That would allow for "@echo -n..."           * pipes? That would allow for "@echo -n..."
          */           */
         oFILE = fopen (job->outFile, "r");          oFILE = fopen(job->outFile, "r");
         if (oFILE != (FILE *) NULL) {          if (oFILE != NULL) {
             printf ("Results of making %s:\n", job->node->name);              (void) fprintf(stdout, "Results of making %s:\n", job->node->name);
             while (fgets (inLine, sizeof(inLine), oFILE) != NULL) {              (void) fflush(stdout);
                 register char   *cp, *ecp, *endp;              while (fgets(inLine, sizeof(inLine), oFILE) != NULL) {
                   register char   *cp, *endp, *oendp;
   
                 cp = inLine;                  cp = inLine;
                 endp = inLine + strlen(inLine);                  oendp = endp = inLine + strlen(inLine);
                 if (endp[-1] == '\n') {                  if (endp[-1] == '\n') {
                     *--endp = '\0';                      *--endp = '\0';
                 }                  }
                 if (commandShell->noPrint) {                  cp = JobOutput(job, inLine, endp, FALSE);
                     ecp = Str_FindSubstring(cp, commandShell->noPrint);  
                     while (ecp != (char *)NULL) {  
                         if (cp != ecp) {  
                             *ecp = '\0';  
                             /*  
                              * The only way there wouldn't be a newline after  
                              * this line is if it were the last in the buffer.  
                              * however, since the non-printable comes after it,  
                              * there must be a newline, so we don't print one.  
                              */  
                             printf ("%s", cp);  
                         }  
                         cp = ecp + commandShell->noPLen;  
                         if (cp != endp) {  
                             /*  
                              * Still more to print, look again after skipping  
                              * the whitespace following the non-printable  
                              * command....  
                              */  
                             cp++;  
                             while (*cp == ' ' || *cp == '\t' || *cp == '\n') {  
                                 cp++;  
                             }  
                             ecp = Str_FindSubstring(cp, commandShell->noPrint);  
                         } else {  
                             break;  
                         }  
                     }  
                 }  
   
                 /*                  /*
                  * There's still more in that thar buffer. This time, though,                   * There's still more in that thar buffer. This time, though,
                  * we know there's no newline at the end, so we add one of                   * we know there's no newline at the end, so we add one of
                  * our own free will.                   * our own free will.
                  */                   */
                 if (*cp != '\0') {                  (void) fprintf(stdout, "%s", cp);
                     printf ("%s\n", cp);                  (void) fflush(stdout);
                   if (endp != oendp) {
                       (void) fprintf(stdout, "\n");
                       (void) fflush(stdout);
                 }                  }
             }              }
             fclose (oFILE);              (void) fclose(oFILE);
             (void) unlink (job->outFile);              (void) eunlink(job->outFile);
         }          }
     }      }
     fflush(stdout);  
 }  }
   
 /*-  /*-
Line 1940 
Line 2208 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_CatchChildren (block)  Job_CatchChildren(block)
     Boolean       block;        /* TRUE if should block on the wait. */      Boolean       block;        /* TRUE if should block on the wait. */
 {  {
     int           pid;          /* pid of dead child */      int           pid;          /* pid of dead child */
     register Job  *job;         /* job descriptor for dead child */      register Job  *job;         /* job descriptor for dead child */
     LstNode       jnode;        /* list element for finding job */      LstNode       jnode;        /* list element for finding job */
     union wait    status;       /* Exit/termination status */      int           status;       /* Exit/termination status */
   
     /*      /*
      * Don't even bother if we know there's no one around.       * Don't even bother if we know there's no one around.
Line 1955 
Line 2223 
         return;          return;
     }      }
   
     while ((pid = wait3((int *)&status, (block?0:WNOHANG)|WUNTRACED,      while ((pid = waitpid((pid_t) -1, &status,
                         (struct rusage *)0)) > 0)                            (block?0:WNOHANG)|WUNTRACED)) > 0)
     {      {
         if (DEBUG(JOB))          if (DEBUG(JOB)) {
             printf("Process %d exited or stopped.\n", pid);              (void) fprintf(stdout, "Process %d exited or stopped.\n", pid);
               (void) fflush(stdout);
           }
   
   
         jnode = Lst_Find (jobs, (ClientData)&pid, JobCmpPid);          jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid);
   
         if (jnode == NILLNODE) {          if (jnode == NILLNODE) {
             if (WIFSIGNALED(status) && (status.w_termsig == SIGCONT)) {              if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) {
                 jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);                  jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);
                 if (jnode == NILLNODE) {                  if (jnode == NILLNODE) {
                     Error("Resumed child (%d) not in table", pid);                      Error("Resumed child(%d) not in table", pid);
                     continue;                      continue;
                 }                  }
                 job = (Job *)Lst_Datum(jnode);                  job = (Job *)Lst_Datum(jnode);
                 (void)Lst_Remove(stoppedJobs, jnode);                  (void) Lst_Remove(stoppedJobs, jnode);
             } else {              } else {
                 Error ("Child (%d) not in table?", pid);                  Error("Child(%d) not in table?", pid);
                 continue;                  continue;
             }              }
         } else {          } else {
             job = (Job *) Lst_Datum (jnode);              job = (Job *) Lst_Datum(jnode);
             (void)Lst_Remove (jobs, jnode);              (void) Lst_Remove(jobs, jnode);
             nJobs -= 1;              nJobs -= 1;
             if (jobFull && DEBUG(JOB)) {              if (jobFull && DEBUG(JOB)) {
                 printf("Job queue is no longer full.\n");                  (void) fprintf(stdout, "Job queue is no longer full.\n");
                   (void) fflush(stdout);
             }              }
             jobFull = FALSE;              jobFull = FALSE;
   #ifdef REMOTE
               if (!(job->flags & JOB_REMOTE)) {
                   if (DEBUG(JOB)) {
                       (void) fprintf(stdout,
                                      "Job queue has one fewer local process.\n");
                       (void) fflush(stdout);
                   }
                   nLocal -= 1;
               }
   #else
             nLocal -= 1;              nLocal -= 1;
   #endif
         }          }
   
         JobFinish (job, status);          JobFinish(job, &status);
     }      }
 }  }
   
Line 1997 
Line 2279 
  * Job_CatchOutput --   * Job_CatchOutput --
  *      Catch the output from our children, if we're using   *      Catch the output from our children, if we're using
  *      pipes do so. Otherwise just block time until we get a   *      pipes do so. Otherwise just block time until we get a
  *      signal (most likely a SIGCHLD) since there's no point in   *      signal(most likely a SIGCHLD) since there's no point in
  *      just spinning when there's nothing to do and the reaping   *      just spinning when there's nothing to do and the reaping
  *      of a child can wait for a while.   *      of a child can wait for a while.
  *   *
Line 2009 
Line 2291 
  * -----------------------------------------------------------------------   * -----------------------------------------------------------------------
  */   */
 void  void
 Job_CatchOutput ()  Job_CatchOutput()
 {  {
     int                   nfds;      int                   nfds;
     struct timeval        timeout;      struct timeval        timeout;
Line 2020 
Line 2302 
     int                   pnJobs;       /* Previous nJobs */      int                   pnJobs;       /* Previous nJobs */
 #endif  #endif
   
     fflush(stdout);      (void) fflush(stdout);
 #ifdef RMT_WILL_WATCH  #ifdef RMT_WILL_WATCH
     pnJobs = nJobs;      pnJobs = nJobs;
   
Line 2037 
Line 2319 
      * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren       * NOTE: IT IS THE RESPONSIBILITY OF Rmt_Wait TO CALL Job_CatchChildren
      * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.       * IN A TIMELY FASHION TO CATCH ANY LOCALLY RUNNING JOBS THAT EXIT.
      * It may use the variable nLocal to determine if it needs to call       * It may use the variable nLocal to determine if it needs to call
      * Job_CatchChildren (if nLocal is 0, there's nothing for which to       * Job_CatchChildren(if nLocal is 0, there's nothing for which to
      * wait...)       * wait...)
      */       */
     while (nJobs != 0 && pnJobs == nJobs) {      while (nJobs != 0 && pnJobs == nJobs) {
Line 2049 
Line 2331 
         timeout.tv_sec = SEL_SEC;          timeout.tv_sec = SEL_SEC;
         timeout.tv_usec = SEL_USEC;          timeout.tv_usec = SEL_USEC;
   
         if ((nfds = select (FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout)) < 0)          if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0,
         {                             (fd_set *) 0, &timeout)) <= 0)
             return;              return;
         } else {          else {
             if (Lst_Open (jobs) == FAILURE) {              if (Lst_Open(jobs) == FAILURE) {
                 Punt ("Cannot open job table");                  Punt("Cannot open job table");
             }              }
             while (nfds && (ln = Lst_Next (jobs)) != NILLNODE) {              while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) {
                 job = (Job *) Lst_Datum (ln);                  job = (Job *) Lst_Datum(ln);
                 if (FD_ISSET(job->inPipe, &readfds)) {                  if (FD_ISSET(job->inPipe, &readfds)) {
                     JobDoOutput (job, FALSE);                      JobDoOutput(job, FALSE);
                     nfds -= 1;                      nfds -= 1;
                 }                  }
             }              }
             Lst_Close (jobs);              Lst_Close(jobs);
         }          }
     }      }
 #endif /* RMT_WILL_WATCH */  #endif /* RMT_WILL_WATCH */
Line 2084 
Line 2366 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_Make (gn)  Job_Make(gn)
     GNode   *gn;      GNode   *gn;
 {  {
     (void)JobStart (gn, 0, (Job *)NULL);      (void) JobStart(gn, 0, NULL);
 }  }
   
 /*-  /*-
Line 2103 
Line 2385 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_Init (maxproc, maxlocal)  Job_Init(maxproc, maxlocal)
     int           maxproc;  /* the greatest number of jobs which may be      int           maxproc;  /* the greatest number of jobs which may be
                              * running at one time */                               * running at one time */
     int           maxlocal; /* the greatest number of local jobs which may      int           maxlocal; /* the greatest number of local jobs which may
Line 2111 
Line 2393 
 {  {
     GNode         *begin;     /* node for commands to do at the very start */      GNode         *begin;     /* node for commands to do at the very start */
   
     sprintf (tfile, "/tmp/make%05d", getpid());      (void) sprintf(tfile, "/tmp/make%05d", getpid());
   
     jobs =        Lst_Init (FALSE);      jobs =        Lst_Init(FALSE);
     stoppedJobs = Lst_Init(FALSE);      stoppedJobs = Lst_Init(FALSE);
     maxJobs =     maxproc;      maxJobs =     maxproc;
     maxLocal =    maxlocal;      maxLocal =    maxlocal;
Line 2126 
Line 2408 
   
     lastNode =    NILGNODE;      lastNode =    NILGNODE;
   
     if (maxJobs == 1) {      if (maxJobs == 1
   #ifdef REMOTE
           || noMessages
   #endif
                        ) {
         /*          /*
          * If only one job can run at a time, there's no need for a banner,           * If only one job can run at a time, there's no need for a banner,
          * no is there?           * no is there?
Line 2136 
Line 2422 
         targFmt = TARG_FMT;          targFmt = TARG_FMT;
     }      }
   
     if (shellPath == (char *) NULL) {      if (shellPath == NULL) {
         /*          /*
          * The user didn't specify a shell to use, so we are using the           * The user didn't specify a shell to use, so we are using the
          * default one... Both the absolute path and the last component           * default one... Both the absolute path and the last component
Line 2145 
Line 2431 
          * All default shells are located in _PATH_DEFSHELLDIR.           * All default shells are located in _PATH_DEFSHELLDIR.
          */           */
         shellName = commandShell->name;          shellName = commandShell->name;
         shellPath = str_concat (_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);          shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);
     }      }
   
     if (commandShell->exit == (char *)NULL) {      if (commandShell->exit == NULL) {
         commandShell->exit = "";          commandShell->exit = "";
     }      }
     if (commandShell->echo == (char *)NULL) {      if (commandShell->echo == NULL) {
         commandShell->echo = "";          commandShell->echo = "";
     }      }
   
Line 2159 
Line 2445 
      * Catch the four signals that POSIX specifies if they aren't ignored.       * Catch the four signals that POSIX specifies if they aren't ignored.
      * JobPassSig will take care of calling JobInterrupt if appropriate.       * JobPassSig will take care of calling JobInterrupt if appropriate.
      */       */
     if (signal (SIGINT, SIG_IGN) != SIG_IGN) {      if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
         signal (SIGINT, JobPassSig);          (void) signal(SIGINT, JobPassSig);
     }      }
     if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {      if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
         signal (SIGHUP, JobPassSig);          (void) signal(SIGHUP, JobPassSig);
     }      }
     if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) {      if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) {
         signal (SIGQUIT, JobPassSig);          (void) signal(SIGQUIT, JobPassSig);
     }      }
     if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {      if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
         signal (SIGTERM, JobPassSig);          (void) signal(SIGTERM, JobPassSig);
     }      }
     /*      /*
      * There are additional signals that need to be caught and passed if       * There are additional signals that need to be caught and passed if
      * either the export system wants to be told directly of signals or if       * either the export system wants to be told directly of signals or if
      * we're giving each job its own process group (since then it won't get       * we're giving each job its own process group(since then it won't get
      * signals from the terminal driver as we own the terminal)       * signals from the terminal driver as we own the terminal)
      */       */
 #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)  #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP)
     if (signal (SIGTSTP, SIG_IGN) != SIG_IGN) {      if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) {
         signal (SIGTSTP, JobPassSig);          (void) signal(SIGTSTP, JobPassSig);
     }      }
     if (signal (SIGTTOU, SIG_IGN) != SIG_IGN) {      if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) {
         signal (SIGTTOU, JobPassSig);          (void) signal(SIGTTOU, JobPassSig);
     }      }
     if (signal (SIGTTIN, SIG_IGN) != SIG_IGN) {      if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) {
         signal (SIGTTIN, JobPassSig);          (void) signal(SIGTTIN, JobPassSig);
     }      }
     if (signal (SIGWINCH, SIG_IGN) != SIG_IGN) {      if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) {
         signal (SIGWINCH, JobPassSig);          (void) signal(SIGWINCH, JobPassSig);
     }      }
 #endif  #endif
   
     begin = Targ_FindNode (".BEGIN", TARG_NOCREATE);      begin = Targ_FindNode(".BEGIN", TARG_NOCREATE);
   
     if (begin != NILGNODE) {      if (begin != NILGNODE) {
         JobStart (begin, JOB_SPECIAL, (Job *)0);          JobStart(begin, JOB_SPECIAL, (Job *)0);
         while (nJobs) {          while (nJobs) {
             Job_CatchOutput();              Job_CatchOutput();
 #ifndef RMT_WILL_WATCH  #ifndef RMT_WILL_WATCH
             Job_CatchChildren (!usePipes);              Job_CatchChildren(!usePipes);
 #endif /* RMT_WILL_WATCH */  #endif /* RMT_WILL_WATCH */
         }          }
     }      }
     postCommands = Targ_FindNode (".END", TARG_CREATE);      postCommands = Targ_FindNode(".END", TARG_CREATE);
 }  }
   
 /*-  /*-
Line 2221 
Line 2507 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 Boolean  Boolean
 Job_Full ()  Job_Full()
 {  {
     return (aborting || jobFull);      return(aborting || jobFull);
 }  }
   
 /*-  /*-
Line 2243 
Line 2529 
  * -----------------------------------------------------------------------   * -----------------------------------------------------------------------
  */   */
 Boolean  Boolean
 Job_Empty ()  Job_Empty()
 {  {
     if (nJobs == 0) {      if (nJobs == 0) {
         if (!Lst_IsEmpty(stoppedJobs) && !aborting) {          if (!Lst_IsEmpty(stoppedJobs) && !aborting) {
Line 2252 
Line 2538 
              * it...Try and restart the stopped jobs.               * it...Try and restart the stopped jobs.
              */               */
             jobFull = FALSE;              jobFull = FALSE;
             while (!jobFull && !Lst_IsEmpty(stoppedJobs)) {              JobRestartJobs();
                 JobRestart((Job *)Lst_DeQueue(stoppedJobs));  
             }  
             return(FALSE);              return(FALSE);
         } else {          } else {
             return(TRUE);              return(TRUE);
Line 2278 
Line 2562 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Shell *  static Shell *
 JobMatchShell (name)  JobMatchShell(name)
     char          *name;      /* Final component of shell path */      char          *name;      /* Final component of shell path */
 {  {
     register Shell *sh;       /* Pointer into shells table */      register Shell *sh;       /* Pointer into shells table */
Line 2287 
Line 2571 
                   *cp2;                    *cp2;
     char          *eoname;      char          *eoname;
   
     eoname = name + strlen (name);      eoname = name + strlen(name);
   
     match = (Shell *) NULL;      match = NULL;
   
     for (sh = shells; sh->name != NULL; sh++) {      for (sh = shells; sh->name != NULL; sh++) {
         for (cp1 = eoname - strlen (sh->name), cp2 = sh->name;          for (cp1 = eoname - strlen(sh->name), cp2 = sh->name;
              *cp1 != '\0' && *cp1 == *cp2;               *cp1 != '\0' && *cp1 == *cp2;
              cp1++, cp2++) {               cp1++, cp2++) {
                  continue;                   continue;
         }          }
         if (*cp1 != *cp2) {          if (*cp1 != *cp2) {
             continue;              continue;
         } else if (match == (Shell *) NULL ||          } else if (match == NULL || strlen(match->name) < strlen(sh->name)) {
                    strlen (match->name) < strlen (sh->name)) {             match = sh;
                        match = sh;  
         }          }
     }      }
     return (match == (Shell *) NULL ? sh : match);      return(match == NULL ? sh : match);
 }  }
   
 /*-  /*-
Line 2351 
Line 2634 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 ReturnStatus  ReturnStatus
 Job_ParseShell (line)  Job_ParseShell(line)
     char          *line;  /* The shell spec */      char          *line;  /* The shell spec */
 {  {
     char          **words;      char          **words;
Line 2362 
Line 2645 
     Shell         newShell;      Shell         newShell;
     Boolean       fullSpec = FALSE;      Boolean       fullSpec = FALSE;
   
     while (isspace (*line)) {      while (isspace(*line)) {
         line++;          line++;
     }      }
     words = brk_string (line, &wordCount, TRUE);      words = brk_string(line, &wordCount, TRUE);
   
     memset ((Address)&newShell, 0, sizeof(newShell));      memset((Address)&newShell, 0, sizeof(newShell));
   
     /*      /*
      * Parse the specification by keyword       * Parse the specification by keyword
      */       */
     for (path = (char *)NULL, argc = wordCount - 1, argv = words + 1;      for (path = NULL, argc = wordCount - 1, argv = words + 1;
          argc != 0;           argc != 0;
          argc--, argv++) {           argc--, argv++) {
              if (strncmp (*argv, "path=", 5) == 0) {               if (strncmp(*argv, "path=", 5) == 0) {
                  path = &argv[0][5];                   path = &argv[0][5];
              } else if (strncmp (*argv, "name=", 5) == 0) {               } else if (strncmp(*argv, "name=", 5) == 0) {
                  newShell.name = &argv[0][5];                   newShell.name = &argv[0][5];
              } else {               } else {
                  if (strncmp (*argv, "quiet=", 6) == 0) {                   if (strncmp(*argv, "quiet=", 6) == 0) {
                      newShell.echoOff = &argv[0][6];                       newShell.echoOff = &argv[0][6];
                  } else if (strncmp (*argv, "echo=", 5) == 0) {                   } else if (strncmp(*argv, "echo=", 5) == 0) {
                      newShell.echoOn = &argv[0][5];                       newShell.echoOn = &argv[0][5];
                  } else if (strncmp (*argv, "filter=", 7) == 0) {                   } else if (strncmp(*argv, "filter=", 7) == 0) {
                      newShell.noPrint = &argv[0][7];                       newShell.noPrint = &argv[0][7];
                      newShell.noPLen = strlen(newShell.noPrint);                       newShell.noPLen = strlen(newShell.noPrint);
                  } else if (strncmp (*argv, "echoFlag=", 9) == 0) {                   } else if (strncmp(*argv, "echoFlag=", 9) == 0) {
                      newShell.echo = &argv[0][9];                       newShell.echo = &argv[0][9];
                  } else if (strncmp (*argv, "errFlag=", 8) == 0) {                   } else if (strncmp(*argv, "errFlag=", 8) == 0) {
                      newShell.exit = &argv[0][8];                       newShell.exit = &argv[0][8];
                  } else if (strncmp (*argv, "hasErrCtl=", 10) == 0) {                   } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) {
                      char c = argv[0][10];                       char c = argv[0][10];
                      newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&                       newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&
                                             (c != 'T') && (c != 't'));                                             (c != 'T') && (c != 't'));
                  } else if (strncmp (*argv, "check=", 6) == 0) {                   } else if (strncmp(*argv, "check=", 6) == 0) {
                      newShell.errCheck = &argv[0][6];                       newShell.errCheck = &argv[0][6];
                  } else if (strncmp (*argv, "ignore=", 7) == 0) {                   } else if (strncmp(*argv, "ignore=", 7) == 0) {
                      newShell.ignErr = &argv[0][7];                       newShell.ignErr = &argv[0][7];
                  } else {                   } else {
                      Parse_Error (PARSE_FATAL, "Unknown keyword \"%s\"",                       Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"",
                                   *argv);                                    *argv);
                      return (FAILURE);                       return(FAILURE);
                  }                   }
                  fullSpec = TRUE;                   fullSpec = TRUE;
              }               }
     }      }
   
     if (path == (char *)NULL) {      if (path == NULL) {
         /*          /*
          * If no path was given, the user wants one of the pre-defined shells,           * If no path was given, the user wants one of the pre-defined shells,
          * yes? So we find the one s/he wants with the help of JobMatchShell           * yes? So we find the one s/he wants with the help of JobMatchShell
          * and set things up the right way. shellPath will be set up by           * and set things up the right way. shellPath will be set up by
          * Job_Init.           * Job_Init.
          */           */
         if (newShell.name == (char *)NULL) {          if (newShell.name == NULL) {
             Parse_Error (PARSE_FATAL, "Neither path nor name specified");              Parse_Error(PARSE_FATAL, "Neither path nor name specified");
             return (FAILURE);              return(FAILURE);
         } else {          } else {
             commandShell = JobMatchShell (newShell.name);              commandShell = JobMatchShell(newShell.name);
             shellName = newShell.name;              shellName = newShell.name;
         }          }
     } else {      } else {
         /*          /*
          * The user provided a path. If s/he gave nothing else (fullSpec is           * The user provided a path. If s/he gave nothing else(fullSpec is
          * FALSE), try and find a matching shell in the ones we know of.           * FALSE), try and find a matching shell in the ones we know of.
          * Else we just take the specification at its word and copy it           * Else we just take the specification at its word and copy it
          * to a new location. In either case, we need to record the           * to a new location. In either case, we need to record the
          * path the user gave for the shell.           * path the user gave for the shell.
          */           */
         shellPath = path;          shellPath = path;
         path = strrchr (path, '/');          path = strrchr(path, '/');
         if (path == (char *)NULL) {          if (path == NULL) {
             path = shellPath;              path = shellPath;
         } else {          } else {
             path += 1;              path += 1;
         }          }
         if (newShell.name != (char *)NULL) {          if (newShell.name != NULL) {
             shellName = newShell.name;              shellName = newShell.name;
         } else {          } else {
             shellName = path;              shellName = path;
         }          }
         if (!fullSpec) {          if (!fullSpec) {
             commandShell = JobMatchShell (shellName);              commandShell = JobMatchShell(shellName);
         } else {          } else {
             commandShell = (Shell *) emalloc(sizeof(Shell));              commandShell = (Shell *) emalloc(sizeof(Shell));
             *commandShell = newShell;              *commandShell = newShell;
Line 2455 
Line 2738 
     }      }
   
     if (!commandShell->hasErrCtl) {      if (!commandShell->hasErrCtl) {
         if (commandShell->errCheck == (char *)NULL) {          if (commandShell->errCheck == NULL) {
             commandShell->errCheck = "";              commandShell->errCheck = "";
         }          }
         if (commandShell->ignErr == (char *)NULL) {          if (commandShell->ignErr == NULL) {
             commandShell->ignErr = "%s\n";              commandShell->ignErr = "%s\n";
         }          }
     }      }
Line 2467 
Line 2750 
      * Do not free up the words themselves, since they might be in use by the       * Do not free up the words themselves, since they might be in use by the
      * shell specification...       * shell specification...
      */       */
     free (words);      free(words);
     return SUCCESS;      return SUCCESS;
 }  }
   
Line 2485 
Line 2768 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  static void
 JobInterrupt (runINTERRUPT)  JobInterrupt(runINTERRUPT, signo)
     int     runINTERRUPT;       /* Non-zero if commands for the .INTERRUPT      int     runINTERRUPT;       /* Non-zero if commands for the .INTERRUPT
                                  * target should be executed */                                   * target should be executed */
       int     signo;              /* signal received */
 {  {
     LstNode       ln;           /* element in job table */      LstNode       ln;           /* element in job table */
     Job           *job;         /* job descriptor in that element */      Job           *job;         /* job descriptor in that element */
Line 2495 
Line 2779 
   
     aborting = ABORT_INTERRUPT;      aborting = ABORT_INTERRUPT;
   
     (void)Lst_Open (jobs);     (void) Lst_Open(jobs);
     while ((ln = Lst_Next (jobs)) != NILLNODE) {      while ((ln = Lst_Next(jobs)) != NILLNODE) {
         job = (Job *) Lst_Datum (ln);          job = (Job *) Lst_Datum(ln);
   
         if (!Targ_Precious (job->node)) {          if (!Targ_Precious(job->node)) {
             char        *file = (job->node->path == (char *)NULL ?              char        *file = (job->node->path == NULL ?
                                  job->node->name :                                   job->node->name :
                                  job->node->path);                                   job->node->path);
             struct stat st;              if (!noExecute && eunlink(file) != -1) {
             if (!noExecute && lstat(file, &st) != -1 && !S_ISDIR(st.st_mode) &&                  Error("*** %s removed", file);
                 unlink(file) != -1) {  
                 Error ("*** %s removed", file);  
             }              }
         }          }
 #ifdef RMT_WANTS_SIGNALS  #ifdef RMT_WANTS_SIGNALS
Line 2514 
Line 2796 
             /*              /*
              * If job is remote, let the Rmt module do the killing.               * If job is remote, let the Rmt module do the killing.
              */               */
             if (!Rmt_Signal(job, SIGINT)) {              if (!Rmt_Signal(job, signo)) {
                 /*                  /*
                  * If couldn't kill the thing, finish it out now with an                   * If couldn't kill the thing, finish it out now with an
                  * error code, since no exit report will come in likely.                   * error code, since no exit report will come in likely.
                  */                   */
                 union wait status;                  int status;
   
                 status.w_status = 0;                  status.w_status = 0;
                 status.w_retcode = 1;                  status.w_retcode = 1;
                 JobFinish(job, status);                  JobFinish(job, &status);
             }              }
         } else if (job->pid) {          } else if (job->pid) {
             KILL(job->pid, SIGINT);              KILL(job->pid, signo);
         }          }
 #else  #else
         if (job->pid) {          if (job->pid) {
               if (DEBUG(JOB)) {
                   (void) fprintf(stdout,
                                  "JobInterrupt passing signal to child %d.\n",
                                  job->pid);
                   (void) fflush(stdout);
               }
               KILL(job->pid, signo);
           }
   #endif /* RMT_WANTS_SIGNALS */
       }
   
   #ifdef REMOTE
      (void)Lst_Open(stoppedJobs);
       while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) {
           job = (Job *) Lst_Datum(ln);
   
           if (job->flags & JOB_RESTART) {
               if (DEBUG(JOB)) {
                   (void) fprintf(stdout, "%s%s",
                                  "JobInterrupt skipping job on stopped queue",
                                  "-- it was waiting to be restarted.\n");
                   (void) fflush(stdout);
               }
               continue;
           }
           if (!Targ_Precious(job->node)) {
               char        *file = (job->node->path == NULL ?
                                    job->node->name :
                                    job->node->path);
               if (eunlink(file) == 0) {
                   Error("*** %s removed", file);
               }
           }
           /*
            * Resume the thing so it will take the signal.
            */
           if (DEBUG(JOB)) {
               (void) fprintf(stdout,
                              "JobInterrupt passing CONT to stopped child %d.\n",
                              job->pid);
               (void) fflush(stdout);
           }
           KILL(job->pid, SIGCONT);
   #ifdef RMT_WANTS_SIGNALS
           if (job->flags & JOB_REMOTE) {
               /*
                * If job is remote, let the Rmt module do the killing.
                */
               if (!Rmt_Signal(job, SIGINT)) {
                   /*
                    * If couldn't kill the thing, finish it out now with an
                    * error code, since no exit report will come in likely.
                    */
                   int status;
                   status.w_status = 0;
                   status.w_retcode = 1;
                   JobFinish(job, &status);
               }
           } else if (job->pid) {
               if (DEBUG(JOB)) {
                   (void) fprintf(stdout,
                          "JobInterrupt passing interrupt to stopped child %d.\n",
                                  job->pid);
                   (void) fflush(stdout);
               }
             KILL(job->pid, SIGINT);              KILL(job->pid, SIGINT);
         }          }
 #endif /* RMT_WANTS_SIGNALS */  #endif /* RMT_WANTS_SIGNALS */
     }      }
     Lst_Close (jobs);  #endif
       Lst_Close(stoppedJobs);
   
     if (runINTERRUPT && !touchFlag) {      if (runINTERRUPT && !touchFlag) {
         interrupt = Targ_FindNode (".INTERRUPT", TARG_NOCREATE);          interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
         if (interrupt != NILGNODE) {          if (interrupt != NILGNODE) {
             ignoreErrors = FALSE;              ignoreErrors = FALSE;
   
             JobStart (interrupt, JOB_IGNDOTS, (Job *)0);              JobStart(interrupt, JOB_IGNDOTS, (Job *)0);
             while (nJobs) {              while (nJobs) {
                 Job_CatchOutput();                  Job_CatchOutput();
 #ifndef RMT_WILL_WATCH  #ifndef RMT_WILL_WATCH
                 Job_CatchChildren (!usePipes);                  Job_CatchChildren(!usePipes);
 #endif /* RMT_WILL_WATCH */  #endif /* RMT_WILL_WATCH */
             }              }
         }          }
     }      }
     (void) unlink (tfile);      (void) eunlink(tfile);
     exit (0);      exit(signo);
 }  }
   
 /*  /*
Line 2564 
Line 2912 
  *      Number of errors reported.   *      Number of errors reported.
  *   *
  * Side Effects:   * Side Effects:
  *      The process' temporary file (tfile) is removed if it still   *      The process' temporary file(tfile) is removed if it still
  *      existed.   *      existed.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 int  int
 Job_End ()  Job_End()
 {  {
     if (postCommands != NILGNODE && !Lst_IsEmpty (postCommands->commands)) {      if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) {
         if (errors) {          if (errors) {
             Error ("Errors reported so .END ignored");              Error("Errors reported so .END ignored");
         } else {          } else {
             JobStart (postCommands, JOB_SPECIAL | JOB_IGNDOTS,              JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL);
                        (Job *)0);  
   
             while (nJobs) {              while (nJobs) {
                 Job_CatchOutput();                  Job_CatchOutput();
 #ifndef RMT_WILL_WATCH  #ifndef RMT_WILL_WATCH
                 Job_CatchChildren (!usePipes);                  Job_CatchChildren(!usePipes);
 #endif /* RMT_WILL_WATCH */  #endif /* RMT_WILL_WATCH */
             }              }
         }          }
     }      }
     (void) unlink (tfile);      (void) eunlink(tfile);
     return(errors);      return(errors);
 }  }
   
Line 2632 
Line 2979 
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Job_AbortAll ()  Job_AbortAll()
 {  {
     LstNode             ln;             /* element in job table */      LstNode             ln;     /* element in job table */
     Job                 *job;   /* the job descriptor in that element */      Job                 *job;   /* the job descriptor in that element */
     int                 foo;      int                 foo;
   
Line 2642 
Line 2989 
   
     if (nJobs) {      if (nJobs) {
   
         (void)Lst_Open (jobs);          (void) Lst_Open(jobs);
         while ((ln = Lst_Next (jobs)) != NILLNODE) {          while ((ln = Lst_Next(jobs)) != NILLNODE) {
             job = (Job *) Lst_Datum (ln);              job = (Job *) Lst_Datum(ln);
   
             /*              /*
              * kill the child process with increasingly drastic signals to make               * kill the child process with increasingly drastic signals to make
Line 2668 
Line 3015 
     /*      /*
      * Catch as many children as want to report in at first, then give up       * Catch as many children as want to report in at first, then give up
      */       */
     while (wait3(&foo, WNOHANG, (struct rusage *)0) > 0)      while (waitpid((pid_t) -1, &foo, WNOHANG) > 0)
         continue;          continue;
     (void) unlink (tfile);      (void) eunlink(tfile);
   }
   
   #ifdef REMOTE
   /*-
    *-----------------------------------------------------------------------
    * JobFlagForMigration --
    *      Handle the eviction of a child. Called from RmtStatusChange.
    *      Flags the child as remigratable and then suspends it.
    *
    * Results:
    *      none.
    *
    * Side Effects:
    *      The job descriptor is flagged for remigration.
    *
    *-----------------------------------------------------------------------
    */
   void
   JobFlagForMigration(hostID)
       int           hostID;       /* ID of host we used, for matching children. */
   {
       register Job  *job;         /* job descriptor for dead child */
       LstNode       jnode;        /* list element for finding job */
   
       if (DEBUG(JOB)) {
           (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID);
           (void) fflush(stdout);
       }
       jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID);
   
       if (jnode == NILLNODE) {
           jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID);
                   if (jnode == NILLNODE) {
                       if (DEBUG(JOB)) {
                           Error("Evicting host(%d) not in table", hostID);
                       }
                       return;
                   }
       }
       job = (Job *) Lst_Datum(jnode);
   
       if (DEBUG(JOB)) {
           (void) fprintf(stdout,
                          "JobFlagForMigration(%d) found job '%s'.\n", hostID,
                          job->node->name);
           (void) fflush(stdout);
       }
   
       KILL(job->pid, SIGSTOP);
   
       job->flags |= JOB_REMIGRATE;
   }
   
   #endif
   
   /*-
    *-----------------------------------------------------------------------
    * JobRestartJobs --
    *      Tries to restart stopped jobs if there are slots available.
    *      Note that this tries to restart them regardless of pending errors.
    *      It's not good to leave stopped jobs lying around!
    *
    * Results:
    *      None.
    *
    * Side Effects:
    *      Resumes(and possibly migrates) jobs.
    *
    *-----------------------------------------------------------------------
    */
   static void
   JobRestartJobs()
   {
       while (!jobFull && !Lst_IsEmpty(stoppedJobs)) {
           if (DEBUG(JOB)) {
               (void) fprintf(stdout,
                          "Job queue is not full. Restarting a stopped job.\n");
               (void) fflush(stdout);
           }
           JobRestart((Job *)Lst_DeQueue(stoppedJobs));
       }
 }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2