diff options
author | Greg Brockman <gdb@MIT.EDU> | 2010-07-28 17:31:01 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-08-12 15:16:15 -0700 |
commit | 2dbc887eaa6fbd787edfc9472b86b0faeb54e2ae (patch) | |
tree | 5821f1adecc58bf28c513d53addaf6d37f3093a2 /shell.c | |
parent | 64fdc08dac6694d1e754580e7acb82dfa4988bb9 (diff) | |
download | git-2dbc887eaa6fbd787edfc9472b86b0faeb54e2ae.tar.gz |
Allow creation of arbitrary git-shell commands
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@example.com
can invoke a command by
ssh user@example.com $command
Signed-off-by: Greg Brockman <gdb@mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'shell.c')
-rw-r--r-- | shell.c | 44 |
1 files changed, 42 insertions, 2 deletions
@@ -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,29 @@ 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)); + strcpy(prefix, COMMAND_DIR); + strcat(prefix, "/"); + strcat(prefix, prog); + return prefix; +} + +static void cd_to_homedir(void) +{ + const char *home = getenv("HOME"); + if (!home) + die("could not determine user's home directory; HOME is unset"); + if (chdir(home) == -1) + die("could not chdir to user's home directory"); +} static struct commands { const char *name; @@ -48,6 +73,7 @@ static struct commands { int main(int argc, char **argv) { char *prog; + const char **user_argv; struct commands *cmd; int devnull_fd; @@ -76,7 +102,7 @@ int main(int argc, char **argv) else if (argc != 3 || strcmp(argv[1], "-c")) die("What do you think I am? A shell?"); - prog = argv[2]; + prog = xstrdup(argv[2]); if (!strncmp(prog, "git", 3) && isspace(prog[3])) /* Accept "git foo" as if the caller said "git-foo". */ prog[3] = '-'; @@ -99,5 +125,19 @@ int main(int argc, char **argv) } exit(cmd->exec(cmd->name, arg)); } - die("unrecognized command '%s'", prog); + + cd_to_homedir(); + 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); + die("unrecognized command '%s'", argv[2]); + } else { + free(prog); + die("invalid command format '%s'", argv[2]); + } } |