Code

Improve the mingw getaddrinfo stub to handle more use cases
[git.git] / daemon.c
index 7ccd097e1d1234d06316e8b7f271e86127750f85..941c095df4530b700858afeb9a30187725dda4d3 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -5,8 +5,6 @@
 #include "strbuf.h"
 #include "string-list.h"
 
-#include <syslog.h>
-
 #ifndef HOST_NAME_MAX
 #define HOST_NAME_MAX 256
 #endif
@@ -69,12 +67,14 @@ static void logreport(int priority, const char *err, va_list params)
                syslog(priority, "%s", buf);
        } else {
                /*
-                * Since stderr is set to linebuffered mode, the
+                * Since stderr is set to buffered mode, the
                 * logging of different processes will not overlap
+                * unless they overflow the (rather big) buffers.
                 */
                fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
                vfprintf(stderr, err, params);
                fputc('\n', stderr);
+               fflush(stderr);
        }
 }
 
@@ -616,17 +616,17 @@ static unsigned int live_children;
 
 static struct child {
        struct child *next;
-       pid_t pid;
+       struct child_process cld;
        struct sockaddr_storage address;
 } *firstborn;
 
-static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
+static void add_child(struct child_process *cld, struct sockaddr *addr, int addrlen)
 {
        struct child *newborn, **cradle;
 
        newborn = xcalloc(1, sizeof(*newborn));
        live_children++;
-       newborn->pid = pid;
+       memcpy(&newborn->cld, cld, sizeof(*cld));
        memcpy(&newborn->address, addr, addrlen);
        for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
                if (!addrcmp(&(*cradle)->address, &newborn->address))
@@ -635,19 +635,6 @@ static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
        *cradle = newborn;
 }
 
-static void remove_child(pid_t pid)
-{
-       struct child **cradle, *blanket;
-
-       for (cradle = &firstborn; (blanket = *cradle); cradle = &blanket->next)
-               if (blanket->pid == pid) {
-                       *cradle = blanket->next;
-                       live_children--;
-                       free(blanket);
-                       break;
-               }
-}
-
 /*
  * This gets called if the number of connections grows
  * past "max_connections".
@@ -663,7 +650,7 @@ static void kill_some_child(void)
 
        for (; (next = blanket->next); blanket = next)
                if (!addrcmp(&blanket->address, &next->address)) {
-                       kill(blanket->pid, SIGTERM);
+                       kill(blanket->cld.pid, SIGTERM);
                        break;
                }
 }
@@ -673,18 +660,26 @@ static void check_dead_children(void)
        int status;
        pid_t pid;
 
-       while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
-               const char *dead = "";
-               remove_child(pid);
-               if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
-                       dead = " (with error)";
-               loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
-       }
+       struct child **cradle, *blanket;
+       for (cradle = &firstborn; (blanket = *cradle);)
+               if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
+                       const char *dead = "";
+                       if (status)
+                               dead = " (with error)";
+                       loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
+
+                       /* remove the child */
+                       *cradle = blanket->next;
+                       live_children--;
+                       free(blanket);
+               } else
+                       cradle = &blanket->next;
 }
 
+static char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, int addrlen)
 {
-       pid_t pid;
+       struct child_process cld = { 0 };
 
        if (max_connections && live_children >= max_connections) {
                kill_some_child();
@@ -697,22 +692,15 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen)
                }
        }
 
-       if ((pid = fork())) {
-               close(incoming);
-               if (pid < 0) {
-                       logerror("Couldn't fork %s", strerror(errno));
-                       return;
-               }
+       cld.argv = (const char **)cld_argv;
+       cld.in = incoming;
+       cld.out = dup(incoming);
 
-               add_child(pid, addr, addrlen);
-               return;
-       }
-
-       dup2(incoming, 0);
-       dup2(incoming, 1);
+       if (start_command(&cld))
+               logerror("unable to fork");
+       else
+               add_child(&cld, addr, addrlen);
        close(incoming);
-
-       exit(execute(addr));
 }
 
 static void child_handler(int signo)
@@ -993,7 +981,7 @@ int main(int argc, char **argv)
 {
        int listen_port = 0;
        struct string_list listen_addr = STRING_LIST_INIT_NODUP;
-       int inetd_mode = 0;
+       int serve_mode = 0, inetd_mode = 0;
        const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
        struct passwd *pass = NULL;
@@ -1019,6 +1007,10 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
+               if (!strcmp(arg, "--serve")) {
+                       serve_mode = 1;
+                       continue;
+               }
                if (!strcmp(arg, "--inetd")) {
                        inetd_mode = 1;
                        log_syslog = 1;
@@ -1127,7 +1119,7 @@ int main(int argc, char **argv)
                set_die_routine(daemon_die);
        } else
                /* avoid splitting a message in the middle */
-               setvbuf(stderr, NULL, _IOLBF, 0);
+               setvbuf(stderr, NULL, _IOFBF, 4096);
 
        if (inetd_mode && (group_name || user_name))
                die("--user and --group are incompatible with --inetd");
@@ -1164,17 +1156,19 @@ int main(int argc, char **argv)
                    base_path);
 
        if (inetd_mode) {
+               if (!freopen("/dev/null", "w", stderr))
+                       die_errno("failed to redirect stderr to /dev/null");
+       }
+
+       if (inetd_mode || serve_mode) {
                struct sockaddr_storage ss;
                struct sockaddr *peer = (struct sockaddr *)&ss;
                socklen_t slen = sizeof(ss);
 
-               if (!freopen("/dev/null", "w", stderr))
-                       die_errno("failed to redirect stderr to /dev/null");
-
                if (getpeername(0, peer, &slen))
-                       peer = NULL;
-
-               return execute(peer);
+                       return execute(NULL);
+               else
+                       return execute(peer);
        }
 
        if (detach) {
@@ -1187,5 +1181,12 @@ int main(int argc, char **argv)
        if (pid_file)
                store_pid(pid_file);
 
+       /* prepare argv for serving-processes */
+       cld_argv = xmalloc(sizeof (char *) * (argc + 2));
+       for (i = 0; i < argc; ++i)
+               cld_argv[i] = argv[i];
+       cld_argv[argc] = "--serve";
+       cld_argv[argc+1] = NULL;
+
        return serve(&listen_addr, listen_port, pass, gid);
 }