From ff270e6d53374bddca9f3fe0bb7a8c2294548edc Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ritschard Date: Fri, 7 Nov 2014 13:56:21 +0100 Subject: [PATCH] Support both systemd and upstart. This checks appropriate environment variables. When supervised by either upstart or systemd, collectd will not daemonize but will signal readyness with the appropriate method. This allows collectd to be either configured with `expect stop` in upstart or `Type=notify` with systemd. The rationale for this is detailed here: http://spootnik.org/entries/2014/11/09_pid-tracking-in-modern-init-systems.html --- src/daemon/collectd.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index 2e2d821a..eb5404f8 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -191,7 +192,7 @@ static int change_basedir (const char *orig_dir) sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } - + dirlen = strlen (dir); while ((dirlen > 0) && (dir[dirlen - 1] == '/')) dir[--dirlen] = '\0'; @@ -270,7 +271,7 @@ static void update_kstat (void) static void exit_usage (int status) { printf ("Usage: "PACKAGE" [OPTIONS]\n\n" - + "Available options:\n" " General:\n" " -C Configuration file.\n" @@ -409,6 +410,72 @@ static int pidfile_remove (void) } /* static int pidfile_remove (const char *file) */ #endif /* COLLECT_DAEMON */ +int notify_upstart (void) +{ + const char *upstart_job = getenv("UPSTART_JOB"); + + if (upstart_job == NULL) + return 0; + + if (strcmp(upstart_job, "collectd") != 0) + return 0; + + WARNING ("supervised by upstart, will stop to signal readyness"); + raise(SIGSTOP); + unsetenv("UPSTART_JOB"); + + return 1; +} + +int notify_systemd (void) +{ + int fd = -1; + const char *notifysocket = getenv("NOTIFY_SOCKET"); + struct sockaddr_un su; + struct iovec iov; + struct msghdr hdr; + + if (notifysocket == NULL) + return 0; + + if ((strchr("@/", notifysocket[0])) == NULL || + strlen(notifysocket) < 2) + return 0; + + WARNING ("supervised by systemd, will signal readyness"); + if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + WARNING ("cannot contact systemd socket %s", notifysocket); + return 0; + } + + bzero(&su, sizeof(su)); + su.sun_family = AF_UNIX; + sstrncpy (su.sun_path, notifysocket, sizeof(su.sun_path)); + + if (notifysocket[0] == '@') + su.sun_path[0] = 0; + + bzero(&iov, sizeof(iov)); + iov.iov_base = "READY=1"; + iov.iov_len = strlen("READY=1"); + + bzero(&hdr, sizeof(hdr)); + hdr.msg_name = &su; + hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + + strlen(notifysocket); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + unsetenv("NOTIFY_SOCKET"); + if (sendmsg(fd, &hdr, MSG_NOSIGNAL) < 0) { + WARNING ("cannot send notification to systemd"); + close(fd); + return 0; + } + close(fd); + return 1; +} + int main (int argc, char **argv) { struct sigaction sig_int_action; @@ -525,7 +592,11 @@ int main (int argc, char **argv) sig_chld_action.sa_handler = SIG_IGN; sigaction (SIGCHLD, &sig_chld_action, NULL); - if (daemonize) + /* + * Only daemonize if we're not being supervised + * by upstart or systemd. + */ + if (daemonize && notify_upstart() == 0 && notify_systemd() == 0) { if ((pid = fork ()) == -1) { -- 2.11.0