xref: /openbmc/linux/samples/pidfd/pidfd-metadata.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
143c6afeeSChristian Brauner // SPDX-License-Identifier: GPL-2.0
243c6afeeSChristian Brauner 
343c6afeeSChristian Brauner #define _GNU_SOURCE
443c6afeeSChristian Brauner #include <err.h>
543c6afeeSChristian Brauner #include <errno.h>
643c6afeeSChristian Brauner #include <fcntl.h>
743c6afeeSChristian Brauner #include <inttypes.h>
843c6afeeSChristian Brauner #include <limits.h>
943c6afeeSChristian Brauner #include <sched.h>
1043c6afeeSChristian Brauner #include <signal.h>
1143c6afeeSChristian Brauner #include <stdio.h>
1243c6afeeSChristian Brauner #include <stdlib.h>
1343c6afeeSChristian Brauner #include <string.h>
1443c6afeeSChristian Brauner #include <sys/stat.h>
1543c6afeeSChristian Brauner #include <sys/syscall.h>
1643c6afeeSChristian Brauner #include <sys/types.h>
1743c6afeeSChristian Brauner #include <sys/wait.h>
1843c6afeeSChristian Brauner #include <unistd.h>
1943c6afeeSChristian Brauner 
2043c6afeeSChristian Brauner #ifndef CLONE_PIDFD
2143c6afeeSChristian Brauner #define CLONE_PIDFD 0x00001000
2243c6afeeSChristian Brauner #endif
2343c6afeeSChristian Brauner 
247c33277bSGuenter Roeck #ifndef __NR_pidfd_send_signal
257c33277bSGuenter Roeck #define __NR_pidfd_send_signal -1
267c33277bSGuenter Roeck #endif
277c33277bSGuenter Roeck 
do_child(void * args)2843c6afeeSChristian Brauner static int do_child(void *args)
2943c6afeeSChristian Brauner {
3043c6afeeSChristian Brauner 	printf("%d\n", getpid());
3143c6afeeSChristian Brauner 	_exit(EXIT_SUCCESS);
3243c6afeeSChristian Brauner }
3343c6afeeSChristian Brauner 
pidfd_clone(int flags,int * pidfd)3443c6afeeSChristian Brauner static pid_t pidfd_clone(int flags, int *pidfd)
3543c6afeeSChristian Brauner {
3643c6afeeSChristian Brauner 	size_t stack_size = 1024;
3743c6afeeSChristian Brauner 	char *stack[1024] = { 0 };
3843c6afeeSChristian Brauner 
3943c6afeeSChristian Brauner #ifdef __ia64__
4043c6afeeSChristian Brauner 	return __clone2(do_child, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
4143c6afeeSChristian Brauner #else
4243c6afeeSChristian Brauner 	return clone(do_child, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
4343c6afeeSChristian Brauner #endif
4443c6afeeSChristian Brauner }
4543c6afeeSChristian Brauner 
sys_pidfd_send_signal(int pidfd,int sig,siginfo_t * info,unsigned int flags)4643c6afeeSChristian Brauner static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
4743c6afeeSChristian Brauner 					unsigned int flags)
4843c6afeeSChristian Brauner {
4943c6afeeSChristian Brauner 	return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
5043c6afeeSChristian Brauner }
5143c6afeeSChristian Brauner 
pidfd_metadata_fd(pid_t pid,int pidfd)5243c6afeeSChristian Brauner static int pidfd_metadata_fd(pid_t pid, int pidfd)
5343c6afeeSChristian Brauner {
5443c6afeeSChristian Brauner 	int procfd, ret;
5543c6afeeSChristian Brauner 	char path[100];
5643c6afeeSChristian Brauner 
5743c6afeeSChristian Brauner 	snprintf(path, sizeof(path), "/proc/%d", pid);
5843c6afeeSChristian Brauner 	procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
5943c6afeeSChristian Brauner 	if (procfd < 0) {
6043c6afeeSChristian Brauner 		warn("Failed to open %s\n", path);
6143c6afeeSChristian Brauner 		return -1;
6243c6afeeSChristian Brauner 	}
6343c6afeeSChristian Brauner 
6443c6afeeSChristian Brauner 	/*
6543c6afeeSChristian Brauner 	 * Verify that the pid has not been recycled and our /proc/<pid> handle
6643c6afeeSChristian Brauner 	 * is still valid.
6743c6afeeSChristian Brauner 	 */
6843c6afeeSChristian Brauner 	ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0);
6943c6afeeSChristian Brauner 	if (ret < 0) {
7043c6afeeSChristian Brauner 		switch (errno) {
7143c6afeeSChristian Brauner 		case EPERM:
7243c6afeeSChristian Brauner 			/* Process exists, just not allowed to signal it. */
7343c6afeeSChristian Brauner 			break;
7443c6afeeSChristian Brauner 		default:
7543c6afeeSChristian Brauner 			warn("Failed to signal process\n");
7643c6afeeSChristian Brauner 			close(procfd);
7743c6afeeSChristian Brauner 			procfd = -1;
7843c6afeeSChristian Brauner 		}
7943c6afeeSChristian Brauner 	}
8043c6afeeSChristian Brauner 
8143c6afeeSChristian Brauner 	return procfd;
8243c6afeeSChristian Brauner }
8343c6afeeSChristian Brauner 
main(int argc,char * argv[])8443c6afeeSChristian Brauner int main(int argc, char *argv[])
8543c6afeeSChristian Brauner {
86*bee19cd8SDmitry V. Levin 	int pidfd = -1, ret = EXIT_FAILURE;
8743c6afeeSChristian Brauner 	char buf[4096] = { 0 };
8843c6afeeSChristian Brauner 	pid_t pid;
8943c6afeeSChristian Brauner 	int procfd, statusfd;
9043c6afeeSChristian Brauner 	ssize_t bytes;
9143c6afeeSChristian Brauner 
9243c6afeeSChristian Brauner 	pid = pidfd_clone(CLONE_PIDFD, &pidfd);
9343c6afeeSChristian Brauner 	if (pid < 0)
94*bee19cd8SDmitry V. Levin 		err(ret, "CLONE_PIDFD");
95*bee19cd8SDmitry V. Levin 	if (pidfd == -1) {
96*bee19cd8SDmitry V. Levin 		warnx("CLONE_PIDFD is not supported by the kernel");
97*bee19cd8SDmitry V. Levin 		goto out;
98*bee19cd8SDmitry V. Levin 	}
9943c6afeeSChristian Brauner 
10043c6afeeSChristian Brauner 	procfd = pidfd_metadata_fd(pid, pidfd);
10143c6afeeSChristian Brauner 	close(pidfd);
10243c6afeeSChristian Brauner 	if (procfd < 0)
10343c6afeeSChristian Brauner 		goto out;
10443c6afeeSChristian Brauner 
10543c6afeeSChristian Brauner 	statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC);
10643c6afeeSChristian Brauner 	close(procfd);
10743c6afeeSChristian Brauner 	if (statusfd < 0)
10843c6afeeSChristian Brauner 		goto out;
10943c6afeeSChristian Brauner 
11043c6afeeSChristian Brauner 	bytes = read(statusfd, buf, sizeof(buf));
11143c6afeeSChristian Brauner 	if (bytes > 0)
11243c6afeeSChristian Brauner 		bytes = write(STDOUT_FILENO, buf, bytes);
11343c6afeeSChristian Brauner 	close(statusfd);
11443c6afeeSChristian Brauner 	ret = EXIT_SUCCESS;
11543c6afeeSChristian Brauner 
11643c6afeeSChristian Brauner out:
11743c6afeeSChristian Brauner 	(void)wait(NULL);
11843c6afeeSChristian Brauner 
11943c6afeeSChristian Brauner 	exit(ret);
12043c6afeeSChristian Brauner }
121