This provides a mechanism for the server to expose custom functionality to clients. My particular use case is that I would like a way of discovering all repositories available for cloning. A client that clones via git clone user@xxxxxxxxxxx can invoke a command by ssh user@xxxxxxxxxxx $command Signed-off-by: Greg Brockman <gdb@xxxxxxx> --- shell.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 40 insertions(+), 1 deletions(-) diff --git a/shell.c b/shell.c index e4864e0..fe1fe73 100644 --- a/shell.c +++ b/shell.c @@ -3,6 +3,8 @@ #include "exec_cmd.h" #include "strbuf.h" +#define COMMAND_DIR "git-shell-commands" + static int do_generic_cmd(const char *me, char *arg) { const char *my_argv[4]; @@ -33,6 +35,20 @@ static int do_cvs_cmd(const char *me, char *arg) return execv_git_cmd(cvsserver_argv); } +static int is_valid_cmd_name(const char *cmd) +{ + /* Test command contains no . or / characters */ + return cmd[strcspn(cmd, "./")] == '\0'; +} + +static char *make_cmd(const char *prog) +{ + char *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2) * sizeof(char)); + strcpy(prefix, COMMAND_DIR); + strcat(prefix, "/"); + strcat(prefix, prog); + return prefix; +} static struct commands { const char *name; @@ -48,6 +64,8 @@ static struct commands { int main(int argc, char **argv) { char *prog; + char *prog_cpy; + const char **user_argv; struct commands *cmd; int devnull_fd; @@ -77,6 +95,7 @@ int main(int argc, char **argv) die("What do you think I am? A shell?"); prog = argv[2]; + prog_cpy = xstrdup(prog); if (!strncmp(prog, "git", 3) && isspace(prog[3])) /* Accept "git foo" as if the caller said "git-foo". */ prog[3] = '-'; @@ -99,5 +118,25 @@ int main(int argc, char **argv) } exit(cmd->exec(cmd->name, arg)); } - die("unrecognized command '%s'", prog); + + if (split_cmdline(prog, &user_argv) != -1) { + if (is_valid_cmd_name(user_argv[0])) { + prog = make_cmd(user_argv[0]); + user_argv[0] = prog; + execv(user_argv[0], (char *const *) user_argv); + free(prog); + } + free(user_argv); + /* + * split_cmdline modifies its argument in-place, so 'prog' now + * holds the actual command name + */ + die("unrecognized command '%s'", prog_cpy); + } else { + /* + * split_cmdline has clobbered prog and printed an + * error message, so print the original + */ + die("invalid command format '%s'", prog_cpy); + } } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html