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 <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Dec 30, 2009 at 05:53 UTC
8dba1e634af1d973a47fca616a63e7062a256790
2 files changed
+49
run-command.c
+47
@@ -15,6 +15,48 @@ static inline void dup_devnull(int to)
15
close(fd);
16
}
17
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
+
60
int start_command(struct child_process *cmd)
61
{
62
int need_in, need_out, need_err;
@@ -123,6 +165,8 @@ fail_pipe:
165
cmd->preexec_cb();
166
if (cmd->git_cmd) {
167
execv_git_cmd(cmd->argv);
168
+ } else if (cmd->use_shell) {
169
+ execv_shell_cmd(cmd->argv);
170
} else {
171
execvp(cmd->argv[0], (char *const*) cmd->argv);
172
}
@@ -179,6 +223,8 @@ fail_pipe:
223
224
if (cmd->git_cmd) {
225
cmd->argv = prepare_git_cmd(cmd->argv);
226
+ } else if (cmd->use_shell) {
227
+ cmd->argv = prepare_shell_cmd(cmd->argv);
228
}
229
230
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,
343
cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
344
cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
345
cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
346
+ cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
347
}
348
349
int run_command_v_opt(const char **argv, int opt)
run-command.h
+2
@@ -33,6 +33,7 @@ struct child_process {
33
unsigned git_cmd:1; /* if this is to be git sub-command */
34
unsigned silent_exec_failure:1;
35
unsigned stdout_to_stderr:1;
36
+ unsigned use_shell:1;
37
void (*preexec_cb)(void);
38
};
39
@@ -46,6 +47,7 @@ extern int run_hook(const char *index_file, const char *name, ...);
47
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
48
#define RUN_COMMAND_STDOUT_TO_STDERR 4
49
#define RUN_SILENT_EXEC_FAILURE 8
50
+#define RUN_USING_SHELL 16
51
int run_command_v_opt(const char **argv, int opt);
52
53
/*