1 /* Tests for posix_spawn signal handling.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
30 #include <support/check.h>
31 #include <support/xunistd.h>
32 #include <support/support.h>
34 #include <arch-fd_to_filename.h>
35 #include <array_length.h>
36 #include <tst-spawn.h>
38 /* Nonzero if the program gets called via `exec'. */
41 /* Hold the four initial argument used to respawn the process, plus
42 the extra '--direct' and '--restart', and a final NULL. */
43 static char *initial_argv
[7];
44 static int initial_argv_count
;
46 #define CMDLINE_OPTIONS \
47 { "restart", no_argument, &restart, 1 },
52 parse_fd (const char *str
)
55 long unsigned int fd
= strtoul (str
, &endptr
, 10);
56 if (*endptr
!= '\0' || fd
> INT_MAX
)
57 FAIL_EXIT1 ("invalid file descriptor value: %s", str
);
61 /* Called on process re-execution. The arguments are the expected opened
64 handle_restart (int argc
, char *argv
[])
66 TEST_VERIFY (argc
> 0);
67 int lowfd
= parse_fd (argv
[0]);
69 size_t nfds
= argc
> 1 ? argc
- 1 : 0;
74 } *fds
= xmalloc (sizeof (struct fd_t
) * nfds
);
75 for (int i
= 0; i
< nfds
; i
++)
77 fds
[i
].fd
= parse_fd (argv
[i
+ 1]);
81 DIR *dirp
= opendir (FD_TO_FILENAME_PREFIX
);
83 FAIL_EXIT1 ("opendir (\"" FD_TO_FILENAME_PREFIX
"\"): %m");
88 struct dirent64
*e
= readdir64 (dirp
);
92 FAIL_EXIT1 ("readdir: %m");
96 if (e
->d_name
[0] == '.')
100 long int fd
= strtol (e
->d_name
, &endptr
, 10);
101 if (*endptr
!= '\0' || fd
< 0 || fd
> INT_MAX
)
102 FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
105 /* Ignore the descriptors not in the range of the opened files. */
106 if (fd
< lowfd
|| fd
== dirfd (dirp
))
110 for (int i
= 0; i
< nfds
; i
++)
112 fds
[i
].found
= found
= true;
116 char *path
= xasprintf ("/proc/self/fd/%s", e
->d_name
);
117 char *resolved
= xreadlink (path
);
118 FAIL_EXIT1 ("unexpected open file descriptor %ld: %s", fd
, resolved
);
123 for (int i
= 0; i
< nfds
; i
++)
125 FAIL_EXIT1 ("file descriptor %d not opened", fds
[i
].fd
);
133 spawn_closefrom_test (posix_spawn_file_actions_t
*fa
, int lowfd
, int highfd
,
134 int *extrafds
, size_t nextrafds
)
136 /* 3 or 7 elements from initial_argv:
137 + path to ld.so optional
138 + --library-path optional
139 + the library path optional
143 + lowest opened file descriptor
144 + up to 2 * maximum_fd arguments (the expected open file descriptors),
147 int argv_size
= initial_argv_count
+ 2 * NFDS
+ 1;
148 char *args
[argv_size
];
151 for (char **arg
= initial_argv
; *arg
!= NULL
; arg
++)
154 args
[argc
++] = xasprintf ("%d", lowfd
);
156 for (int i
= lowfd
; i
< highfd
; i
++)
157 args
[argc
++] = xasprintf ("%d", i
);
159 for (int i
= 0; i
< nextrafds
; i
++)
160 args
[argc
++] = xasprintf ("%d", extrafds
[i
]);
163 TEST_VERIFY (argc
< argv_size
);
168 TEST_COMPARE (POSIX_SPAWN (&pid
, args
[0], fa
, NULL
, args
, environ
), 0);
169 TEST_COMPARE (WAITID (P_PID
, pid
, &sinfo
, WEXITED
), 0);
170 TEST_COMPARE (sinfo
.si_code
, CLD_EXITED
);
171 TEST_COMPARE (sinfo
.si_status
, 0);
175 do_test_closefrom (void)
177 int lowfd
= support_open_dev_null_range (NFDS
, O_RDONLY
, 0600);
178 const int half_fd
= lowfd
+ NFDS
/ 2;
180 /* Close half of the descriptors and check result. */
182 posix_spawn_file_actions_t fa
;
183 TEST_COMPARE (posix_spawn_file_actions_init (&fa
), 0);
185 int ret
= posix_spawn_file_actions_addclosefrom_np (&fa
, half_fd
);
187 /* Hurd currently does not support closefrom fileaction. */
188 FAIL_UNSUPPORTED ("posix_spawn_file_actions_addclosefrom_np unsupported");
189 TEST_COMPARE (ret
, 0);
191 spawn_closefrom_test (&fa
, lowfd
, half_fd
, NULL
, 0);
193 TEST_COMPARE (posix_spawn_file_actions_destroy (&fa
), 0);
196 /* Create some gaps, close up to a threshold, and check result. */
205 posix_spawn_file_actions_t fa
;
206 TEST_COMPARE (posix_spawn_file_actions_init (&fa
), 0);
208 TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa
, half_fd
), 0);
210 spawn_closefrom_test (&fa
, lowfd
, half_fd
, NULL
, 0);
212 TEST_COMPARE (posix_spawn_file_actions_destroy (&fa
), 0);
215 /* Close the remaining but the last one. */
217 posix_spawn_file_actions_t fa
;
218 TEST_COMPARE (posix_spawn_file_actions_init (&fa
), 0);
220 TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa
, lowfd
+ 1), 0);
222 spawn_closefrom_test (&fa
, lowfd
, lowfd
+ 1, NULL
, 0);
224 TEST_COMPARE (posix_spawn_file_actions_destroy (&fa
), 0);
227 /* Close everything. */
229 posix_spawn_file_actions_t fa
;
230 TEST_COMPARE (posix_spawn_file_actions_init (&fa
), 0);
232 TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa
, lowfd
), 0);
234 spawn_closefrom_test (&fa
, lowfd
, lowfd
, NULL
, 0);
236 TEST_COMPARE (posix_spawn_file_actions_destroy (&fa
), 0);
239 /* Close a range and add some file actions. */
241 posix_spawn_file_actions_t fa
;
242 TEST_COMPARE (posix_spawn_file_actions_init (&fa
), 0);
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",
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",
251 spawn_closefrom_test (&fa
, lowfd
, lowfd
, (int[]){lowfd
, lowfd
+ 1}, 2);
253 TEST_COMPARE (posix_spawn_file_actions_destroy (&fa
), 0);
258 do_test (int argc
, char *argv
[])
260 /* We must have either:
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
268 - six parameters left if called through re-execution:
269 + argv[1]: the application name
270 + argv[2]: the lowest file descriptor expected
271 + argv[3]: first expected open file descriptor optional
272 + argv[n]: last expected open file descriptor optional
274 * When built with --enable-hardcoded-path-in-tests or issued without
275 using the loader directly. */
278 /* Ignore the application name. */
279 handle_restart (argc
- 1, &argv
[1]);
281 TEST_VERIFY_EXIT (argc
== 2 || argc
== 5);
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";
290 initial_argv_count
= i
;
292 do_test_closefrom ();
297 #define TEST_FUNCTION_ARGV do_test
298 #include <support/test-driver.c>