pidfd: introduce pidfd_info_mask_is_supported() (#43298)
The helper is currently unused. But should be useful for checking the kernel features. It will be used in systemd-coredump.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -171,6 +171,7 @@ simple_tests += files(
|
||||
'test-path-lookup.c',
|
||||
'test-path-util.c',
|
||||
'test-percent-util.c',
|
||||
'test-pidfd-util.c',
|
||||
'test-pidref.c',
|
||||
'test-plymouth-util.c',
|
||||
'test-pressure.c',
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "format-util.h"
|
||||
#include "pidfd-util.h"
|
||||
#include "process-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(pidfd_get_inode_id_self_cached) {
|
||||
int r;
|
||||
|
||||
log_info("pid=" PID_FMT, getpid_cached());
|
||||
|
||||
uint64_t id;
|
||||
r = pidfd_get_inode_id_self_cached(&id);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
log_info("pidfdid not supported");
|
||||
else {
|
||||
assert(r >= 0);
|
||||
log_info("pidfdid=%" PRIu64, id);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "log.h"
|
||||
#include "namespace-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "pidfd-util.h"
|
||||
#include "pidref.h"
|
||||
#include "process-util.h"
|
||||
#include "procfs-util.h"
|
||||
@@ -1075,21 +1074,6 @@ TEST(pidref_from_same_root_fs) {
|
||||
ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2, &self));
|
||||
}
|
||||
|
||||
TEST(pidfd_get_inode_id_self_cached) {
|
||||
int r;
|
||||
|
||||
log_info("pid=" PID_FMT, getpid_cached());
|
||||
|
||||
uint64_t id;
|
||||
r = pidfd_get_inode_id_self_cached(&id);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
log_info("pidfdid not supported");
|
||||
else {
|
||||
assert(r >= 0);
|
||||
log_info("pidfdid=%" PRIu64, id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(getenv_for_pid) {
|
||||
_cleanup_strv_free_ char **copy_env = NULL;
|
||||
pid_t pid = getpid_cached();
|
||||
|
||||
Reference in New Issue
Block a user