Skip to content

Commit dcf0ef3

Browse files
committed
pidfd-util: try to translate pidfd -> pid through ioctl(PIDFD_GET_INFO)
1 parent 92b8e5e commit dcf0ef3

1 file changed

Lines changed: 65 additions & 10 deletions

File tree

src/basic/pidfd-util.c

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,32 @@ int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) {
6868
return nsfd;
6969
}
7070

71-
int pidfd_get_pid(int fd, pid_t *ret) {
71+
static int pidfd_get_info(int fd, struct pidfd_info *info) {
72+
static bool cached_supported = true;
73+
74+
assert(fd >= 0);
75+
assert(info);
76+
77+
if (have_pidfs == 0 || !cached_supported)
78+
return -EOPNOTSUPP;
79+
80+
if (ioctl(fd, PIDFD_GET_INFO, info) < 0) {
81+
if (ERRNO_IS_IOCTL_NOT_SUPPORTED(errno)) {
82+
cached_supported = false;
83+
return -EOPNOTSUPP;
84+
}
85+
86+
return -errno;
87+
}
88+
89+
return 0;
90+
}
91+
92+
static int pidfd_get_pid_fdinfo(int fd, pid_t *ret) {
7293
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
7394
_cleanup_free_ char *fdinfo = NULL;
7495
int r;
7596

76-
/* Converts a pidfd into a pid. Well known errors:
77-
*
78-
* -EBADF → fd invalid
79-
* -ENOSYS → /proc/ not mounted
80-
* -ENOTTY → fd valid, but not a pidfd
81-
* -EREMOTE → fd valid, but pid is in another namespace we cannot translate to the local one
82-
* -ESRCH → fd valid, but process is already reaped
83-
*/
84-
8597
assert(fd >= 0);
8698

8799
xsprintf(path, "/proc/self/fdinfo/%i", fd);
@@ -107,6 +119,49 @@ int pidfd_get_pid(int fd, pid_t *ret) {
107119
return parse_pid(p, ret);
108120
}
109121

122+
static int pidfd_get_pid_ioctl(int fd, pid_t *ret) {
123+
struct pidfd_info info = { .mask = PIDFD_INFO_PID };
124+
int r;
125+
126+
assert(fd >= 0);
127+
128+
r = pidfd_get_info(fd, &info);
129+
if (r < 0)
130+
return r;
131+
132+
assert(FLAGS_SET(info.mask, PIDFD_INFO_PID));
133+
134+
if (ret)
135+
*ret = info.pid;
136+
return 0;
137+
}
138+
139+
int pidfd_get_pid(int fd, pid_t *ret) {
140+
int r;
141+
142+
/* Converts a pidfd into a pid. We try ioctl(PIDFD_GET_INFO) (kernel 6.13+) first,
143+
* /proc/self/fdinfo/ as fallback. Well known errors:
144+
*
145+
* -EBADF → fd invalid
146+
* -ESRCH → fd valid, but process is already reaped
147+
*
148+
* pidfd_get_pid_fdinfo() might additionally fail for other reasons:
149+
*
150+
* -ENOSYS → /proc/ not mounted
151+
* -ENOTTY → fd valid, but not a pidfd
152+
* -EREMOTE → fd valid, but pid is in another namespace we cannot translate to the local one
153+
* (when using PIDFD_GET_INFO this is indistinguishable from -ESRCH)
154+
*/
155+
156+
assert(fd >= 0);
157+
158+
r = pidfd_get_pid_ioctl(fd, ret);
159+
if (r != -EOPNOTSUPP)
160+
return r;
161+
162+
return pidfd_get_pid_fdinfo(fd, ret);
163+
}
164+
110165
int pidfd_verify_pid(int pidfd, pid_t pid) {
111166
pid_t current_pid;
112167
int r;

0 commit comments

Comments
 (0)