Merge branch 'dg/run-command-child-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Sat, 15 Sep 2012 04:39:37 +0000 (21:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 15 Sep 2012 04:39:37 +0000 (21:39 -0700)
The code to wait for subprocess and remove it from our internal queue
wasn't quite right.

* dg/run-command-child-cleanup:
run-command.c: fix broken list iteration in clear_child_for_cleanup

1  2 
run-command.c
diff --combined run-command.c
index f9922b9ecc8e4956e19d7143bb6cb6ef4d97abf8,d1d58d3e21bdcc8f80bda7aadb35ccd5066f4b38..1101ef72378a502b1681a8e1bc306f38027974ae
@@@ -4,10 -4,6 +4,10 @@@
  #include "sigchain.h"
  #include "argv-array.h"
  
 +#ifndef SHELL_PATH
 +# define SHELL_PATH "/bin/sh"
 +#endif
 +
  struct child_to_clean {
        pid_t pid;
        struct child_to_clean *next;
@@@ -53,13 -49,14 +53,14 @@@ static void mark_child_for_cleanup(pid_
  
  static void clear_child_for_cleanup(pid_t pid)
  {
-       struct child_to_clean **last, *p;
+       struct child_to_clean **pp;
  
-       last = &children_to_clean;
-       for (p = children_to_clean; p; p = p->next) {
-               if (p->pid == pid) {
-                       *last = p->next;
-                       free(p);
+       for (pp = &children_to_clean; *pp; pp = &(*pp)->next) {
+               struct child_to_clean *clean_me = *pp;
+               if (clean_me->pid == pid) {
+                       *pp = clean_me->next;
+                       free(clean_me);
                        return;
                }
        }
@@@ -80,70 -77,6 +81,70 @@@ static inline void dup_devnull(int to
  }
  #endif
  
 +static char *locate_in_PATH(const char *file)
 +{
 +      const char *p = getenv("PATH");
 +      struct strbuf buf = STRBUF_INIT;
 +
 +      if (!p || !*p)
 +              return NULL;
 +
 +      while (1) {
 +              const char *end = strchrnul(p, ':');
 +
 +              strbuf_reset(&buf);
 +
 +              /* POSIX specifies an empty entry as the current directory. */
 +              if (end != p) {
 +                      strbuf_add(&buf, p, end - p);
 +                      strbuf_addch(&buf, '/');
 +              }
 +              strbuf_addstr(&buf, file);
 +
 +              if (!access(buf.buf, F_OK))
 +                      return strbuf_detach(&buf, NULL);
 +
 +              if (!*end)
 +                      break;
 +              p = end + 1;
 +      }
 +
 +      strbuf_release(&buf);
 +      return NULL;
 +}
 +
 +static int exists_in_PATH(const char *file)
 +{
 +      char *r = locate_in_PATH(file);
 +      free(r);
 +      return r != NULL;
 +}
 +
 +int sane_execvp(const char *file, char * const argv[])
 +{
 +      if (!execvp(file, argv))
 +              return 0; /* cannot happen ;-) */
 +
 +      /*
 +       * When a command can't be found because one of the directories
 +       * listed in $PATH is unsearchable, execvp reports EACCES, but
 +       * careful usability testing (read: analysis of occasional bug
 +       * reports) reveals that "No such file or directory" is more
 +       * intuitive.
 +       *
 +       * We avoid commands with "/", because execvp will not do $PATH
 +       * lookups in that case.
 +       *
 +       * The reassignment of EACCES to errno looks like a no-op below,
 +       * but we need to protect against exists_in_PATH overwriting errno.
 +       */
 +      if (errno == EACCES && !strchr(file, '/'))
 +              errno = exists_in_PATH(file) ? EACCES : ENOENT;
 +      else if (errno == ENOTDIR && !strchr(file, '/'))
 +              errno = ENOENT;
 +      return -1;
 +}
 +
  static const char **prepare_shell_cmd(const char **argv)
  {
        int argc, nargc = 0;
                die("BUG: shell command is empty");
  
        if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
 +#ifndef WIN32
 +              nargv[nargc++] = SHELL_PATH;
 +#else
                nargv[nargc++] = "sh";
 +#endif
                nargv[nargc++] = "-c";
  
                if (argc < 2)
@@@ -186,7 -115,7 +187,7 @@@ static int execv_shell_cmd(const char *
  {
        const char **nargv = prepare_shell_cmd(argv);
        trace_argv_printf(nargv, "trace: exec:");
 -      execvp(nargv[0], (char **)nargv);
 +      sane_execvp(nargv[0], (char **)nargv);
        free(nargv);
        return -1;
  }
@@@ -411,7 -340,7 +412,7 @@@ fail_pipe
                } else if (cmd->use_shell) {
                        execv_shell_cmd(cmd->argv);
                } else {
 -                      execvp(cmd->argv[0], (char *const*) cmd->argv);
 +                      sane_execvp(cmd->argv[0], (char *const*) cmd->argv);
                }
                if (errno == ENOENT) {
                        if (!cmd->silent_exec_failure)
@@@ -569,7 -498,6 +570,7 @@@ static void prepare_run_command_v_opt(s
        cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
        cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
        cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
 +      cmd->clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
  }
  
  int run_command_v_opt(const char **argv, int opt)