From 03ed251b015e8bb4bcdf84f5f330ba2edcdd117a Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 8 Jul 2015 11:57:35 +0200 Subject: [PATCH] daemon: Clean up the Upstart and Systemd notification code. Document the use of "Linux abstract namespace sockets" and use sendto(2) instead of sendmsg(2) to avoid having to initialize struct msghdr and struct iovec. Removes the non-portable bzero() calls. --- src/daemon/collectd.c | 82 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index 46e13b3f..cffb9a5f 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -418,15 +418,18 @@ static int pidfile_remove (void) #ifdef KERNEL_LINUX int notify_upstart (void) { - const char *upstart_job = getenv("UPSTART_JOB"); + char const *upstart_job = getenv("UPSTART_JOB"); if (upstart_job == NULL) return 0; if (strcmp(upstart_job, "collectd") != 0) + { + WARNING ("Environment specifies unexpected UPSTART_JOB=\"%s\", expected \"collectd\". Ignoring the variable.", upstart_job); return 0; + } - WARNING ("supervised by upstart, will stop to signal readyness"); + NOTICE("Upstart detected, stopping now to signal readyness."); raise(SIGSTOP); unsetenv("UPSTART_JOB"); @@ -435,49 +438,70 @@ int notify_upstart (void) int notify_systemd (void) { - int fd = -1; - const char *notifysocket = getenv("NOTIFY_SOCKET"); + int fd; + const char *notifysocket; struct sockaddr_un su; - struct iovec iov; - struct msghdr hdr; + size_t su_size; + char buffer[] = "READY=1\n"; + notifysocket = getenv ("NOTIFY_SOCKET"); if (notifysocket == NULL) return 0; - if ((strchr("@/", notifysocket[0])) == NULL || - strlen(notifysocket) < 2) + if ((strlen (notifysocket) < 2) + || ((notifysocket[0] != '@') && (notifysocket[0] != '/'))) + { + ERROR ("invalid notification socket NOTIFY_SOCKET=\"%s\": path must be absolute", notifysocket); return 0; + } + NOTICE ("Systemd detected, trying to signal readyness."); + + unsetenv ("NOTIFY_SOCKET"); - WARNING ("supervised by systemd, will signal readyness"); - if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { - WARNING ("cannot contact systemd socket %s", notifysocket); + fd = socket (AF_UNIX, SOCK_DGRAM, /* protocol = */ 0); + if (fd < 0) { + char errbuf[1024]; + ERROR ("creating UNIX socket failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); return 0; } - bzero(&su, sizeof(su)); + memset (&su, 0, sizeof (su)); su.sun_family = AF_UNIX; - sstrncpy (su.sun_path, notifysocket, sizeof(su.sun_path)); - - if (notifysocket[0] == '@') + if (notifysocket[0] != '@') + { + /* regular UNIX socket */ + sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path)); + su_size = sizeof (su); + } + else + { +#if KERNEL_LINUX + /* Linux abstract namespace socket: specify address as "\0foo", i.e. + * start with a null byte. Since null bytes have no special meaning in + * that case, we have to set su_size correctly to cover only the bytes + * that are part of the address. */ + sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path)); su.sun_path[0] = 0; + su_size = sizeof (sa_family_t) + strlen (notifysocket); + if (su_size > sizeof (su)) + su_size = sizeof (su); +#else + ERROR ("Systemd socket uses Linux abstract namespace notation (\"%s\"), " + "but I don't appear to be running on Linux.", notifysocket); + return 0; +#endif + } - 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"); + if (sendto (fd, buffer, strlen (buffer), MSG_NOSIGNAL, (void *) &su, (socklen_t) su_size) < 0) + { + char errbuf[1024]; + ERROR ("sendto(\"%s\") failed: %s", notifysocket, + sstrerror (errno, errbuf, sizeof (errbuf))); close(fd); return 0; } + close(fd); return 1; } -- 2.11.0