home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / MAK358AS.ZIP / JOB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-22  |  33.8 KB  |  1,428 lines

  1. /* Job execution and handling for GNU Make.
  2. Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc.
  3. This file is part of GNU Make.
  4.  
  5. GNU Make is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. GNU Make is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Make; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /*
  20.  * MS-DOS port (c) 1990 by Thorsten Ohl <ohl@gnu.ai.mit.edu>
  21.  *
  22.  * To this port, the same copying conditions apply as to the
  23.  * original release.
  24.  *
  25.  * IMPORTANT:
  26.  * This file is not identical to the original GNU release!
  27.  * You should have received this code as patch to the official
  28.  * GNU release.
  29.  *
  30.  * MORE IMPORTANT:
  31.  * This port comes with ABSOLUTELY NO WARRANTY.
  32.  *
  33.  * $Header: e:/gnu/make/RCS/job.c'v 3.58.0.7 90/08/27 01:24:50 tho Exp $
  34.  */
  35.  
  36. #include "make.h"
  37. #include "commands.h"
  38. #include "job.h"
  39. #include "file.h"
  40. #include "variable.h"
  41. #include <errno.h>
  42.  
  43. #ifdef MSDOS
  44. #define PATHSEP    ';'
  45. #else
  46. #define PATHSEP    ':'
  47. #endif
  48.  
  49. #ifndef MSDOS
  50. extern int errno;
  51. #endif /* not MSDOS */
  52.  
  53. #ifdef MSDOS
  54.  
  55. #include <time.h>
  56. #include <process.h>
  57. #include <io.h>
  58.  
  59. #include <swaplib.h>
  60.  
  61. int last_child_pid = 0;            /* no child started yet ... */
  62. int last_child_status = 0;
  63.  
  64. #endif /* MSDOS */
  65.  
  66. #if    defined(USG) && !defined(HAVE_VFORK)
  67. #define    vfork    fork
  68. #define    VFORK_NAME    "fork"
  69. #else    /* Have vfork or not USG.  */
  70. #define    VFORK_NAME    "vfork"
  71. #endif    /* USG and don't have vfork.  */
  72. extern int vfork ();
  73.  
  74. #if    defined(HAVE_SYS_WAIT) || !defined(USG)
  75. #include <sys/wait.h>
  76. #include <sys/time.h>
  77. #include <sys/resource.h>
  78. #include <signal.h>
  79. extern int wait3 ();
  80. #endif
  81.  
  82. #if    defined(WTERMSIG) || (defined(USG) && !defined(HAVE_SYS_WAIT))
  83. #define    WAIT_T int
  84.  
  85. #ifndef    WTERMSIG
  86. #define WTERMSIG(x) ((x) & 0x7f)
  87. #endif
  88. #ifndef    WCOREDUMP
  89. #define WCOREDUMP(x) ((x) & 0x80)
  90. #endif
  91. #ifndef    WEXITSTATUS
  92. #define WEXITSTATUS(x) (((x) >> 8) & 0xff)
  93. #endif
  94. #ifndef    WIFSIGNALED
  95. #define WIFSIGNALED(x) (WTERMSIG (x) != 0)
  96. #endif
  97. #ifndef    WIFEXITED
  98. #define WIFEXITED(x) (WTERMSIG (x) == 0)
  99. #endif
  100.  
  101. #else    /* WTERMSIG not defined and have <sys/wait.h> or not USG.  */
  102.  
  103. #define WAIT_T union wait
  104. #define WTERMSIG(x) ((x).w_termsig)
  105. #define WCOREDUMP(x) ((x).w_coredump)
  106. #define WEXITSTATUS(x) ((x).w_retcode)
  107. #ifndef    WIFSIGNALED
  108. #define    WIFSIGNALED(x)    (WTERMSIG(x) != 0)
  109. #endif
  110.  
  111. #endif    /* WTERMSIG defined or USG and don't have <sys/wait.h>.  */
  112.  
  113. #ifdef MSDOS
  114. static char *search_path (char *file, char *path);
  115. static  void child_error (char *target_name, int exit_code, int exit_sig, int coredump, int ignored);
  116. #endif /* MSDOS */
  117.  
  118. extern int dup2 ();
  119. extern int fork (), wait (), execve ();
  120. extern void _exit ();
  121. extern int geteuid (), getegid ();
  122.  
  123. #if    !defined(USG) && !defined(sigmask)
  124. #define sigmask(sig) (1 << ((sig) - 1))
  125. #endif
  126.  
  127. #ifdef MSDOS
  128. #define getdtablesize() _NFILE
  129. #else /* not MSDOS */
  130. #ifndef USG
  131. extern int getdtablesize ();
  132. #else
  133. #include <sys/param.h>
  134. #define getdtablesize() NOFILE
  135. #endif
  136. #endif /* not MSDOS */
  137.  
  138. extern void wait_to_start_job ();
  139. extern int start_remote_job_p ();
  140. extern int start_remote_job (), remote_status ();
  141.  
  142.  
  143. #if    defined(USG) && !defined(HAVE_SIGLIST)
  144. static char *sys_siglist[NSIG];
  145. void init_siglist ();
  146. #else    /* Not USG and or HAVE_SIGLIST.  */
  147. extern char *sys_siglist[];
  148. #endif    /* USG and not HAVE_SIGLIST.  */
  149.  
  150. #ifdef MSDOS
  151. extern  int child_handler (int sig);
  152. static void start_job (struct child *child);
  153. static void free_child (struct child *child);
  154. #else /* not MSDOS */
  155. int child_handler ();
  156. static void free_child (), start_job ();
  157. #endif /* not MSDOS */
  158.  
  159. /* Chain of all children.  */
  160.  
  161. struct child *children = 0;
  162.  
  163. /* Number of children currently running.  */
  164.  
  165. unsigned int job_slots_used = 0;
  166.  
  167. /* Nonzero if the `good' standard input is in use.  */
  168.  
  169. static int good_stdin_used = 0;
  170.  
  171. /* Write an error message describing the exit status given in
  172.    EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
  173.    Append "(ignored)" if IGNORED is nonzero.  */
  174.  
  175. static void
  176. child_error (target_name, exit_code, exit_sig, coredump, ignored)
  177.      char *target_name;
  178.      int exit_code, exit_sig, coredump;
  179.      int ignored;
  180. {
  181.   char *ignore_string = ignored ? " (ignored)" : "";
  182.  
  183.   if (exit_sig == 0)
  184.     error ("*** [%s] Error %d%s", target_name, exit_code, ignore_string);
  185.   else
  186.     {
  187.       char *coredump_string = coredump ? " (core dumped)" : "";
  188.       if (exit_sig > 0 && exit_sig < NSIG)
  189.     error ("*** [%s] %s%s",
  190.            target_name, sys_siglist[exit_sig], coredump_string);
  191.       else
  192.     error ("*** [%s] Signal %d%s", target_name, exit_sig, coredump_string);
  193.     }
  194. }
  195.  
  196. extern void block_remote_children (), unblock_remote_children ();
  197.  
  198. /* Block the child termination signal.  */
  199.  
  200. void
  201. block_children ()
  202. {
  203. #ifndef MSDOS
  204. #ifdef USG
  205.   /* Ignoring SIGCLD makes wait always return -1.
  206.      Using the default action does the right thing.  */
  207.   (void) signal (SIGCLD, SIG_DFL);
  208. #else
  209.   (void) sigblock (sigmask (SIGCHLD));
  210. #endif
  211. #endif /* ! MSDOS */
  212.  
  213.   block_remote_children ();
  214. }
  215.  
  216. /* Unblock the child termination signal.  */
  217. void
  218. unblock_children ()
  219. {
  220. #ifndef MSDOS
  221. #ifdef    USG
  222.   (void) signal (SIGCLD, child_handler);
  223. #else
  224.   (void) sigsetmask (sigblock (0) & ~sigmask (SIGCHLD));
  225. #endif
  226. #endif /* ! MSDOS */
  227.  
  228.   unblock_remote_children ();
  229. }
  230.  
  231. extern int shell_function_pid, shell_function_completed;
  232.  
  233. /* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
  234.    storing the returned status and the new command state (`cs_finished')
  235.    in the `file' member of the `struct child' for the dead child,
  236.    and removing the child from the chain.
  237.  
  238.    If we were called as a signal handler, SIG should be SIGCHLD
  239.    (SIGCLD for USG).  If instead it is zero, we were called explicitly
  240.    and should block waiting for running children.
  241.    If SIG is < 0, - SIG is the maximum number of children to bury (record
  242.    status of and remove from the chain).  */
  243.  
  244. int
  245. child_handler (sig)
  246.      int sig;
  247. {
  248.   WAIT_T status;
  249.   unsigned int dead_children = 0;
  250.  
  251.   if (sig > 0)
  252.     block_remote_children ();
  253.  
  254.   while (1)
  255.     {
  256.       int remote = 0;
  257.       register int pid;
  258.       int exit_code, exit_sig, coredump;
  259.       register struct child *lastc, *c;
  260.       int child_failed;
  261.  
  262.       /* First, check for remote children.  */
  263.       pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
  264.       if (pid < 0)
  265.     {
  266.       /* No remote children.  Check for local children.  */
  267.  
  268. #if    !defined(USG) || defined(HAVE_SYS_WAIT)
  269.       if (sig > 0)
  270.         pid = wait3 (&status, WNOHANG, (struct rusage *) 0);
  271.       else
  272.         pid = wait (&status);
  273. #else    /* USG and don't HAVE_SYS_WAIT.  */
  274.       /* System V cannot do non-blocking waits, so we have two
  275.          choices if called as a signal handler: handle only one
  276.          child (there may be more if the signal was blocked),
  277.          or block waiting for more.  The latter option makes
  278.          parallelism useless, so we must choose the former.  */
  279.       pid = wait (&status);
  280. #endif    /* HAVE_SYS_WAIT or not USG.  */
  281.  
  282.       if (pid <= 0)
  283.         /* No local children.  */
  284.         break;
  285.       else
  286.         {
  287.           /* Chop the status word up.  */
  288.           exit_code = WEXITSTATUS (status);
  289.           exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
  290.           coredump = WCOREDUMP (status);
  291.         }
  292.     }
  293.       else
  294.     /* We got a remote child.  */
  295.     remote = 1;
  296.  
  297.       /* Check if this is the child of the `shell' function.  */
  298.       if (!remote && pid == shell_function_pid)
  299.     {
  300.       /* It is.  Leave an indicator for the `shell' function.  */
  301.       if (exit_sig == 0 && exit_code == 127)
  302.         shell_function_completed = -1;
  303.       else
  304.         shell_function_completed = 1;
  305.  
  306.       /* Check if we have reached our quota of children.  */
  307.       ++dead_children;
  308.       if (sig < 0 && dead_children == -sig)
  309.         break;
  310. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  311.       else if (sig > 0)
  312.         break;
  313. #endif
  314.       else
  315.         continue;
  316.     }
  317.  
  318.       child_failed = exit_sig != 0 || exit_code != 0;
  319.  
  320.       /* Search for a child matching the deceased one.  */
  321.       lastc = 0;
  322.       for (c = children; c != 0; lastc = c, c = c->next)
  323.     if (c->remote == remote && c->pid == pid)
  324.       break;
  325.  
  326.       if (c == 0)
  327.     {
  328.       /* An unknown child died.  */
  329.       char buf[100];
  330.       sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
  331.       if (child_failed)
  332.         child_error (buf, exit_code, exit_sig, coredump,
  333.              ignore_errors_flag);
  334.       else
  335.         error ("%s finished.", buf);
  336.     }
  337.       else
  338.     {
  339.       /* If this child had the good stdin, say it is now free.  */
  340.       if (c->good_stdin)
  341.         good_stdin_used = 0;
  342.  
  343.       if (child_failed && !c->noerror && !ignore_errors_flag)
  344.         {
  345.           /* The commands failed.  Write an error message,
  346.          delete non-precious targets, and abort.  */
  347.           child_error (c->file->name, exit_code, exit_sig, coredump, 0);
  348.           c->file->update_status = 1;
  349.           if (exit_sig != 0)
  350.         delete_child_targets (c);
  351.         }
  352.       else
  353.         {
  354.           if (child_failed)
  355.         {
  356.           /* The commands failed, but we don't care.  */
  357.           child_error (c->file->name,
  358.                    exit_code, exit_sig, coredump, 1);
  359.           child_failed = 0;
  360.         }
  361.  
  362.           /* If there are more commands to run, try to start them.  */
  363.           start_job (c);
  364.           switch (c->file->command_state)
  365.         {
  366.         case cs_running:
  367.           /* Successfully started.  Loop to reap more children.  */
  368.           continue;
  369.  
  370.         case cs_finished:
  371.           if (c->file->update_status != 0)
  372.             {
  373.               /* We failed to start the commands.  */
  374.               delete_child_targets (c);
  375.             }
  376.           break;
  377.  
  378.         default:
  379.           error ("internal error: `%s' command_state \
  380. %d in child_handler", c->file->name);
  381.           abort ();
  382.           break;
  383.         }
  384.         }
  385.  
  386.       /* Set the state flag to say the commands have finished.  */
  387.       c->file->command_state = cs_finished;
  388.       notice_finished_file (c->file);
  389.  
  390.       /* Remove the child from the chain and free it.  */
  391.       if (lastc == 0)
  392.         children = c->next;
  393.       else
  394.         lastc->next = c->next;
  395.       free_child (c);
  396.  
  397.       /* There is now another slot open.  */
  398.       --job_slots_used;
  399.  
  400.       /* If the job failed, and the -k flag was not given, die.  */
  401.       if (child_failed && !keep_going_flag)
  402.         die (1);
  403.  
  404.       /* See if we have reached our quota for blocking.  */
  405.       ++dead_children;
  406.       if (sig < 0 && dead_children == -sig)
  407.         break;
  408. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  409.       else if (sig > 0)
  410.         break;
  411. #endif
  412.     }
  413.     }
  414.  
  415. #ifdef    USG
  416.   if (sig > 0)
  417.     (void) signal (sig, child_handler);
  418. #endif
  419.  
  420.   if (sig > 0)
  421.     unblock_remote_children ();
  422.  
  423.   return 0;
  424. }
  425.  
  426.  
  427. /* Wait for N children, blocking if necessary.
  428.    If N is zero, wait until we run out of children.
  429.    If ERR is nonzero and we have any children to wait for,
  430.    print a message on stderr.  */
  431.  
  432. void
  433. wait_for_children (n, err)
  434.      unsigned int n;
  435.      int err;
  436. {
  437.   block_children ();
  438.  
  439. #ifndef MSDOS
  440.   if (err && (children != 0 || shell_function_pid != 0))
  441.     {
  442.       fflush (stdout);
  443.       error ("*** Waiting for unfinished jobs....");
  444.     }
  445. #endif /* not MSDOS */
  446.  
  447.   /* Call child_handler to do the work.  */
  448.   (void) child_handler (- (int) n);
  449.  
  450.   unblock_children ();
  451. }
  452.  
  453. /* Free the storage allocated for CHILD.  */
  454.  
  455. static void
  456. free_child (child)
  457.      register struct child *child;
  458. {
  459.   if (child->commands != 0)
  460.     free (child->commands);
  461.   free ((char *) child);
  462. }
  463.  
  464. /* Start a job to run the commands specified in CHILD.
  465.    CHILD is updated to reflect the commands and ID of the child process.  */
  466.  
  467. static void
  468. start_job (child)
  469.      register struct child *child;
  470. {
  471.   static int bad_stdin = -1;
  472.   char *end;
  473.   register char *p;
  474.   int backslash;
  475.   char noprint = 0, recursive;
  476.   char **argv;
  477.  
  478.   if (child->command_ptr == 0 || *child->command_ptr == '\0')
  479.     /* There are no more lines in the expansion of this line.  */
  480.     if (child->file->cmds->command_lines[child->command_line] == 0)
  481.       {
  482.     /* There are no more lines to be expanded.  */
  483.     child->command_ptr = 0;
  484.     child->file->command_state = cs_finished;
  485.     child->file->update_status = 0;
  486.     return;
  487.       }
  488.     else
  489.       {
  490.     /* Expand and run the next line.  */
  491.     child->command_ptr = child->commands
  492. #ifdef MSDOS
  493.       = allocated_var_exp_for_file
  494. #else
  495.       = allocated_variable_expand_for_file
  496. #endif /* MSDOS */
  497.         (child->file->cmds->command_lines[child->command_line++],
  498.          child->file);
  499.       }
  500.  
  501.   /* Set RECURSIVE if the unexpanded line contains $(MAKE).  */
  502.   recursive = child->file->cmds->lines_recurse[child->command_line - 1];
  503.  
  504.   /* Find the end of this line.  Backslash-newlines don't mean the end.  */
  505.  
  506.   end = child->command_ptr;
  507.   while (*end != '\0')
  508.     {
  509.       p = index (end, '\n');
  510.       if (p == 0)
  511.     {
  512.       end += strlen (end);
  513.       break;
  514.     }
  515.  
  516.       end = p;
  517.       backslash = 0;
  518.       while (*--p == '\\')
  519.     backslash = !backslash;
  520.  
  521.       if (backslash)
  522.     {
  523.       ++end;
  524.       /* If there is a tab after a backslash-newline,
  525.          remove it, since it was most likely used to line
  526.          up the continued line with the previous one.  */
  527.       if (*end == '\t')
  528.         strcpy (end, end + 1);
  529.     }
  530.       else
  531.     break;
  532.     }
  533.  
  534.   p = child->command_ptr;
  535.  
  536.   if (*end == '\0')
  537.     child->command_ptr = 0;
  538.   else
  539.     {
  540.       *end = '\0';
  541.       child->command_ptr = end + 1;
  542.     }
  543.  
  544.   child->noerror = 0;
  545.   while (*p != '\0')
  546.     {
  547.       if (*p == '@')
  548.     noprint = 1;
  549.       else if (*p == '-')
  550.     child->noerror = 1;
  551.       else if (*p == '+')
  552.     recursive = 1;
  553.       else if (*p != ' ' && *p != '\t')
  554.     break;
  555.       ++p;
  556.     }
  557.  
  558.   /* If -q was given, just say that updating `failed'.  */
  559.   if (question_flag && !recursive)
  560.     goto error;
  561.  
  562.   /* There may be some preceding whitespace left if there
  563.      was nothing but a backslash on the first line.  */
  564.   p = next_token (p);
  565.  
  566.   if (*p == '\0')
  567.     /* There were no commands on this line.  Go to the next.  */
  568.     {
  569.       start_job (child);
  570.       return;
  571.     }
  572.  
  573.   /* Print out the command.  */
  574.  
  575.   if (just_print_flag || (!noprint && !silent_flag))
  576.     puts (p);
  577.  
  578.   /* If -n was given, recurse to get the next line in the sequence.  */
  579.  
  580.   if (just_print_flag && !recursive)
  581.     {
  582.       start_job (child);
  583.       return;
  584.     }
  585.  
  586.   /* Collapse backslash-newlines in this line.  */
  587.  
  588.   collapse_continuations (p);
  589.  
  590.   /* Figure out an argument list from this command line.  */
  591.  
  592.   argv = construct_command_argv (p, child->file);
  593.  
  594.   /* Flush the output streams so they won't have things written twice.  */
  595.  
  596.   fflush (stdout);
  597.   fflush (stderr);
  598.   
  599.   /* Set up a bad standard input that reads from a broken pipe.  */
  600.  
  601. #ifndef MSDOS
  602.   if (bad_stdin == -1)
  603.     {
  604.       /* Make a file descriptor that is the read end of a broken pipe.
  605.      This will be used for some children's standard inputs.  */
  606.       int pd[2];
  607.       if (pipe (pd) == 0)
  608.     {
  609.       /* Close the write side.  */
  610.       (void) close (pd[1]);
  611.       /* Save the read side.  */
  612.       bad_stdin = pd[0];
  613.     }
  614.     }
  615. #endif /* ! MSDOS */
  616.  
  617.   /* Decide whether to give this child the `good' standard input
  618.      (one that points to the terminal or whatever), or the `bad' one
  619.      that points to the read side of a broken pipe.  */
  620.  
  621.   child->good_stdin = !good_stdin_used;
  622.   if (child->good_stdin)
  623.     good_stdin_used = 1;
  624.  
  625.   child->deleted = 0;
  626.  
  627.   /* Set up the environment for the child.  */
  628.   if (child->environment == 0)
  629.     child->environment = target_environment (child->file);
  630.  
  631. #ifdef MSDOS
  632.  
  633.   child->remote = 0;
  634.   child->pid = abs ((int) clock());        /* reasonably random */
  635.  
  636. #if (0)
  637.        {
  638.               int ac = 0;
  639.               char **av = argv;
  640.               printf ( "start_job(): spawning process");
  641.               while (*av)
  642.                printf( " $%d=`%s'", ac++, *av++);
  643.               printf( "\n");
  644.        }
  645. #endif /* NEVER */
  646.  
  647.   /* LAST_CHILD_STATUS and LAST_CHILD_PID will be used by our
  648.      (faked) wait for MS-DOS to bury this 'child' */
  649.  
  650.   last_child_status = swap_spawnvpe (argv[0], argv, child->environment);
  651.  
  652.   last_child_pid = child->pid;
  653.  
  654.   if (last_child_status == -1)
  655.     pfatal_with_name (argv[0]);
  656.  
  657.   child->file->command_state = cs_running;    /* in *some* sense ...  */
  658.  
  659. #else /* not MSDOS */
  660.  
  661.   if (start_remote_job_p ())
  662.     {
  663.       int is_remote, id, used_stdin;
  664.       if (start_remote_job (argv, child->good_stdin ? 0 : bad_stdin,
  665.                 &is_remote, &id, &used_stdin))
  666.     goto error;
  667.       else
  668.     {
  669.       if (child->good_stdin && !used_stdin)
  670.         {
  671.           child->good_stdin = 0;
  672.           good_stdin_used = 0;
  673.         }
  674.       child->remote = is_remote;
  675.       child->pid = id;
  676.     }
  677.     }
  678.   else
  679.     {
  680.       if (child->command_line - 1 == 0)
  681.     /* Wait for the load to be low enough if this
  682.        is the first command in the sequence.  */
  683.     wait_to_start_job ();
  684.  
  685.       /* Fork the child process.  */
  686.  
  687.       child->remote = 0;
  688.       child->pid = vfork ();
  689.       if (child->pid == 0)
  690.     /* We are the child side.  */
  691.     child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
  692.                child->file, argv, child->environment);
  693.       else if (child->pid < 0)
  694.     {
  695.       /* Fork failed!  */
  696.       perror_with_name (VFORK_NAME, "");
  697.       goto error;
  698.     }
  699.     }
  700.  
  701.   /* We are the parent side.  Set the state to
  702.      say the commands are running and return.  */
  703.  
  704.   child->file->command_state = cs_running;
  705.  
  706. #endif /* not MSDOS */
  707.  
  708.   return;
  709.  
  710.  error:;
  711.   child->file->update_status = 1;
  712.   child->file->command_state = cs_finished;
  713. }
  714.  
  715.  
  716. /* Create a `struct child' for FILE and start its commands running.  */
  717.  
  718. void
  719. new_job (file)
  720.      register struct file *file;
  721. {
  722.   extern unsigned int files_remade;
  723.   register struct commands *cmds = file->cmds;
  724.   register struct child *c;
  725.  
  726.   /* Chop the commands up into lines if they aren't already.  */
  727.   chop_commands (cmds);
  728.  
  729.   if (job_slots > 0)
  730.     /* Wait for a job slot to be freed up.  */
  731.     while (job_slots_used == job_slots)
  732.       wait_for_children (1, 0);
  733.  
  734.   /* Start the command sequence, record it in a new
  735.      `struct child', and add that to the chain.  */
  736.  
  737.   block_children ();
  738.  
  739.   c = (struct child *) xmalloc (sizeof (struct child));
  740.   c->file = file;
  741.   c->command_line = 0;
  742.   c->command_ptr = c->commands = 0;
  743.   c->environment = 0;
  744.   start_job (c);
  745.   switch (file->command_state)
  746.     {
  747.     case cs_running:
  748.       c->next = children;
  749.       children = c;
  750.       /* One more job slot is in use.  */
  751.       ++job_slots_used;
  752.       break;
  753.  
  754.     case cs_finished:
  755.       free_child (c);
  756.       notice_finished_file (file);
  757.       break;
  758.  
  759.     default:
  760.       error ("internal error: `%s' command_state == %d in new_job",
  761.          file->name, (int) file->command_state);
  762.       abort ();
  763.       break;
  764.     }
  765.  
  766.   unblock_children ();
  767.  
  768.   ++files_remade;
  769.  
  770.   if (job_slots == 1 && file->command_state == cs_running)
  771.     {
  772.       /* Since there is only one job slot, make things run linearly.
  773.      Wait for the child to finish, setting the state to `cs_finished'.  */
  774.       while (file->command_state != cs_finished)
  775.     wait_for_children (1, 0);
  776.     }
  777. }
  778.  
  779. #ifndef MSDOS
  780. /* Replace the current process with one executing the command in ARGV.
  781.    STDIN_FD and STDOUT_FD are used as the process's stdin and stdout;
  782.    FILE, if not nil, is used as the variable-set to expand `PATH' and `SHELL';
  783.    ENVP is the environment of the new program.  This function won't return.  */
  784.  
  785. void
  786. child_execute_job (stdin_fd, stdout_fd, file, argv, envp)
  787.      int stdin_fd, stdout_fd;
  788.      struct file *file;
  789.      char **argv, **envp;
  790. {
  791.   if (stdin_fd != 0)
  792.     (void) dup2 (stdin_fd, 0);
  793.   if (stdout_fd != 1)
  794.     (void) dup2 (stdout_fd, 1);
  795.  
  796.   /* Free up file descriptors.  */
  797.   {
  798.     register int d;
  799.     int max = getdtablesize ();
  800.     for (d = 3; d < max; ++d)
  801.       (void) close (d);
  802.   }
  803.  
  804.   /* Don't block children for our child.  */
  805.   unblock_children ();
  806.  
  807.   /* Run the command.  */
  808.   exec_command (argv, envp,
  809.         allocated_variable_expand_for_file ("$(PATH)", file),
  810.         allocated_variable_expand_for_file ("$(SHELL)", file));
  811. }
  812. #endif /* not MSDOS */
  813.  
  814. /* Search PATH for FILE, returning a full pathname or nil.
  815.    The returned pathname is allocated via `malloc'.  */
  816.  
  817. static char *
  818. search_path (file, path)
  819.      char *file, *path;
  820. {
  821.   if (*path == '\0' || index (file, '/') != 0)
  822.     return file;
  823.   else
  824.     {
  825.       char *program;
  826.       unsigned int len;
  827.  
  828. #ifndef    USG
  829.       extern int getgroups ();
  830.       static int groups[NGROUPS];
  831.       static int ngroups = -1;
  832.       if (ngroups == -1)
  833.     ngroups = getgroups (NGROUPS, groups);
  834. #endif    /* Not USG.  */
  835.  
  836.       len = strlen (file) + 1;
  837.       program = (char *) xmalloc (strlen (path) + 1 + len);
  838.       do
  839.     {
  840.       struct stat st;
  841.       int perm;
  842.       char *p;
  843.  
  844.       p = index (path, PATHSEP);
  845.       if (p == 0)
  846.         p = path + strlen (path);
  847.  
  848.       if (p == path)
  849.         bcopy (file, program, len);
  850.       else
  851.         {
  852.           bcopy (path, program, p - path);
  853.           program[p - path] = '/';
  854.           bcopy (file, program + (p - path) + 1, len);
  855.         }
  856.  
  857.       if (stat (program, &st) == 0
  858.           && (st.st_mode & S_IFMT) == S_IFREG)
  859.         {
  860. #ifdef MSDOS            /* we always have permission */
  861.           return program;
  862. #else /* not MSDOS */
  863.           if (st.st_uid == geteuid ())
  864.         perm = (st.st_mode & 0100);
  865.           else if (st.st_gid == getegid ())
  866.         perm = (st.st_mode & 0010);
  867.           else
  868.         {
  869. #ifndef    USG
  870.           register int i;
  871.           for (i = 0; i < ngroups; ++i)
  872.             if (groups[i] == st.st_gid)
  873.               break;
  874.           if (i < ngroups)
  875.             perm = (st.st_mode & 0010);
  876.           else
  877. #endif    /* Not USG.  */
  878.             perm = (st.st_mode & 0001);
  879.         }
  880.  
  881.           if (perm != 0)
  882.         return program;
  883. #endif /* not MSDOS */
  884.         }
  885.  
  886.       path = p + 1;
  887.     } while (*path != '\0');
  888.     }
  889.  
  890.   return 0;
  891. }
  892.  
  893. #ifndef MSDOS
  894. /* Replace the current process with one running the command in ARGV,
  895.    with environment ENVP.  The program named in ARGV[0] is searched
  896.    for in PATH.  SHELL is the shell program to run for shell scripts.
  897.    This function does not return.  */
  898.  
  899. void
  900. exec_command (argv, envp, path, shell)
  901.      char **argv, **envp;
  902.      char *path, *shell;
  903. {
  904.   char *program;
  905.  
  906.   program = search_path (argv[0], path);
  907.   if (program == 0)
  908.     error ("%s: Command not found", argv[0]);
  909.   else
  910.     {
  911.       /* Run the program.  */
  912.       execve (program, argv, envp);
  913.  
  914.       if (errno == ENOEXEC)
  915.     {
  916.       char *shell_path = search_path (shell, path);
  917.       if (shell_path == 0)
  918.         error ("%s: Shell program not found", shell);
  919.       else
  920.         {
  921.           char **new_argv;
  922.           int argc;
  923.  
  924.           argc = 1;
  925.           while (argv[argc] != 0)
  926.         ++argc;
  927.  
  928.           new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *));
  929.           new_argv[0] = shell_path;
  930.           new_argv[1] = program;
  931.           while (argc > 0)
  932.         {
  933.           new_argv[1 + argc] = argv[argc];
  934.           --argc;
  935.         }
  936.  
  937.           execve (shell_path, new_argv, envp);
  938.           perror_with_name ("execve: ", shell_path);
  939.         }
  940.     }
  941.       else
  942.     perror_with_name ("execve: ", program);
  943.     }
  944.  
  945.   _exit (127);
  946. }
  947. #endif /* not MSDOS */
  948.  
  949. /* Figure out the argument list necessary to run LINE as a command.
  950.    Try to avoid using a shell.  This routine handles only ' quoting.
  951.    Starting quotes may be escaped with a backslash.  If any of the
  952.    characters in sh_chars[] is seen, or any of the builtin commands
  953.    listed in sh_cmds[] is the first word of a line, the shell is used.
  954.  
  955.    FILE is the target whose commands these are.  It is used for
  956.    variable expansion for $(SHELL) and $(IFS).  */
  957.  
  958. char **
  959. construct_command_argv (line, file)
  960.      char *line;
  961.      struct file *file;
  962. {
  963.   register int i;
  964.   register char *p;
  965.   register char *ap;
  966.   char *end;
  967.   int instring;
  968.   char **new_argv = 0;
  969.  
  970. #ifdef MSDOS
  971.  
  972.   char *sh_chars;
  973.   char **sh_cmds;
  974.   char *base;
  975.   char *shell_command;
  976.   char switch_char = '/';
  977.  
  978.   static char _sh_chars[]
  979.     = "#;\"*?[]&|<>(){}=$`";
  980.   static char *_sh_cmds[]
  981.     = {    "cd", "echo", "eval", "exec", "exit", "login", "logout", "set",
  982.     "umask", "wait", "while", "for", "case", "if", ":", ".", "break",
  983.     "continue", "export", "read", "readonly", "shift", "times",
  984.     "trap", "switch", NULL };
  985.  
  986.   static char _4dos_chars[]
  987.     = "<|>^&%";
  988.   static char *_4dos_cmds[]
  989.     = {    "alias", "attrib", "beep", "cd", "cdd", "chdir", "copy", "del",
  990.     "dir", "echo", "erase", "except", "for", "global", "if", "iff",
  991.     "keystack", "md", "move", "popd", "pushd", "rd", "ren", "rename",
  992.     "set", "timer", "unalias", "unset", NULL };
  993.  
  994.   static char _command_com_chars[]
  995.     = "<|>%";
  996.   static char *_command_com_cmds[]
  997.     = { "attrib", "cd", "chdir", "copy", "del", "dir", "echo", "erase",
  998.     "for", "if", "md", "quit", "rd", "ren", "rename", "set", "unset",
  999.     NULL };
  1000.  
  1001.  
  1002.   /* See if it is safe to parse commands internally.  */
  1003.  
  1004.   /* $(SHELL) is always defined (see variable.c)  */
  1005.   p = base = shell_command
  1006.     = strlwr (allocated_var_exp_for_file ("$(SHELL)", file));
  1007.  
  1008.   while (*p)
  1009.     {
  1010.       if ((*p == '/' || *p == '\\' || *p == ':') && p[1])
  1011.     base = p + 1;
  1012.       p++;
  1013.     }
  1014.  
  1015.   if (!strncmp ("sh", base, 2))
  1016.     {
  1017.       sh_chars = _sh_chars;
  1018.       sh_cmds = _sh_cmds;
  1019.       switch_char = '/';    /* this is true for by Bourne shell */
  1020.     }
  1021.   else if (!strncmp ("4dos", base, 4))
  1022.     {
  1023.       sh_chars = _4dos_chars;
  1024.       sh_cmds = _4dos_cmds;
  1025.     }
  1026.   else if (!strncmp ("command", base, 7))
  1027.     {
  1028.       sh_chars = _command_com_chars;
  1029.       sh_cmds = _command_com_cmds;
  1030.     }
  1031.   else
  1032.     {
  1033.       free (shell_command);
  1034.       goto slow;
  1035.     }
  1036.  
  1037. #else /* not MSDOS */
  1038.  
  1039.   static char sh_chars[] = "#;\"*?[]&|<>(){}=$`";
  1040.   static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
  1041.                  "logout", "set", "umask", "wait", "while", "for",
  1042.                  "case", "if", ":", ".", "break", "continue",
  1043.                  "export", "read", "readonly", "shift", "times",
  1044.                  "trap", "switch", 0 };
  1045.  
  1046.   /* See if it is safe to parse commands internally.  */
  1047.   p = variable_expand_for_file ("$(SHELL)", file);
  1048.   if (strcmp (p, "/bin/sh"))
  1049.     goto slow;
  1050.  
  1051. #endif /* not MSDOS */
  1052.  
  1053.   p = variable_expand_for_file ("$(IFS)", file);
  1054.   for (ap = p; *ap != '\0'; ++ap)
  1055.     if (*ap != ' ' && *ap != '\t' && *ap != '\n')
  1056.       goto slow;
  1057.  
  1058.   i = strlen (line) + 1;
  1059.  
  1060.   /* More than 1 arg per character is impossible.  */
  1061.   new_argv = (char **) xmalloc (i * sizeof (char *));
  1062.  
  1063.   /* All the args can fit in a buffer as big as LINE is.   */
  1064.   ap = new_argv[0] = (char *) xmalloc (i);
  1065.   end = ap + i;
  1066.  
  1067.   /* I is how many complete arguments have been found.  */
  1068.   i = 0;
  1069.   instring = 0;
  1070.   for (p = line; *p != '\0'; ++p)
  1071.     {
  1072.       if (ap > end)
  1073.     abort ();
  1074.  
  1075.       if (instring)
  1076.     {
  1077.       /* Inside a string, just copy any char except a closing quote.  */
  1078.       if (*p == '\'')
  1079.         instring = 0;
  1080.       else
  1081.         *ap++ = *p;
  1082.     }
  1083.       else if (index (sh_chars, *p) != 0)
  1084.     /* Not inside a string, but it's a special char.  */
  1085.     goto slow;
  1086.       else
  1087.     /* Not a special char.  */
  1088.     switch (*p)
  1089.       {
  1090.       case '\\':
  1091.         if (p[1] != '\0' && p[1] != '\n')
  1092.           /* Copy and skip the following char.  */
  1093.           *ap++ = *++p;
  1094.         break;
  1095.  
  1096.       case '\'':
  1097.         instring = 1;
  1098.         break;
  1099.  
  1100.       case '\n':
  1101.       case ' ':
  1102.       case '\t':
  1103.         /* We have the end of an argument.
  1104.            Terminate the text of the argument.  */
  1105.         *ap++ = '\0';
  1106.         new_argv[++i] = ap;
  1107.         /* If this argument is the command name,
  1108.            see if it is a built-in shell command.
  1109.            If so, have the shell handle it.  */
  1110.         if (i == 1)
  1111.           {
  1112.         register int j;
  1113.         for (j = 0; sh_cmds[j] != 0; ++j)
  1114.           if (streq (sh_cmds[j], new_argv[0]))
  1115.             goto slow;
  1116.           }
  1117.  
  1118.         /* Ignore multiple whitespace chars.  */
  1119.         p = next_token (p);
  1120.         /* Next iteration should examine the first nonwhite char.  */
  1121.         --p;
  1122.         break;
  1123.  
  1124.       default:
  1125.         *ap++ = *p;
  1126.         break;
  1127.       }
  1128.     }
  1129.  
  1130.   /* Terminate the last argument and the argument list.  */
  1131.  
  1132.   *ap = '\0';
  1133.   if (new_argv[i][0] != '\0')
  1134.     ++i;
  1135.   new_argv[i] = 0;
  1136.  
  1137.   if (new_argv[0] == 0)
  1138.     /* Line was empty.  */
  1139.     return 0;
  1140.   else
  1141.     return new_argv;
  1142.  
  1143.  slow:;
  1144.   if (new_argv != 0)
  1145.     free (new_argv);
  1146.   new_argv = (char **) xmalloc (4 * sizeof (char *));
  1147. #ifdef MSDOS
  1148.   new_argv[0] = allocated_var_exp_for_file ("$(SHELL)", file);
  1149.   new_argv[1] = (switch_char == '-') ? "-c" : "/c";
  1150. #else /* not MSDOS */
  1151.   new_argv[0] = allocated_variable_expand_for_file ("$(SHELL)", file);
  1152.   new_argv[1] = "-c";
  1153. #endif /* not MSDOS */
  1154.   new_argv[2] = line;
  1155.   new_argv[3] = 0;
  1156.  
  1157.   return new_argv;
  1158. }
  1159.  
  1160. #if    defined(USG) && !defined(HAVE_SIGLIST)
  1161. /* Initialize sys_siglist.  */
  1162.  
  1163. void
  1164. init_siglist ()
  1165. {
  1166.   char buf[100];
  1167.   register unsigned int i;
  1168.  
  1169.   for (i = 0; i < NSIG; ++i)
  1170.     switch (i)
  1171.       {
  1172.       default:
  1173.     sprintf (buf, "Signal %u", i);
  1174.     sys_siglist[i] = savestring (buf, strlen (buf));
  1175.     break;
  1176. #ifndef MSDOS
  1177.       case SIGHUP:
  1178.     sys_siglist[i] = "Hangup";
  1179.     break;
  1180. #endif /* ! MSDOS */
  1181.       case SIGINT:
  1182.     sys_siglist[i] = "Interrupt";
  1183.     break;
  1184. #ifndef MSDOS
  1185.       case SIGQUIT:
  1186.     sys_siglist[i] = "Quit";
  1187.     break;
  1188.       case SIGILL:
  1189.     sys_siglist[i] = "Illegal Instruction";
  1190.     break;
  1191.       case SIGTRAP:
  1192.     sys_siglist[i] = "Trace Trap";
  1193.     break;
  1194.       case SIGIOT:
  1195.     sys_siglist[i] = "IOT Trap";
  1196.     break;
  1197. #endif /* ! MSDOS */
  1198. #ifdef    SIGEMT
  1199.       case SIGEMT:
  1200.     sys_siglist[i] = "EMT Trap";
  1201.     break;
  1202. #endif
  1203. #ifdef    SIGDANGER
  1204.       case SIGDANGER:
  1205.     sys_siglist[i] = "Danger signal";
  1206.     break;
  1207. #endif
  1208.       case SIGFPE:
  1209.     sys_siglist[i] = "Floating Point Exception";
  1210.     break;
  1211. #ifndef MSDOS
  1212.       case SIGKILL:
  1213.     sys_siglist[i] = "Killed";
  1214.     break;
  1215.       case SIGBUS:
  1216.     sys_siglist[i] = "Bus Error";
  1217.     break;
  1218.       case SIGSEGV:
  1219.     sys_siglist[i] = "Segmentation fault";
  1220.     break;
  1221.       case SIGSYS:
  1222.     sys_siglist[i] = "Bad Argument to System Call";
  1223.     break;
  1224.       case SIGPIPE:
  1225.     sys_siglist[i] = "Broken Pipe";
  1226.     break;
  1227.       case SIGALRM:
  1228.     sys_siglist[i] = "Alarm Clock";
  1229.     break;
  1230.       case SIGTERM:
  1231.     sys_siglist[i] = "Terminated";
  1232.     break;
  1233.       case SIGUSR1:
  1234.     sys_siglist[i] = "User-defined signal 1";
  1235.     break;
  1236.       case SIGUSR2:
  1237.     sys_siglist[i] = "User-defined signal 2";
  1238.     break;
  1239. #endif /* ! MSDOS */
  1240. #ifdef    SIGCLD
  1241.       case SIGCLD:
  1242. #endif
  1243. #if    defined(SIGCHLD) && !defined(SIGCLD)
  1244.       case SIGCHLD:
  1245. #endif
  1246.     sys_siglist[i] = "Child Process Exited";
  1247.     break;
  1248. #ifdef    SIGPWR
  1249.       case SIGPWR:
  1250.     sys_siglist[i] = "Power Failure";
  1251.     break;
  1252. #endif
  1253. #ifdef    SIGVTALRM
  1254.       case SIGVTALRM:
  1255.     sys_siglist[i] = "Virtual Timer Alarm";
  1256.     break;
  1257. #endif
  1258. #ifdef    SIGPROF
  1259.       case SIGPROF:
  1260.     sys_siglist[i] = "Profiling Alarm Clock";
  1261.     break;
  1262. #endif
  1263. #ifdef    SIGIO
  1264.       case SIGIO:
  1265.     sys_siglist[i] = "I/O Possible";
  1266.     break;
  1267. #endif
  1268. #ifdef    SIGWINDOW
  1269.       case SIGWINDOW:
  1270.     sys_siglist[i] = "Window System Signal";
  1271.     break;
  1272. #endif
  1273. #ifdef    SIGSTOP
  1274.       case SIGSTOP:
  1275.     sys_siglist[i] = "Stopped (signal)";
  1276.     break;
  1277. #endif
  1278. #ifdef    SIGTSTP
  1279.       case SIGTSTP:
  1280.     sys_siglist[i] = "Stopped";
  1281.     break;
  1282. #endif
  1283. #ifdef    SIGCONT
  1284.       case SIGCONT:
  1285.     sys_siglist[i] = "Continued";
  1286.     break;
  1287. #endif
  1288. #ifdef    SIGTTIN
  1289.       case SIGTTIN:
  1290.     sys_siglist[i] = "Stopped (tty input)";
  1291.     break;
  1292. #endif
  1293. #ifdef    SIGTTOU
  1294.       case SIGTTOU:
  1295.     sys_siglist[i] = "Stopped (tty output)";
  1296.     break;
  1297. #endif
  1298. #ifdef    SIGURG
  1299.       case SIGURG:
  1300.     sys_siglist[i] = "Urgent Condition on Socket";
  1301.     break;
  1302. #endif
  1303. #ifdef    SIGXCPU
  1304.       case SIGXCPU:
  1305.     sys_siglist[i] = "CPU Limit Exceeded";
  1306.     break;
  1307. #endif
  1308. #ifdef    SIGXFSZ
  1309.       case SIGXFSZ:
  1310.     sys_siglist[i] = "File Size Limit Exceeded";
  1311.     break;
  1312. #endif
  1313.       }
  1314. }
  1315. #endif    /* USG and not HAVE_SIGLIST.  */
  1316.  
  1317. #if defined(USG) && !defined(USGr3) && !defined(HAVE_DUP2) && !defined (MSDOS)
  1318. int
  1319. dup2 (old, new)
  1320.      int old, new;
  1321. {
  1322.   int fd;
  1323.  
  1324.   (void) close (new);
  1325.   fd = dup (old);
  1326.   if (fd != new)
  1327.     {
  1328.       (void) close (fd);
  1329.       errno = EMFILE;
  1330.       return -1;
  1331.     }
  1332.  
  1333.   return fd;
  1334. }
  1335. #endif    /* USG and not USGr3 and not HAVE_DUP2 and not MSDOS.  */
  1336.  
  1337. #ifdef MSDOS
  1338.  
  1339. /* Here we fake a wait () ... */
  1340.  
  1341. int
  1342. wait (WAIT_T *status)
  1343.  {
  1344.    int pid = last_child_pid;
  1345.  
  1346.    /* Swap the high and low byte of the STATUS word:
  1347.       error codes > 256  (e.g. those generated by spawn_child ())
  1348.       will be interpreted as signals and cause the target to be
  1349.       deleted.  In any case, we mask off the coredump bit.  */
  1350.  
  1351.    *status = (last_child_status << 8) + ((last_child_status >> 8) & 0x7f);
  1352.  
  1353.    /* This was the only child .... */
  1354.    last_child_pid = 0;
  1355.  
  1356.    return pid;
  1357.  }
  1358.  
  1359. /* Interface to swaplib.  */
  1360.  
  1361. #define DELIMITER ":"
  1362. static char *smart_programs (void);
  1363.  
  1364. int
  1365. swap_smart_p (char *name)
  1366. {
  1367.   char *list = smart_programs ();
  1368.   char *tok;
  1369.  
  1370.   tok = strtok (list, DELIMITER);
  1371.  
  1372.   while (tok && strcmp (tok, name))
  1373.     tok = strtok (NULL, DELIMITER);
  1374.  
  1375.   free (list);
  1376.   return (tok != NULL);
  1377. }
  1378.  
  1379. char *
  1380. smart_programs (void)
  1381. {
  1382.   struct variable *smart
  1383.     = lookup_variable ("LONGARGS", sizeof ("LONGARGS") - 1);
  1384.   char *string;
  1385.  
  1386.   if (smart && smart->value)
  1387.     {
  1388.       string = (char *) xmalloc (strlen (smart->value) + 1);
  1389.       strcpy (string, smart->value);
  1390.     }
  1391.   else
  1392.     {
  1393.       string = (char *) xmalloc (1);
  1394.       strcpy (string, "");
  1395.     }
  1396.  
  1397.   return string;
  1398. }
  1399.  
  1400.  
  1401. enum swap_swapping_mode
  1402. swap_set_swapping_mode (char *cmd, char **argv)
  1403. {
  1404.   /* Default to XMS.  */
  1405.  
  1406.   enum swap_swapping_mode mode = xms;
  1407.  
  1408.   struct variable *swapping
  1409.     = lookup_variable ("SWAPPING", sizeof ("SWAPPING") - 1);
  1410.  
  1411.   if (!swapping || !(swapping->value))
  1412.     return mode;
  1413.  
  1414.   if (strcmp ("xms", swapping->value) == 0)
  1415.     mode = xms;
  1416.   else if (strcmp ("ems", swapping->value) == 0)
  1417.     mode = ems;
  1418.   else if (strcmp ("disk", swapping->value) == 0)
  1419.     mode = disk;
  1420.   else if (strcmp ("none", swapping->value) == 0)
  1421.     mode = none;
  1422.  
  1423.   return mode;
  1424. }
  1425.  
  1426. #endif    /* MSDOS */
  1427.  
  1428.