af57d402862c4d0572612b3e53e304978c35b352
   1#include "cache.h"
   2
   3static const char send_pack_usage[] = "git-send-pack [--exec=other] destination [heads]*";
   4
   5static const char *exec = "git-receive-pack";
   6
   7static int send_pack(int in, int out)
   8{
   9        for (;;) {
  10                static char buffer[1000];
  11                int ret = read(in, buffer, sizeof(buffer));
  12                if (ret > 0) {
  13                        write(1, buffer, ret);
  14                        continue;
  15                }
  16                break;
  17        }
  18        close(out);
  19        return 0;
  20}
  21
  22/*
  23 * First, make it shell-safe.  We do this by just disallowing any
  24 * special characters. Somebody who cares can do escaping and let
  25 * through the rest. But since we're doing to feed this to ssh as
  26 * a command line, we're going to be pretty damn anal for now.
  27 */
  28static char *shell_safe(char *url)
  29{
  30        char *n = url;
  31        unsigned char c;
  32        static const char flags[256] = {
  33                ['0'...'9'] = 1,
  34                ['a'...'z'] = 1,
  35                ['A'...'Z'] = 1,
  36                ['.'] = 1, ['/'] = 1,
  37                ['-'] = 1, ['+'] = 1,
  38                [':'] = 1
  39        };
  40
  41        while ((c = *n++) != 0) {
  42                if (flags[c] != 1)
  43                        die("I don't like '%c'. Sue me.", c);
  44        }
  45        return url;
  46}
  47
  48/*
  49 * Yeah, yeah, fixme. Need to pass in the heads etc.
  50 */
  51static int setup_connection(int fd[2], char *url, char **heads)
  52{
  53        char command[1024];
  54        const char *host, *path;
  55        char *colon;
  56        int pipefd[2][2];
  57
  58        url = shell_safe(url);
  59        host = NULL;
  60        path = url;
  61        colon = strchr(url, ':');
  62        if (colon) {
  63                *colon = 0;
  64                host = url;
  65                path = colon+1;
  66        }
  67        snprintf(command, sizeof(command), "%s %s", exec, path);
  68        if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
  69                die("unable to create pipe pair for communication");
  70        if (!fork()) {
  71                dup2(pipefd[1][0], 0);
  72                dup2(pipefd[0][1], 1);
  73                close(pipefd[0][0]);
  74                close(pipefd[0][1]);
  75                close(pipefd[1][0]);
  76                close(pipefd[1][1]);
  77                if (host)
  78                        execlp("ssh", "ssh", host, command, NULL);
  79                else
  80                        execlp(host, command, NULL);
  81                die("exec failed");
  82        }               
  83        fd[0] = pipefd[0][0];
  84        fd[1] = pipefd[1][1];
  85        close(pipefd[0][1]);
  86        close(pipefd[1][0]);
  87        return 0;
  88}
  89
  90int main(int argc, char **argv)
  91{
  92        int i, nr_heads = 0;
  93        char *dest = NULL;
  94        char **heads = NULL;
  95        int fd[2];
  96
  97        argv++;
  98        for (i = 1; i < argc; i++) {
  99                char *arg = *argv++;
 100
 101                if (*arg == '-') {
 102                        if (!strncmp(arg, "--exec=", 7)) {
 103                                exec = arg + 7;
 104                                continue;
 105                        }
 106                        usage(send_pack_usage);
 107                }
 108                dest = arg;
 109                heads = argv;
 110                nr_heads = argc - i -1;
 111                break;
 112        }
 113        if (!dest)
 114                usage(send_pack_usage);
 115        if (setup_connection(fd, dest, heads))
 116                return 1;
 117        return send_pack(fd[0], fd[1]);
 118}