]>
Commit | Line | Data |
---|---|---|
882d6e17 | 1 | /* Tests for posix_spawn signal handling. |
581c785b | 2 | Copyright (C) 2021-2022 Free Software Foundation, Inc. |
882d6e17 AZ |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <stdio.h> | |
20 | #include <stdlib.h> | |
21 | #include <getopt.h> | |
22 | #include <spawn.h> | |
23 | #include <fcntl.h> | |
24 | #include <sys/wait.h> | |
25 | #include <dirent.h> | |
26 | #include <stdbool.h> | |
27 | #include <errno.h> | |
28 | #include <limits.h> | |
29 | ||
30 | #include <support/check.h> | |
31 | #include <support/xunistd.h> | |
32 | #include <support/support.h> | |
33 | ||
34 | #include <arch-fd_to_filename.h> | |
35 | #include <array_length.h> | |
36 | ||
37 | /* Nonzero if the program gets called via `exec'. */ | |
38 | static int restart; | |
39 | ||
40 | /* Hold the four initial argument used to respawn the process, plus | |
41 | the extra '--direct' and '--restart', and a final NULL. */ | |
42 | static char *initial_argv[7]; | |
0ec97597 | 43 | static int initial_argv_count; |
882d6e17 AZ |
44 | |
45 | #define CMDLINE_OPTIONS \ | |
46 | { "restart", no_argument, &restart, 1 }, | |
47 | ||
48 | #define NFDS 100 | |
49 | ||
9ed752af AZ |
50 | static int |
51 | parse_fd (const char *str) | |
52 | { | |
53 | char *endptr; | |
54 | long unsigned int fd = strtoul (str, &endptr, 10); | |
55 | if (*endptr != '\0' || fd > INT_MAX) | |
56 | FAIL_EXIT1 ("invalid file descriptor value: %s", str); | |
57 | return fd; | |
58 | } | |
59 | ||
882d6e17 AZ |
60 | /* Called on process re-execution. The arguments are the expected opened |
61 | file descriptors. */ | |
62 | _Noreturn static void | |
63 | handle_restart (int argc, char *argv[]) | |
64 | { | |
9ed752af AZ |
65 | TEST_VERIFY (argc > 0); |
66 | int lowfd = parse_fd (argv[0]); | |
67 | ||
882d6e17 AZ |
68 | size_t nfds = argc > 1 ? argc - 1 : 0; |
69 | struct fd_t | |
70 | { | |
71 | int fd; | |
72 | _Bool found; | |
73 | } *fds = xmalloc (sizeof (struct fd_t) * nfds); | |
74 | for (int i = 0; i < nfds; i++) | |
75 | { | |
9ed752af | 76 | fds[i].fd = parse_fd (argv[i + 1]); |
882d6e17 AZ |
77 | fds[i].found = false; |
78 | } | |
79 | ||
80 | DIR *dirp = opendir (FD_TO_FILENAME_PREFIX); | |
81 | if (dirp == NULL) | |
82 | FAIL_EXIT1 ("opendir (\"" FD_TO_FILENAME_PREFIX "\"): %m"); | |
83 | ||
84 | while (true) | |
85 | { | |
86 | errno = 0; | |
87 | struct dirent64 *e = readdir64 (dirp); | |
88 | if (e == NULL) | |
89 | { | |
90 | if (errno != 0) | |
91 | FAIL_EXIT1 ("readdir: %m"); | |
92 | break; | |
93 | } | |
94 | ||
95 | if (e->d_name[0] == '.') | |
96 | continue; | |
97 | ||
98 | char *endptr; | |
99 | long int fd = strtol (e->d_name, &endptr, 10); | |
100 | if (*endptr != '\0' || fd < 0 || fd > INT_MAX) | |
101 | FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", | |
102 | e->d_name); | |
103 | ||
9ed752af AZ |
104 | /* Ignore the descriptors not in the range of the opened files. */ |
105 | if (fd < lowfd || fd == dirfd (dirp)) | |
106 | continue; | |
882d6e17 AZ |
107 | |
108 | bool found = false; | |
109 | for (int i = 0; i < nfds; i++) | |
110 | if (fds[i].fd == fd) | |
111 | fds[i].found = found = true; | |
112 | ||
113 | if (!found) | |
9ed752af AZ |
114 | { |
115 | char *path = xasprintf ("/proc/self/fd/%s", e->d_name); | |
116 | char *resolved = xreadlink (path); | |
117 | FAIL_EXIT1 ("unexpected open file descriptor %ld: %s", fd, resolved); | |
118 | } | |
882d6e17 AZ |
119 | } |
120 | closedir (dirp); | |
121 | ||
122 | for (int i = 0; i < nfds; i++) | |
123 | if (!fds[i].found) | |
124 | FAIL_EXIT1 ("file descriptor %d not opened", fds[i].fd); | |
125 | ||
126 | free (fds); | |
127 | ||
128 | exit (EXIT_SUCCESS); | |
129 | } | |
130 | ||
131 | static void | |
132 | spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd, | |
133 | int *extrafds, size_t nextrafds) | |
134 | { | |
9ed752af | 135 | /* 3 or 7 elements from initial_argv: |
0ec97597 L |
136 | + path to ld.so optional |
137 | + --library-path optional | |
138 | + the library path optional | |
139 | + application name | |
140 | + --direct | |
141 | + --restart | |
9ed752af AZ |
142 | + lowest opened file descriptor |
143 | + up to 2 * maximum_fd arguments (the expected open file descriptors), | |
144 | plus NULL. */ | |
145 | ||
0ec97597 | 146 | int argv_size = initial_argv_count + 2 * NFDS + 1; |
882d6e17 AZ |
147 | char *args[argv_size]; |
148 | int argc = 0; | |
149 | ||
150 | for (char **arg = initial_argv; *arg != NULL; arg++) | |
151 | args[argc++] = *arg; | |
152 | ||
9ed752af AZ |
153 | args[argc++] = xasprintf ("%d", lowfd); |
154 | ||
882d6e17 AZ |
155 | for (int i = lowfd; i < highfd; i++) |
156 | args[argc++] = xasprintf ("%d", i); | |
157 | ||
158 | for (int i = 0; i < nextrafds; i++) | |
159 | args[argc++] = xasprintf ("%d", extrafds[i]); | |
160 | ||
161 | args[argc] = NULL; | |
162 | TEST_VERIFY (argc < argv_size); | |
163 | ||
164 | pid_t pid; | |
165 | int status; | |
166 | ||
167 | TEST_COMPARE (posix_spawn (&pid, args[0], fa, NULL, args, environ), 0); | |
168 | TEST_COMPARE (xwaitpid (pid, &status, 0), pid); | |
169 | TEST_VERIFY (WIFEXITED (status)); | |
170 | TEST_VERIFY (!WIFSIGNALED (status)); | |
171 | TEST_COMPARE (WEXITSTATUS (status), 0); | |
172 | } | |
173 | ||
174 | static void | |
175 | do_test_closefrom (void) | |
176 | { | |
6b20880b | 177 | int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); |
882d6e17 AZ |
178 | const int half_fd = lowfd + NFDS / 2; |
179 | ||
180 | /* Close half of the descriptors and check result. */ | |
181 | { | |
182 | posix_spawn_file_actions_t fa; | |
183 | TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0); | |
184 | ||
185 | int ret = posix_spawn_file_actions_addclosefrom_np (&fa, half_fd); | |
186 | if (ret == EINVAL) | |
187 | /* Hurd currently does not support closefrom fileaction. */ | |
188 | FAIL_UNSUPPORTED ("posix_spawn_file_actions_addclosefrom_np unsupported"); | |
189 | TEST_COMPARE (ret, 0); | |
190 | ||
191 | spawn_closefrom_test (&fa, lowfd, half_fd, NULL, 0); | |
192 | ||
193 | TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0); | |
194 | } | |
195 | ||
196 | /* Create some gaps, close up to a threshold, and check result. */ | |
197 | xclose (lowfd + 57); | |
198 | xclose (lowfd + 78); | |
199 | xclose (lowfd + 81); | |
200 | xclose (lowfd + 82); | |
201 | xclose (lowfd + 84); | |
202 | xclose (lowfd + 90); | |
203 | ||
204 | { | |
205 | posix_spawn_file_actions_t fa; | |
206 | TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0); | |
207 | ||
208 | TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, half_fd), 0); | |
209 | ||
210 | spawn_closefrom_test (&fa, lowfd, half_fd, NULL, 0); | |
211 | ||
212 | TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0); | |
213 | } | |
214 | ||
215 | /* Close the remaining but the last one. */ | |
216 | { | |
217 | posix_spawn_file_actions_t fa; | |
218 | TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0); | |
219 | ||
220 | TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd + 1), 0); | |
221 | ||
222 | spawn_closefrom_test (&fa, lowfd, lowfd + 1, NULL, 0); | |
223 | ||
224 | TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0); | |
225 | } | |
226 | ||
227 | /* Close everything. */ | |
228 | { | |
229 | posix_spawn_file_actions_t fa; | |
230 | TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0); | |
231 | ||
232 | TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd), 0); | |
233 | ||
234 | spawn_closefrom_test (&fa, lowfd, lowfd, NULL, 0); | |
235 | ||
236 | TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0); | |
237 | } | |
238 | ||
239 | /* Close a range and add some file actions. */ | |
240 | { | |
241 | posix_spawn_file_actions_t fa; | |
242 | TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0); | |
243 | ||
244 | TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd + 1), 0); | |
245 | TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, lowfd, "/dev/null", | |
246 | 0666, O_RDONLY), 0); | |
247 | TEST_COMPARE (posix_spawn_file_actions_adddup2 (&fa, lowfd, lowfd + 1), 0); | |
248 | TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, lowfd, "/dev/null", | |
249 | 0666, O_RDONLY), 0); | |
250 | ||
251 | spawn_closefrom_test (&fa, lowfd, lowfd, (int[]){lowfd, lowfd + 1}, 2); | |
252 | ||
253 | TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0); | |
254 | } | |
255 | } | |
256 | ||
257 | static int | |
258 | do_test (int argc, char *argv[]) | |
259 | { | |
260 | /* We must have either: | |
261 | ||
262 | - one or four parameters if called initially: | |
263 | + argv[1]: path for ld.so optional | |
264 | + argv[2]: "--library-path" optional | |
265 | + argv[3]: the library path optional | |
266 | + argv[4]: the application name | |
267 | ||
268 | - six parameters left if called through re-execution: | |
269 | + argv[1]: the application name | |
9ed752af AZ |
270 | + argv[2]: the lowest file descriptor expected |
271 | + argv[3]: first expected open file descriptor optional | |
272 | + argv[n]: last expected open file descritptor optional | |
882d6e17 AZ |
273 | |
274 | * When built with --enable-hardcoded-path-in-tests or issued without | |
275 | using the loader directly. */ | |
276 | ||
277 | if (restart) | |
9ed752af AZ |
278 | /* Ignore the application name. */ |
279 | handle_restart (argc - 1, &argv[1]); | |
882d6e17 | 280 | |
0ec97597 L |
281 | TEST_VERIFY_EXIT (argc == 2 || argc == 5); |
282 | ||
283 | int i; | |
284 | ||
285 | for (i = 0; i < argc - 1; i++) | |
286 | initial_argv[i] = argv[i + 1]; | |
287 | initial_argv[i++] = (char *) "--direct"; | |
288 | initial_argv[i++] = (char *) "--restart"; | |
289 | ||
290 | initial_argv_count = i; | |
882d6e17 AZ |
291 | |
292 | do_test_closefrom (); | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
297 | #define TEST_FUNCTION_ARGV do_test | |
298 | #include <support/test-driver.c> |