]>
Commit | Line | Data |
---|---|---|
c23de0aa | 1 | /* Main worker function for the test driver. |
2b778ceb | 2 | Copyright (C) 1998-2021 Free Software Foundation, Inc. |
c23de0aa FW |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
c23de0aa FW |
18 | |
19 | #include <support/test-driver.h> | |
5f0b8437 | 20 | #include <support/check.h> |
c23de0aa | 21 | #include <support/temp_file-internal.h> |
4052fa22 | 22 | #include <support/support.h> |
c23de0aa FW |
23 | |
24 | #include <assert.h> | |
25 | #include <errno.h> | |
26 | #include <getopt.h> | |
27 | #include <malloc.h> | |
28 | #include <signal.h> | |
29 | #include <stdbool.h> | |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
32 | #include <sys/param.h> | |
33 | #include <sys/resource.h> | |
35e3fbc4 | 34 | #include <sys/time.h> |
c23de0aa FW |
35 | #include <sys/types.h> |
36 | #include <sys/wait.h> | |
37 | #include <time.h> | |
38 | #include <unistd.h> | |
39 | ||
4052fa22 DD |
40 | #include <xstdio.h> |
41 | ||
c23de0aa FW |
42 | static const struct option default_options[] = |
43 | { | |
f47ae518 | 44 | TEST_DEFAULT_OPTIONS |
c23de0aa FW |
45 | { NULL, 0, NULL, 0 } |
46 | }; | |
47 | ||
48 | /* Show people how to run the program. */ | |
49 | static void | |
50 | usage (const struct option *options) | |
51 | { | |
52 | size_t i; | |
53 | ||
54 | printf ("Usage: %s [options]\n" | |
55 | "\n" | |
56 | "Environment Variables:\n" | |
57 | " TIMEOUTFACTOR An integer used to scale the timeout\n" | |
58 | " TMPDIR Where to place temporary files\n" | |
59 | " TEST_COREDUMPS Do not disable coredumps if set\n" | |
60 | "\n", | |
61 | program_invocation_short_name); | |
62 | printf ("Options:\n"); | |
63 | for (i = 0; options[i].name; ++i) | |
64 | { | |
65 | int indent; | |
66 | ||
67 | indent = printf (" --%s", options[i].name); | |
68 | if (options[i].has_arg == required_argument) | |
69 | indent += printf (" <arg>"); | |
70 | printf ("%*s", 25 - indent, ""); | |
71 | switch (options[i].val) | |
72 | { | |
f47ae518 FW |
73 | case 'v': |
74 | printf ("Increase the output verbosity"); | |
75 | break; | |
c23de0aa FW |
76 | case OPT_DIRECT: |
77 | printf ("Run the test directly (instead of forking & monitoring)"); | |
78 | break; | |
79 | case OPT_TESTDIR: | |
80 | printf ("Override the TMPDIR env var"); | |
81 | break; | |
82 | } | |
83 | printf ("\n"); | |
84 | } | |
85 | } | |
86 | ||
87 | /* The PID of the test process. */ | |
88 | static pid_t test_pid; | |
89 | ||
90 | /* The cleanup handler passed to test_main. */ | |
91 | static void (*cleanup_function) (void); | |
92 | ||
35e3fbc4 | 93 | static void |
4a39c34c | 94 | print_timestamp (const char *what, struct timespec tv) |
35e3fbc4 FW |
95 | { |
96 | struct tm tm; | |
4a39c34c ZW |
97 | /* Casts of tv.tv_nsec below are necessary because the type of |
98 | tv_nsec is not literally long int on all supported platforms. */ | |
35e3fbc4 | 99 | if (gmtime_r (&tv.tv_sec, &tm) == NULL) |
4a39c34c ZW |
100 | printf ("%s: %lld.%09ld\n", |
101 | what, (long long int) tv.tv_sec, (long int) tv.tv_nsec); | |
35e3fbc4 | 102 | else |
4a39c34c | 103 | printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%09ld\n", |
35e3fbc4 | 104 | what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, |
4a39c34c | 105 | tm.tm_hour, tm.tm_min, tm.tm_sec, (long int) tv.tv_nsec); |
35e3fbc4 FW |
106 | } |
107 | ||
c23de0aa FW |
108 | /* Timeout handler. We kill the child and exit with an error. */ |
109 | static void | |
110 | __attribute__ ((noreturn)) | |
111 | signal_handler (int sig) | |
112 | { | |
113 | int killed; | |
114 | int status; | |
115 | ||
35e3fbc4 FW |
116 | /* Do this first to avoid further interference from the |
117 | subprocess. */ | |
4a39c34c ZW |
118 | struct timespec now; |
119 | clock_gettime (CLOCK_REALTIME, &now); | |
35e3fbc4 FW |
120 | struct stat64 st; |
121 | bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0; | |
122 | ||
c23de0aa FW |
123 | assert (test_pid > 1); |
124 | /* Kill the whole process group. */ | |
125 | kill (-test_pid, SIGKILL); | |
126 | /* In case setpgid failed in the child, kill it individually too. */ | |
127 | kill (test_pid, SIGKILL); | |
128 | ||
129 | /* Wait for it to terminate. */ | |
130 | int i; | |
131 | for (i = 0; i < 5; ++i) | |
132 | { | |
133 | killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); | |
134 | if (killed != 0) | |
135 | break; | |
136 | ||
137 | /* Delay, give the system time to process the kill. If the | |
138 | nanosleep() call return prematurely, all the better. We | |
139 | won't restart it since this probably means the child process | |
140 | finally died. */ | |
141 | struct timespec ts; | |
142 | ts.tv_sec = 0; | |
143 | ts.tv_nsec = 100000000; | |
144 | nanosleep (&ts, NULL); | |
145 | } | |
146 | if (killed != 0 && killed != test_pid) | |
147 | { | |
148 | printf ("Failed to kill test process: %m\n"); | |
149 | exit (1); | |
150 | } | |
151 | ||
152 | if (cleanup_function != NULL) | |
153 | cleanup_function (); | |
154 | ||
155 | if (sig == SIGINT) | |
156 | { | |
157 | signal (sig, SIG_DFL); | |
158 | raise (sig); | |
159 | } | |
160 | ||
161 | if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) | |
162 | puts ("Timed out: killed the child process"); | |
163 | else if (WIFSTOPPED (status)) | |
164 | printf ("Timed out: the child process was %s\n", | |
165 | strsignal (WSTOPSIG (status))); | |
166 | else if (WIFSIGNALED (status)) | |
167 | printf ("Timed out: the child process got signal %s\n", | |
168 | strsignal (WTERMSIG (status))); | |
169 | else | |
170 | printf ("Timed out: killed the child process but it exited %d\n", | |
171 | WEXITSTATUS (status)); | |
172 | ||
4a39c34c | 173 | print_timestamp ("Termination time", now); |
35e3fbc4 | 174 | if (st_available) |
4a39c34c | 175 | print_timestamp ("Last write to standard output", st.st_mtim); |
35e3fbc4 | 176 | |
c23de0aa FW |
177 | /* Exit with an error. */ |
178 | exit (1); | |
179 | } | |
180 | ||
4052fa22 DD |
181 | /* This must be volatile as it will be modified by the debugger. */ |
182 | static volatile int wait_for_debugger = 0; | |
183 | ||
c23de0aa FW |
184 | /* Run test_function or test_function_argv. */ |
185 | static int | |
186 | run_test_function (int argc, char **argv, const struct test_config *config) | |
187 | { | |
4052fa22 DD |
188 | const char *wfd = getenv("WAIT_FOR_DEBUGGER"); |
189 | if (wfd != NULL) | |
190 | wait_for_debugger = atoi (wfd); | |
191 | if (wait_for_debugger) | |
192 | { | |
193 | pid_t mypid; | |
194 | FILE *gdb_script; | |
195 | char *gdb_script_name; | |
196 | int inside_container = 0; | |
197 | ||
198 | mypid = getpid(); | |
199 | if (mypid < 3) | |
200 | { | |
201 | const char *outside_pid = getenv("PID_OUTSIDE_CONTAINER"); | |
202 | if (outside_pid) | |
203 | { | |
204 | mypid = atoi (outside_pid); | |
205 | inside_container = 1; | |
206 | } | |
207 | } | |
208 | ||
209 | gdb_script_name = (char *) xmalloc (strlen (argv[0]) + strlen (".gdb") + 1); | |
210 | sprintf (gdb_script_name, "%s.gdb", argv[0]); | |
211 | gdb_script = xfopen (gdb_script_name, "w"); | |
212 | ||
213 | fprintf (stderr, "Waiting for debugger, test process is pid %d\n", mypid); | |
214 | fprintf (stderr, "gdb -x %s\n", gdb_script_name); | |
215 | if (inside_container) | |
216 | fprintf (gdb_script, "set sysroot %s/testroot.root\n", support_objdir_root); | |
217 | fprintf (gdb_script, "file\n"); | |
218 | fprintf (gdb_script, "file %s\n", argv[0]); | |
219 | fprintf (gdb_script, "symbol-file %s\n", argv[0]); | |
220 | fprintf (gdb_script, "exec-file %s\n", argv[0]); | |
221 | fprintf (gdb_script, "attach %ld\n", (long int) mypid); | |
222 | fprintf (gdb_script, "set wait_for_debugger = 0\n"); | |
223 | fclose (gdb_script); | |
224 | } | |
225 | ||
226 | /* Wait for the debugger to set wait_for_debugger to zero. */ | |
227 | while (wait_for_debugger) | |
228 | usleep (1000); | |
229 | ||
c23de0aa FW |
230 | if (config->test_function != NULL) |
231 | return config->test_function (); | |
232 | else if (config->test_function_argv != NULL) | |
233 | return config->test_function_argv (argc, argv); | |
234 | else | |
235 | { | |
236 | printf ("error: no test function defined\n"); | |
237 | exit (1); | |
238 | } | |
239 | } | |
240 | ||
241 | static bool test_main_called; | |
242 | ||
243 | const char *test_dir = NULL; | |
f47ae518 | 244 | unsigned int test_verbose = 0; |
5f0b8437 FW |
245 | |
246 | /* If test failure reporting has been linked in, it may contribute | |
247 | additional test failures. */ | |
248 | static int | |
249 | adjust_exit_status (int status) | |
250 | { | |
251 | if (support_report_failure != NULL) | |
252 | return support_report_failure (status); | |
253 | return status; | |
254 | } | |
255 | ||
c23de0aa FW |
256 | int |
257 | support_test_main (int argc, char **argv, const struct test_config *config) | |
258 | { | |
259 | if (test_main_called) | |
260 | { | |
261 | printf ("error: test_main called for a second time\n"); | |
262 | exit (1); | |
263 | } | |
264 | test_main_called = true; | |
265 | const struct option *options; | |
266 | if (config->options != NULL) | |
267 | options = config->options; | |
268 | else | |
269 | options = default_options; | |
270 | ||
271 | cleanup_function = config->cleanup_function; | |
272 | ||
273 | int direct = 0; /* Directly call the test function? */ | |
274 | int status; | |
275 | int opt; | |
276 | unsigned int timeoutfactor = 1; | |
277 | pid_t termpid; | |
278 | ||
4052fa22 DD |
279 | /* If we're debugging the test, we need to disable timeouts and use |
280 | the initial pid (esp if we're running inside a container). */ | |
281 | if (getenv("WAIT_FOR_DEBUGGER") != NULL) | |
282 | direct = 1; | |
283 | ||
c23de0aa FW |
284 | if (!config->no_mallopt) |
285 | { | |
286 | /* Make uses of freed and uninitialized memory known. Do not | |
287 | pull in a definition for mallopt if it has not been defined | |
288 | already. */ | |
289 | extern __typeof__ (mallopt) mallopt __attribute__ ((weak)); | |
290 | if (mallopt != NULL) | |
291 | mallopt (M_PERTURB, 42); | |
292 | } | |
293 | ||
244361eb AZ |
294 | while ((opt = getopt_long (argc, argv, config->optstring, options, NULL)) |
295 | != -1) | |
c23de0aa FW |
296 | switch (opt) |
297 | { | |
298 | case '?': | |
299 | usage (options); | |
300 | exit (1); | |
f47ae518 FW |
301 | case 'v': |
302 | ++test_verbose; | |
303 | break; | |
c23de0aa FW |
304 | case OPT_DIRECT: |
305 | direct = 1; | |
306 | break; | |
307 | case OPT_TESTDIR: | |
308 | test_dir = optarg; | |
309 | break; | |
310 | default: | |
311 | if (config->cmdline_function != NULL) | |
312 | config->cmdline_function (opt); | |
313 | } | |
314 | ||
315 | /* If set, read the test TIMEOUTFACTOR value from the environment. | |
316 | This value is used to scale the default test timeout values. */ | |
317 | char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); | |
318 | if (envstr_timeoutfactor != NULL) | |
319 | { | |
320 | char *envstr_conv = envstr_timeoutfactor; | |
321 | unsigned long int env_fact; | |
322 | ||
323 | env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); | |
324 | if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) | |
325 | timeoutfactor = MAX (env_fact, 1); | |
326 | } | |
327 | ||
328 | /* Set TMPDIR to specified test directory. */ | |
329 | if (test_dir != NULL) | |
330 | { | |
331 | setenv ("TMPDIR", test_dir, 1); | |
332 | ||
333 | if (chdir (test_dir) < 0) | |
334 | { | |
335 | printf ("chdir: %m\n"); | |
336 | exit (1); | |
337 | } | |
338 | } | |
339 | else | |
340 | { | |
341 | test_dir = getenv ("TMPDIR"); | |
342 | if (test_dir == NULL || test_dir[0] == '\0') | |
343 | test_dir = "/tmp"; | |
344 | } | |
345 | if (support_set_test_dir != NULL) | |
346 | support_set_test_dir (test_dir); | |
347 | ||
348 | int timeout = config->timeout; | |
349 | if (timeout == 0) | |
350 | timeout = DEFAULT_TIMEOUT; | |
351 | ||
352 | /* Make sure we see all message, even those on stdout. */ | |
5c0202af FW |
353 | if (!config->no_setvbuf) |
354 | setvbuf (stdout, NULL, _IONBF, 0); | |
c23de0aa FW |
355 | |
356 | /* Make sure temporary files are deleted. */ | |
357 | if (support_delete_temp_files != NULL) | |
358 | atexit (support_delete_temp_files); | |
359 | ||
360 | /* Correct for the possible parameters. */ | |
361 | argv[optind - 1] = argv[0]; | |
362 | argv += optind - 1; | |
363 | argc -= optind - 1; | |
364 | ||
365 | /* Call the initializing function, if one is available. */ | |
366 | if (config->prepare_function != NULL) | |
367 | config->prepare_function (argc, argv); | |
368 | ||
369 | const char *envstr_direct = getenv ("TEST_DIRECT"); | |
370 | if (envstr_direct != NULL) | |
371 | { | |
372 | FILE *f = fopen (envstr_direct, "w"); | |
373 | if (f == NULL) | |
374 | { | |
375 | printf ("cannot open TEST_DIRECT output file '%s': %m\n", | |
376 | envstr_direct); | |
377 | exit (1); | |
378 | } | |
379 | ||
380 | fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", | |
381 | config->timeout, timeoutfactor); | |
382 | if (config->expected_status != 0) | |
383 | fprintf (f, "exit=%u\n", config->expected_status); | |
384 | if (config->expected_signal != 0) | |
385 | fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); | |
386 | ||
387 | if (support_print_temp_files != NULL) | |
388 | support_print_temp_files (f); | |
389 | ||
390 | fclose (f); | |
391 | direct = 1; | |
392 | } | |
393 | ||
394 | bool disable_coredumps; | |
395 | { | |
396 | const char *coredumps = getenv ("TEST_COREDUMPS"); | |
397 | disable_coredumps = coredumps == NULL || coredumps[0] == '\0'; | |
398 | } | |
399 | ||
400 | /* If we are not expected to fork run the function immediately. */ | |
401 | if (direct) | |
5f0b8437 | 402 | return adjust_exit_status (run_test_function (argc, argv, config)); |
c23de0aa FW |
403 | |
404 | /* Set up the test environment: | |
405 | - prevent core dumps | |
406 | - set up the timer | |
407 | - fork and execute the function. */ | |
408 | ||
67f779f1 | 409 | test_pid = fork (); |
c23de0aa FW |
410 | if (test_pid == 0) |
411 | { | |
412 | /* This is the child. */ | |
413 | if (disable_coredumps) | |
414 | { | |
415 | /* Try to avoid dumping core. This is necessary because we | |
416 | run the test from the source tree, and the coredumps | |
417 | would end up there (and not in the build tree). */ | |
418 | struct rlimit core_limit; | |
419 | core_limit.rlim_cur = 0; | |
420 | core_limit.rlim_max = 0; | |
421 | setrlimit (RLIMIT_CORE, &core_limit); | |
422 | } | |
423 | ||
424 | /* We put the test process in its own pgrp so that if it bogusly | |
425 | generates any job control signals, they won't hit the whole build. */ | |
426 | if (setpgid (0, 0) != 0) | |
427 | printf ("Failed to set the process group ID: %m\n"); | |
428 | ||
429 | /* Execute the test function and exit with the return value. */ | |
430 | exit (run_test_function (argc, argv, config)); | |
431 | } | |
432 | else if (test_pid < 0) | |
433 | { | |
434 | printf ("Cannot fork test program: %m\n"); | |
435 | exit (1); | |
436 | } | |
437 | ||
438 | /* Set timeout. */ | |
439 | signal (SIGALRM, signal_handler); | |
fea34d51 | 440 | alarm (timeout * timeoutfactor); |
c23de0aa FW |
441 | |
442 | /* Make sure we clean up if the wrapper gets interrupted. */ | |
443 | signal (SIGINT, signal_handler); | |
444 | ||
445 | /* Wait for the regular termination. */ | |
446 | termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0)); | |
447 | if (termpid == -1) | |
448 | { | |
449 | printf ("Waiting for test program failed: %m\n"); | |
450 | exit (1); | |
451 | } | |
452 | if (termpid != test_pid) | |
453 | { | |
454 | printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", | |
455 | (long int) test_pid, (long int) termpid); | |
456 | exit (1); | |
457 | } | |
458 | ||
459 | /* Process terminated normaly without timeout etc. */ | |
460 | if (WIFEXITED (status)) | |
461 | { | |
462 | if (config->expected_status == 0) | |
463 | { | |
464 | if (config->expected_signal == 0) | |
5f0b8437 FW |
465 | /* Exit with the return value of the test. */ |
466 | return adjust_exit_status (WEXITSTATUS (status)); | |
c23de0aa FW |
467 | else |
468 | { | |
469 | printf ("Expected signal '%s' from child, got none\n", | |
470 | strsignal (config->expected_signal)); | |
471 | exit (1); | |
472 | } | |
473 | } | |
474 | else | |
475 | { | |
476 | /* Non-zero exit status is expected */ | |
477 | if (WEXITSTATUS (status) != config->expected_status) | |
478 | { | |
479 | printf ("Expected status %d, got %d\n", | |
480 | config->expected_status, WEXITSTATUS (status)); | |
481 | exit (1); | |
482 | } | |
483 | } | |
5f0b8437 | 484 | return adjust_exit_status (0); |
c23de0aa FW |
485 | } |
486 | /* Process was killed by timer or other signal. */ | |
487 | else | |
488 | { | |
489 | if (config->expected_signal == 0) | |
490 | { | |
491 | printf ("Didn't expect signal from child: got `%s'\n", | |
492 | strsignal (WTERMSIG (status))); | |
493 | exit (1); | |
494 | } | |
495 | else if (WTERMSIG (status) != config->expected_signal) | |
496 | { | |
497 | printf ("Incorrect signal from child: got `%s', need `%s'\n", | |
498 | strsignal (WTERMSIG (status)), | |
499 | strsignal (config->expected_signal)); | |
500 | exit (1); | |
501 | } | |
502 | ||
5f0b8437 | 503 | return adjust_exit_status (0); |
c23de0aa FW |
504 | } |
505 | } |