diff options
Diffstat (limited to 'run-command.c')
| -rw-r--r-- | run-command.c | 153 |
1 files changed, 114 insertions, 39 deletions
diff --git a/run-command.c b/run-command.c index 3db26b7b0e..ea4d0fb4b1 100644 --- a/run-command.c +++ b/run-command.c @@ -2,23 +2,24 @@ #include "run-command.h" #include "exec-cmd.h" #include "sigchain.h" -#include "argv-array.h" +#include "strvec.h" #include "thread-utils.h" #include "strbuf.h" #include "string-list.h" #include "quote.h" +#include "config.h" void child_process_init(struct child_process *child) { memset(child, 0, sizeof(*child)); - argv_array_init(&child->args); - argv_array_init(&child->env_array); + strvec_init(&child->args); + strvec_init(&child->env_array); } void child_process_clear(struct child_process *child) { - argv_array_clear(&child->args); - argv_array_clear(&child->env_array); + strvec_clear(&child->args); + strvec_clear(&child->env_array); } struct child_to_clean { @@ -213,15 +214,36 @@ static char *locate_in_PATH(const char *file) static int exists_in_PATH(const char *file) { char *r = locate_in_PATH(file); + int found = r != NULL; free(r); - return r != NULL; + return found; } int sane_execvp(const char *file, char * const argv[]) { +#ifndef GIT_WINDOWS_NATIVE + /* + * execvp() doesn't return, so we all we can do is tell trace2 + * what we are about to do and let it leave a hint in the log + * (unless of course the execvp() fails). + * + * we skip this for Windows because the compat layer already + * has to emulate the execvp() call anyway. + */ + int exec_id = trace2_exec(file, (const char **)argv); +#endif + if (!execvp(file, argv)) return 0; /* cannot happen ;-) */ +#ifndef GIT_WINDOWS_NATIVE + { + int ec = errno; + trace2_exec_result(exec_id, ec); + errno = ec; + } +#endif + /* * When a command can't be found because one of the directories * listed in $PATH is unsearchable, execvp reports EACCES, but @@ -242,31 +264,31 @@ int sane_execvp(const char *file, char * const argv[]) return -1; } -static const char **prepare_shell_cmd(struct argv_array *out, const char **argv) +static const char **prepare_shell_cmd(struct strvec *out, const char **argv) { if (!argv[0]) BUG("shell command is empty"); if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { #ifndef GIT_WINDOWS_NATIVE - argv_array_push(out, SHELL_PATH); + strvec_push(out, SHELL_PATH); #else - argv_array_push(out, "sh"); + strvec_push(out, "sh"); #endif - argv_array_push(out, "-c"); + strvec_push(out, "-c"); /* * If we have no extra arguments, we do not even need to * bother with the "$@" magic. */ if (!argv[1]) - argv_array_push(out, argv[0]); + strvec_push(out, argv[0]); else - argv_array_pushf(out, "%s \"$@\"", argv[0]); + strvec_pushf(out, "%s \"$@\"", argv[0]); } - argv_array_pushv(out, argv); - return out->argv; + strvec_pushv(out, argv); + return out->v; } #ifndef GIT_WINDOWS_NATIVE @@ -380,7 +402,7 @@ static void child_err_spew(struct child_process *cmd, struct child_err *cerr) set_error_routine(old_errfn); } -static int prepare_cmd(struct argv_array *out, const struct child_process *cmd) +static int prepare_cmd(struct strvec *out, const struct child_process *cmd) { if (!cmd->argv[0]) BUG("command is empty"); @@ -389,30 +411,29 @@ static int prepare_cmd(struct argv_array *out, const struct child_process *cmd) * Add SHELL_PATH so in the event exec fails with ENOEXEC we can * attempt to interpret the command with 'sh'. */ - argv_array_push(out, SHELL_PATH); + strvec_push(out, SHELL_PATH); if (cmd->git_cmd) { - argv_array_push(out, "git"); - argv_array_pushv(out, cmd->argv); + prepare_git_cmd(out, cmd->argv); } else if (cmd->use_shell) { prepare_shell_cmd(out, cmd->argv); } else { - argv_array_pushv(out, cmd->argv); + strvec_pushv(out, cmd->argv); } /* - * If there are no '/' characters in the command then perform a path - * lookup and use the resolved path as the command to exec. If there - * are '/' characters, we have exec attempt to invoke the command - * directly. + * If there are no dir separator characters in the command then perform + * a path lookup and use the resolved path as the command to exec. If + * there are dir separator characters, we have exec attempt to invoke + * the command directly. */ - if (!strchr(out->argv[1], '/')) { - char *program = locate_in_PATH(out->argv[1]); + if (!has_dir_sep(out->v[1])) { + char *program = locate_in_PATH(out->v[1]); if (program) { - free((char *)out->argv[1]); - out->argv[1] = program; + free((char *)out->v[1]); + out->v[1] = program; } else { - argv_array_clear(out); + strvec_clear(out); errno = ENOENT; return -1; } @@ -652,9 +673,9 @@ int start_command(struct child_process *cmd) char *str; if (!cmd->argv) - cmd->argv = cmd->args.argv; + cmd->argv = cmd->args.v; if (!cmd->env) - cmd->env = cmd->env_array.argv; + cmd->env = cmd->env_array.v; /* * In case of errors we must keep the promise to close FDs @@ -712,6 +733,7 @@ fail_pipe: cmd->err = fderr[0]; } + trace2_child_start(cmd); trace_run_command(cmd); fflush(NULL); @@ -721,7 +743,7 @@ fail_pipe: int notify_pipe[2]; int null_fd = -1; char **childenv; - struct argv_array argv = ARGV_ARRAY_INIT; + struct strvec argv = STRVEC_INIT; struct child_err cerr; struct atfork_state as; @@ -825,10 +847,10 @@ fail_pipe: * be used in the event exec failed with ENOEXEC at which point * we will try to interpret the command using 'sh'. */ - execve(argv.argv[1], (char *const *) argv.argv + 1, + execve(argv.v[1], (char *const *) argv.v + 1, (char *const *) childenv); if (errno == ENOEXEC) - execve(argv.argv[0], (char *const *) argv.argv, + execve(argv.v[0], (char *const *) argv.v, (char *const *) childenv); if (errno == ENOENT) { @@ -867,7 +889,7 @@ fail_pipe: if (null_fd >= 0) close(null_fd); - argv_array_clear(&argv); + strvec_clear(&argv); free(childenv); } end_of_spawn: @@ -876,7 +898,7 @@ end_of_spawn: { int fhin = 0, fhout = 1, fherr = 2; const char **sargv = cmd->argv; - struct argv_array nargv = ARGV_ARRAY_INIT; + struct strvec nargv = STRVEC_INIT; if (cmd->no_stdin) fhin = open("/dev/null", O_RDWR); @@ -914,7 +936,7 @@ end_of_spawn: if (cmd->clean_on_exit && cmd->pid >= 0) mark_child_for_cleanup(cmd->pid, cmd); - argv_array_clear(&nargv); + strvec_clear(&nargv); cmd->argv = sargv; if (fhin != 0) close(fhin); @@ -926,6 +948,8 @@ end_of_spawn: #endif if (cmd->pid < 0) { + trace2_child_exit(cmd, -1); + if (need_in) close_pair(fdin); else if (cmd->in) @@ -964,13 +988,16 @@ end_of_spawn: int finish_command(struct child_process *cmd) { int ret = wait_or_whine(cmd->pid, cmd->argv[0], 0); + trace2_child_exit(cmd, ret); child_process_clear(cmd); return ret; } int finish_command_in_signal(struct child_process *cmd) { - return wait_or_whine(cmd->pid, cmd->argv[0], 1); + int ret = wait_or_whine(cmd->pid, cmd->argv[0], 1); + trace2_child_exit(cmd, ret); + return ret; } @@ -992,8 +1019,19 @@ int run_command_v_opt(const char **argv, int opt) return run_command_v_opt_cd_env(argv, opt, NULL, NULL); } +int run_command_v_opt_tr2(const char **argv, int opt, const char *tr2_class) +{ + return run_command_v_opt_cd_env_tr2(argv, opt, NULL, NULL, tr2_class); +} + int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env) { + return run_command_v_opt_cd_env_tr2(argv, opt, dir, env, NULL); +} + +int run_command_v_opt_cd_env_tr2(const char **argv, int opt, const char *dir, + const char *const *env, const char *tr2_class) +{ struct child_process cmd = CHILD_PROCESS_INIT; cmd.argv = argv; cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; @@ -1002,8 +1040,10 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const 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; + cmd.wait_after_clean = opt & RUN_WAIT_AFTER_CLEAN ? 1 : 0; cmd.dir = dir; cmd.env = env; + cmd.trace2_child_class = tr2_class; return run_command(&cmd); } @@ -1313,12 +1353,13 @@ int run_hook_ve(const char *const *env, const char *name, va_list args) if (!p) return 0; - argv_array_push(&hook.args, p); + strvec_push(&hook.args, p); while ((p = va_arg(args, const char *))) - argv_array_push(&hook.args, p); + strvec_push(&hook.args, p); hook.env = env; hook.no_stdin = 1; hook.stdout_to_stderr = 1; + hook.trace2_hook_name = name; return run_command(&hook); } @@ -1807,3 +1848,37 @@ int run_processes_parallel(int n, pp_cleanup(&pp); return 0; } + +int run_processes_parallel_tr2(int n, get_next_task_fn get_next_task, + start_failure_fn start_failure, + task_finished_fn task_finished, void *pp_cb, + const char *tr2_category, const char *tr2_label) +{ + int result; + + trace2_region_enter_printf(tr2_category, tr2_label, NULL, "max:%d", + ((n < 1) ? online_cpus() : n)); + + result = run_processes_parallel(n, get_next_task, start_failure, + task_finished, pp_cb); + + trace2_region_leave(tr2_category, tr2_label, NULL); + + return result; +} + +int run_auto_maintenance(int quiet) +{ + int enabled; + struct child_process maint = CHILD_PROCESS_INIT; + + if (!git_config_get_bool("maintenance.auto", &enabled) && + !enabled) + return 0; + + maint.git_cmd = 1; + strvec_pushl(&maint.args, "maintenance", "run", "--auto", NULL); + strvec_push(&maint.args, quiet ? "--quiet" : "--no-quiet"); + + return run_command(&maint); +} |
