From 0a47dc110e042b5bcc63dc94c8d517e67efe9306 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 1 Dec 2007 22:16:19 -0800 Subject: git-shell: accept "git foo" form Signed-off-by: Junio C Hamano --- shell.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/shell.c b/shell.c index 9826109d5b..b27d01c9e4 100644 --- a/shell.c +++ b/shell.c @@ -7,6 +7,7 @@ static int do_generic_cmd(const char *me, char *arg) { const char *my_argv[4]; + setup_path(NULL); if (!arg || !(arg = sq_dequote(arg))) die("bad argument"); if (prefixcmp(me, "git-")) @@ -29,7 +30,6 @@ static int do_cvs_cmd(const char *me, char *arg) die("git-cvsserver only handles server: %s", arg); setup_path(NULL); - return execv_git_cmd(cvsserver_argv); } @@ -49,15 +49,24 @@ int main(int argc, char **argv) char *prog; struct commands *cmd; + /* + * Special hack to pretend to be a CVS server + */ if (argc == 2 && !strcmp(argv[1], "cvs server")) argv--; - /* We want to see "-c cmd args", and nothing else */ + + /* + * We do not accept anything but "-c" followed by "cmd arg", + * where "cmd" is a very limited subset of git commands. + */ else if (argc != 3 || strcmp(argv[1], "-c")) die("What do you think I am? A shell?"); prog = argv[2]; - argv += 2; - argc -= 2; + if (!strncmp(prog, "git", 3) && isspace(prog[3])) + /* Accept "git foo" as if the caller said "git-foo". */ + prog[3] = '-'; + for (cmd = cmd_list ; cmd->name ; cmd++) { int len = strlen(cmd->name); char *arg; -- cgit v1.2.3 From 7550be0a2bbf47aaa63c806bb5d7fcb8ab197cf8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 1 Dec 2007 22:09:22 -0800 Subject: 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 --- exec_cmd.c | 31 ++++++++++++------------------- git.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index e189caca62..0f8f4b5b7d 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -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 59f0fcc1f2..22ac5226de 100644 --- 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 -- cgit v1.2.3