{"thread":{"id":"38979","subject":"[RFC 2] systemd socket activation support","startedAt":"2015-04-02T16:15:10Z","lastAt":"2015-04-02T17:20:28Z","messageCount":2,"participants":["Shawn Landden","Eric Sunshine"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"258863","messageId":"1427991310-19754-1-git-send-email-shawn@churchofgit.com","threadId":"38979","inReplyTo":null,"subject":"[RFC 2] systemd socket activation support","fromName":"Shawn Landden","fromEmail":"shawn@churchofgit.com","sentAt":"2015-04-02T16:15:10Z","receivedAt":"2015-04-02T16:15:10Z","isPatch":false,"sender":{"key":"shawn@churchofgit.com","avatar":"https://gravatar.com/avatar/66fa92115ac78085af2524ca39ccca362bd1ca7571a4b0b843a8a7017b210df2?d=mp&s=160"},"body":"systemd support git-daemon's --inetd mode as well.\n\nv2: actually test...\n\nSigned-off-by: Shawn Landden <shawn@churchofgit.com>\n---\n Documentation/git-daemon.txt |  25 +++++++\n Makefile                     |   1 +\n daemon.c                     |  35 ++++++++--\n sd-daemon.c                  | 152 +++++++++++++++++++++++++++++++++++++++++++\n sd-daemon.h                  | 104 +++++++++++++++++++++++++++++\n 5 files changed, 311 insertions(+), 6 deletions(-)\n create mode 100644 sd-daemon.c\n create mode 100644 sd-daemon.h\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex a69b361..898e01f 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -20,6 +20,7 @@ SYNOPSIS\n \t     [--inetd |\n \t      [--listen=<host_or_ipaddr>] [--port=<n>]\n \t      [--user=<user> [--group=<group>]]]\n+\t      [--systemd]\n \t     [<directory>...]\n \n DESCRIPTION\n@@ -190,6 +191,12 @@ Git configuration files in that directory are readable by `<user>`.\n \texiting with a zero status).  It can also look at the $REMOTE_ADDR\n \tand $REMOTE_PORT environment variables to learn about the\n \trequestor when making this decision.\n+--systemd::\n+\tFor running git-daemon under systemd(1) which will pass\n+\tan open connection. This is similar to --inetd, except\n+\tthat more than one address/port can be listened to at once\n+\tboth through systemd and through --listen, and git-daemon doesn't get\n+\tinvoked for every connection. For more details see systemd.socket(5).\n +\n The external command can optionally write a single line to its\n standard output to be sent to the requestor as an error message when\n@@ -304,7 +311,25 @@ selectively enable/disable services per repository::\n \t\tuploadpack = false\n \t\tuploadarch = true\n ----------------------------------------------------------------\n++\n+systemd configuration example:\n+\n+# /etc/systemd/system/git-daemon.socket\n+[Unit]\n+Description=Git Daemon socket\n+\n+[Socket]\n+ListenStream=9418\n+\n+[Install]\n+WantedBy=sockets.target\n+# /etc/systemd/system/git-daemon.service\n+[Unit]\n+Description=Git Daemon\n \n+[Service]\n+ExecStart=/usr/lib/git-core/git-daemon --systemd --reuseaddr --base-path=/var/lib /var/lib/git\n+User=gitdaemon\n \n ENVIRONMENT\n -----------\ndiff --git a/Makefile b/Makefile\nindex 5f3987f..4a813b9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -765,6 +765,7 @@ LIB_OBJS += rerere.o\n LIB_OBJS += resolve-undo.o\n LIB_OBJS += revision.o\n LIB_OBJS += run-command.o\n+LIB_OBJS += sd-daemon.o\n LIB_OBJS += send-pack.o\n LIB_OBJS += sequencer.o\n LIB_OBJS += server-info.o\ndiff --git a/daemon.c b/daemon.c\nindex 9ee2187..e809a4c 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -4,6 +4,7 @@\n #include \"run-command.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n+#include \"sd-daemon.h\"\n \n #ifndef HOST_NAME_MAX\n #define HOST_NAME_MAX 256\n@@ -29,6 +30,7 @@ static const char daemon_usage[] =\n \"           [--access-hook=<path>]\\n\"\n \"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\\n\"\n \"                      [--detach] [--user=<user> [--group=<group>]]\\n\"\n+\"           [--systemd]\\n\"\n \"           [<directory>...]\";\n \n /* List of acceptable pathname prefixes */\n@@ -1176,11 +1178,22 @@ static void store_pid(const char *path)\n }\n \n static int serve(struct string_list *listen_addr, int listen_port,\n-    struct credentials *cred)\n+    struct credentials *cred, int systemd_mode)\n {\n \tstruct socketlist socklist = { NULL, 0, 0 };\n \n-\tsocksetup(listen_addr, listen_port, &socklist);\n+\tif (systemd_mode) {\n+\t\tint i;\n+\t\tint n;\n+\n+\t\tn = sd_listen_fds(0);\n+\t\tALLOC_GROW(socklist.list, socklist.nr + n, socklist.alloc);\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tsocklist.list[socklist.nr++] = SD_LISTEN_FDS_START + i;\n+\t}\n+\n+\tif (listen_addr->nr > 0 || !systemd_mode)\n+\t\tsocksetup(listen_addr, listen_port, &socklist);\n \tif (socklist.nr == 0)\n \t\tdie(\"unable to allocate any listen sockets on port %u\",\n \t\t    listen_port);\n@@ -1196,7 +1209,7 @@ int main(int argc, char **argv)\n {\n \tint listen_port = 0;\n \tstruct string_list listen_addr = STRING_LIST_INIT_NODUP;\n-\tint serve_mode = 0, inetd_mode = 0;\n+\tint serve_mode = 0, inetd_mode = 0, systemd_mode = 0;\n \tconst char *pid_file = NULL, *user_name = NULL, *group_name = NULL;\n \tint detach = 0;\n \tstruct credentials *cred = NULL;\n@@ -1331,6 +1344,10 @@ int main(int argc, char **argv)\n \t\t\tinformative_errors = 0;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--systemd\")) {\n+\t\t\tsystemd_mode = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\tok_paths = &argv[i+1];\n \t\t\tbreak;\n@@ -1349,14 +1366,20 @@ int main(int argc, char **argv)\n \t\t/* avoid splitting a message in the middle */\n \t\tsetvbuf(stderr, NULL, _IOFBF, 4096);\n \n-\tif (inetd_mode && (detach || group_name || user_name))\n-\t\tdie(\"--detach, --user and --group are incompatible with --inetd\");\n+\tif ((inetd_mode || systemd_mode) && (detach || group_name || user_name))\n+\t\tdie(\"--detach, --user and --group are incompatible with --inetd and --systemd\");\n+\n+\tif (systemd_mode && inetd_mode)\n+\t\tdie(\"--inetd is incompatible with --systemd\");\n \n \tif (inetd_mode && (listen_port || (listen_addr.nr > 0)))\n \t\tdie(\"--listen= and --port= are incompatible with --inetd\");\n \telse if (listen_port == 0)\n \t\tlisten_port = DEFAULT_GIT_PORT;\n \n+\tif (systemd_mode && !sd_booted())\n+\t\tdie(\"--systemd passed and not invoked from systemd\");\n+\n \tif (group_name && !user_name)\n \t\tdie(\"--group supplied without --user\");\n \n@@ -1395,5 +1418,5 @@ int main(int argc, char **argv)\n \t\tcld_argv[i+1] = argv[i];\n \tcld_argv[argc+1] = NULL;\n \n-\treturn serve(&listen_addr, listen_port, cred);\n+\treturn serve(&listen_addr, listen_port, cred, systemd_mode);\n }\ndiff --git a/sd-daemon.c b/sd-daemon.c\nnew file mode 100644\nindex 0000000..1d43904\n--- /dev/null\n+++ b/sd-daemon.c\n@@ -0,0 +1,152 @@\n+/* stripped down version */\n+/***\n+  Copyright 2010 Lennart Poettering\n+\n+  Permission is hereby granted, free of charge, to any person\n+  obtaining a copy of this software and associated documentation files\n+  (the \"Software\"), to deal in the Software without restriction,\n+  including without limitation the rights to use, copy, modify, merge,\n+  publish, distribute, sublicense, and/or sell copies of the Software,\n+  and to permit persons to whom the Software is furnished to do so,\n+  subject to the following conditions:\n+\n+  The above copyright notice and this permission notice shall be\n+  included in all copies or substantial portions of the Software.\n+\n+  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+  SOFTWARE.\n+***/\n+\n+#ifndef _GNU_SOURCE\n+#  define _GNU_SOURCE\n+#endif\n+\n+#include <stdlib.h>\n+#include <unistd.h>\n+#include <fcntl.h>\n+#include <errno.h>\n+#include <sys/types.h>\n+#include <sys/stat.h>\n+\n+#include \"sd-daemon.h\"\n+\n+#if (__GNUC__ >= 4)\n+#  ifdef SD_EXPORT_SYMBOLS\n+/* Export symbols */\n+#    define _sd_export_ __attribute__ ((visibility(\"default\")))\n+#  else\n+/* Don't export the symbols */\n+#    define _sd_export_ __attribute__ ((visibility(\"hidden\")))\n+#  endif\n+#else\n+#  define _sd_export_\n+#endif\n+\n+_sd_export_ int sd_listen_fds(int unset_environment) {\n+\n+#if defined(DISABLE_SYSTEMD) || !defined(__linux__)\n+        return 0;\n+#else\n+        int r, fd;\n+        const char *e;\n+        char *p = NULL;\n+        unsigned long l;\n+\n+        e = getenv(\"LISTEN_PID\");\n+        if (!e) {\n+                r = 0;\n+                goto finish;\n+        }\n+\n+        errno = 0;\n+        l = strtoul(e, &p, 10);\n+\n+        if (errno > 0) {\n+                r = -errno;\n+                goto finish;\n+        }\n+\n+        if (!p || p == e || *p || l <= 0) {\n+                r = -EINVAL;\n+                goto finish;\n+        }\n+\n+        /* Is this for us? */\n+        if (getpid() != (pid_t) l) {\n+                r = 0;\n+                goto finish;\n+        }\n+\n+        e = getenv(\"LISTEN_FDS\");\n+        if (!e) {\n+                r = 0;\n+                goto finish;\n+        }\n+\n+        errno = 0;\n+        l = strtoul(e, &p, 10);\n+\n+        if (errno > 0) {\n+                r = -errno;\n+                goto finish;\n+        }\n+\n+        if (!p || p == e || *p) {\n+                r = -EINVAL;\n+                goto finish;\n+        }\n+\n+        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {\n+                int flags;\n+\n+                flags = fcntl(fd, F_GETFD);\n+                if (flags < 0) {\n+                        r = -errno;\n+                        goto finish;\n+                }\n+\n+                if (flags & FD_CLOEXEC)\n+                        continue;\n+\n+                if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {\n+                        r = -errno;\n+                        goto finish;\n+                }\n+        }\n+\n+        r = (int) l;\n+\n+finish:\n+        if (unset_environment) {\n+                unsetenv(\"LISTEN_PID\");\n+                unsetenv(\"LISTEN_FDS\");\n+        }\n+\n+        return r;\n+#endif\n+}\n+\n+_sd_export_ int sd_booted(void) {\n+\n+#if defined(DISABLE_SYSTEMD) || !defined(__linux__)\n+        return 0;\n+#else\n+        struct stat st;\n+\n+        /* We test whether the runtime unit file directory has been\n+         * created. This takes place in mount-setup.c, so is\n+         * guaranteed to happen very early during boot. */\n+\n+        if (lstat(\"/run/systemd/system/\", &st) < 0)\n+                return 0;\n+\n+        return !!S_ISDIR(st.st_mode);\n+#endif\n+}\n+\ndiff --git a/sd-daemon.h b/sd-daemon.h\nnew file mode 100644\nindex 0000000..e297955\n--- /dev/null\n+++ b/sd-daemon.h\n@@ -0,0 +1,104 @@\n+/* stripped down version */\n+\n+#ifndef foosddaemonhfoo\n+#define foosddaemonhfoo\n+\n+/***\n+  Copyright 2010 Lennart Poettering\n+\n+  Permission is hereby granted, free of charge, to any person\n+  obtaining a copy of this software and associated documentation files\n+  (the \"Software\"), to deal in the Software without restriction,\n+  including without limitation the rights to use, copy, modify, merge,\n+  publish, distribute, sublicense, and/or sell copies of the Software,\n+  and to permit persons to whom the Software is furnished to do so,\n+  subject to the following conditions:\n+\n+  The above copyright notice and this permission notice shall be\n+  included in all copies or substantial portions of the Software.\n+\n+  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+  SOFTWARE.\n+***/\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/*\n+  Reference implementation of a few systemd related interfaces for\n+  writing daemons. These interfaces are trivial to implement. To\n+  simplify porting we provide this reference implementation.\n+  Applications are welcome to reimplement the algorithms described\n+  here if they do not want to include these two source files.\n+\n+  The following functionality is provided:\n+\n+  - Support for logging with log levels on stderr\n+  - File descriptor passing for socket-based activation\n+  - Daemon startup and status notification\n+  - Detection of systemd boots\n+\n+  You may compile this with -DDISABLE_SYSTEMD to disable systemd\n+  support. This makes all those calls NOPs that are directly related to\n+  systemd (i.e. only sd_is_xxx() will stay useful).\n+\n+  Since this is drop-in code we don't want any of our symbols to be\n+  exported in any case. Hence we declare hidden visibility for all of\n+  them.\n+\n+  You may find an up-to-date version of these source files online:\n+\n+  http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h\n+  http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/sd-daemon.c\n+\n+  This should compile on non-Linux systems, too, but with the\n+  exception of the sd_is_xxx() calls all functions will become NOPs.\n+\n+  See sd-daemon(3) for more information.\n+*/\n+\n+/* The first passed file descriptor is fd 3 */\n+#define SD_LISTEN_FDS_START 3\n+\n+/*\n+  Returns how many file descriptors have been passed, or a negative\n+  errno code on failure. Optionally, removes the $LISTEN_FDS and\n+  $LISTEN_PID file descriptors from the environment (recommended, but\n+  problematic in threaded environments). If r is the return value of\n+  this function you'll find the file descriptors passed as fds\n+  SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative\n+  errno style error code on failure. This function call ensures that\n+  the FD_CLOEXEC flag is set for the passed file descriptors, to make\n+  sure they are not passed on to child processes. If FD_CLOEXEC shall\n+  not be set, the caller needs to unset it after this call for all file\n+  descriptors that are used.\n+\n+  See sd_listen_fds(3) for more information.\n+*/\n+int sd_listen_fds(int unset_environment);\n+\n+/*\n+  Returns > 0 if the system was booted with systemd. Returns < 0 on\n+  error. Returns 0 if the system was not booted with systemd. Note\n+  that all of the functions above handle non-systemd boots just\n+  fine. You should NOT protect them with a call to this function. Also\n+  note that this function checks whether the system, not the user\n+  session is controlled by systemd. However the functions above work\n+  for both user and system services.\n+\n+  See sd_booted(3) for more information.\n+*/\n+int sd_booted(void);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\n-- \n2.2.1.209.g41e5f3a\n"},{"id":"258867","messageId":"CAPig+cT45fsT47XTgRE23geqisc_Q+9AZLjtPJWWorzjXi8uqQ@mail.gmail.com","threadId":"38979","inReplyTo":"1427991310-19754-1-git-send-email-shawn@churchofgit.com","subject":"Re: [RFC 2] systemd socket activation support","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-04-02T17:20:28Z","receivedAt":"2015-04-02T17:20:28Z","isPatch":false,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Apr 2, 2015 at 12:15 PM, Shawn Landden <shawn@churchofgit.com> wrote:\n> [RFC 2] systemd socket activation support\n\nRephrase this as:\n\n    [PATCH/RFC v2] daemon: add systemd support\n\n> systemd support git-daemon's --inetd mode as well.\n\nUnable to make sense of this sentence (fragment). A better commit\nmessage would explain the purpose of the change, its justification,\nand any important issues which readers need to know to understand and\nreview the patch. See my previous review[1] for some ideas.\n\n[1]: http://article.gmane.org/gmane.comp.version-control.git/266631\n\n> v2: actually test...\n\nIt is indeed a good idea to explain what changed between versions of\nthe patch, however, this isn't telling us much. To ease the task of\nreviewers, explain changes between versions with sufficient detail so\nthat readers don't need to guess. Also, it is very helpful to provide\na link to the previous version of the patch and its discussion since\nthis is a high-traffic list, and reviewers won't necessarily remember\nthe details of the previous version.\n\nAlso, you don't generally want this sort of commentary recorded in the\npermanent project history, so it doesn't belong in the commit message\nproper. Instead, place it below the \"---\" line following your\nsign-off, just above the diffstat.\n\n> Signed-off-by: Shawn Landden <shawn@churchofgit.com>\n> ---\n\nThis is where you should place commentary which you don't want in the\npermanent project history.\n\n> diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\n> index a69b361..898e01f 100644\n> --- a/Documentation/git-daemon.txt\n> +++ b/Documentation/git-daemon.txt\n> @@ -20,6 +20,7 @@ SYNOPSIS\n>              [--inetd |\n>               [--listen=<host_or_ipaddr>] [--port=<n>]\n>               [--user=<user> [--group=<group>]]]\n> +             [--systemd]\n>              [<directory>...]\n>\n>  DESCRIPTION\n> @@ -190,6 +191,12 @@ Git configuration files in that directory are readable by `<user>`.\n>         exiting with a zero status).  It can also look at the $REMOTE_ADDR\n>         and $REMOTE_PORT environment variables to learn about the\n>         requestor when making this decision.\n> +--systemd::\n> +       For running git-daemon under systemd(1) which will pass\n> +       an open connection. This is similar to --inetd, except\n> +       that more than one address/port can be listened to at once\n> +       both through systemd and through --listen, and git-daemon doesn't get\n> +       invoked for every connection. For more details see systemd.socket(5).\n\nThe documentation for the --inetd option mentions other options with\nwhich it is incompatible. This new documentation probably ought to do\nthe same. Moreover, you should update the --inetd documentation to\nmention that it is incompatible with --systemd.\n\nUnfortunately, you plopped this new text right in the middle of the\nthe description of --access-hook (which is continued by the \"+\" line\nand the left-justified paragraph below). If you format the\ndocumentation and look at the before and after output, you will see\nthe problem.\n\n>  +\n>  The external command can optionally write a single line to its\n>  standard output to be sent to the requestor as an error message when\n> @@ -304,7 +311,25 @@ selectively enable/disable services per repository::\n>                 uploadpack = false\n>                 uploadarch = true\n>  ----------------------------------------------------------------\n\nUnfortunately, the new example you've added (below) doesn't format\nproperly, and results in Asciidoc warnings. To ensure correctness,\nfollow the other examples more closely, and try formatting it\nyourself.\n\n> ++\n\nThis \"+\" line incorrectly ties your new example to the preceding\n\"selectively enable/disable services per repository\" item. Just insert\na blank line here rather than a \"+\" line.\n\n> +systemd configuration example:\n\nThis item must end with \"::\", not just \":\".\n\n> +\n\nInstead of a blank line, this should be a \"+\" line in order to tie the\nexample (below) to the \"systemd configuration example\" item.\n\n> +# /etc/systemd/system/git-daemon.socket\n> +[Unit]\n> +Description=Git Daemon socket\n> +\n> +[Socket]\n> +ListenStream=9418\n> +\n> +[Install]\n> +WantedBy=sockets.target\n> +# /etc/systemd/system/git-daemon.service\n> +[Unit]\n> +Description=Git Daemon\n>\n> +[Service]\n> +ExecStart=/usr/lib/git-core/git-daemon --systemd --reuseaddr --base-path=/var/lib /var/lib/git\n> +User=gitdaemon\n\nThe example block must be delimited by \"------\" lines to be formatted\ncorrectly as literal text. (Both \"------\" lines should have the same\nnumber of dashes in order to satisfy all versions of Asciidoc).\n\nAlso, indent the text as other examples in git-daemon.txt.\n\nMore below.\n\n>  ENVIRONMENT\n>  -----------\n> diff --git a/daemon.c b/daemon.c\n> index 9ee2187..e809a4c 100644\n> --- a/daemon.c\n> +++ b/daemon.c\n> @@ -4,6 +4,7 @@\n>  #include \"run-command.h\"\n>  #include \"strbuf.h\"\n>  #include \"string-list.h\"\n> +#include \"sd-daemon.h\"\n>\n>  #ifndef HOST_NAME_MAX\n>  #define HOST_NAME_MAX 256\n> @@ -29,6 +30,7 @@ static const char daemon_usage[] =\n>  \"           [--access-hook=<path>]\\n\"\n>  \"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\\n\"\n>  \"                      [--detach] [--user=<user> [--group=<group>]]\\n\"\n> +\"           [--systemd]\\n\"\n>  \"           [<directory>...]\";\n>\n>  /* List of acceptable pathname prefixes */\n> @@ -1176,11 +1178,22 @@ static void store_pid(const char *path)\n>  }\n>\n>  static int serve(struct string_list *listen_addr, int listen_port,\n> -    struct credentials *cred)\n> +    struct credentials *cred, int systemd_mode)\n>  {\n>         struct socketlist socklist = { NULL, 0, 0 };\n>\n> -       socksetup(listen_addr, listen_port, &socklist);\n> +       if (systemd_mode) {\n> +               int i;\n> +               int n;\n\nMinor: If you examine other parts of daemon.c, you will find that\nthese declarations are normally placed together on a single line, so\nyou could collapse this to:\n\n    int i, n = sd_listen_fds(0);\n\nor:\n\n    int i, n;\n    n = ...;\n\nin order make better use of precious vertical screen real-estate.\n\nMore below.\n\n> +\n> +               n = sd_listen_fds(0);\n> +               ALLOC_GROW(socklist.list, socklist.nr + n, socklist.alloc);\n> +               for (i = 0; i < n; i++)\n> +                       socklist.list[socklist.nr++] = SD_LISTEN_FDS_START + i;\n> +       }\n> +\n> +       if (listen_addr->nr > 0 || !systemd_mode)\n> +               socksetup(listen_addr, listen_port, &socklist);\n>         if (socklist.nr == 0)\n>                 die(\"unable to allocate any listen sockets on port %u\",\n>                     listen_port);\n> @@ -1196,7 +1209,7 @@ int main(int argc, char **argv)\n>  {\n>         int listen_port = 0;\n>         struct string_list listen_addr = STRING_LIST_INIT_NODUP;\n> -       int serve_mode = 0, inetd_mode = 0;\n> +       int serve_mode = 0, inetd_mode = 0, systemd_mode = 0;\n>         const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;\n>         int detach = 0;\n>         struct credentials *cred = NULL;\n> @@ -1331,6 +1344,10 @@ int main(int argc, char **argv)\n>                         informative_errors = 0;\n>                         continue;\n>                 }\n> +               if (!strcmp(arg, \"--systemd\")) {\n> +                       systemd_mode = 1;\n\nThe --inetd switch implies --syslog. Should --systemd do the same by\nsetting \"log_syslog = 1\"?\n\n> +                       continue;\n> +               }\n>                 if (!strcmp(arg, \"--\")) {\n>                         ok_paths = &argv[i+1];\n>                         break;\n> @@ -1349,14 +1366,20 @@ int main(int argc, char **argv)\n>                 /* avoid splitting a message in the middle */\n>                 setvbuf(stderr, NULL, _IOFBF, 4096);\n>\n> -       if (inetd_mode && (detach || group_name || user_name))\n> -               die(\"--detach, --user and --group are incompatible with --inetd\");\n> +       if ((inetd_mode || systemd_mode) && (detach || group_name || user_name))\n> +               die(\"--detach, --user and --group are incompatible with --inetd and --systemd\");\n> +\n> +       if (systemd_mode && inetd_mode)\n> +               die(\"--inetd is incompatible with --systemd\");\n>\n>         if (inetd_mode && (listen_port || (listen_addr.nr > 0)))\n>                 die(\"--listen= and --port= are incompatible with --inetd\");\n>         else if (listen_port == 0)\n>                 listen_port = DEFAULT_GIT_PORT;\n>\n> +       if (systemd_mode && !sd_booted())\n> +               die(\"--systemd passed and not invoked from systemd\");\n> +\n>         if (group_name && !user_name)\n>                 die(\"--group supplied without --user\");\n\nNote shown in this patch, but --inetd redirects stderr to /dev/null.\nShould --systemd be doing so as well?\n\n> @@ -1395,5 +1418,5 @@ int main(int argc, char **argv)\n>                 cld_argv[i+1] = argv[i];\n>         cld_argv[argc+1] = NULL;\n>\n> -       return serve(&listen_addr, listen_port, cred);\n> +       return serve(&listen_addr, listen_port, cred, systemd_mode);\n>  }\n"}]}