diff options
Diffstat (limited to 'run-command.c')
-rw-r--r-- | run-command.c | 141 |
1 files changed, 121 insertions, 20 deletions
diff --git a/run-command.c b/run-command.c index 8d42a4f534..d679cc267c 100644 --- a/run-command.c +++ b/run-command.c @@ -1,10 +1,12 @@ #include "cache.h" #include "run-command.h" -#include "exec_cmd.h" +#include "exec-cmd.h" #include "sigchain.h" #include "argv-array.h" #include "thread-utils.h" #include "strbuf.h" +#include "string-list.h" +#include "quote.h" void child_process_init(struct child_process *child) { @@ -243,7 +245,7 @@ int sane_execvp(const char *file, char * const argv[]) static const char **prepare_shell_cmd(struct argv_array *out, const char **argv) { if (!argv[0]) - die("BUG: shell command is empty"); + BUG("shell command is empty"); if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { #ifndef GIT_WINDOWS_NATIVE @@ -381,7 +383,7 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr) static int prepare_cmd(struct argv_array *out, const struct child_process *cmd) { if (!cmd->argv[0]) - die("BUG: command is empty"); + BUG("command is empty"); /* * Add SHELL_PATH so in the event exec fails with ENOEXEC we can @@ -475,15 +477,12 @@ struct atfork_state { sigset_t old; }; -#ifndef NO_PTHREADS -static void bug_die(int err, const char *msg) -{ - if (err) { - errno = err; - die_errno("BUG: %s", msg); - } -} -#endif +#define CHECK_BUG(err, msg) \ + do { \ + int e = (err); \ + if (e) \ + BUG("%s: %s", msg, strerror(e)); \ + } while(0) static void atfork_prepare(struct atfork_state *as) { @@ -495,9 +494,9 @@ static void atfork_prepare(struct atfork_state *as) if (sigprocmask(SIG_SETMASK, &all, &as->old)) die_errno("sigprocmask"); #else - bug_die(pthread_sigmask(SIG_SETMASK, &all, &as->old), + CHECK_BUG(pthread_sigmask(SIG_SETMASK, &all, &as->old), "blocking all signals"); - bug_die(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &as->cs), + CHECK_BUG(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &as->cs), "disabling cancellation"); #endif } @@ -508,9 +507,9 @@ static void atfork_parent(struct atfork_state *as) if (sigprocmask(SIG_SETMASK, &as->old, NULL)) die_errno("sigprocmask"); #else - bug_die(pthread_setcancelstate(as->cs, NULL), + CHECK_BUG(pthread_setcancelstate(as->cs, NULL), "re-enabling cancellation"); - bug_die(pthread_sigmask(SIG_SETMASK, &as->old, NULL), + CHECK_BUG(pthread_sigmask(SIG_SETMASK, &as->old, NULL), "restoring signal mask"); #endif } @@ -561,6 +560,90 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal) return code; } +static void trace_add_env(struct strbuf *dst, const char *const *deltaenv) +{ + struct string_list envs = STRING_LIST_INIT_DUP; + const char *const *e; + int i; + int printed_unset = 0; + + /* Last one wins, see run-command.c:prep_childenv() for context */ + for (e = deltaenv; e && *e; e++) { + struct strbuf key = STRBUF_INIT; + char *equals = strchr(*e, '='); + + if (equals) { + strbuf_add(&key, *e, equals - *e); + string_list_insert(&envs, key.buf)->util = equals + 1; + } else { + string_list_insert(&envs, *e)->util = NULL; + } + strbuf_release(&key); + } + + /* "unset X Y...;" */ + for (i = 0; i < envs.nr; i++) { + const char *var = envs.items[i].string; + const char *val = envs.items[i].util; + + if (val || !getenv(var)) + continue; + + if (!printed_unset) { + strbuf_addstr(dst, " unset"); + printed_unset = 1; + } + strbuf_addf(dst, " %s", var); + } + if (printed_unset) + strbuf_addch(dst, ';'); + + /* ... followed by "A=B C=D ..." */ + for (i = 0; i < envs.nr; i++) { + const char *var = envs.items[i].string; + const char *val = envs.items[i].util; + const char *oldval; + + if (!val) + continue; + + oldval = getenv(var); + if (oldval && !strcmp(val, oldval)) + continue; + + strbuf_addf(dst, " %s=", var); + sq_quote_buf_pretty(dst, val); + } + string_list_clear(&envs, 0); +} + +static void trace_run_command(const struct child_process *cp) +{ + struct strbuf buf = STRBUF_INIT; + + if (!trace_want(&trace_default_key)) + return; + + strbuf_addstr(&buf, "trace: run_command:"); + if (cp->dir) { + strbuf_addstr(&buf, " cd "); + sq_quote_buf_pretty(&buf, cp->dir); + strbuf_addch(&buf, ';'); + } + /* + * The caller is responsible for initializing cp->env from + * cp->env_array if needed. We only check one place. + */ + if (cp->env) + trace_add_env(&buf, cp->env); + if (cp->git_cmd) + strbuf_addstr(&buf, " git"); + sq_quote_argv_pretty(&buf, cp->argv); + + trace_printf("%s", buf.buf); + strbuf_release(&buf); +} + int start_command(struct child_process *cmd) { int need_in, need_out, need_err; @@ -629,7 +712,8 @@ fail_pipe: cmd->err = fderr[0]; } - trace_argv_printf(cmd->argv, "trace: run_command:"); + trace_run_command(cmd); + fflush(NULL); #ifndef GIT_WINDOWS_NATIVE @@ -893,7 +977,7 @@ int run_command(struct child_process *cmd) int code; if (cmd->out < 0 || cmd->err < 0) - die("BUG: run_command with a pipe can cause deadlock"); + BUG("run_command with a pipe can cause deadlock"); code = start_command(cmd); if (code) @@ -1182,11 +1266,28 @@ const char *find_hook(const char *name) strbuf_reset(&path); strbuf_git_path(&path, "hooks/%s", name); if (access(path.buf, X_OK) < 0) { + int err = errno; + #ifdef STRIP_EXTENSION strbuf_addstr(&path, STRIP_EXTENSION); if (access(path.buf, X_OK) >= 0) return path.buf; + if (errno == EACCES) + err = errno; #endif + + if (err == EACCES && advice_ignored_hook) { + static struct string_list advise_given = STRING_LIST_INIT_DUP; + + if (!string_list_lookup(&advise_given, name)) { + string_list_insert(&advise_given, name); + advise(_("The '%s' hook was ignored because " + "it's not set as executable.\n" + "You can disable this warning with " + "`git config advice.ignoredHook false`."), + path.buf); + } + } return NULL; } return path.buf; @@ -1466,7 +1567,7 @@ static void pp_init(struct parallel_processes *pp, pp->data = data; if (!get_next_task) - die("BUG: you need to specify a get_next_task function"); + BUG("you need to specify a get_next_task function"); pp->get_next_task = get_next_task; pp->start_failure = start_failure ? start_failure : default_start_failure; @@ -1528,7 +1629,7 @@ static int pp_start_one(struct parallel_processes *pp) if (pp->children[i].state == GIT_CP_FREE) break; if (i == pp->max_processes) - die("BUG: bookkeeping is hard"); + BUG("bookkeeping is hard"); code = pp->get_next_task(&pp->children[i].process, &pp->children[i].err, |