From a87e8be2aece466e3f41dfde81c80709e1d56cd3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 13 Jul 2005 19:45:26 -0700 Subject: [PATCH] Add a "git-daemon" that listens on a TCP port .. and does a "git-upload-pack" on demand. --- Makefile | 2 +- daemon.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 daemon.c diff --git a/Makefile b/Makefile index 779fbbbf..21dd5822 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ PROG= git-update-cache git-diff-files git-init-db git-write-tree \ git-diff-stages git-rev-parse git-patch-id git-pack-objects \ git-unpack-objects git-verify-pack git-receive-pack git-send-pack \ git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \ - git-show-index + git-show-index git-daemon all: $(PROG) diff --git a/daemon.c b/daemon.c new file mode 100644 index 00000000..315a74bf --- /dev/null +++ b/daemon.c @@ -0,0 +1,117 @@ +#include "cache.h" +#include "pkt-line.h" +#include +#include + +static const char daemon_usage[] = "git-daemon [--port=n]"; + +static int upload(char *dir, int dirlen) +{ + if (chdir(dir) < 0) + return -1; + chdir(".git"); + + /* + * Security on the cheap. + * + * We want a readable HEAD, usable "objects" directory, and + * a "git-daemon-export-ok" flag that says that the other side + * is ok with us doing this. + */ + if (access("git-daemon-export-ok", F_OK) || + access("objects/00", X_OK) || + access("HEAD", R_OK)) + return -1; + + /* git-upload-pack only ever reads stuff, so this is safe */ + execlp("git-upload-pack", "git-upload-pack", ".", NULL); + return -1; +} + +static int execute(char *line, int len) +{ + if (!strncmp("git-upload-pack /", line, 17)) + return upload(line + 16, len - 16); + + fprintf(stderr, "got bad connection '%s'\n", line); + return -1; +} + +static void handle(int incoming, struct sockaddr_in *addr, int addrlen) +{ + static char line[1000]; + int len; + + if (fork()) { + close(incoming); + return; + } + + dup2(incoming, 0); + dup2(incoming, 1); + close(incoming); + len = packet_read_line(0, line, sizeof(line)); + + if (len && line[len-1] == '\n') + line[--len] = 0; + + exit(execute(line, len)); +} + +static int serve(int port) +{ + int sockfd; + struct sockaddr_in addr; + + sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP); + if (sockfd < 0) + die("unable to open socket (%s)", strerror(errno)); + memset(&addr, 0, sizeof(addr)); + addr.sin_port = htons(port); + addr.sin_family = AF_INET; + if (bind(sockfd, (void *)&addr, sizeof(addr)) < 0) + die("unable to bind to port %d (%s)", port, strerror(errno)); + if (listen(sockfd, 5) < 0) + die("unable to listen to port %d (%s)", port, strerror(errno)); + + for (;;) { + struct sockaddr_in in; + socklen_t addrlen = sizeof(in); + int incoming = accept(sockfd, (void *)&in, &addrlen); + + if (incoming < 0) { + switch (errno) { + case EAGAIN: + case EINTR: + case ECONNABORTED: + continue; + default: + die("accept returned %s", strerror(errno)); + } + } + handle(incoming, &in, addrlen); + } +} + +int main(int argc, char **argv) +{ + int port = DEFAULT_GIT_PORT; + int i; + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + + if (!strncmp(arg, "--port=", 7)) { + char *end; + unsigned long n; + n = strtoul(arg+7, &end, 0); + if (arg[7] && !*end) { + port = n; + continue; + } + } + usage(daemon_usage); + } + + return serve(port); +} -- 2.11.0