]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysupdated: port to notify_recv()
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Feb 2025 10:50:15 +0000 (11:50 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 18 Feb 2025 12:17:54 +0000 (13:17 +0100)
src/libsystemd/sd-event/event-util.c
src/libsystemd/sd-event/event-util.h
src/sysupdate/sysupdated.c

index 42e973564e3c56613bb6ebc7271926f7085325cf..81745812dc8a945a772a36f1d97c69b5a508fd3e 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 
+#include "errno-util.h"
 #include "event-source.h"
 #include "event-util.h"
 #include "fd-util.h"
@@ -172,6 +173,33 @@ int event_add_child_pidref(
         return sd_event_add_child(e, s, pid->pid, options, callback, userdata);
 }
 
+int event_source_get_child_pidref(
+                sd_event_source *s,
+                PidRef *ret) {
+
+        int r;
+
+        assert(s);
+        assert(ret);
+
+        pid_t pid;
+        r = sd_event_source_get_child_pid(s, &pid);
+        if (r < 0)
+                return r;
+
+        int pidfd = sd_event_source_get_child_pidfd(s);
+        if (pidfd < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(pidfd))
+                return pidfd;
+
+        /* Note, we don't actually duplicate the fd here, i.e. we do not pass ownership of this PidRef to the caller */
+        *ret = (PidRef) {
+                .pid = pid,
+                .fd = pidfd,
+        };
+
+        return 0;
+}
+
 dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts) {
         assert(e);
         assert(ts);
index 383b4c82b7c9b2e82f3369b76c45ff2abd226437..2c6fcccb90850e2be674ce899ee99396c784e8cf 100644 (file)
@@ -37,6 +37,8 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle
 
 int event_add_child_pidref(sd_event *e, sd_event_source **s, const PidRef *pid, int options, sd_event_child_handler_t callback, void *userdata);
 
+int event_source_get_child_pidref(sd_event_source *s, PidRef *ret);
+
 dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts);
 
 void event_source_unref_many(sd_event_source **array, size_t n);
index 58967930f774aa0539e273921e0b0edda61a6d9d..6f6bdde5c6627c58760ac9b89f49955dea2f25ba 100644 (file)
@@ -24,6 +24,7 @@
 #include "main-func.h"
 #include "memfd-util.h"
 #include "mkdir-label.h"
+#include "notify-util.h"
 #include "os-util.h"
 #include "process-util.h"
 #include "service-util.h"
@@ -1645,76 +1646,49 @@ static Manager *manager_free(Manager *m) {
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager *, manager_free);
 
 static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        char buf[NOTIFY_BUFFER_MAX+1];
-        struct iovec iovec = {
-                .iov_base = buf,
-                .iov_len = sizeof(buf)-1,
-        };
-        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
-        struct msghdr msghdr = {
-                .msg_iov = &iovec,
-                .msg_iovlen = 1,
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-        struct ucred *ucred;
         Manager *m = ASSERT_PTR(userdata);
-        Job *j;
-        ssize_t n;
-        char *version, *progress, *errno_str, *ready;
-
-        n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-        if (ERRNO_IS_NEG_TRANSIENT(n))
-                return 0;
-        if (n == -ECHRNG) {
-                log_warning_errno(n, "Got message with truncated control data (unexpected fds sent?), ignoring.");
-                return 0;
-        }
-        if (n == -EXFULL) {
-                log_warning_errno(n, "Got message with truncated payload data, ignoring.");
-                return 0;
-        }
-        if (n < 0)
-                return (int) n;
+        int r;
 
-        cmsg_close_all(&msghdr);
+        assert(fd >= 0);
 
-        ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
-        if (!ucred || ucred->pid <= 0) {
-                log_warning("Got notification datagram lacking credential information, ignoring.");
+        _cleanup_(pidref_done) PidRef sender_pidref = PIDREF_NULL;
+        _cleanup_free_ char *buf = NULL;
+        r = notify_recv(fd, &buf, /* ret_ucred= */ NULL, &sender_pidref);
+        if (r == -EAGAIN)
                 return 0;
-        }
+        if (r < 0)
+                return log_warning_errno(r, "Failed to receive notification message: %m");
 
+        Job *j;
         HASHMAP_FOREACH(j, m->jobs) {
-                pid_t pid;
-                assert_se(sd_event_source_get_child_pid(j->child, &pid) >= 0);
+                PidRef child_pidref = PIDREF_NULL;
+
+                r = event_source_get_child_pidref(j->child, &child_pidref);
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to get child pidref: %m");
 
-                if (ucred->pid == pid)
+                if (pidref_equal(&sender_pidref, &child_pidref))
                         break;
         }
-
         if (!j) {
                 log_warning("Got notification datagram from unexpected peer, ignoring.");
                 return 0;
         }
 
-        buf[n] = 0;
-
-        version = find_line_startswith(buf, "X_SYSUPDATE_VERSION=");
-        progress = find_line_startswith(buf, "X_SYSUPDATE_PROGRESS=");
-        errno_str = find_line_startswith(buf, "ERRNO=");
-        ready = find_line_startswith(buf, "READY=1");
-
+        char *version = find_line_startswith(buf, "X_SYSUPDATE_VERSION=");
         if (version)
                 job_on_version(j, truncate_nl(version));
 
+        char *progress = find_line_startswith(buf, "X_SYSUPDATE_PROGRESS=");
         if (progress)
                 job_on_progress(j, truncate_nl(progress));
 
+        char *errno_str = find_line_startswith(buf, "ERRNO=");
         if (errno_str)
                 job_on_errno(j, truncate_nl(errno_str));
 
         /* Should come last, since this might actually detach the job */
+        const char *ready = find_line_startswith(buf, "READY=1");
         if (ready)
                 job_on_ready(j);
 
@@ -1777,6 +1751,10 @@ static int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
+        r = setsockopt_int(notify_fd, SOL_SOCKET, SO_PASSPIDFD, true);
+        if (r < 0)
+                log_debug_errno(r, "Failed to enable SO_PASSPIDFD, ignoring: %m");
+
         r = sd_event_add_io(m->event, &m->notify_event, notify_fd, EPOLLIN, manager_on_notify, m);
         if (r < 0)
                 return r;