daemon: prepare for multiple services.
authorJunio C Hamano <junkio@cox.net>
Mon, 21 Aug 2006 02:03:13 +0000 (19:03 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 28 Aug 2006 06:32:36 +0000 (23:32 -0700)
This adds an infrastructure to selectively enable and disable
more than one services in git-daemon.  Currently upload-pack
service, which serves the git-fetch-pack and git-peek-remote
clients, is the only service that is defined.

Signed-off-by: Junio C Hamano <junkio@cox.net>
daemon.c

index 66ec830b7cab775e16c3fe06539e698edd6b7aff..e430cfbc8d0f4daccaae19fe44c9d699db6412e8 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -232,13 +232,42 @@ static char *path_ok(char *dir)
        return NULL;            /* Fallthrough. Deny by default */
 }
 
-static int upload(char *dir)
+typedef int (*daemon_service_fn)(void);
+struct daemon_service {
+       const char *name;
+       const char *config_name;
+       daemon_service_fn fn;
+       int enabled;
+       int overridable;
+};
+
+static struct daemon_service *service_looking_at;
+static int service_enabled;
+
+static int git_daemon_config(const char *var, const char *value)
+{
+       if (!strncmp(var, "daemon.", 7) &&
+           !strcmp(var + 7, service_looking_at->config_name)) {
+               service_enabled = git_config_bool(var, value);
+               return 0;
+       }
+
+       /* we are not interested in parsing any other configuration here */
+       return 0;
+}
+
+static int run_service(char *dir, struct daemon_service *service)
 {
-       /* Timeout as string */
-       char timeout_buf[64];
        const char *path;
+       int enabled = service->enabled;
+
+       loginfo("Request %s for '%s'", service->name, dir);
 
-       loginfo("Request for '%s'", dir);
+       if (!enabled && !service->overridable) {
+               logerror("'%s': service not enabled.", service->name);
+               errno = EACCES;
+               return -1;
+       }
 
        if (!(path = path_ok(dir)))
                return -1;
@@ -260,12 +289,34 @@ static int upload(char *dir)
                return -1;
        }
 
+       if (service->overridable) {
+               service_looking_at = service;
+               service_enabled = -1;
+               git_config(git_daemon_config);
+               if (0 <= service_enabled)
+                       enabled = service_enabled;
+       }
+       if (!enabled) {
+               logerror("'%s': service not enabled for '%s'",
+                        service->name, path);
+               errno = EACCES;
+               return -1;
+       }
+
        /*
         * We'll ignore SIGTERM from now on, we have a
         * good client.
         */
        signal(SIGTERM, SIG_IGN);
 
+       return service->fn();
+}
+
+static int upload_pack(void)
+{
+       /* Timeout as string */
+       char timeout_buf[64];
+
        snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
 
        /* git-upload-pack only ever reads stuff, so this is safe */
@@ -273,10 +324,36 @@ static int upload(char *dir)
        return -1;
 }
 
+static struct daemon_service daemon_service[] = {
+       { "upload-pack", "uploadpack", upload_pack, 1, 1 },
+};
+
+static void enable_service(const char *name, int ena) {
+       int i;
+       for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
+               if (!strcmp(daemon_service[i].name, name)) {
+                       daemon_service[i].enabled = ena;
+                       return;
+               }
+       }
+       die("No such service %s", name);
+}
+
+static void make_service_overridable(const char *name, int ena) {
+       int i;
+       for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
+               if (!strcmp(daemon_service[i].name, name)) {
+                       daemon_service[i].overridable = ena;
+                       return;
+               }
+       }
+       die("No such service %s", name);
+}
+
 static int execute(struct sockaddr *addr)
 {
        static char line[1000];
-       int pktlen, len;
+       int pktlen, len, i;
 
        if (addr) {
                char addrbuf[256] = "";
@@ -313,8 +390,14 @@ static int execute(struct sockaddr *addr)
        if (len && line[len-1] == '\n')
                line[--len] = 0;
 
-       if (!strncmp("git-upload-pack ", line, 16))
-               return upload(line+16);
+       for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
+               struct daemon_service *s = &(daemon_service[i]);
+               int namelen = strlen(s->name);
+               if (!strncmp("git-", line, 4) &&
+                   !strncmp(s->name, line + 4, namelen) &&
+                   line[namelen + 4] == ' ')
+                       return run_service(line + namelen + 5, s);
+       }
 
        logerror("Protocol error: '%s'", line);
        return -1;
@@ -805,6 +888,22 @@ int main(int argc, char **argv)
                        group_name = arg + 8;
                        continue;
                }
+               if (!strncmp(arg, "--enable=", 9)) {
+                       enable_service(arg + 9, 1);
+                       continue;
+               }
+               if (!strncmp(arg, "--disable=", 10)) {
+                       enable_service(arg + 10, 0);
+                       continue;
+               }
+               if (!strncmp(arg, "--enable-override=", 18)) {
+                       make_service_overridable(arg + 18, 1);
+                       continue;
+               }
+               if (!strncmp(arg, "--disable-override=", 19)) {
+                       make_service_overridable(arg + 19, 0);
+                       continue;
+               }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
                        break;