|  | // SPDX-License-Identifier: GPL-2.0 | 
|  |  | 
|  | #define _GNU_SOURCE | 
|  | #include <err.h> | 
|  | #include <errno.h> | 
|  | #include <fcntl.h> | 
|  | #include <inttypes.h> | 
|  | #include <limits.h> | 
|  | #include <sched.h> | 
|  | #include <signal.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/syscall.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/wait.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #ifndef CLONE_PIDFD | 
|  | #define CLONE_PIDFD 0x00001000 | 
|  | #endif | 
|  |  | 
|  | #ifndef __NR_pidfd_send_signal | 
|  | #define __NR_pidfd_send_signal -1 | 
|  | #endif | 
|  |  | 
|  | static int do_child(void *args) | 
|  | { | 
|  | printf("%d\n", getpid()); | 
|  | _exit(EXIT_SUCCESS); | 
|  | } | 
|  |  | 
|  | static pid_t pidfd_clone(int flags, int *pidfd) | 
|  | { | 
|  | size_t stack_size = 1024; | 
|  | char *stack[1024] = { 0 }; | 
|  |  | 
|  | #ifdef __ia64__ | 
|  | return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd); | 
|  | #else | 
|  | return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, | 
|  | unsigned int flags) | 
|  | { | 
|  | return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); | 
|  | } | 
|  |  | 
|  | static int pidfd_metadata_fd(pid_t pid, int pidfd) | 
|  | { | 
|  | int procfd, ret; | 
|  | char path[100]; | 
|  |  | 
|  | snprintf(path, sizeof(path), "/proc/%d", pid); | 
|  | procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); | 
|  | if (procfd < 0) { | 
|  | warn("Failed to open %s\n", path); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Verify that the pid has not been recycled and our /proc/<pid> handle | 
|  | * is still valid. | 
|  | */ | 
|  | ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); | 
|  | if (ret < 0) { | 
|  | switch (errno) { | 
|  | case EPERM: | 
|  | /* Process exists, just not allowed to signal it. */ | 
|  | break; | 
|  | default: | 
|  | warn("Failed to signal process\n"); | 
|  | close(procfd); | 
|  | procfd = -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return procfd; | 
|  | } | 
|  |  | 
|  | int main(int argc, char *argv[]) | 
|  | { | 
|  | int pidfd = -1, ret = EXIT_FAILURE; | 
|  | char buf[4096] = { 0 }; | 
|  | pid_t pid; | 
|  | int procfd, statusfd; | 
|  | ssize_t bytes; | 
|  |  | 
|  | pid = pidfd_clone(CLONE_PIDFD, &pidfd); | 
|  | if (pid < 0) | 
|  | err(ret, "CLONE_PIDFD"); | 
|  | if (pidfd == -1) { | 
|  | warnx("CLONE_PIDFD is not supported by the kernel"); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | procfd = pidfd_metadata_fd(pid, pidfd); | 
|  | close(pidfd); | 
|  | if (procfd < 0) | 
|  | goto out; | 
|  |  | 
|  | statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC); | 
|  | close(procfd); | 
|  | if (statusfd < 0) | 
|  | goto out; | 
|  |  | 
|  | bytes = read(statusfd, buf, sizeof(buf)); | 
|  | if (bytes > 0) | 
|  | bytes = write(STDOUT_FILENO, buf, bytes); | 
|  | close(statusfd); | 
|  | ret = EXIT_SUCCESS; | 
|  |  | 
|  | out: | 
|  | (void)wait(NULL); | 
|  |  | 
|  | exit(ret); | 
|  | } |