Blame view

samples/pidfd/pidfd-metadata.c 2.33 KB
43c6afee4   Christian Brauner   samples: show rac...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  // 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
7c33277b9   Guenter Roeck   samples: fix pidf...
23
24
25
  #ifndef __NR_pidfd_send_signal
  #define __NR_pidfd_send_signal -1
  #endif
43c6afee4   Christian Brauner   samples: show rac...
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  static int do_child(void *args)
  {
  	printf("%d
  ", 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
  ", 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
  ");
  			close(procfd);
  			procfd = -1;
  		}
  	}
  
  	return procfd;
  }
  
  int main(int argc, char *argv[])
  {
bee19cd8f   Dmitry V. Levin   samples: make pid...
87
  	int pidfd = -1, ret = EXIT_FAILURE;
43c6afee4   Christian Brauner   samples: show rac...
88
89
90
91
92
93
94
  	char buf[4096] = { 0 };
  	pid_t pid;
  	int procfd, statusfd;
  	ssize_t bytes;
  
  	pid = pidfd_clone(CLONE_PIDFD, &pidfd);
  	if (pid < 0)
bee19cd8f   Dmitry V. Levin   samples: make pid...
95
96
97
98
99
  		err(ret, "CLONE_PIDFD");
  	if (pidfd == -1) {
  		warnx("CLONE_PIDFD is not supported by the kernel");
  		goto out;
  	}
43c6afee4   Christian Brauner   samples: show rac...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  
  	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);
  }