From: Lennart Poettering Date: Mon, 17 Feb 2025 10:50:15 +0000 (+0100) Subject: sysupdated: port to notify_recv() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a17da0737574e68e9e69eba947ee1937285977d2;p=thirdparty%2Fsystemd.git sysupdated: port to notify_recv() --- diff --git a/src/libsystemd/sd-event/event-util.c b/src/libsystemd/sd-event/event-util.c index 42e973564e3..81745812dc8 100644 --- a/src/libsystemd/sd-event/event-util.c +++ b/src/libsystemd/sd-event/event-util.c @@ -2,6 +2,7 @@ #include +#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); diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h index 383b4c82b7c..2c6fcccb908 100644 --- a/src/libsystemd/sd-event/event-util.h +++ b/src/libsystemd/sd-event/event-util.h @@ -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); diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 58967930f77..6f6bdde5c66 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -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;