diff options
author | H. Peter Anvin <hpa@zytor.com> | 2005-09-15 12:33:14 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2005-09-15 13:42:03 -0700 |
commit | 0de68d28d34f915951324b9f387e6e67172e9951 (patch) | |
tree | c4ddf7ba97472b7f8140945eb8760be5ee375e7f /rsh.c | |
parent | [PATCH] Fix fetch completeness assumptions (diff) | |
download | tgif-0de68d28d34f915951324b9f387e6e67172e9951.tar.xz |
[PATCH] rsh.c env and quoting cleanup, take 2
This patch does proper quoting, and uses "env" to be compatible with
tcsh. As a side benefit, I believe the code is a lot cleaner to read.
[jc: I am accepting this not because I necessarily agree with the
quoting approach taken by it, but because (1) the code is only used
by ssh-fetch/ssh-upload pair which I do not care much about (if you
have ssh account on the remote end you should be using git-send-pack
git-fetch-pack pair over ssh anyway), and (2) HPA is one of the more
important customers belonging to the Linux kernel community and I
want to help his workflow -- which includes not wasting his time by
asking him to switch to git-send-pack/git-fetch-pack pair, nor to use
a better shell ;-). I might not have taken this patch if it mucked
with git_connect in connect.c in its current form.]
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'rsh.c')
-rw-r--r-- | rsh.c | 105 |
1 files changed, 89 insertions, 16 deletions
@@ -8,6 +8,71 @@ #define COMMAND_SIZE 4096 +/* + * Write a shell-quoted version of a string into a buffer, and + * return bytes that ought to be output excluding final null. + */ +static int shell_quote(char *buf, int nmax, const char *str) +{ + char ch; + int nq; + int oc = 0; + + while ( (ch = *str++) ) { + nq = 0; + if ( strchr(" !\"#$%&\'()*;<=>?[\\]^`{|}", ch) ) + nq = 1; + + if ( nq ) { + if ( nmax > 1 ) { + *buf++ = '\\'; + nmax--; + } + oc++; + } + + if ( nmax > 1 ) { + *buf++ = ch; + nmax--; + } + oc++; + } + + if ( nmax ) + *buf = '\0'; + + return oc; +} + +/* + * Append a string to a string buffer, with or without quoting. Return true + * if the buffer overflowed. + */ +static int add_to_string(char **ptrp, int *sizep, const char *str, int quote) +{ + char *p = *ptrp; + int size = *sizep; + int oc; + + if ( quote ) { + oc = shell_quote(p, size, str); + } else { + oc = strlen(str); + memcpy(p, str, (oc >= size) ? size-1 : oc); + } + + if ( oc >= size ) { + p[size-1] = '\0'; + *ptrp += size-1; + *sizep = 1; + return 1; /* Overflow, string unusable */ + } + + *ptrp += oc; + *sizep -= oc; + return 0; +} + int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, char *url, int rmt_argc, char **rmt_argv) { @@ -16,6 +81,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, int sv[2]; char command[COMMAND_SIZE]; char *posn; + int sizen; + int of; int i; if (!strcmp(url, "-")) { @@ -37,24 +104,30 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, if (!path) { return error("Bad URL: %s", url); } - /* ssh <host> 'cd <path>; stdio-pull <arg...> <commit-id>' */ - snprintf(command, COMMAND_SIZE, - "%s='%s' %s", - GIT_DIR_ENVIRONMENT, path, remote_prog); - *path = '\0'; - posn = command + strlen(command); - for (i = 0; i < rmt_argc; i++) { - *(posn++) = ' '; - strncpy(posn, rmt_argv[i], COMMAND_SIZE - (posn - command)); - posn += strlen(rmt_argv[i]); - if (posn - command + 4 >= COMMAND_SIZE) { - return error("Command line too long"); - } + /* $GIT_RSH <host> "env GIR_DIR=<path> <remote_prog> <args...>" */ + sizen = COMMAND_SIZE; + posn = command; + of = 0; + of |= add_to_string(&posn, &sizen, "env ", 0); + of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT, 0); + of |= add_to_string(&posn, &sizen, "=", 0); + of |= add_to_string(&posn, &sizen, path, 1); + of |= add_to_string(&posn, &sizen, " ", 0); + of |= add_to_string(&posn, &sizen, remote_prog, 1); + + for ( i = 0 ; i < rmt_argc ; i++ ) { + of |= add_to_string(&posn, &sizen, " ", 0); + of |= add_to_string(&posn, &sizen, rmt_argv[i], 1); } - strcpy(posn, " -"); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) { + + of |= add_to_string(&posn, &sizen, " -", 0); + + if ( of ) + return error("Command line too long"); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) return error("Couldn't create socket"); - } + if (!fork()) { const char *ssh, *ssh_basename; ssh = getenv("GIT_SSH"); |