diff options
Diffstat (limited to 'src/sd-daemon.c')
-rw-r--r-- | src/sd-daemon.c | 113 |
1 files changed, 112 insertions, 1 deletions
diff --git a/src/sd-daemon.c b/src/sd-daemon.c index 29bd204680..0dad73f94d 100644 --- a/src/sd-daemon.c +++ b/src/sd-daemon.c @@ -24,6 +24,10 @@ SOFTWARE. ***/ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> @@ -34,12 +38,14 @@ #include <errno.h> #include <unistd.h> #include <string.h> +#include <stdarg.h> +#include <stdio.h> #include "sd-daemon.h" int sd_listen_fds(int unset_environment) { -#ifdef DISABLE_SYSTEMD +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) return 0; #else int r, fd; @@ -317,3 +323,108 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t return 1; } + +int sd_notify(int unset_environment, const char *state) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + int fd = -1, r; + struct msghdr msghdr; + struct iovec iovec; + union sockaddr_union sockaddr; + struct ucred *ucred; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + const char *e; + + if (!state) { + r = -EINVAL; + goto finish; + } + + if (!(e = getenv("NOTIFY_SOCKET"))) { + r = 0; + goto finish; + } + + /* Must be an abstract socket, or an absolute path */ + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + r = -EINVAL; + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + r = -errno; + goto finish; + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sa.sa_family = AF_UNIX; + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); + + if (sockaddr.un.sun_path[0] == '@') + sockaddr.un.sun_path[0] = 0; + + memset(&iovec, 0, sizeof(iovec)); + iovec.iov_base = (char*) state; + iovec.iov_len = strlen(state); + + memset(&control, 0, sizeof(control)); + control.cmsghdr.cmsg_level = SOL_SOCKET; + control.cmsghdr.cmsg_type = SCM_CREDENTIALS; + control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = &sockaddr; + msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = &control; + msghdr.msg_controllen = control.cmsghdr.cmsg_len; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { + r = -errno; + goto finish; + } + + r = 0; + +finish: + if (unset_environment) + unsetenv("NOTIFY_SOCKET"); + + if (fd >= 0) + close(fd); + + return r; +#endif +} + +int sd_notifyf(int unset_environment, const char *format, ...) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + va_list ap; + char *p = NULL; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0 || !p) + return -ENOMEM; + + r = sd_notify(unset_environment, p); + free(p); + + return r; +#endif +} |