@matheusbsbs / matheus-bagliano / commits / 7550be0a2b
Fork 0

Prepare execv_git_cmd() for removal of builtins from the filesystem

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>

Junio C Hamano committed Dec 1, 2007 at 22:09 UTC 7550be0a2bbf47aaa63c806bb5d7fcb8ab197cf8
2 files changed +43 -20
exec_cmd.c
+12 -19
@@ -65,32 +65,25 @@ void setup_path(const char *cmd_path)
65
66 int execv_git_cmd(const char **argv)
67 {
68 - struct strbuf cmd;
69 - const char *tmp;
70 -
71 - strbuf_init(&cmd, 0);
72 - strbuf_addf(&cmd, "git-%s", argv[0]);
68 + int argc;
69 + const char **nargv;
70
74 - /*
75 - * argv[0] must be the git command, but the argv array
76 - * belongs to the caller, and may be reused in
77 - * subsequent loop iterations. Save argv[0] and
78 - * restore it on error.
79 - */
80 - tmp = argv[0];
81 - argv[0] = cmd.buf;
71 + for (argc = 0; argv[argc]; argc++)
72 + ; /* just counting */
73 + nargv = xmalloc(sizeof(*nargv) * (argc + 2));
74
83 - trace_argv_printf(argv, "trace: exec:");
75 + nargv[0] = "git";
76 + for (argc = 0; argv[argc]; argc++)
77 + nargv[argc + 1] = argv[argc];
78 + nargv[argc + 1] = NULL;
79 + trace_argv_printf(nargv, "trace: exec:");
80
81 /* execvp() can only ever return if it fails */
86 - execvp(cmd.buf, (char **)argv);
82 + execvp("git", (char **)nargv);
83
84 trace_printf("trace: exec failed: %s\n", strerror(errno));
85
90 - argv[0] = tmp;
91 -
92 - strbuf_release(&cmd);
93 -
86 + free(nargv);
87 return -1;
88 }
89
git.c
+31 -1
@@ -384,6 +384,36 @@ static void handle_internal_command(int argc, const char **argv)
384 }
385 }
386
387 +static void execv_dashed_external(const char **argv)
388 +{
389 + struct strbuf cmd;
390 + const char *tmp;
391 +
392 + strbuf_init(&cmd, 0);
393 + strbuf_addf(&cmd, "git-%s", argv[0]);
394 +
395 + /*
396 + * argv[0] must be the git command, but the argv array
397 + * belongs to the caller, and may be reused in
398 + * subsequent loop iterations. Save argv[0] and
399 + * restore it on error.
400 + */
401 + tmp = argv[0];
402 + argv[0] = cmd.buf;
403 +
404 + trace_argv_printf(argv, "trace: exec:");
405 +
406 + /* execvp() can only ever return if it fails */
407 + execvp(cmd.buf, (char **)argv);
408 +
409 + trace_printf("trace: exec failed: %s\n", strerror(errno));
410 +
411 + argv[0] = tmp;
412 +
413 + strbuf_release(&cmd);
414 +}
415 +
416 +
417 int main(int argc, const char **argv)
418 {
419 const char *cmd = argv[0] ? argv[0] : "git-help";
@@ -448,7 +478,7 @@ int main(int argc, const char **argv)
478 handle_internal_command(argc, argv);
479
480 /* .. then try the external ones */
451 - execv_git_cmd(argv);
481 + execv_dashed_external(argv);
482
483 /* It could be an alias -- this works around the insanity
484 * of overriding "git log" with "git show" by having