{"thread":{"id":"38998","subject":"[RFCv4 PATCH] daemon: add systemd support","startedAt":"2015-04-04T03:19:40Z","lastAt":"2015-04-04T03:19:40Z","messageCount":1,"participants":["Shawn Landden"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"258974","messageId":"1428117580-32289-1-git-send-email-shawn@churchofgit.com","threadId":"38998","inReplyTo":null,"subject":"[RFCv4 PATCH] daemon: add systemd support","fromName":"Shawn Landden","fromEmail":"shawn@churchofgit.com","sentAt":"2015-04-04T03:19:40Z","receivedAt":"2015-04-04T03:19:40Z","isPatch":true,"sender":{"key":"shawn@churchofgit.com","avatar":"https://gravatar.com/avatar/66fa92115ac78085af2524ca39ccca362bd1ca7571a4b0b843a8a7017b210df2?d=mp&s=160"},"body":"systemd supports git-daemon's existing --inetd mode as well.\n\nSigned-off-by: Shawn Landden <shawn@churchofgit.com>\n---\n Documentation/git-daemon.txt | 41 +++++++++++++++++++++++++++++++++++-----\n Makefile                     | 14 ++++++++++++--\n daemon.c                     | 45 ++++++++++++++++++++++++++++++++++++++------\n 3 files changed, 87 insertions(+), 13 deletions(-)\n\nRespond to review in http://article.gmane.org/gmane.comp.version-control.git/266650\nI did not indent the example documents as that was for inetd, and that would break copy/paste.\n\nThese are all documentation changes, no functional differences. (Well, the example\ngained StandardError=null to match --inetd)\n\ndiff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt\nindex a69b361..a273565 100644\n--- a/Documentation/git-daemon.txt\n+++ b/Documentation/git-daemon.txt\n@@ -18,7 +18,7 @@ SYNOPSIS\n \t     [--allow-override=<service>] [--forbid-override=<service>]\n \t     [--access-hook=<path>] [--[no-]informative-errors]\n \t     [--inetd |\n-\t      [--listen=<host_or_ipaddr>] [--port=<n>]\n+\t      [--listen=<host_or_ipaddr>] [--port=<n>] [--systemd]\n \t      [--user=<user> [--group=<group>]]]\n \t     [<directory>...]\n \n@@ -81,8 +81,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 +146,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 +180,14 @@ 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, and git-daemon doesn't get\n+\tinvoked for every connection. For more details see systemd.socket(5).\n+\tIncompatible with --inetd, --detach, --user and --group options.\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@@ -304,7 +312,30 @@ selectively enable/disable services per repository::\n \t\tuploadpack = false\n \t\tuploadarch = true\n ----------------------------------------------------------------\n++\n+\n+systemd configuration example::\n++\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+\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=git-daemon\n+StandardError=null\n+----------------------------------------------------------------\n \n ENVIRONMENT\n -----------\ndiff --git a/Makefile b/Makefile\nindex 5f3987f..644db71 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 && 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\n@@ -1403,8 +1413,8 @@ ifdef NATIVE_CRLF\n endif\n \n ifdef USE_NED_ALLOCATOR\n-       COMPAT_CFLAGS += -Icompat/nedmalloc\n-       COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n+        COMPAT_CFLAGS += -Icompat/nedmalloc\n+        COMPAT_OBJS += compat/nedmalloc/nedmalloc.o\n endif\n \n ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT\ndiff --git a/daemon.c b/daemon.c\nindex 9ee2187..ad8a79a 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@@ -29,6 +33,9 @@ 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+#ifdef HAVE_SYSTEMD\n+\"           [--systemd]\\n\"\n+#endif\n \"           [<directory>...]\";\n \n /* List of acceptable pathname prefixes */\n@@ -1176,11 +1183,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 +1215,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 +1350,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 +1374,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 +1428,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"}]}