Prepare execv_git_cmd() for removal of builtins from the filesystem
authorJunio C Hamano <gitster@pobox.com>
Sun, 2 Dec 2007 06:09:22 +0000 (22:09 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 24 Jun 2008 05:45:41 +0000 (22:45 -0700)
Currently, execv_git_cmd() always try running the dashed form, which
means we cannot easily remove the git-foo hardlinks for built-in
commands.  This updates the function to always exec "git foo" form, and
makes sure "git" potty does not infinitely recurse to itself.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
exec_cmd.c
git.c

index e189caca629262334541ea8313d2931b06e67adf..0f8f4b5b7d9dea4458b9944dd81cf98c2e9a1322 100644 (file)
@@ -65,32 +65,25 @@ void setup_path(const char *cmd_path)
 
 int execv_git_cmd(const char **argv)
 {
-       struct strbuf cmd;
-       const char *tmp;
-
-       strbuf_init(&cmd, 0);
-       strbuf_addf(&cmd, "git-%s", argv[0]);
+       int argc;
+       const char **nargv;
 
-       /*
-        * argv[0] must be the git command, but the argv array
-        * belongs to the caller, and may be reused in
-        * subsequent loop iterations. Save argv[0] and
-        * restore it on error.
-        */
-       tmp = argv[0];
-       argv[0] = cmd.buf;
+       for (argc = 0; argv[argc]; argc++)
+               ; /* just counting */
+       nargv = xmalloc(sizeof(*nargv) * (argc + 2));
 
-       trace_argv_printf(argv, "trace: exec:");
+       nargv[0] = "git";
+       for (argc = 0; argv[argc]; argc++)
+               nargv[argc + 1] = argv[argc];
+       nargv[argc + 1] = NULL;
+       trace_argv_printf(nargv, "trace: exec:");
 
        /* execvp() can only ever return if it fails */
-       execvp(cmd.buf, (char **)argv);
+       execvp("git", (char **)nargv);
 
        trace_printf("trace: exec failed: %s\n", strerror(errno));
 
-       argv[0] = tmp;
-
-       strbuf_release(&cmd);
-
+       free(nargv);
        return -1;
 }
 
diff --git a/git.c b/git.c
index 59f0fcc1f2278d3234a7e4a306db56c7cfcde9a2..22ac5226def5c2dd4e699533255b84e18f630bfa 100644 (file)
--- a/git.c
+++ b/git.c
@@ -384,6 +384,36 @@ static void handle_internal_command(int argc, const char **argv)
        }
 }
 
+static void execv_dashed_external(const char **argv)
+{
+       struct strbuf cmd;
+       const char *tmp;
+
+       strbuf_init(&cmd, 0);
+       strbuf_addf(&cmd, "git-%s", argv[0]);
+
+       /*
+        * argv[0] must be the git command, but the argv array
+        * belongs to the caller, and may be reused in
+        * subsequent loop iterations. Save argv[0] and
+        * restore it on error.
+        */
+       tmp = argv[0];
+       argv[0] = cmd.buf;
+
+       trace_argv_printf(argv, "trace: exec:");
+
+       /* execvp() can only ever return if it fails */
+       execvp(cmd.buf, (char **)argv);
+
+       trace_printf("trace: exec failed: %s\n", strerror(errno));
+
+       argv[0] = tmp;
+
+       strbuf_release(&cmd);
+}
+
+
 int main(int argc, const char **argv)
 {
        const char *cmd = argv[0] ? argv[0] : "git-help";
@@ -448,7 +478,7 @@ int main(int argc, const char **argv)
                handle_internal_command(argc, argv);
 
                /* .. then try the external ones */
-               execv_git_cmd(argv);
+               execv_dashed_external(argv);
 
                /* It could be an alias -- this works around the insanity
                 * of overriding "git log" with "git show" by having