18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci#include <err.h> 58c2ecf20Sopenharmony_ci#include <errno.h> 68c2ecf20Sopenharmony_ci#include <fcntl.h> 78c2ecf20Sopenharmony_ci#include <inttypes.h> 88c2ecf20Sopenharmony_ci#include <limits.h> 98c2ecf20Sopenharmony_ci#include <sched.h> 108c2ecf20Sopenharmony_ci#include <signal.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <sys/stat.h> 158c2ecf20Sopenharmony_ci#include <sys/syscall.h> 168c2ecf20Sopenharmony_ci#include <sys/types.h> 178c2ecf20Sopenharmony_ci#include <sys/wait.h> 188c2ecf20Sopenharmony_ci#include <unistd.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifndef CLONE_PIDFD 218c2ecf20Sopenharmony_ci#define CLONE_PIDFD 0x00001000 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#ifndef __NR_pidfd_send_signal 258c2ecf20Sopenharmony_ci#define __NR_pidfd_send_signal -1 268c2ecf20Sopenharmony_ci#endif 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int do_child(void *args) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci printf("%d\n", getpid()); 318c2ecf20Sopenharmony_ci _exit(EXIT_SUCCESS); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic pid_t pidfd_clone(int flags, int *pidfd) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci size_t stack_size = 1024; 378c2ecf20Sopenharmony_ci char *stack[1024] = { 0 }; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#ifdef __ia64__ 408c2ecf20Sopenharmony_ci return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd); 418c2ecf20Sopenharmony_ci#else 428c2ecf20Sopenharmony_ci return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd); 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info, 478c2ecf20Sopenharmony_ci unsigned int flags) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int pidfd_metadata_fd(pid_t pid, int pidfd) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int procfd, ret; 558c2ecf20Sopenharmony_ci char path[100]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci snprintf(path, sizeof(path), "/proc/%d", pid); 588c2ecf20Sopenharmony_ci procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); 598c2ecf20Sopenharmony_ci if (procfd < 0) { 608c2ecf20Sopenharmony_ci warn("Failed to open %s\n", path); 618c2ecf20Sopenharmony_ci return -1; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* 658c2ecf20Sopenharmony_ci * Verify that the pid has not been recycled and our /proc/<pid> handle 668c2ecf20Sopenharmony_ci * is still valid. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); 698c2ecf20Sopenharmony_ci if (ret < 0) { 708c2ecf20Sopenharmony_ci switch (errno) { 718c2ecf20Sopenharmony_ci case EPERM: 728c2ecf20Sopenharmony_ci /* Process exists, just not allowed to signal it. */ 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci default: 758c2ecf20Sopenharmony_ci warn("Failed to signal process\n"); 768c2ecf20Sopenharmony_ci close(procfd); 778c2ecf20Sopenharmony_ci procfd = -1; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return procfd; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int pidfd = -1, ret = EXIT_FAILURE; 878c2ecf20Sopenharmony_ci char buf[4096] = { 0 }; 888c2ecf20Sopenharmony_ci pid_t pid; 898c2ecf20Sopenharmony_ci int procfd, statusfd; 908c2ecf20Sopenharmony_ci ssize_t bytes; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pid = pidfd_clone(CLONE_PIDFD, &pidfd); 938c2ecf20Sopenharmony_ci if (pid < 0) 948c2ecf20Sopenharmony_ci err(ret, "CLONE_PIDFD"); 958c2ecf20Sopenharmony_ci if (pidfd == -1) { 968c2ecf20Sopenharmony_ci warnx("CLONE_PIDFD is not supported by the kernel"); 978c2ecf20Sopenharmony_ci goto out; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci procfd = pidfd_metadata_fd(pid, pidfd); 1018c2ecf20Sopenharmony_ci close(pidfd); 1028c2ecf20Sopenharmony_ci if (procfd < 0) 1038c2ecf20Sopenharmony_ci goto out; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC); 1068c2ecf20Sopenharmony_ci close(procfd); 1078c2ecf20Sopenharmony_ci if (statusfd < 0) 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci bytes = read(statusfd, buf, sizeof(buf)); 1118c2ecf20Sopenharmony_ci if (bytes > 0) 1128c2ecf20Sopenharmony_ci bytes = write(STDOUT_FILENO, buf, bytes); 1138c2ecf20Sopenharmony_ci close(statusfd); 1148c2ecf20Sopenharmony_ci ret = EXIT_SUCCESS; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciout: 1178c2ecf20Sopenharmony_ci (void)wait(NULL); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci exit(ret); 1208c2ecf20Sopenharmony_ci} 121