Add a "git-daemon" that listens on a TCP port
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 14 Jul 2005 02:45:26 +0000 (19:45 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 14 Jul 2005 02:45:26 +0000 (19:45 -0700)
.. and does a "git-upload-pack" on demand.

Makefile
daemon.c [new file with mode: 0644]
index 779fbbbfc90baf2a01d0cc87ee48873e9b9d2bb0..21dd582255aca8793e230ffae0e4b6f321fc6ea5 100644 (file)
--- 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 (file)
index 0000000..315a74b
--- /dev/null
+++ b/daemon.c
@@ -0,0 +1,117 @@
+#include "cache.h"
+#include "pkt-line.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+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);
+}