]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pidfd-util: introduce helper for obtaining ns fd using PIDFD_GET_*_NAMESPACE directly
authorMike Yuan <me@yhndnzj.com>
Tue, 19 Nov 2024 23:14:12 +0000 (00:14 +0100)
committerMike Yuan <me@yhndnzj.com>
Sat, 4 Jan 2025 16:07:59 +0000 (17:07 +0100)
src/basic/pidfd-util.c
src/basic/pidfd-util.h

index 53f2a688a740717c49b8a807df5694c1ee0e539e..c29173471b43b748c3abd8e1a00fccfecfba7775 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <sys/ioctl.h>
 #include <unistd.h>
 
 #include "errno-util.h"
@@ -33,6 +34,40 @@ static int pidfd_check_pidfs(void) {
         return (have_pidfs = fd_is_fs_type(fd, PID_FS_MAGIC));
 }
 
+int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) {
+        static bool cached_supported = true;
+
+        /* Obtain the namespace fd from pidfd directly through ioctl(PIDFD_GET_*_NAMESPACE).
+         *
+         * Returns -EOPNOTSUPP if ioctl on pidfds are not supported, -ENOPKG if the requested namespace
+         * is disabled in kernel. (The errno used are different from what kernel returns via ioctl(),
+         * see below) */
+
+        assert(fd >= 0);
+
+        /* If we know ahead of time that pidfs is unavailable, shortcut things. But otherwise we don't
+         * call pidfd_check_pidfs() here, which is kinda extraneous and our own cache is required
+         * anyways (pidfs is introduced in kernel 6.9 while ioctl support there is added in 6.11). */
+        if (have_pidfs == 0 || !cached_supported)
+                return -EOPNOTSUPP;
+
+        int nsfd = ioctl(fd, ns_type_cmd);
+        if (nsfd < 0) {
+                /* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look
+                 * at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */
+                if (IN_SET(errno, ENOTTY, EINVAL)) {
+                        cached_supported = false;
+                        return -EOPNOTSUPP;
+                }
+                if (errno == EOPNOTSUPP) /* Translate to something more recognizable */
+                        return -ENOPKG;
+
+                return -errno;
+        }
+
+        return nsfd;
+}
+
 int pidfd_get_pid(int fd, pid_t *ret) {
         char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
         _cleanup_free_ char *fdinfo = NULL;
index 4db9368e4072bae215752863646a2c95ad68808d..2ffece0c4fe6d1682abae7a107c5ab134cb1d889 100644 (file)
@@ -7,6 +7,8 @@
 #include "missing_pidfd.h"
 #include "missing_syscall.h"
 
+int pidfd_get_namespace(int fd, unsigned long ns_type_cmd);
+
 int pidfd_get_pid(int fd, pid_t *ret);
 int pidfd_verify_pid(int pidfd, pid_t pid);