1/* Main worker function for the test driver.
2 Copyright (C) 1998-2020 Free Software Foundation, Inc.
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 <https://www.gnu.org/licenses/>. */
18
19#include <support/test-driver.h>
20#include <support/check.h>
21#include <support/temp_file-internal.h>
22#include <support/support.h>
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>
34#include <sys/time.h>
35#include <sys/types.h>
36#include <sys/wait.h>
37#include <time.h>
38#include <unistd.h>
39
40#include <xstdio.h>
41
42static const struct option default_options[] =
43{
44 TEST_DEFAULT_OPTIONS
45 { NULL, 0, NULL, 0 }
46};
47
48/* Show people how to run the program. */
49static void
50usage (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 {
73 case 'v':
74 printf ("Increase the output verbosity");
75 break;
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. */
88static pid_t test_pid;
89
90/* The cleanup handler passed to test_main. */
91static void (*cleanup_function) (void);
92
93static void
94print_timestamp (const char *what, struct timespec tv)
95{
96 struct tm tm;
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. */
99 if (gmtime_r (&tv.tv_sec, &tm) == NULL)
100 printf ("%s: %lld.%09ld\n",
101 what, (long long int) tv.tv_sec, (long int) tv.tv_nsec);
102 else
103 printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%09ld\n",
104 what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
105 tm.tm_hour, tm.tm_min, tm.tm_sec, (long int) tv.tv_nsec);
106}
107
108/* Timeout handler. We kill the child and exit with an error. */
109static void
110__attribute__ ((noreturn))
111signal_handler (int sig)
112{
113 int killed;
114 int status;
115
116 /* Do this first to avoid further interference from the
117 subprocess. */
118 struct timespec now;
119 clock_gettime (CLOCK_REALTIME, &now);
120 struct stat64 st;
121 bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0;
122
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
173 print_timestamp ("Termination time", now);
174 if (st_available)
175 print_timestamp ("Last write to standard output", st.st_mtim);
176
177 /* Exit with an error. */
178 exit (1);
179}
180
181/* This must be volatile as it will be modified by the debugger. */
182static volatile int wait_for_debugger = 0;
183
184/* Run test_function or test_function_argv. */
185static int
186run_test_function (int argc, char **argv, const struct test_config *config)
187{
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
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
241static bool test_main_called;
242
243const char *test_dir = NULL;
244unsigned int test_verbose = 0;
245
246/* If test failure reporting has been linked in, it may contribute
247 additional test failures. */
248static int
249adjust_exit_status (int status)
250{
251 if (support_report_failure != NULL)
252 return support_report_failure (status);
253 return status;
254}
255
256int
257support_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
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
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
294 while ((opt = getopt_long (argc, argv, config->optstring, options, NULL))
295 != -1)
296 switch (opt)
297 {
298 case '?':
299 usage (options);
300 exit (1);
301 case 'v':
302 ++test_verbose;
303 break;
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. */
353 if (!config->no_setvbuf)
354 setvbuf (stdout, NULL, _IONBF, 0);
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)
402 return adjust_exit_status (run_test_function (argc, argv, config));
403
404 /* Set up the test environment:
405 - prevent core dumps
406 - set up the timer
407 - fork and execute the function. */
408
409 test_pid = fork ();
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);
440 alarm (timeout * timeoutfactor);
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)
465 /* Exit with the return value of the test. */
466 return adjust_exit_status (WEXITSTATUS (status));
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 }
484 return adjust_exit_status (0);
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
503 return adjust_exit_status (0);
504 }
505}
506