{"thread":{"id":"38975","subject":"[PATCH] systemd socket activation support","startedAt":"2015-04-02T06:09:11Z","lastAt":"2015-04-08T20:21:20Z","messageCount":4,"participants":["Shawn Landden","Erik Faye-Lund","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"258849","messageId":"1427954951-17649-1-git-send-email-shawn@churchofgit.com","threadId":"38975","inReplyTo":null,"subject":"[PATCH] systemd socket activation support","fromName":"Shawn Landden","fromEmail":"shawn@churchofgit.com","sentAt":"2015-04-02T06:09:11Z","receivedAt":"2015-04-02T06:09:11Z","isPatch":true,"sender":{"key":"shawn@churchofgit.com","avatar":"https://gravatar.com/avatar/66fa92115ac78085af2524ca39ccca362bd1ca7571a4b0b843a8a7017b210df2?d=mp&s=160"},"body":"From: Shawn Landden <shawnlandden@gmail.com>\n\nv1.1: actually test...\n\nSigned-off-by: Shawn Landden <shawn@churchofgit.com>\n---\n daemon.c           |  35 +++++++++++---\n git-daemon.service |   7 +++\n git-daemon.socket  |   9 ++++\n sd-daemon.c        | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n sd-daemon.h        |  91 ++++++++++++++++++++++++++++++++++++\n 5 files changed, 268 insertions(+), 6 deletions(-)\n create mode 100644 git-daemon.service\n create mode 100644 git-daemon.socket\n create mode 100644 sd-daemon.c\n create mode 100644 sd-daemon.h\n\ndiff --git a/daemon.c b/daemon.c\nindex 9ee2187..4677058 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -5,6 +5,8 @@\n #include \"strbuf.h\"\n #include \"string-list.h\"\n \n+#include \"sd-daemon.c\"\n+\n #ifndef HOST_NAME_MAX\n #define HOST_NAME_MAX 256\n #endif\n@@ -29,6 +31,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 +1179,21 @@ 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+\tint i;\n+\tint n;\n+\n+\tif (systemd_mode) {\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-\tsocksetup(listen_addr, listen_port, &socklist);\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 running 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/git-daemon.service b/git-daemon.service\nnew file mode 100644\nindex 0000000..b0c99f3\n--- /dev/null\n+++ b/git-daemon.service\n@@ -0,0 +1,7 @@\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+\ndiff --git a/git-daemon.socket b/git-daemon.socket\nnew file mode 100644\nindex 0000000..b3dd981\n--- /dev/null\n+++ b/git-daemon.socket\n@@ -0,0 +1,9 @@\n+[Unit]\n+Description=Git Daemon socket\n+\n+[Socket]\n+ListenStream=9418\n+\n+[Install]\n+WantedBy=sockets.target\n+\ndiff --git a/sd-daemon.c b/sd-daemon.c\nnew file mode 100644\nindex 0000000..653fbf5\n--- /dev/null\n+++ b/sd-daemon.c\n@@ -0,0 +1,132 @@\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+\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+\ndiff --git a/sd-daemon.h b/sd-daemon.h\nnew file mode 100644\nindex 0000000..f6f2959\n--- /dev/null\n+++ b/sd-daemon.h\n@@ -0,0 +1,91 @@\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+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\n-- \n2.2.1.209.g41e5f3a\n"},{"id":"259174","messageId":"CABPQNSa-45ZsUX54Ym3dQa+HU63abcQ9O3v8maRe9e_-38Ef+Q@mail.gmail.com","threadId":"38975","inReplyTo":"1427954951-17649-1-git-send-email-shawn@churchofgit.com","subject":"Re: [PATCH] systemd socket activation support","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2015-04-08T14:26:42Z","receivedAt":"2015-04-08T14:26:42Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Thu, Apr 2, 2015 at 8:09 AM, Shawn Landden <shawn@churchofgit.com> wrote:\n> From: Shawn Landden <shawnlandden@gmail.com>\n>\n> v1.1: actually test...\n>\n> Signed-off-by: Shawn Landden <shawn@churchofgit.com>\n> ---\n>  daemon.c           |  35 +++++++++++---\n>  git-daemon.service |   7 +++\n>  git-daemon.socket  |   9 ++++\n>  sd-daemon.c        | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  sd-daemon.h        |  91 ++++++++++++++++++++++++++++++++++++\n>  5 files changed, 268 insertions(+), 6 deletions(-)\n>  create mode 100644 git-daemon.service\n>  create mode 100644 git-daemon.socket\n>  create mode 100644 sd-daemon.c\n>  create mode 100644 sd-daemon.h\n>\n> diff --git a/daemon.c b/daemon.c\n> index 9ee2187..4677058 100644\n> --- a/daemon.c\n> +++ b/daemon.c\n> @@ -5,6 +5,8 @@\n>  #include \"strbuf.h\"\n>  #include \"string-list.h\"\n>\n> +#include \"sd-daemon.c\"\n> +\n\nYou meant \"sd-daemon.h\", no?\n"},{"id":"259183","messageId":"1428520491-74980-1-git-send-email-shawn@churchofgit.com","threadId":"38975","inReplyTo":"CABPQNSa-45ZsUX54Ym3dQa+HU63abcQ9O3v8maRe9e_-38Ef+Q@mail.gmail.com","subject":"[v7 PATCH] daemon: add systemd support","fromName":"Shawn Landden","fromEmail":"shawn@churchofgit.com","sentAt":"2015-04-08T19:14:51Z","receivedAt":"2015-04-08T19:14:51Z","isPatch":true,"sender":{"key":"shawn@churchofgit.com","avatar":"https://gravatar.com/avatar/66fa92115ac78085af2524ca39ccca362bd1ca7571a4b0b843a8a7017b210df2?d=mp&s=160"},"body":"git-daemon's --systemd mode allows git-daemon to be connect-activated\non one or more addresses or ports. Unlike --inetd[1], git-daemon is\nnot spawned for every connection.\n\n[1]which systemd is compatible with using its Accept=yes mode\n\nSigned-off-by: Shawn Landden <shawn@churchofgit.com>\n---\nRepond to Eric Sunshine's review of v6\nMore documentation.\n Documentation/git-daemon.txt | 49 +++++++++++++++++++++++++++++++++++++++-----\n Makefile                     | 10 +++++++++\n daemon.c                     | 46 +++++++++++++++++++++++++++++++++++------\n 3 files changed, 94 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex a69b361..0eab51b 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -19,7 +19,8 @@ SYNOPSIS\n \t     [--access-hook=<path>] [--[no-]informative-errors]\n \t     [--inetd |\n \t      [--listen=<host_or_ipaddr>] [--port=<n>]\n-\t      [--user=<user> [--group=<group>]]]\n+\t      [--systemd |\n+\t       [--user=<user> [--group=<group>]]]\n \t     [<directory>...]\n \n DESCRIPTION\n@@ -81,8 +82,8 @@ OPTIONS\n \n --inetd::\n \tHave the server run as an inetd service. Implies --syslog.\n-\tIncompatible with --detach, --port, --listen, --user and --group\n-\toptions.\n+\tIncompatible with --systemd, --detach, --port, --listen, --user and\n+\t--group options.\n \n --listen=<host_or_ipaddr>::\n \tListen on a specific IP address or hostname.  IP addresses can\n@@ -146,8 +147,8 @@ OPTIONS\n \tthe option are given to `getpwnam(3)` and `getgrnam(3)`\n \tand numeric IDs are not supported.\n +\n-Giving these options is an error when used with `--inetd`; use\n-the facility of inet daemon to achieve the same before spawning\n+Giving these options is an error when used with `--inetd` or `--systemd`; use\n+the facility of systemd or the inet daemon to achieve the same before spawning\n 'git daemon' if needed.\n +\n Like many programs that switch user id, the daemon does not reset\n@@ -180,6 +181,16 @@ Git configuration files in that directory are readable by `<user>`.\n \terrors are not enabled, all errors report \"access denied\" to the\n \tclient. The default is --no-informative-errors.\n \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/--port, and git-daemon\n+\tdoesn't get invoked for every connection, but only the first.\n+\tFor more details see systemd.socket(5). Incompatible with\n+\t--inetd, --detach, --user and --group options.\n+\tWorks with the session manager (systemd --user) too.\n+\n --access-hook=<path>::\n \tEvery time a client connects, first run an external command\n \tspecified by the <path> with service name (e.g. \"upload-pack\"),\n@@ -305,6 +316,34 @@ selectively enable/disable services per repository::\n \t\tuploadarch = true\n ----------------------------------------------------------------\n \n+systemd configuration example::\n+Example systemd configuration files, typically placed in `/etc/systemd/system`\n+or `$HOME/.config/systemd/user`.\n++\n+`git-daemon.socket`\n++\n+----------------------------------------------------------------\n+[Unit]\n+Description=Git Daemon socket\n+\n+[Socket]\n+ListenStream=9418\n+\n+[Install]\n+WantedBy=sockets.target\n+----------------------------------------------------------------\n++\n+`git-daemon.service`\n++\n+----------------------------------------------------------------\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=git-daemon\n+StandardError=null\n+----------------------------------------------------------------\n \n ENVIRONMENT\n -----------\ndiff --git a/Makefile b/Makefile\nindex 5f3987f..415ac21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -42,6 +42,9 @@ all::\n # Define NO_EXPAT if you do not have expat installed.  git-http-push is\n # not built, and you cannot push using http:// and https:// transports (dumb).\n #\n+# Define NO_SYSTEMD to prevent systemd socket activation support from being\n+# built into git-daemon.\n+#\n # Define EXPATDIR=/foo/bar if your expat header and library files are in\n # /foo/bar/include and /foo/bar/lib directories.\n #\n@@ -995,6 +998,13 @@ ifeq ($(uname_S),Darwin)\n \tPTHREAD_LIBS =\n endif\n \n+ifndef NO_SYSTEMD\n+\tifeq ($(shell echo \"\\#include <systemd/sd-daemon.h>\" | $(CC) -E - -o /dev/null 2>/dev/null && echo y),y)\n+\t\tBASIC_CFLAGS += -DHAVE_SYSTEMD\n+\t\tEXTLIBS += -lsystemd\n+\tendif\n+endif\n+\n ifndef CC_LD_DYNPATH\n \tifdef NO_R_TO_GCC_LINKER\n \t\t# Some gcc does not accept and pass -R to the linker to specify\ndiff --git a/daemon.c b/daemon.c\nindex 9ee2187..9880858 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -1,3 +1,7 @@\n+#ifdef HAVE_SYSTEMD\n+#  include <systemd/sd-daemon.h>\n+#endif\n+\n #include \"cache.h\"\n #include \"pkt-line.h\"\n #include \"exec_cmd.h\"\n@@ -28,7 +32,11 @@ static const char daemon_usage[] =\n \"           [--(enable|disable|allow-override|forbid-override)=<service>]\\n\"\n \"           [--access-hook=<path>]\\n\"\n \"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\\n\"\n+#ifdef HAVE_SYSTEMD\n+\"                      [--systemd | [--detach] [--user=<user> [--group=<group>]]]\\n\" /* exactly 80 characters */\n+#else\n \"                      [--detach] [--user=<user> [--group=<group>]]\\n\"\n+#endif\n \"           [<directory>...]\";\n \n /* List of acceptable pathname prefixes */\n@@ -1176,11 +1184,23 @@ 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+#ifdef HAVE_SYSTEMD\n+\tif (systemd_mode) {\n+\t\tint i, 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+#endif\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 +1216,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 +1351,12 @@ int main(int argc, char **argv)\n \t\t\tinformative_errors = 0;\n \t\t\tcontinue;\n \t\t}\n+#ifdef HAVE_SYSTEMD\n+\t\tif (!strcmp(arg, \"--systemd\")) {\n+\t\t\tsystemd_mode = 1;\n+\t\t\tcontinue;\n+\t\t}\n+#endif\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\tok_paths = &argv[i+1];\n \t\t\tbreak;\n@@ -1349,8 +1375,16 @@ 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+#ifdef HAVE_SYSTEMD\n+\tif (systemd_mode && inetd_mode)\n+\t\tdie(\"--inetd is incompatible with --systemd\");\n+\n+\tif (systemd_mode && !sd_booted())\n+\t\tdie(\"--systemd passed and not invoked from systemd\");\n+#endif\n \n \tif (inetd_mode && (listen_port || (listen_addr.nr > 0)))\n \t\tdie(\"--listen= and --port= are incompatible with --inetd\");\n@@ -1395,5 +1429,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 }\n-- \n2.2.1.209.g41e5f3a\n"},{"id":"259184","messageId":"CAPig+cT4Y7RD+7N3GcfNgUfTn2cDGpC6CJU-0JKQ7-oFECKuFQ@mail.gmail.com","threadId":"38975","inReplyTo":"1428520491-74980-1-git-send-email-shawn@churchofgit.com","subject":"Re: [v7 PATCH] daemon: add systemd support","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-04-08T20:21:20Z","receivedAt":"2015-04-08T20:21:20Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 8, 2015 at 3:14 PM, Shawn Landden <shawn@churchofgit.com> wrote:\n> [v7 PATCH] daemon: add systemd support\n>\n> git-daemon's --systemd mode allows git-daemon to be connect-activated\n> on one or more addresses or ports. Unlike --inetd[1], git-daemon is\n> not spawned for every connection.\n>\n> [1]which systemd is compatible with using its Accept=yes mode\n>\n> Signed-off-by: Shawn Landden <shawn@churchofgit.com>\n> ---\n> Repond to Eric Sunshine's review of v6\n> More documentation.\n\nDoes this v7 differ from the v7 which you sent yesterday[1]?\n\n[1]: http://git.661346.n2.nabble.com/v7-PATCH-daemon-add-systemd-support-td7628519.html\n\n> diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\n> index a69b361..0eab51b 100644\n> --- a/Documentation/git-daemon.txt\n> +++ b/Documentation/git-daemon.txt\n> @@ -19,7 +19,8 @@ SYNOPSIS\n>              [--access-hook=<path>] [--[no-]informative-errors]\n>              [--inetd |\n>               [--listen=<host_or_ipaddr>] [--port=<n>]\n> -             [--user=<user> [--group=<group>]]]\n> +             [--systemd |\n> +              [--user=<user> [--group=<group>]]]\n>              [<directory>...]\n>\n>  DESCRIPTION\n> @@ -81,8 +82,8 @@ OPTIONS\n>\n>  --inetd::\n>         Have the server run as an inetd service. Implies --syslog.\n> -       Incompatible with --detach, --port, --listen, --user and --group\n> -       options.\n> +       Incompatible with --systemd, --detach, --port, --listen, --user and\n> +       --group options.\n>\n>  --listen=<host_or_ipaddr>::\n>         Listen on a specific IP address or hostname.  IP addresses can\n> @@ -146,8 +147,8 @@ OPTIONS\n>         the option are given to `getpwnam(3)` and `getgrnam(3)`\n>         and numeric IDs are not supported.\n>  +\n> -Giving these options is an error when used with `--inetd`; use\n> -the facility of inet daemon to achieve the same before spawning\n> +Giving these options is an error when used with `--inetd` or `--systemd`; use\n> +the facility of systemd or the inet daemon to achieve the same before spawning\n>  'git daemon' if needed.\n>  +\n>  Like many programs that switch user id, the daemon does not reset\n> @@ -180,6 +181,16 @@ Git configuration files in that directory are readable by `<user>`.\n>         errors are not enabled, all errors report \"access denied\" to the\n>         client. The default is --no-informative-errors.\n>\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/--port, and git-daemon\n> +       doesn't get invoked for every connection, but only the first.\n> +       For more details see systemd.socket(5). Incompatible with\n> +       --inetd, --detach, --user and --group options.\n> +       Works with the session manager (systemd --user) too.\n> +\n>  --access-hook=<path>::\n>         Every time a client connects, first run an external command\n>         specified by the <path> with service name (e.g. \"upload-pack\"),\n> @@ -305,6 +316,34 @@ selectively enable/disable services per repository::\n>                 uploadarch = true\n>  ----------------------------------------------------------------\n>\n> +systemd configuration example::\n> +Example systemd configuration files, typically placed in `/etc/systemd/system`\n> +or `$HOME/.config/systemd/user`.\n> ++\n> +`git-daemon.socket`\n> ++\n> +----------------------------------------------------------------\n> +[Unit]\n> +Description=Git Daemon socket\n> +\n> +[Socket]\n> +ListenStream=9418\n> +\n> +[Install]\n> +WantedBy=sockets.target\n> +----------------------------------------------------------------\n> ++\n> +`git-daemon.service`\n> ++\n> +----------------------------------------------------------------\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=git-daemon\n> +StandardError=null\n> +----------------------------------------------------------------\n>\n>  ENVIRONMENT\n>  -----------\n> diff --git a/Makefile b/Makefile\n> index 5f3987f..415ac21 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -42,6 +42,9 @@ all::\n>  # Define NO_EXPAT if you do not have expat installed.  git-http-push is\n>  # not built, and you cannot push using http:// and https:// transports (dumb).\n>  #\n> +# Define NO_SYSTEMD to prevent systemd socket activation support from being\n> +# built into git-daemon.\n> +#\n>  # Define EXPATDIR=/foo/bar if your expat header and library files are in\n>  # /foo/bar/include and /foo/bar/lib directories.\n>  #\n> @@ -995,6 +998,13 @@ ifeq ($(uname_S),Darwin)\n>         PTHREAD_LIBS =\n>  endif\n>\n> +ifndef NO_SYSTEMD\n> +       ifeq ($(shell echo \"\\#include <systemd/sd-daemon.h>\" | $(CC) -E - -o /dev/null 2>/dev/null && echo y),y)\n> +               BASIC_CFLAGS += -DHAVE_SYSTEMD\n> +               EXTLIBS += -lsystemd\n> +       endif\n> +endif\n> +\n>  ifndef CC_LD_DYNPATH\n>         ifdef NO_R_TO_GCC_LINKER\n>                 # Some gcc does not accept and pass -R to the linker to specify\n> diff --git a/daemon.c b/daemon.c\n> index 9ee2187..9880858 100644\n> --- a/daemon.c\n> +++ b/daemon.c\n> @@ -1,3 +1,7 @@\n> +#ifdef HAVE_SYSTEMD\n> +#  include <systemd/sd-daemon.h>\n> +#endif\n> +\n>  #include \"cache.h\"\n>  #include \"pkt-line.h\"\n>  #include \"exec_cmd.h\"\n> @@ -28,7 +32,11 @@ static const char daemon_usage[] =\n>  \"           [--(enable|disable|allow-override|forbid-override)=<service>]\\n\"\n>  \"           [--access-hook=<path>]\\n\"\n>  \"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\\n\"\n> +#ifdef HAVE_SYSTEMD\n> +\"                      [--systemd | [--detach] [--user=<user> [--group=<group>]]]\\n\" /* exactly 80 characters */\n> +#else\n>  \"                      [--detach] [--user=<user> [--group=<group>]]\\n\"\n> +#endif\n>  \"           [<directory>...]\";\n>\n>  /* List of acceptable pathname prefixes */\n> @@ -1176,11 +1184,23 @@ 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> +#ifdef HAVE_SYSTEMD\n> +       if (systemd_mode) {\n> +               int i, 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> +#endif\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 +1216,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 +1351,12 @@ int main(int argc, char **argv)\n>                         informative_errors = 0;\n>                         continue;\n>                 }\n> +#ifdef HAVE_SYSTEMD\n> +               if (!strcmp(arg, \"--systemd\")) {\n> +                       systemd_mode = 1;\n> +                       continue;\n> +               }\n> +#endif\n>                 if (!strcmp(arg, \"--\")) {\n>                         ok_paths = &argv[i+1];\n>                         break;\n> @@ -1349,8 +1375,16 @@ 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> +#ifdef HAVE_SYSTEMD\n> +       if (systemd_mode && inetd_mode)\n> +               die(\"--inetd is incompatible with --systemd\");\n> +\n> +       if (systemd_mode && !sd_booted())\n> +               die(\"--systemd passed and not invoked from systemd\");\n> +#endif\n>\n>         if (inetd_mode && (listen_port || (listen_addr.nr > 0)))\n>                 die(\"--listen= and --port= are incompatible with --inetd\");\n> @@ -1395,5 +1429,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> --\n> 2.2.1.209.g41e5f3a\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"}]}