@@ -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+
110165int pidfd_verify_pid (int pidfd , pid_t pid ) {
111166 pid_t current_pid ;
112167 int r ;
0 commit comments