run-command: add "use shell" option
[gitweb.git] / run-command.c
index bb76750cd063a05483856f1f744f79c04ed80352..b2bdcfda3df9cc9a50453dae33926da7377a7b57 100644 (file)
@@ -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;
@@ -75,7 +117,7 @@ int start_command(struct child_process *cmd)
 
        trace_argv_printf(cmd->argv, "trace: run_command:");
 
-#ifndef __MINGW32__
+#ifndef WIN32
        fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
@@ -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);
                }
@@ -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);
@@ -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)
@@ -315,7 +362,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
        return run_command(&cmd);
 }
 
-#ifdef __MINGW32__
+#ifdef WIN32
 static unsigned __stdcall run_thread(void *data)
 {
        struct async *async = data;
@@ -331,7 +378,7 @@ int start_async(struct async *async)
                return error("cannot create pipe: %s", strerror(errno));
        async->out = pipe_out[0];
 
-#ifndef __MINGW32__
+#ifndef WIN32
        /* Flush stdio before fork() to avoid cloning buffers */
        fflush(NULL);
 
@@ -360,7 +407,7 @@ int start_async(struct async *async)
 
 int finish_async(struct async *async)
 {
-#ifndef __MINGW32__
+#ifndef WIN32
        int ret = wait_or_whine(async->pid, "child process", 0);
 #else
        DWORD ret = 0;