]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pidfd-util: introduce pidfd_info_mask_is_supported() helper function 43298/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 5 Aug 2026 17:23:16 +0000 (02:23 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 14 Aug 2026 16:35:23 +0000 (01:35 +0900)
Since kernel v6.19, ioctl(PIDFD_GET_INFO) can return the set of
supported flags when PIDFD_INFO_SUPPORTED_MASK is specified.

This allows checking whether, e.g., PIDFD_INFO_COREDUMP_SIGNAL is
supported by the running kernel.

src/basic/pidfd-util.c
src/basic/pidfd-util.h
src/test/test-pidfd-util.c

index 545d387613791a94ff4a923bad6760ce858aa0dd..f15235f5c22942b0dc57bd07401585467265b8af 100644 (file)
@@ -92,6 +92,48 @@ int pidfd_get_info(int fd, struct pidfd_info *info) {
         return 0;
 }
 
+int pidfd_info_mask_is_supported(uint64_t mask) {
+        static thread_local uint64_t cached_mask = 0;
+        static thread_local int cached = 0; /* 0 when not cached, 1 when cached, negative errno on failure. */
+        int r;
+
+        if (cached < 0)
+                return cached;
+
+        if (cached == 0) {
+                _cleanup_close_ int pidfd = r = RET_NERRNO(pidfd_open(getpid_cached(), /* flags= */ 0));
+                if (r < 0)
+                        return r;
+
+                struct pidfd_info info = {
+                        .mask = PIDFD_INFO_SUPPORTED_MASK, /* Since dfd78546c95330db2252e0d7e937a15ab5eddb4e (v6.19). */
+                };
+
+                r = pidfd_get_info(pidfd, &info);
+                if (r == -EOPNOTSUPP)
+                        return (cached = -EOPNOTSUPP);
+                if (r < 0)
+                        return r;
+
+                if (FLAGS_SET(info.mask, PIDFD_INFO_SUPPORTED_MASK) &&
+                    FLAGS_SET(info.supported_mask, PIDFD_INFO_SUPPORTED_MASK))
+                        /* The kernel is v6.19 or newer. Let's use the provided supported_mask. */
+                        cached_mask = info.supported_mask;
+                else
+                        /* The kernel is older than v6.19. These three flags have been supported since
+                         * ioctl(PIDFD_GET_INFO) was introduced, so a successful pidfd_get_info() call
+                         * guarantees they are supported. However, there is no reliable way to
+                         * determine whether PIDFD_INFO_EXIT and PIDFD_INFO_COREDUMP are supported, as
+                         * they predate PIDFD_INFO_SUPPORTED_MASK, so assume they are not. */
+                        cached_mask = PIDFD_INFO_PID | PIDFD_INFO_CREDS | PIDFD_INFO_CGROUPID;
+
+                cached = true;
+        }
+
+        /* Return true when all requested features are supported. */
+        return FLAGS_SET(cached_mask, mask);
+}
+
 static int pidfd_get_pid_fdinfo(int fd, pid_t *ret) {
         char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
         _cleanup_free_ char *p = NULL;
index d6d3e46139353654b7d4f9a671e018733b573825..2503a10efe8d29562fee7ef7148fca536706d54a 100644 (file)
@@ -8,6 +8,7 @@
 int pidfd_get_namespace(int fd, unsigned long ns_type_cmd);
 
 int pidfd_get_info(int fd, struct pidfd_info *info);
+int pidfd_info_mask_is_supported(uint64_t mask);
 
 int pidfd_get_pid(int fd, pid_t *ret);
 int pidfd_verify_pid(int pidfd, pid_t pid);
index 12e9b313348e25fdc471ea33d7db53257d79cadc..e77e6b7cbde3723f9c3d0633e01994f9374ddf36 100644 (file)
@@ -21,4 +21,45 @@ TEST(pidfd_get_inode_id_self_cached) {
         }
 }
 
+TEST(pidfd_info_mask_is_supported) {
+        int r;
+
+        r = pidfd_info_mask_is_supported(PIDFD_INFO_PID | PIDFD_INFO_CREDS | PIDFD_INFO_CGROUPID);
+        if (r > 0)
+                log_info("PIDFD_INFO_PID, PIDFD_INFO_CREDS, and PIDFD_INFO_CGROUPID are supported.");
+        else {
+                ASSERT_ERROR(r, EOPNOTSUPP);
+                log_info("ioctl(PIDFD_GET_INFO) is not supported. Maybe the kernel is older than v6.13.");
+        }
+
+        /* The flag PIDFD_INFO_EXIT itself is supported since v6.15, but we have no way to check if it is
+         * supported without PIDFD_INFO_SUPPORTED_MASK (since v6.19) (or, of course, we can check it by
+         * terminating a process...). */
+        if (ASSERT_OK_OR(pidfd_info_mask_is_supported(PIDFD_INFO_EXIT), -EOPNOTSUPP) > 0)
+                log_info("PIDFD_INFO_EXIT is supported.");
+        else
+                log_info("PIDFD_INFO_EXIT is not supported. Maybe the kernel is older than v6.19.");
+
+        /* Similar here. The flag PIDFD_INFO_COREDUMP itself is supported since v6.16. */
+        if (ASSERT_OK_OR(pidfd_info_mask_is_supported(PIDFD_INFO_COREDUMP), -EOPNOTSUPP) > 0)
+                log_info("PIDFD_INFO_COREDUMP is supported.");
+        else
+                log_info("PIDFD_INFO_COREDUMP is not supported. Maybe the kernel is older than v6.19.");
+
+        if (ASSERT_OK_OR(pidfd_info_mask_is_supported(PIDFD_INFO_SUPPORTED_MASK), -EOPNOTSUPP) > 0)
+                log_info("PIDFD_INFO_SUPPORTED_MASK is supported.");
+        else
+                log_info("PIDFD_INFO_SUPPORTED_MASK is not supported. Maybe the kernel is older than v6.19.");
+
+        if (ASSERT_OK_OR(pidfd_info_mask_is_supported(PIDFD_INFO_COREDUMP_SIGNAL), -EOPNOTSUPP) > 0)
+                log_info("PIDFD_INFO_COREDUMP_SIGNAL is supported.");
+        else
+                log_info("PIDFD_INFO_COREDUMP_SIGNAL is not supported. Maybe the kernel is older than v6.19.");
+
+        if (ASSERT_OK_OR(pidfd_info_mask_is_supported(PIDFD_INFO_COREDUMP_CODE), -EOPNOTSUPP) > 0)
+                log_info("PIDFD_INFO_COREDUMP_CODE is supported.");
+        else
+                log_info("PIDFD_INFO_COREDUMP_CODE is not supported. Maybe the kernel is older than v7.1.");
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);