162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#define _GNU_SOURCE 462306a36Sopenharmony_ci#include <err.h> 562306a36Sopenharmony_ci#include <errno.h> 662306a36Sopenharmony_ci#include <fcntl.h> 762306a36Sopenharmony_ci#include <inttypes.h> 862306a36Sopenharmony_ci#include <limits.h> 962306a36Sopenharmony_ci#include <sched.h> 1062306a36Sopenharmony_ci#include <signal.h> 1162306a36Sopenharmony_ci#include <stdio.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <sys/stat.h> 1562306a36Sopenharmony_ci#include <sys/syscall.h> 1662306a36Sopenharmony_ci#include <sys/types.h> 1762306a36Sopenharmony_ci#include <sys/wait.h> 1862306a36Sopenharmony_ci#include <unistd.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifndef CLONE_PIDFD 2162306a36Sopenharmony_ci#define CLONE_PIDFD 0x00001000 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifndef __NR_pidfd_send_signal 2562306a36Sopenharmony_ci#define __NR_pidfd_send_signal -1 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int do_child(void *args) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci printf("%d\n", getpid()); 3162306a36Sopenharmony_ci _exit(EXIT_SUCCESS); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic pid_t pidfd_clone(int flags, int *pidfd) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci size_t stack_size = 1024; 3762306a36Sopenharmony_ci char *stack[1024] = { 0 }; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#ifdef __ia64__ 4062306a36Sopenharmony_ci return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 4162306a36Sopenharmony_ci#else 4262306a36Sopenharmony_ci return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 4362306a36Sopenharmony_ci#endif 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 4762306a36Sopenharmony_ci unsigned int flags) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int pidfd_metadata_fd(pid_t pid, int pidfd) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int procfd, ret; 5562306a36Sopenharmony_ci char path[100]; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci snprintf(path, sizeof(path), "/proc/%d", pid); 5862306a36Sopenharmony_ci procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); 5962306a36Sopenharmony_ci if (procfd < 0) { 6062306a36Sopenharmony_ci warn("Failed to open %s\n", path); 6162306a36Sopenharmony_ci return -1; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* 6562306a36Sopenharmony_ci * Verify that the pid has not been recycled and our /proc/<pid> handle 6662306a36Sopenharmony_ci * is still valid. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 6962306a36Sopenharmony_ci if (ret < 0) { 7062306a36Sopenharmony_ci switch (errno) { 7162306a36Sopenharmony_ci case EPERM: 7262306a36Sopenharmony_ci /* Process exists, just not allowed to signal it. */ 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci default: 7562306a36Sopenharmony_ci warn("Failed to signal process\n"); 7662306a36Sopenharmony_ci close(procfd); 7762306a36Sopenharmony_ci procfd = -1; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return procfd; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciint main(int argc, char *argv[]) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci int pidfd = -1, ret = EXIT_FAILURE; 8762306a36Sopenharmony_ci char buf[4096] = { 0 }; 8862306a36Sopenharmony_ci pid_t pid; 8962306a36Sopenharmony_ci int procfd, statusfd; 9062306a36Sopenharmony_ci ssize_t bytes; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd); 9362306a36Sopenharmony_ci if (pid < 0) 9462306a36Sopenharmony_ci err(ret, "CLONE_PIDFD"); 9562306a36Sopenharmony_ci if (pidfd == -1) { 9662306a36Sopenharmony_ci warnx("CLONE_PIDFD is not supported by the kernel"); 9762306a36Sopenharmony_ci goto out; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci procfd = pidfd_metadata_fd(pid, pidfd); 10162306a36Sopenharmony_ci close(pidfd); 10262306a36Sopenharmony_ci if (procfd < 0) 10362306a36Sopenharmony_ci goto out; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC); 10662306a36Sopenharmony_ci close(procfd); 10762306a36Sopenharmony_ci if (statusfd < 0) 10862306a36Sopenharmony_ci goto out; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci bytes = read(statusfd, buf, sizeof(buf)); 11162306a36Sopenharmony_ci if (bytes > 0) 11262306a36Sopenharmony_ci bytes = write(STDOUT_FILENO, buf, bytes); 11362306a36Sopenharmony_ci close(statusfd); 11462306a36Sopenharmony_ci ret = EXIT_SUCCESS; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciout: 11762306a36Sopenharmony_ci (void)wait(NULL); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci exit(ret); 12062306a36Sopenharmony_ci} 121