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