I've looked into the man pages, and there's basically nothing that explains anything, and my web searching has failed.
Man pages for pidfd_*
:
pidfd_open
syscall: https://man7.org/linux/man-pages/man2/pidfd_open.2.htmlpidfd_send_signal
syscall: https://man7.org/linux/man-pages/man2/pidfd_send_signal.2.htmlpidfd_getfd
syscall: https://man7.org/linux/man-pages/man2/pidfd_getfd.2.htmlI've also looked through other man pages that could have been relevant:
clone3
syscall: https://man7.org/linux/man-pages/man2/clone3.2.htmlwaitid
syscall: https://man7.org/linux/man-pages/man2/waitid.2.htmlpoll
syscall: https://man7.org/linux/man-pages/man2/poll.2.htmlselect
syscall: https://man7.org/linux/man-pages/man2/select.2.htmlUpdate: I also tried dereferencing the /proc/self/fd/<PID_FD>
symlink, but unfortunately, it just returns anon_inode:[pidfd]
, which is entirely unhelpful. I initially specified that as an answer, but I later found readlink /proc/self/fd/<PID_FD>
wasn't returning the same as readlink /proc/$PID/fd/<PID_FD>
, and so I deleted it. If someone can help me out here, bounty's open!
/proc/self/fdinfo contains information about all file descriptors opened by the current process.
For example, if pidfd is 3, then cat /proc/self/fdinfo/3
can give following information:
pos: 0
flags: 02000002
mnt_id: 15
ino: 8404
Pid: 440
NSpid: 440
where Pid is what we are looking for.
Here is one implementation of get_pid_for_pidfd
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#define ENOENT 2
#define ERANGE 34
int errno;
static int parse_pid(const char *str, pid_t *pid) {
unsigned long long int v; char *end; pid_t p;
errno = 0;
v = strtoull(str, &end, 0);
if (end == str) return -ENOENT;
else if (errno != 0) return -errno;
p = (pid_t)v;
if (p < 1 || (unsigned long long int)p != v) return -ERANGE;
if (pid) *pid = p;
return 0;
}
static int parse_status_field_pid(const char *val, pid_t *pid) {
const char *t = strrchr(val, '\t');
if (t == NULL) return -ENOENT;
return parse_pid(t, pid);
}
static int get_pid_for_pidfd(int pidfd, pid_t *pid) {
char *key = NULL; char *val = NULL; char name[256] = { 0, }; int found = 0;
FILE *f = NULL; size_t keylen = 0; size_t vallen = 0; ssize_t n; int fd; int r = 0;
int fdinfo = open("/proc/self/fdinfo", O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
*pid = 0;
snprintf(name, 256, "%d", pidfd);
fd = openat(fdinfo, name, O_RDONLY | O_CLOEXEC | O_NOCTTY);
if (fd != -1) f = fdopen(fd, "r");
if (f == NULL) return -errno;
do { n = getdelim(&key, &keylen, ':', f);
if (n == -1) { r = errno; break; }
n = getdelim(&val, &vallen, '\n', f);
if (n == -1) { r = errno; break; }
if (!strncmp(key, "Pid", 3)) { r = parse_status_field_pid(val, pid); found = r > -1; }
} while (r == 0 && !found);
fclose(f);
if (r < 0) return r; else if (!found) return -ENOENT;
return 0;
}
int main(int argc, char *argv[]) {
int pidfd; pid_t pid;
pidfd = syscall(SYS_pidfd_open, atoi(argv[1]), 0);
if (pidfd == -1) { perror("pidfd_open"); exit(EXIT_FAILURE); }
if (get_pid_for_pidfd(pidfd, &pid) == 0)
printf("Input PID is %s, PID returned by get_pid_for_pidfd is %d\n", argv[1], pid);
}
Compile with :
gcc -o main main.c
Test with :
./main $$