summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-daemon
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-01-06 00:26:25 +0100
committerLennart Poettering <lennart@poettering.net>2015-01-06 03:16:39 +0100
commita354329f724d6ce913d2ccffb2be8f3327a67faa (patch)
treeb6b05cc2c42c274f8385a16b1896d6c88bf4fc8f /src/libsystemd/sd-daemon
parent75399049653f2d5e22032da70cf96f20d7b4d9a6 (diff)
core: add new logic for services to store file descriptors in PID 1
With this change it is possible to send file descriptors to PID 1, via sd_pid_notify_with_fds() which PID 1 will store individually for each service, and pass via the usual fd passing logic on next invocation. This is useful for enable daemon reload schemes where daemons serialize their state to /run, push their fds into PID 1 and terminate, restoring their state on next start from the data in /run and passed in from PID 1. The fds are kept by PID 1 as long as no POLLHUP or POLLERR is seen on them, and the service they belong to are either not dead or failed, or have a job queued.
Diffstat (limited to 'src/libsystemd/sd-daemon')
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c94
1 files changed, 62 insertions, 32 deletions
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 1f2a53393f..028c2a7a5b 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -340,16 +340,28 @@ _public_ int sd_is_mq(int fd, const char *path) {
return 1;
}
-_public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
- union sockaddr_union sockaddr = {};
- _cleanup_close_ int fd = -1;
- struct msghdr msghdr = {};
- struct iovec iovec = {};
- const char *e;
+_public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
+ union sockaddr_union sockaddr = {
+ .sa.sa_family = AF_UNIX,
+ };
+ struct iovec iovec = {
+ .iov_base = (char*) state,
+ };
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_name = &sockaddr,
+ };
union {
struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control = {};
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * n_fds)];
+ } control;
+ _cleanup_close_ int fd = -1;
+ struct cmsghdr *cmsg = NULL;
+ const char *e;
+ size_t controllen_without_ucred = 0;
+ bool try_without_ucred = false;
int r;
if (!state) {
@@ -357,6 +369,11 @@ _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
goto finish;
}
+ if (n_fds > 0 && !fds) {
+ r = -EINVAL;
+ goto finish;
+ }
+
e = getenv("NOTIFY_SOCKET");
if (!e)
return 0;
@@ -373,42 +390,50 @@ _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
goto finish;
}
- sockaddr.sa.sa_family = AF_UNIX;
- strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
+ iovec.iov_len = strlen(state);
+ strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
if (sockaddr.un.sun_path[0] == '@')
sockaddr.un.sun_path[0] = 0;
- iovec.iov_base = (char*) state;
- iovec.iov_len = strlen(state);
-
- msghdr.msg_name = &sockaddr;
msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
-
if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
msghdr.msg_namelen = sizeof(struct sockaddr_un);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
+ if (n_fds > 0) {
+ msghdr.msg_control = &control;
+ msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds);
+
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
+
+ memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
+ }
if (pid != 0 && pid != getpid()) {
- struct cmsghdr *cmsg;
- struct ucred ucred = {};
+ struct ucred *ucred;
+
+ try_without_ucred = true;
+ controllen_without_ucred = msghdr.msg_controllen;
msghdr.msg_control = &control;
- msghdr.msg_controllen = sizeof(control);
+ msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred));
+
+ if (cmsg)
+ cmsg = CMSG_NXTHDR(&msghdr, cmsg);
+ else
+ cmsg = CMSG_FIRSTHDR(&msghdr);
- cmsg = CMSG_FIRSTHDR(&msghdr);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDENTIALS;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
- ucred.pid = pid;
- ucred.uid = getuid();
- ucred.gid = getgid();
-
- memcpy(CMSG_DATA(cmsg), &ucred, sizeof(struct ucred));
- msghdr.msg_controllen = cmsg->cmsg_len;
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ ucred->pid = pid;
+ ucred->uid = getuid();
+ ucred->gid = getgid();
}
/* First try with fake ucred data, as requested */
@@ -417,10 +442,11 @@ _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state)
goto finish;
}
- /* If that failed, try with our own instead */
- if (msghdr.msg_control) {
- msghdr.msg_control = NULL;
- msghdr.msg_controllen = 0;
+ /* If that failed, try with our own ucred instead */
+ if (try_without_ucred) {
+ if (controllen_without_ucred <= 0)
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = controllen_without_ucred;
if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
r = 1;
@@ -437,8 +463,12 @@ finish:
return r;
}
+_public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
+ return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
+}
+
_public_ int sd_notify(int unset_environment, const char *state) {
- return sd_pid_notify(0, unset_environment, state);
+ return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
}
_public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {