Merge branch 'tr/fd-gotcha-fixes'
[git/git.git] / run-command.c
index afc573e..1b7f88e 100644 (file)
@@ -72,7 +72,7 @@ static inline void close_pair(int fd[2])
        close(fd[1]);
 }
 
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
 static inline void dup_devnull(int to)
 {
        int fd = open("/dev/null", O_RDWR);
@@ -162,7 +162,7 @@ static const char **prepare_shell_cmd(const char **argv)
                die("BUG: shell command is empty");
 
        if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
                nargv[nargc++] = SHELL_PATH;
 #else
                nargv[nargc++] = "sh";
@@ -185,7 +185,7 @@ static const char **prepare_shell_cmd(const char **argv)
        return nargv;
 }
 
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
 static int execv_shell_cmd(const char **argv)
 {
        const char **nargv = prepare_shell_cmd(argv);
@@ -196,7 +196,7 @@ static int execv_shell_cmd(const char **argv)
 }
 #endif
 
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
 static int child_err = 2;
 static int child_notifier = -1;
 
@@ -276,7 +276,8 @@ int start_command(struct child_process *cmd)
 {
        int need_in, need_out, need_err;
        int fdin[2], fdout[2], fderr[2];
-       int failed_errno = failed_errno;
+       int failed_errno;
+       char *str;
 
        /*
         * In case of errors we must keep the promise to close FDs
@@ -289,6 +290,7 @@ int start_command(struct child_process *cmd)
                        failed_errno = errno;
                        if (cmd->out > 0)
                                close(cmd->out);
+                       str = "standard input";
                        goto fail_pipe;
                }
                cmd->in = fdin[1];
@@ -304,6 +306,7 @@ int start_command(struct child_process *cmd)
                                close_pair(fdin);
                        else if (cmd->in)
                                close(cmd->in);
+                       str = "standard output";
                        goto fail_pipe;
                }
                cmd->out = fdout[0];
@@ -321,9 +324,10 @@ int start_command(struct child_process *cmd)
                                close_pair(fdout);
                        else if (cmd->out)
                                close(cmd->out);
+                       str = "standard error";
 fail_pipe:
-                       error("cannot create pipe for %s: %s",
-                               cmd->argv[0], strerror(failed_errno));
+                       error("cannot create %s pipe for %s: %s",
+                               str, cmd->argv[0], strerror(failed_errno));
                        errno = failed_errno;
                        return -1;
                }
@@ -333,13 +337,14 @@ fail_pipe:
        trace_argv_printf(cmd->argv, "trace: run_command:");
        fflush(NULL);
 
-#ifndef WIN32
+#ifndef GIT_WINDOWS_NATIVE
 {
        int notify_pipe[2];
        if (pipe(notify_pipe))
                notify_pipe[0] = notify_pipe[1] = -1;
 
        cmd->pid = fork();
+       failed_errno = errno;
        if (!cmd->pid) {
                /*
                 * Redirect the channel to write syscall error messages to
@@ -419,7 +424,7 @@ fail_pipe:
        }
        if (cmd->pid < 0)
                error("cannot fork() for %s: %s", cmd->argv[0],
-                       strerror(failed_errno = errno));
+                       strerror(errno));
        else if (cmd->clean_on_exit)
                mark_child_for_cleanup(cmd->pid);
 
@@ -586,6 +591,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
 static pthread_t main_thread;
 static int main_thread_set;
 static pthread_key_t async_key;
+static pthread_key_t async_die_counter;
 
 static void *run_thread(void *data)
 {
@@ -612,6 +618,14 @@ static NORETURN void die_async(const char *err, va_list params)
 
        exit(128);
 }
+
+static int async_die_is_recursing(void)
+{
+       void *ret = pthread_getspecific(async_die_counter);
+       pthread_setspecific(async_die_counter, (void *)1);
+       return ret != NULL;
+}
+
 #endif
 
 int start_async(struct async *async)
@@ -693,7 +707,9 @@ int start_async(struct async *async)
                main_thread_set = 1;
                main_thread = pthread_self();
                pthread_key_create(&async_key, NULL);
+               pthread_key_create(&async_die_counter, NULL);
                set_die_routine(die_async);
+               set_die_is_recursing_routine(async_die_is_recursing);
        }
 
        if (proc_in >= 0)
@@ -738,6 +754,15 @@ int finish_async(struct async *async)
 #endif
 }
 
+char *find_hook(const char *name)
+{
+       char *path = git_path("hooks/%s", name);
+       if (access(path, X_OK) < 0)
+               path = NULL;
+
+       return path;
+}
+
 int run_hook(const char *index_file, const char *name, ...)
 {
        struct child_process hook;
@@ -747,11 +772,13 @@ int run_hook(const char *index_file, const char *name, ...)
        va_list args;
        int ret;
 
-       if (access(git_path("hooks/%s", name), X_OK) < 0)
+       p = find_hook(name);
+       if (!p)
                return 0;
 
+       argv_array_push(&argv, p);
+
        va_start(args, name);
-       argv_array_push(&argv, git_path("hooks/%s", name));
        while ((p = va_arg(args, const char *)))
                argv_array_push(&argv, p);
        va_end(args);