systemd/1281-pidref-add-structure-that-can-reference-a-pid-via-bo.patch
Jan Macku a673ceed38 systemd-252-60
Resolves: RHEL-115182,RHEL-97175,RHEL-107268
2025-11-05 09:44:11 +01:00

231 lines
6.2 KiB
Diff

From e638eb667af0e8ac9d3d409edbbf51507a4eef0e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Sat, 9 Sep 2023 09:29:27 +0200
Subject: [PATCH] pidref: add structure that can reference a pid via both pidfd
and pid_t
Let's start with the conversion of PID 1 to pidfds. Let's add a simple
structure with just two fields that can be used to maintain a reference
to arbitrary processes via both pid_t and pidfd.
This is an embeddable struct, to keep it in line with where we
previously used a pid_t directly to track a process.
Of course, since this might contain an fd on systems where we have pidfd
this structure has a proper lifecycle.
(Note that this is quite different from sd_event_add_child() event
source objects as that one is only for child processes and collects
process results, while this infra is much simpler and more generic and
can be used to reference any process, anywhere in the tree.)
(cherry picked from commit 3bda3f17fa84557eeb28fa7c330cbd3a3f876d47)
Related: RHEL-104138
---
src/basic/meson.build | 1 +
src/basic/pidref.c | 145 ++++++++++++++++++++++++++++++++++++++++++
src/basic/pidref.h | 29 +++++++++
3 files changed, 175 insertions(+)
create mode 100644 src/basic/pidref.c
create mode 100644 src/basic/pidref.h
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 11053a5ecd..b8b4213c70 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -182,6 +182,7 @@ basic_sources = files(
'path-util.h',
'percent-util.c',
'percent-util.h',
+ 'pidref.c',
'prioq.c',
'prioq.h',
'proc-cmdline.c',
diff --git a/src/basic/pidref.c b/src/basic/pidref.c
new file mode 100644
index 0000000000..f41460938c
--- /dev/null
+++ b/src/basic/pidref.c
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "missing_syscall.h"
+#include "parse-util.h"
+#include "pidref.h"
+#include "process-util.h"
+
+int pidref_set_pid(PidRef *pidref, pid_t pid) {
+ int fd;
+
+ assert(pidref);
+
+ if (pid < 0)
+ return -ESRCH;
+ if (pid == 0)
+ pid = getpid_cached();
+
+ fd = pidfd_open(pid, 0);
+ if (fd < 0) {
+ /* Graceful fallback in case the kernel doesn't support pidfds or is out of fds */
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_RESOURCE(errno))
+ return -errno;
+
+ fd = -EBADF;
+ }
+
+ *pidref = (PidRef) {
+ .fd = fd,
+ .pid = pid,
+ };
+
+ return 0;
+}
+
+int pidref_set_pidstr(PidRef *pidref, const char *pid) {
+ pid_t nr;
+ int r;
+
+ assert(pidref);
+
+ r = parse_pid(pid, &nr);
+ if (r < 0)
+ return r;
+
+ return pidref_set_pid(pidref, nr);
+}
+
+int pidref_set_pidfd(PidRef *pidref, int fd) {
+ int r;
+
+ assert(pidref);
+
+ if (fd < 0)
+ return -EBADF;
+
+ int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (fd_copy < 0) {
+ pid_t pid;
+
+ if (!ERRNO_IS_RESOURCE(errno))
+ return -errno;
+
+ /* Graceful fallback if we are out of fds */
+ r = pidfd_get_pid(fd, &pid);
+ if (r < 0)
+ return r;
+
+ *pidref = (PidRef) {
+ .fd = -EBADF,
+ .pid = pid,
+ };
+
+ return 0;
+ }
+
+ return pidref_set_pidfd_consume(pidref, fd_copy);
+}
+
+int pidref_set_pidfd_take(PidRef *pidref, int fd) {
+ pid_t pid;
+ int r;
+
+ assert(pidref);
+
+ if (fd < 0)
+ return -EBADF;
+
+ r = pidfd_get_pid(fd, &pid);
+ if (r < 0)
+ return r;
+
+ *pidref = (PidRef) {
+ .fd = fd,
+ .pid = pid,
+ };
+
+ return 0;
+}
+
+int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
+ int r;
+
+ r = pidref_set_pidfd_take(pidref, fd);
+ if (r < 0)
+ safe_close(fd);
+
+ return r;
+}
+
+void pidref_done(PidRef *pidref) {
+ assert(pidref);
+
+ *pidref = (PidRef) {
+ .fd = safe_close(pidref->fd),
+ };
+}
+
+int pidref_kill(PidRef *pidref, int sig) {
+
+ if (!pidref)
+ return -ESRCH;
+
+ if (pidref->fd >= 0)
+ return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
+
+ if (pidref->pid > 0)
+ return RET_NERRNO(kill(pidref->pid, sig));
+
+ return -ESRCH;
+}
+
+int pidref_kill_and_sigcont(PidRef *pidref, int sig) {
+ int r;
+
+ r = pidref_kill(pidref, sig);
+ if (r < 0)
+ return r;
+
+ if (!IN_SET(sig, SIGCONT, SIGKILL))
+ (void) pidref_kill(pidref, SIGCONT);
+
+ return 0;
+}
diff --git a/src/basic/pidref.h b/src/basic/pidref.h
new file mode 100644
index 0000000000..2411e510f1
--- /dev/null
+++ b/src/basic/pidref.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "macro.h"
+
+/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continously. */
+typedef struct PidRef {
+ pid_t pid; /* always valid */
+ int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd */
+} PidRef;
+
+#define PIDREF_NULL (PidRef) { .fd = -EBADF }
+
+static inline bool pidref_is_set(const PidRef *pidref) {
+ return pidref && pidref->pid > 0;
+}
+
+int pidref_set_pid(PidRef *pidref, pid_t pid);
+int pidref_set_pidstr(PidRef *pidref, const char *pid);
+int pidref_set_pidfd(PidRef *pidref, int fd);
+int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success*/
+int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */
+
+void pidref_done(PidRef *pidref);
+
+int pidref_kill(PidRef *pidref, int sig);
+int pidref_kill_and_sigcont(PidRef *pidref, int sig);
+
+#define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL)