231 lines
6.2 KiB
Diff
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)
|