OSDN Git Service

mkostemp: fix implementation
[uclinux-h8/uClibc.git] / test / test-skeleton.c
1 /* Skeleton for test programs.
2    Copyright (C) 1998,2000-2004, 2005 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <errno.h>
21 #include <malloc.h>
22 #include <search.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/resource.h>
29 #include <sys/wait.h>
30 #include <sys/param.h>
31 #include <time.h>
32 #include <features.h>
33
34 /* The test function is normally called `do_test' and it is called
35    with argc and argv as the arguments.  We nevertheless provide the
36    possibility to overwrite this name.  */
37 #ifndef TEST_FUNCTION
38 # define TEST_FUNCTION do_test (argc, argv)
39 #endif
40
41 #ifndef TEST_DATA_LIMIT
42 # define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with.  */
43 #endif
44
45 #define OPT_DIRECT 1000
46 #define OPT_TESTDIR 1001
47
48 #if 0 /* Not used in uClibc */
49 static struct option options[] =
50 {
51 #ifdef CMDLINE_OPTIONS
52   CMDLINE_OPTIONS
53 #endif
54   { "direct", no_argument, NULL, OPT_DIRECT },
55   { "test-dir", required_argument, NULL, OPT_TESTDIR },
56   { NULL, 0, NULL, 0 }
57 };
58 #endif
59
60 /* PID of the test itself.  */
61 static pid_t pid;
62
63 /* Directory to place temporary files in.  */
64 static const char *test_dir;
65
66 /* List of temporary files.  */
67 struct temp_name_list
68 {
69   struct qelem q;
70   const char *name;
71 } *temp_name_list;
72
73 /* Add temporary files in list.  */
74 static void
75 __attribute__ ((unused))
76 add_temp_file (const char *name)
77 {
78   struct temp_name_list *newp
79     = (struct temp_name_list *) calloc (sizeof (*newp), 1);
80   if (newp != NULL)
81     {
82       newp->name = name;
83       if (temp_name_list == NULL)
84         temp_name_list = (struct temp_name_list *) &newp->q;
85       else
86         insque (newp, temp_name_list);
87     }
88 }
89
90 /* Delete all temporary files.  */
91 static void
92 delete_temp_files (void)
93 {
94   while (temp_name_list != NULL)
95     {
96       remove (temp_name_list->name);
97       temp_name_list = (struct temp_name_list *) temp_name_list->q.q_forw;
98     }
99 }
100
101 /* Create a temporary file.  */
102 static int
103 __attribute__ ((unused))
104 create_temp_file (const char *base, char **filename)
105 {
106   char *fname;
107   int _fd;
108
109   fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
110                            + sizeof ("XXXXXX"));
111   if (fname == NULL)
112     {
113       puts ("out of memory");
114       return -1;
115     }
116   strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
117
118   _fd = mkstemp (fname);
119   if (_fd == -1)
120     {
121       printf ("cannot open temporary file '%s': %s\n", fname, strerror(errno));
122       free (fname);
123       return -1;
124     }
125
126   add_temp_file (fname);
127   if (filename != NULL)
128     *filename = fname;
129
130   return _fd;
131 }
132
133 /* Timeout handler.  We kill the child and exit with an error.  */
134 static void
135 __attribute__ ((noreturn))
136 signal_handler (int sig __attribute__ ((unused)))
137 {
138   int killed = 0;
139   int status;
140   int i;
141
142   /* Send signal.  */
143   kill (pid, SIGKILL);
144
145   /* Wait for it to terminate.  */
146   for (i = 0; i < 5; ++i)
147     {
148 #ifdef __UCLIBC_HAS_REALTIME__
149       struct timespec ts;
150 #endif
151       killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
152       if (killed != 0)
153         break;
154
155       /* Delay, give the system time to process the kill.  If the
156          nanosleep() call return prematurely, all the better.  We
157          won't restart it since this probably means the child process
158          finally died.  */
159 #ifdef __UCLIBC_HAS_REALTIME__
160       ts.tv_sec = 0;
161       ts.tv_nsec = 100000000;
162       nanosleep (&ts, NULL);
163 #else
164           /* No nanosleep, just sleep 1s instead of 0.1s */
165           sleep(1);
166 #endif
167     }
168   if (killed != 0 && killed != pid)
169     {
170       perror ("Failed to kill test process");
171       exit (1);
172     }
173
174 #ifdef CLEANUP_HANDLER
175   CLEANUP_HANDLER;
176 #endif
177
178   if (sig == SIGINT)
179     {
180       signal (sig, SIG_DFL);
181       raise (sig);
182     }
183
184   /* If we expected this signal: good!  */
185 #ifdef EXPECTED_SIGNAL
186   if (EXPECTED_SIGNAL == SIGALRM)
187     exit (0);
188 #endif
189
190   if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
191     fputs ("Timed out: killed the child process\n", stderr);
192   else if (WIFSTOPPED (status))
193     fprintf (stderr, "Timed out: the child process was %s\n",
194              strsignal (WSTOPSIG (status)));
195   else if (WIFSIGNALED (status))
196     fprintf (stderr, "Timed out: the child process got signal %s\n",
197              strsignal (WTERMSIG (status)));
198   else
199     fprintf (stderr, "Timed out: killed the child process but it exited %d\n",
200              WEXITSTATUS (status));
201
202   /* Exit with an error.  */
203   exit (1);
204 }
205
206 #ifdef __XXX_HANDLE_CTRL_C
207 static void
208 __attribute__ ((noreturn))
209 handler_killpid(int sig)
210 {
211         kill(pid, SIGKILL); /* kill test */
212         signal(sig, SIG_DFL);
213         raise(sig); /* kill ourself */
214         _exit(128 + sig); /* paranoia */
215 }
216 #endif
217
218 /* We provide the entry point here.  */
219 int
220 main (int argc, char *argv[])
221 {
222 #ifdef __ARCH_USE_MMU__
223   int direct = 0;       /* Directly call the test function?  */
224 #else
225   int direct = 1;
226 #endif
227   int status;
228   int opt;
229   unsigned int timeoutfactor = 1;
230   pid_t termpid;
231   char *envstr_timeoutfactor;
232
233   /* Make uses of freed and uninitialized memory known.  */
234 #ifdef __MALLOC_STANDARD__
235 #ifndef M_PERTURB
236 # define M_PERTURB -6
237 #endif
238   mallopt (M_PERTURB, 42);
239 #endif
240
241 #ifdef STDOUT_UNBUFFERED
242   setbuf (stdout, NULL);
243 #endif
244
245 #if 0 /* Not used in uClibc */
246   while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
247 #else
248 # ifndef CMDLINE_OPTIONS
249 #  define CMDLINE_OPTIONS ""
250 # endif
251   while ((opt = getopt (argc, argv, "+" CMDLINE_OPTIONS)) >= 0)
252 #endif
253     switch (opt)
254       {
255       case '?':
256         exit (1);
257       case OPT_DIRECT:
258         direct = 1;
259         break;
260       case OPT_TESTDIR:
261         test_dir = optarg;
262         break;
263 #ifdef CMDLINE_PROCESS
264         CMDLINE_PROCESS
265 #endif
266       }
267
268   /* If set, read the test TIMEOUTFACTOR value from the environment.
269      This value is used to scale the default test timeout values. */
270   envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
271   if (envstr_timeoutfactor != NULL)
272     {
273       char *envstr_conv = envstr_timeoutfactor;
274       unsigned long int env_fact;
275
276       env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
277       if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
278         timeoutfactor = MAX (env_fact, 1);
279     }
280
281   /* Set TMPDIR to specified test directory.  */
282   if (test_dir != NULL)
283     {
284       setenv ("TMPDIR", test_dir, 1);
285
286       if (chdir (test_dir) < 0)
287         {
288           perror ("chdir");
289           exit (1);
290         }
291     }
292   else
293     {
294       test_dir = getenv ("TMPDIR");
295       if (test_dir == NULL || test_dir[0] == '\0')
296         test_dir = "/tmp";
297     }
298
299   /* Make sure we see all message, even those on stdout.  */
300   setvbuf (stdout, NULL, _IONBF, 0);
301
302   /* make sure temporary files are deleted.  */
303   atexit (delete_temp_files);
304
305   /* Correct for the possible parameters.  */
306   argv[optind - 1] = argv[0];
307   argv += optind - 1;
308   argc -= optind - 1;
309
310   /* Call the initializing function, if one is available.  */
311 #ifdef PREPARE
312   PREPARE (argc, argv);
313 #endif
314
315   /* If we are not expected to fork run the function immediately.  */
316   if (direct)
317     return TEST_FUNCTION;
318
319   /* Set up the test environment:
320      - prevent core dumps
321      - set up the timer
322      - fork and execute the function.  */
323
324 #if defined __ARCH_USE_MMU__ || ! defined __UCLIBC__
325   pid = fork ();
326   if (pid == 0)
327     {
328       /* This is the child.  */
329 #ifdef RLIMIT_DATA
330       struct rlimit data_limit;
331 #endif
332 #ifdef RLIMIT_CORE
333       /* Try to avoid dumping core.  */
334       struct rlimit core_limit;
335       core_limit.rlim_cur = 0;
336       core_limit.rlim_max = 0;
337       setrlimit (RLIMIT_CORE, &core_limit);
338 #endif
339
340 #ifdef RLIMIT_DATA
341       /* Try to avoid eating all memory if a test leaks.  */
342       if (getrlimit (RLIMIT_DATA, &data_limit) == 0)
343         {
344           if (TEST_DATA_LIMIT == RLIM_INFINITY)
345             data_limit.rlim_cur = data_limit.rlim_max;
346           else if (data_limit.rlim_cur > (rlim_t) TEST_DATA_LIMIT)
347             data_limit.rlim_cur = MIN ((rlim_t) TEST_DATA_LIMIT,
348                                        data_limit.rlim_max);
349           if (setrlimit (RLIMIT_DATA, &data_limit) < 0)
350             perror ("setrlimit: RLIMIT_DATA");
351         }
352       else
353         perror ("getrlimit: RLIMIT_DATA");
354 #endif
355
356       /* We put the test process in its own pgrp so that if it bogusly
357          generates any job control signals, they won't hit the whole build.  */
358       setpgid (0, 0);
359
360       /* Execute the test function and exit with the return value.   */
361       exit (TEST_FUNCTION);
362     }
363   else if (pid < 0)
364 #endif
365     {
366       perror ("Cannot fork test program");
367       exit (1);
368     }
369
370 #ifdef __XXX_HANDLE_CTRL_C
371   signal (SIGTERM, handler_killpid);
372   signal (SIGINT, handler_killpid);
373   signal (SIGQUIT, handler_killpid);
374 #endif
375
376   /* Set timeout.  */
377 #ifndef TIMEOUT
378   /* Default timeout is two seconds.  */
379 # define TIMEOUT 2
380 #endif
381   signal (SIGALRM, signal_handler);
382   alarm (TIMEOUT * timeoutfactor);
383
384   /* Make sure we clean up if the wrapper gets interrupted.  */
385   signal (SIGINT, signal_handler);
386
387   /* Wait for the regular termination.  */
388   termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
389   if (termpid == -1)
390     {
391       printf ("Waiting for test program failed: %s\n", strerror(errno));
392       exit (1);
393     }
394   if (termpid != pid)
395     {
396       printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
397               (long int) pid, (long int) termpid);
398       exit (1);
399     }
400
401 #ifndef EXPECTED_SIGNAL
402   /* We don't expect any signal.  */
403 # define EXPECTED_SIGNAL 0
404 #endif
405   if (WTERMSIG (status) != EXPECTED_SIGNAL)
406     {
407       if (EXPECTED_SIGNAL != 0)
408         {
409           if (WTERMSIG (status) == 0)
410             fprintf (stderr,
411                      "Expected signal '%s' from child, got none\n",
412                      strsignal (EXPECTED_SIGNAL));
413           else
414             fprintf (stderr,
415                      "Incorrect signal from child: got `%s', need `%s'\n",
416                      strsignal (WTERMSIG (status)),
417                      strsignal (EXPECTED_SIGNAL));
418         }
419       else
420         fprintf (stderr, "Didn't expect signal from child: got `%s'\n",
421                  strsignal (WTERMSIG (status)));
422       exit (1);
423     }
424
425   /* Simply exit with the return value of the test.  */
426 #ifndef EXPECTED_STATUS
427   return WEXITSTATUS (status);
428 #else
429   if (WEXITSTATUS (status) != EXPECTED_STATUS)
430     {
431       fprintf (stderr, "Expected status %d, got %d\n",
432                EXPECTED_STATUS, WEXITSTATUS (status));
433       exit (1);
434     }
435
436   return 0;
437 #endif
438 }