Skip to content

Commit 8dba1e6

Browse files
peffgitster
authored andcommitted
run-command: add "use shell" option
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 902f235 commit 8dba1e6

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

run-command.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,48 @@ static inline void dup_devnull(int to)
1515
close(fd);
1616
}
1717

18+
static const char **prepare_shell_cmd(const char **argv)
19+
{
20+
int argc, nargc = 0;
21+
const char **nargv;
22+
23+
for (argc = 0; argv[argc]; argc++)
24+
; /* just counting */
25+
/* +1 for NULL, +3 for "sh -c" plus extra $0 */
26+
nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));
27+
28+
if (argc < 1)
29+
die("BUG: shell command is empty");
30+
31+
nargv[nargc++] = "sh";
32+
nargv[nargc++] = "-c";
33+
34+
if (argc < 2)
35+
nargv[nargc++] = argv[0];
36+
else {
37+
struct strbuf arg0 = STRBUF_INIT;
38+
strbuf_addf(&arg0, "%s \"$@\"", argv[0]);
39+
nargv[nargc++] = strbuf_detach(&arg0, NULL);
40+
}
41+
42+
for (argc = 0; argv[argc]; argc++)
43+
nargv[nargc++] = argv[argc];
44+
nargv[nargc] = NULL;
45+
46+
return nargv;
47+
}
48+
49+
#ifndef WIN32
50+
static int execv_shell_cmd(const char **argv)
51+
{
52+
const char **nargv = prepare_shell_cmd(argv);
53+
trace_argv_printf(nargv, "trace: exec:");
54+
execvp(nargv[0], (char **)nargv);
55+
free(nargv);
56+
return -1;
57+
}
58+
#endif
59+
1860
int start_command(struct child_process *cmd)
1961
{
2062
int need_in, need_out, need_err;
@@ -123,6 +165,8 @@ int start_command(struct child_process *cmd)
123165
cmd->preexec_cb();
124166
if (cmd->git_cmd) {
125167
execv_git_cmd(cmd->argv);
168+
} else if (cmd->use_shell) {
169+
execv_shell_cmd(cmd->argv);
126170
} else {
127171
execvp(cmd->argv[0], (char *const*) cmd->argv);
128172
}
@@ -179,6 +223,8 @@ int start_command(struct child_process *cmd)
179223

180224
if (cmd->git_cmd) {
181225
cmd->argv = prepare_git_cmd(cmd->argv);
226+
} else if (cmd->use_shell) {
227+
cmd->argv = prepare_shell_cmd(cmd->argv);
182228
}
183229

184230
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
@@ -297,6 +343,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
297343
cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
298344
cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
299345
cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
346+
cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
300347
}
301348

302349
int run_command_v_opt(const char **argv, int opt)

run-command.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct child_process {
3333
unsigned git_cmd:1; /* if this is to be git sub-command */
3434
unsigned silent_exec_failure:1;
3535
unsigned stdout_to_stderr:1;
36+
unsigned use_shell:1;
3637
void (*preexec_cb)(void);
3738
};
3839

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

5153
/*

0 commit comments

Comments
 (0)