1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <err.h> 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <inttypes.h> 8 #include <limits.h> 9 #include <sched.h> 10 #include <signal.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <sys/stat.h> 15 #include <sys/syscall.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <unistd.h> 19 20 #ifndef CLONE_PIDFD 21 #define CLONE_PIDFD 0x00001000 22 #endif 23 24 static int do_child(void *args) 25 { 26 printf("%d\n", getpid()); 27 _exit(EXIT_SUCCESS); 28 } 29 30 static pid_t pidfd_clone(int flags, int *pidfd) 31 { 32 size_t stack_size = 1024; 33 char *stack[1024] = { 0 }; 34 35 #ifdef __ia64__ 36 return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 37 #else 38 return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 39 #endif 40 } 41 42 static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 43 unsigned int flags) 44 { 45 return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 46 } 47 48 static int pidfd_metadata_fd(pid_t pid, int pidfd) 49 { 50 int procfd, ret; 51 char path[100]; 52 53 snprintf(path, sizeof(path), "/proc/%d", pid); 54 procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); 55 if (procfd < 0) { 56 warn("Failed to open %s\n", path); 57 return -1; 58 } 59 60 /* 61 * Verify that the pid has not been recycled and our /proc/<pid> handle 62 * is still valid. 63 */ 64 ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 65 if (ret < 0) { 66 switch (errno) { 67 case EPERM: 68 /* Process exists, just not allowed to signal it. */ 69 break; 70 default: 71 warn("Failed to signal process\n"); 72 close(procfd); 73 procfd = -1; 74 } 75 } 76 77 return procfd; 78 } 79 80 int main(int argc, char *argv[]) 81 { 82 int pidfd = 0, ret = EXIT_FAILURE; 83 char buf[4096] = { 0 }; 84 pid_t pid; 85 int procfd, statusfd; 86 ssize_t bytes; 87 88 pid = pidfd_clone(CLONE_PIDFD, &pidfd); 89 if (pid < 0) 90 exit(ret); 91 92 procfd = pidfd_metadata_fd(pid, pidfd); 93 close(pidfd); 94 if (procfd < 0) 95 goto out; 96 97 statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC); 98 close(procfd); 99 if (statusfd < 0) 100 goto out; 101 102 bytes = read(statusfd, buf, sizeof(buf)); 103 if (bytes > 0) 104 bytes = write(STDOUT_FILENO, buf, bytes); 105 close(statusfd); 106 ret = EXIT_SUCCESS; 107 108 out: 109 (void)wait(NULL); 110 111 exit(ret); 112 } 113