Skip to content

Commit

Permalink
run-command: add "use shell" option
Browse files Browse the repository at this point in the history
Many callsites run "sh -c $CMD" to run $CMD. We can make it
a little simpler for them by factoring out the munging of
argv.

For simple cases with no arguments, this doesn't help much, but:

  1. For cases with arguments, we save the caller from
     having to build the appropriate shell snippet.

  2. We can later optimize to avoid the shell when
     there are no metacharacters in the program.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jeff King authored and Junio C Hamano committed Jan 2, 2010
1 parent 902f235 commit 8dba1e6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
47 changes: 47 additions & 0 deletions run-command.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,48 @@ static inline void dup_devnull(int to)
close(fd);
}

static const char **prepare_shell_cmd(const char **argv)
{
int argc, nargc = 0;
const char **nargv;

for (argc = 0; argv[argc]; argc++)
; /* just counting */
/* +1 for NULL, +3 for "sh -c" plus extra $0 */
nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));

if (argc < 1)
die("BUG: shell command is empty");

nargv[nargc++] = "sh";
nargv[nargc++] = "-c";

if (argc < 2)
nargv[nargc++] = argv[0];
else {
struct strbuf arg0 = STRBUF_INIT;
strbuf_addf(&arg0, "%s \"$@\"", argv[0]);
nargv[nargc++] = strbuf_detach(&arg0, NULL);
}

for (argc = 0; argv[argc]; argc++)
nargv[nargc++] = argv[argc];
nargv[nargc] = NULL;

return nargv;
}

#ifndef WIN32
static int execv_shell_cmd(const char **argv)
{
const char **nargv = prepare_shell_cmd(argv);
trace_argv_printf(nargv, "trace: exec:");
execvp(nargv[0], (char **)nargv);
free(nargv);
return -1;
}
#endif

int start_command(struct child_process *cmd)
{
int need_in, need_out, need_err;
Expand Down Expand Up @@ -123,6 +165,8 @@ int start_command(struct child_process *cmd)
cmd->preexec_cb();
if (cmd->git_cmd) {
execv_git_cmd(cmd->argv);
} else if (cmd->use_shell) {
execv_shell_cmd(cmd->argv);
} else {
execvp(cmd->argv[0], (char *const*) cmd->argv);
}
Expand Down Expand Up @@ -179,6 +223,8 @@ int start_command(struct child_process *cmd)

if (cmd->git_cmd) {
cmd->argv = prepare_git_cmd(cmd->argv);
} else if (cmd->use_shell) {
cmd->argv = prepare_shell_cmd(cmd->argv);
}

cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
Expand Down Expand Up @@ -297,6 +343,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
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;
}

int run_command_v_opt(const char **argv, int opt)
Expand Down
2 changes: 2 additions & 0 deletions run-command.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct child_process {
unsigned git_cmd:1; /* if this is to be git sub-command */
unsigned silent_exec_failure:1;
unsigned stdout_to_stderr:1;
unsigned use_shell:1;
void (*preexec_cb)(void);
};

Expand All @@ -46,6 +47,7 @@ extern int run_hook(const char *index_file, const char *name, ...);
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
#define RUN_SILENT_EXEC_FAILURE 8
#define RUN_USING_SHELL 16
int run_command_v_opt(const char **argv, int opt);

/*
Expand Down

0 comments on commit 8dba1e6

Please sign in to comment.