extras: Introduce new subdirectory for test infrastructure 2016-11-25 Florian Weimer New subdirectory extras for build and test infrastructure. * Makeconfig (link-extra-libs-tests): Define. (+link-pie-tests, +link-static-tests, +link-tests): Use link-extra-libs-tests. (rpath-dirs, all-subdirs): Add extras. (built-modules): Add libextras. (libextras): Define. * extras: New directory. * extras/Makefile, extras/check.c, extras/chech.h, extras/extras.h, extras/ignore_stderr.c, extras/oom_error.c, extras/set_fortify_handler.c, extras/temp_file-internal.h, exteras/temp_file.c, extras_tempfile.h, extras/test-skeleton.c, extras_testmain.c, extras/test_main.h, extras/write_message.c, extras/xasprintf.c, extras/xcalloc.c, extras/xmalloc.c, extras/xrealloc.c: New files. * test-skeleton.c: Include . (_FAIL, FAIL_RET, FAIL_EXIT, FAIL_EXIT1): Remove. Now in extras/check.h. (oom_error, xmalloc, xcalloc, xrealloc, xasprintf, write_message) (ignore_stderr, set_fortify_handler): Remove. Now in extras/extras.h. * dlfcn/Makefile (bug-atexit3-lib.so): Link with $(libextras). * dlfcn/bug-atexit3-lib.cc: Include . (write_message): Remove. * io/test-open-tmpfile: Use new test skeleton. * io/tst-posix_fallocate-common.c: Likewise. * malloc/tst-malloc-backtrace.c: Likewise. * nptl/tst-cleanup0.c: Likewise. * posix/tst-posix_fadvise-common.c: Likewise. * sysdeps/unix/sysv/linux/tst-fallocate-common.c: Likewise. * sysdeps/unix/sysv/linux/tst-sync_file_range.c: Likewise. diff --git a/Makeconfig b/Makeconfig index a785860..c429917 100644 --- a/Makeconfig +++ b/Makeconfig @@ -394,6 +394,9 @@ ifndef after-link after-link = endif +# Additional libraries to link into every test. +link-extra-libs-tests = $(libextras) + # Command for linking PIE programs with the C library. ifndef +link-pie +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \ @@ -412,8 +415,8 @@ $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-pie-after-libc) $(call after-link,$@) endef define +link-pie-tests -$(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ - $(+link-pie-after-libc) +$(+link-pie-before-libc) $(link-extra-libs-tests) \ + $(rtld-tests-LDFLAGS) $(link-libc-tests) $(+link-pie-after-libc) $(call after-link,$@) endef endif @@ -434,7 +437,8 @@ $(+link-static-before-libc) $(link-libc-static) $(+link-static-after-libc) $(call after-link,$@) endef define +link-static-tests -$(+link-static-before-libc) $(link-libc-static-tests) $(+link-static-after-libc) +$(+link-static-before-libc) $(link-extra-libs-tests) \ + $(link-libc-static-tests) $(+link-static-after-libc) $(call after-link,$@) endef endif @@ -462,8 +466,8 @@ $(+link-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-after-libc) $(call after-link,$@) endef define +link-tests -$(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ - $(+link-after-libc) +$(+link-before-libc) $(link-extra-libs-tests) \ + $(link-libc-tests) $(+link-after-libc) $(call after-link,$@) endef endif @@ -503,7 +507,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) link-libc-tests = $(link-libc-tests-rpath-link) \ $(link-libc-before-gnulib) $(gnulib-tests) # This is how to find at build-time things that will be installed there. -rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec +rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec extras rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) else @@ -850,7 +854,7 @@ libio-include = -I$(..)libio # List of non-library modules that we build. built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \ libSegFault libpcprofile librpcsvc locale-programs \ - memusagestat nonlib nscd extramodules libnldbl + memusagestat nonlib nscd extramodules libnldbl libextras in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \ $(libof-$( #include -static void -write_message (const char *message) -{ - ssize_t unused __attribute__ ((unused)); - unused = write (STDOUT_FILENO, message, strlen (message)); -} +#include struct statclass { diff --git a/extras/Makefile b/extras/Makefile new file mode 100644 index 0000000..504078c --- /dev/null +++ b/extras/Makefile @@ -0,0 +1,46 @@ +# Makefile for extras library, used only at build and test time +# Copyright (C) 2016 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +subdir := elf + +include ../Makeconfig + +extra-libs := libextras +extra-libs-others = $(extra-libs) + +libextras-routines = \ + check \ + ignore_stderr \ + oom_error \ + set_fortify_handler \ + temp_file \ + test_main \ + write_message \ + xasprintf \ + xcalloc \ + xmalloc \ + xrealloc \ + +libextras-static-only-routines := $(libextras-routines) +# Only build one variant of the library. +libextras-inhibit-o := .os +ifeq ($(build-shared),yes) +libextras-inhibit-o += .o +endif + +include ../Rules diff --git a/extras/check.c b/extras/check.c new file mode 100644 index 0000000..b24c08c --- /dev/null +++ b/extras/check.c @@ -0,0 +1,54 @@ +/* Support code for reporting test results. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +static void +print_failure (const char *file, int line, const char *format, va_list ap) +{ + printf ("error: %s:%d: ", file, line); + vprintf (format, ap); + puts (""); +} + +int +__extras_print_failure (const char *file, int line, + const char *format, ...) +{ + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + return 1; +} + +void +__extras_exit_failure (int status, const char *file, int line, + const char *format, ...) +{ + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + exit (status); +} + diff --git a/extras/check.h b/extras/check.h new file mode 100644 index 0000000..f18062e --- /dev/null +++ b/extras/check.h @@ -0,0 +1,49 @@ +/* Macros for reporting test results. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef EXTRAS_CHECK_H +#define EXTRAS_CHECK_H + +#include + +__BEGIN_DECLS + +/* Print failure message to standard output and return 1. */ +#define FAIL_RET(...) \ + return __extras_print_failure (__FILE__, __LINE__, __VA_ARGS__) + +/* Print failure message and terminate the process with STATUS. */ +#define FAIL_EXIT(status, ...) \ + __extras_exit_failure (status, __FILE__, __LINE__, __VA_ARGS__) + +/* Print failure message and terminate with exit status 1. */ +#define FAIL_EXIT1(...) \ + __extras_exit_failure (1, __FILE__, __LINE__, __VA_ARGS__) + +int __extras_print_failure (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); +void __extras_exit_failure (int exit_status, + const char *file, int line, + const char *format, ...) + __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); + + +__END_DECLS + +#endif /* EXTRAS_CHECK_H */ diff --git a/extras/extras.h b/extras/extras.h new file mode 100644 index 0000000..006996d --- /dev/null +++ b/extras/extras.h @@ -0,0 +1,62 @@ +/* Common extra functions. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This header file should only contain definitions compatible with + C90. (Using __attribute__ is fine because provides a + fallback.) */ + +#ifndef EXTRAS_H +#define EXTRAS_H + +#include +#include + +/* Test exit status which indicates that the feature is + unsupported. */ +#define EXIT_UNSUPPORTED 77 + +__BEGIN_DECLS + +/* Write a message to standard output. Can be used in signal + handlers. */ +void write_message (const char *message) __attribute__ ((nonnull (1))); + +/* Avoid all the buffer overflow messages on stderr. */ +void ignore_stderr (void); + +/* Set fortification error handler. Used when tests want to verify that bad + code is caught by the library. */ +void set_fortify_handler (void (*handler) (int sig)); + +/* Report an out-of-memory error for the allocation of SIZE bytes in + FUNCTION, terminating the process. */ +void oom_error (const char *function, size_t size) + __attribute__ ((nonnull (1))); + +/* Error-checking wrapper functions which terminate the process on + error. */ + +void *xmalloc (size_t) __attribute__ ((malloc)); +void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); +void *xrealloc (void *p, size_t n); +char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); + +__END_DECLS + +#endif diff --git a/extras/ignore_stderr.c b/extras/ignore_stderr.c new file mode 100644 index 0000000..d5b8ffc --- /dev/null +++ b/extras/ignore_stderr.c @@ -0,0 +1,38 @@ +/* Avoid all the buffer overflow messages on stderr. + Copyright (C) 2015-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +void +ignore_stderr (void) +{ + int fd = open (_PATH_DEVNULL, O_WRONLY); + if (fd == -1) + close (STDERR_FILENO); + else + { + dup2 (fd, STDERR_FILENO); + close (fd); + } + setenv ("LIBC_FATAL_STDERR_", "1", 1); +} diff --git a/extras/oom_error.c b/extras/oom_error.c new file mode 100644 index 0000000..b881645 --- /dev/null +++ b/extras/oom_error.c @@ -0,0 +1,29 @@ +/* Reporting out-of-memory errors. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include + +void +oom_error (const char *function, size_t size) +{ + printf ("%s: unable to allocate %zu bytes: %m\n", function, size); + exit (1); +} diff --git a/extras/set_fortify_handler.c b/extras/set_fortify_handler.c new file mode 100644 index 0000000..3a9043f --- /dev/null +++ b/extras/set_fortify_handler.c @@ -0,0 +1,35 @@ +/* Set signal handler for use in fortify tests. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +set_fortify_handler (void (*handler) (int sig)) +{ + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGABRT, &sa, NULL); + ignore_stderr (); +} + diff --git a/extras/temp_file-internal.h b/extras/temp_file-internal.h new file mode 100644 index 0000000..3c42b6a --- /dev/null +++ b/extras/temp_file-internal.h @@ -0,0 +1,31 @@ +/* Internal weak declarations for temporary file handling. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef EXTRAS_TEMP_FILE_INTERNAL_H +#define EXTRAS_TEMP_FILE_INTERNAL_H + +/* These functions are called by the test driver if they are + defined. Tests should not call them directly. */ + +#include + +void __extras_set_test_dir (const char *name) __attribute__ ((weak)); +void __extras_delete_temp_files (void) __attribute__ ((weak)); +void __extras_print_temp_files (FILE *) __attribute__ ((weak)); + +#endif /* EXTRAS_TEMP_FILE_INTERNAL_H */ diff --git a/extras/temp_file.c b/extras/temp_file.c new file mode 100644 index 0000000..32b6560 --- /dev/null +++ b/extras/temp_file.c @@ -0,0 +1,121 @@ +/* Temporary file handling for tests. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* List of temporary files. */ +static struct temp_name_list +{ + struct qelem q; + char *name; +} *temp_name_list; + +/* Location of the temporary files. Set by the test skeleton via + __extras_set_test_dir. The string is not be freed. */ +static const char *test_dir = _PATH_TMP; + +void +add_temp_file (const char *name) +{ + struct temp_name_list *newp + = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); + char *newname = strdup (name); + if (newname != NULL) + { + newp->name = newname; + if (temp_name_list == NULL) + temp_name_list = (struct temp_name_list *) &newp->q; + else + insque (newp, temp_name_list); + } + else + free (newp); +} + +int +create_temp_file (const char *base, char **filename) +{ + char *fname; + int fd; + + fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) + + sizeof ("XXXXXX")); + strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); + + fd = mkstemp (fname); + if (fd == -1) + { + printf ("cannot open temporary file '%s': %m\n", fname); + free (fname); + return -1; + } + + add_temp_file (fname); + if (filename != NULL) + *filename = fname; + else + free (fname); + + return fd; +} + +/* Helper functions called by the test skeleton follow. */ + +void +__extras_set_test_dir (const char *path) +{ + test_dir = path; +} + +void +__extras_delete_temp_files (void) +{ + while (temp_name_list != NULL) + { + remove (temp_name_list->name); + free (temp_name_list->name); + + struct temp_name_list *next + = (struct temp_name_list *) temp_name_list->q.q_forw; + free (temp_name_list); + temp_name_list = next; + } +} + +void +__extras_print_temp_files (FILE *f) +{ + if (temp_name_list != NULL) + { + struct temp_name_list *n; + fprintf (f, "temp_files=(\n"); + for (n = temp_name_list; + n != NULL; + n = (struct temp_name_list *) n->q.q_forw) + fprintf (f, " '%s'\n", n->name); + fprintf (f, ")\n"); + } +} diff --git a/extras/temp_file.h b/extras/temp_file.h new file mode 100644 index 0000000..258169a --- /dev/null +++ b/extras/temp_file.h @@ -0,0 +1,37 @@ +/* Declarations for temporary file handling. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef EXTRAS_TEMP_FILE_H +#define EXTRAS_TEMP_FILE_H + +#include + +__BEGIN_DECLS + +/* Schedule a temporary file for deletion on exit. */ +void add_temp_file (const char *name); + +/* Create a temporary file. Return the opened file descriptor on + success, or -1 on failure. Write the file name to *FILENAME if + FILENAME is not NULL. In this case, the caller is expected to free + *FILENAME. */ +int create_temp_file (const char *base, char **filename); + +__END_DECLS + +#endif /* EXTRAS_TEMP_FILE_H */ diff --git a/extras/test-skeleton.c b/extras/test-skeleton.c new file mode 100644 index 0000000..0080c89 --- /dev/null +++ b/extras/test-skeleton.c @@ -0,0 +1,90 @@ +/* Skeleton for test programs. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This file should be included from test cases. It will define a + main function which provides the test wrapper. + + It assumes that the test case defines a function + + int do_test (void); + + and arranges for that function being called under the test wrapper. + The do_test function should return 0 to indicate a passing test, 1 + to indicate a failing test, or 77 to indicate an unsupported test. + Other result values could be used to indicate a failing test, but + the result of the expression is passed to exit and exit only + returns the lower 8 bits of its input. A non-zero return with some + values could cause a test to incorrectly be considered passing when + it really failed. For this reason the expression should always + return 0, 1, or 77. + + The test function may print out diagnostic or warning messages as well + as messages about failures. These messages should be printed to stdout + and not stderr so that the output is properly ordered with respect to + the rest of the glibc testsuite run output. + + Several preprocessors macros can be defined before including this + file. + + If PREPARE is defined, it must expand to the name of a function of + the type + + void PREPARE (void); + + This function will be called early, before running the test, in the + parent process which acts as the test supervisor. + + If EXPECTED_SIGNAL is defined, it must expanded to a constant which + denotes the expected signal number. + + If EXPECTED_STATUS is defined, it must expand to the expected exit + status. + + If TIMEOUT is defined, it must be positive constant. It overrides + the default test timeout and is measured in seconds. + + If TEST_NO_MALLOPT is defined, the test wrapper will not call + mallopt. */ + +#include + +#include + +int +main (int argc, char **argv) +{ + struct test_config test_config; + memset (&test_config, 0, sizeof (test_config)); +#ifdef PREPARE + test_config.prepare_function = (PREPARE); +#endif + test_config.test_function = do_test; +#ifdef EXPECTED_SIGNAL + test_config.expected_signal = (EXPECTED_SIGNAL); +#endif +#ifdef EXPECTED_STATUS + test_config.expected_status = (EXPECTED_STATUS); +#endif +#ifdef TEST_NO_MALLOPT + test_config.no_mallopt = 1; +#endif +#ifdef TIMEOUT + test_config.timeout = TIMEOUT; +#endif + return test_main (argc, argv, &test_config); +} diff --git a/extras/test_main.c b/extras/test_main.c new file mode 100644 index 0000000..8c188ca --- /dev/null +++ b/extras/test_main.c @@ -0,0 +1,360 @@ +/* Main function of the test skeleton. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum + { + /* Default timeout is twenty seconds. Tests should normally + complete faster than this, but if they don't, that's abnormal + (a bug) anyways. */ + DEFAULT_TIMEOUT = 20, + + /* Used for command line argument parsing. */ + OPT_DIRECT = 1000, + OPT_TESTDIR, + }; + +static struct option options[] = +{ + { "direct", no_argument, NULL, OPT_DIRECT }, + { "test-dir", required_argument, NULL, OPT_TESTDIR }, + { NULL, 0, NULL, 0 } +}; + +/* Show people how to run the program. */ +static void +usage (void) +{ + size_t i; + + printf ("Usage: %s [options]\n" + "\n" + "Environment Variables:\n" + " TIMEOUTFACTOR An integer used to scale the timeout\n" + " TMPDIR Where to place temporary files\n" + "\n", + program_invocation_short_name); + printf ("Options:\n"); + for (i = 0; options[i].name; ++i) + { + int indent; + + indent = printf (" --%s", options[i].name); + if (options[i].has_arg == required_argument) + indent += printf (" "); + printf ("%*s", 25 - indent, ""); + switch (options[i].val) + { + case OPT_DIRECT: + printf ("Run the test directly (instead of forking & monitoring)"); + break; + case OPT_TESTDIR: + printf ("Override the TMPDIR env var"); + break; + } + printf ("\n"); + } +} + +/* The PID of the test process. */ +static pid_t test_pid; + +/* Timeout handler. We kill the child and exit with an error. */ +static void +__attribute__ ((noreturn)) +signal_handler (int sig __attribute__ ((unused))) +{ + int killed; + int status; + + assert (test_pid > 1); + /* Kill the whole process group. */ + kill (-test_pid, SIGKILL); + /* In case setpgid failed in the child, kill it individually too. */ + kill (test_pid, SIGKILL); + + /* Wait for it to terminate. */ + int i; + for (i = 0; i < 5; ++i) + { + killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); + if (killed != 0) + break; + + /* Delay, give the system time to process the kill. If the + nanosleep() call return prematurely, all the better. We + won't restart it since this probably means the child process + finally died. */ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + if (killed != 0 && killed != test_pid) + { + printf ("Failed to kill test process: %m\n"); + exit (1); + } + + if (sig == SIGINT) + { + signal (sig, SIG_DFL); + raise (sig); + } + + if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) + puts ("Timed out: killed the child process"); + else if (WIFSTOPPED (status)) + printf ("Timed out: the child process was %s\n", + strsignal (WSTOPSIG (status))); + else if (WIFSIGNALED (status)) + printf ("Timed out: the child process got signal %s\n", + strsignal (WTERMSIG (status))); + else + printf ("Timed out: killed the child process but it exited %d\n", + WEXITSTATUS (status)); + + /* Exit with an error. */ + exit (1); +} + + +int +test_main (int argc, char **argv, const struct test_config *config) +{ + int direct = 0; /* Directly call the test function? */ + int status; + int opt; + unsigned int timeoutfactor = 1; + pid_t termpid; + const char *test_dir = NULL; + + if (!config->no_mallopt) + /* Make uses of freed and uninitialized memory known. */ + mallopt (M_PERTURB, 42); + + while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) + switch (opt) + { + case '?': + usage (); + exit (1); + case OPT_DIRECT: + direct = 1; + break; + case OPT_TESTDIR: + test_dir = optarg; + break; + } + + /* If set, read the test TIMEOUTFACTOR value from the environment. + This value is used to scale the default test timeout values. */ + char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); + if (envstr_timeoutfactor != NULL) + { + char *envstr_conv = envstr_timeoutfactor; + unsigned long int env_fact; + + env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); + if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) + timeoutfactor = MAX (env_fact, 1); + } + + /* Set TMPDIR to specified test directory. */ + if (test_dir != NULL) + { + setenv ("TMPDIR", test_dir, 1); + + if (chdir (test_dir) < 0) + { + printf ("chdir: %m\n"); + exit (1); + } + } + else + { + test_dir = getenv ("TMPDIR"); + if (test_dir == NULL || test_dir[0] == '\0') + test_dir = "/tmp"; + } + if (__extras_set_test_dir != NULL) + __extras_set_test_dir (test_dir); + + int timeout = config->timeout; + if (timeout == 0) + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (__extras_delete_temp_files != NULL) + atexit (__extras_delete_temp_files); + + /* Correct for the possible parameters. */ + argv[optind - 1] = argv[0]; + argv += optind - 1; + argc -= optind - 1; + + /* Call the initializing function, if one is available. */ + if (config->prepare_function != NULL) + config->prepare_function (); + + const char *envstr_direct = getenv ("TEST_DIRECT"); + if (envstr_direct != NULL) + { + FILE *f = fopen (envstr_direct, "w"); + if (f == NULL) + { + printf ("cannot open TEST_DIRECT output file '%s': %m\n", + envstr_direct); + exit (1); + } + + fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", + config->timeout, timeoutfactor); + if (config->expected_status != 0) + fprintf (f, "exit=%u\n", config->expected_status); + if (config->expected_signal != 0) + fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); + + if (__extras_print_temp_files != NULL) + __extras_print_temp_files (f); + + fclose (f); + direct = 1; + } + + /* If we are not expected to fork run the function immediately. */ + if (direct) + return config->test_function (); + + /* Set up the test environment: + - prevent core dumps + - set up the timer + - fork and execute the function. */ + + pid_t test_pid = fork (); + if (test_pid == 0) + { + /* This is the child. */ +#ifdef RLIMIT_CORE + /* Try to avoid dumping core. */ + struct rlimit core_limit; + core_limit.rlim_cur = 0; + core_limit.rlim_max = 0; + setrlimit (RLIMIT_CORE, &core_limit); +#endif + + /* We put the test process in its own pgrp so that if it bogusly + generates any job control signals, they won't hit the whole build. */ + if (setpgid (0, 0) != 0) + printf ("Failed to set the process group ID: %m\n"); + + /* Execute the test function and exit with the return value. */ + exit (config->test_function ()); + } + else if (test_pid < 0) + { + printf ("Cannot fork test program: %m\n"); + exit (1); + } + + /* Set timeout. */ + signal (SIGALRM, signal_handler); + alarm (config->timeout * timeoutfactor); + + /* Make sure we clean up if the wrapper gets interrupted. */ + signal (SIGINT, signal_handler); + + /* Wait for the regular termination. */ + termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0)); + if (termpid == -1) + { + printf ("Waiting for test program failed: %m\n"); + exit (1); + } + if (termpid != test_pid) + { + printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", + (long int) test_pid, (long int) termpid); + exit (1); + } + + /* Process terminated normaly without timeout etc. */ + if (WIFEXITED (status)) + { + if (config->expected_status == 0) + { + if (config->expected_signal == 0) + /* Simply exit with the return value of the test. */ + return WEXITSTATUS (status); + else + { + printf ("Expected signal '%s' from child, got none\n", + strsignal (config->expected_signal)); + exit (1); + } + } + else + { + /* Non-zero exit status is expected */ + if (WEXITSTATUS (status) != config->expected_status) + { + printf ("Expected status %d, got %d\n", + config->expected_status, WEXITSTATUS (status)); + exit (1); + } + } + return 0; + } + /* Process was killed by timer or other signal. */ + else + { + if (config->expected_signal == 0) + { + printf ("Didn't expect signal from child: got `%s'\n", + strsignal (WTERMSIG (status))); + exit (1); + } + else if (WTERMSIG (status) != config->expected_signal) + { + printf ("Incorrect signal from child: got `%s', need `%s'\n", + strsignal (WTERMSIG (status)), + strsignal (config->expected_signal)); + exit (1); + } + + return 0; + } +} diff --git a/extras/test_main.h b/extras/test_main.h new file mode 100644 index 0000000..01627ea --- /dev/null +++ b/extras/test_main.h @@ -0,0 +1,34 @@ +/* Interfaces for the test skeleton. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef EXTRAS_TEST_MAIN_H +#define EXTRAS_TEST_MAIN_H + +struct test_config +{ + void (*prepare_function) (void); + int (*test_function) (void); + int timeout; /* Test timeout in seconds. */ + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ +}; + +int test_main (int argc, char **argv, const struct test_config *); + +#endif /* EXTRAS_TEST_MAIN_H */ diff --git a/extras/write_message.c b/extras/write_message.c new file mode 100644 index 0000000..0fd8afc --- /dev/null +++ b/extras/write_message.c @@ -0,0 +1,30 @@ +/* Write a message to standard output. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include + +void +write_message (const char *message) +{ + ssize_t unused __attribute__ ((unused)); + unused = write (STDOUT_FILENO, message, strlen (message)); +} + diff --git a/extras/xasprintf.c b/extras/xasprintf.c new file mode 100644 index 0000000..045c2e8 --- /dev/null +++ b/extras/xasprintf.c @@ -0,0 +1,38 @@ +/* Error-checking wrapper for asprintf. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +char * +xasprintf (const char *format, ...) +{ + va_list ap; + va_start (ap, format); + char *result; + if (vasprintf (&result, format, ap) < 0) + { + printf ("error: asprintf: %m\n"); + exit (1); + } + va_end (ap); + return result; +} diff --git a/extras/xcalloc.c b/extras/xcalloc.c new file mode 100644 index 0000000..4b6af5a --- /dev/null +++ b/extras/xcalloc.c @@ -0,0 +1,34 @@ +/* Error-checking wrapper for calloc. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void * +xcalloc (size_t n, size_t s) +{ + void *p; + + p = calloc (n, s); + if (p == NULL) + oom_error ("calloc", n * s); + return p; +} diff --git a/extras/xmalloc.c b/extras/xmalloc.c new file mode 100644 index 0000000..b53e2a0 --- /dev/null +++ b/extras/xmalloc.c @@ -0,0 +1,34 @@ +/* Error-checking wrapper for malloc. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void * +xmalloc (size_t n) +{ + void *p; + + p = malloc (n); + if (p == NULL) + oom_error ("malloc", n); + return p; +} diff --git a/extras/xrealloc.c b/extras/xrealloc.c new file mode 100644 index 0000000..9b0e7a6 --- /dev/null +++ b/extras/xrealloc.c @@ -0,0 +1,32 @@ +/* Error-checking wrapper for realloc. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void * +xrealloc (void *p, size_t n) +{ + void *result = realloc (p, n); + if (result == NULL && (n > 0 || p == NULL)) + oom_error ("realloc", n); + return result; +} diff --git a/io/tst-open-tmpfile.c b/io/tst-open-tmpfile.c index 9242d62..d89aa79 100644 --- a/io/tst-open-tmpfile.c +++ b/io/tst-open-tmpfile.c @@ -28,10 +28,7 @@ #include #include -static int do_test (void); - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include #ifdef O_TMPFILE typedef int (*wrapper_func) (const char *, int, mode_t); @@ -317,3 +314,5 @@ do_test (void) } #endif /* O_TMPFILE */ + +#include diff --git a/io/tst-posix_fallocate-common.c b/io/tst-posix_fallocate-common.c index 2f15a5d..5157ec9 100644 --- a/io/tst-posix_fallocate-common.c +++ b/io/tst-posix_fallocate-common.c @@ -17,18 +17,15 @@ . */ #include -#include +#include +#include #include +#include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ - -#include +#include +#include +#include static char *temp_filename; static int temp_fd; @@ -41,9 +38,6 @@ do_prepare (void) FAIL_EXIT1 ("cannot create temporary file: %m\n"); } -#define FAIL(str) \ - do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0) - static int do_test_with_offset (off_t offset) { @@ -83,3 +77,10 @@ do_test_with_offset (off_t offset) return 0; } + +#define PREPARE do_prepare + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c index 3aee7fd..a6c34cf 100644 --- a/malloc/tst-malloc-backtrace.c +++ b/malloc/tst-malloc-backtrace.c @@ -16,9 +16,11 @@ License along with the GNU C Library; if not, see . */ - +#include #include +#include + #define SIZE 4096 /* Wrap free with a function to prevent gcc from optimizing it out. */ @@ -30,13 +32,6 @@ call_free (void *ptr) *(size_t *)(ptr - sizeof (size_t)) = 1; } -int do_test (void); - -#define TEST_FUNCTION do_test () -#define EXPECTED_SIGNAL SIGABRT - -#include "../test-skeleton.c" - int do_test (void) { @@ -53,3 +48,6 @@ do_test (void) doesn't optimize out that malloc call. */ return (ptr1 == ptr2); } + +#define EXPECTED_SIGNAL SIGABRT +#include diff --git a/nptl/tst-cleanup0.c b/nptl/tst-cleanup0.c index 011e5a6..a3a868b 100644 --- a/nptl/tst-cleanup0.c +++ b/nptl/tst-cleanup0.c @@ -71,5 +71,4 @@ do_test (void) #define EXPECTED_STATUS 9 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff --git a/posix/tst-posix_fadvise-common.c b/posix/tst-posix_fadvise-common.c index bb04c61..2d37665 100644 --- a/posix/tst-posix_fadvise-common.c +++ b/posix/tst-posix_fadvise-common.c @@ -16,17 +16,17 @@ License along with the GNU C Library; if not, see . */ +#include #include +#include +#include #include #include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#include +#include +#include +#include static char *temp_filename; static int temp_fd; @@ -101,3 +101,10 @@ do_test_common (void) return 0; } + +#define PREPARE do_prepare + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/sysdeps/unix/sysv/linux/tst-fallocate-common.c b/sysdeps/unix/sysv/linux/tst-fallocate-common.c index d98bf4a..b8f4333 100644 --- a/sysdeps/unix/sysv/linux/tst-fallocate-common.c +++ b/sysdeps/unix/sysv/linux/tst-fallocate-common.c @@ -16,23 +16,22 @@ License along with the GNU C Library; if not, see . */ +#include #include -#include +#include +#include +#include #include +#include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ +#include +#include +#include #define XSTR(s) STR(S) #define STR(s) #s -#include - static char *temp_filename; static int temp_fd; @@ -91,3 +90,10 @@ do_test_with_offset (off_t offset) return 0; } + +#define PREPARE do_prepare + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/sysdeps/unix/sysv/linux/tst-sync_file_range.c b/sysdeps/unix/sysv/linux/tst-sync_file_range.c index 499a234..a41e3ed 100644 --- a/sysdeps/unix/sysv/linux/tst-sync_file_range.c +++ b/sysdeps/unix/sysv/linux/tst-sync_file_range.c @@ -18,21 +18,18 @@ /* sync_file_range is only define for LFS. */ #define _FILE_OFFSET_BITS 64 -#include #include +#include +#include +#include +#include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ +#include +#include #define XSTR(s) STR(S) #define STR(s) #s -#include - static char *temp_filename; static int temp_fd; @@ -129,3 +126,8 @@ do_test (void) return 0; } + +#define PREPARE do_prepare + +#include + diff --git a/test-skeleton.c b/test-skeleton.c index fa457be..e66e6f6 100644 --- a/test-skeleton.c +++ b/test-skeleton.c @@ -34,6 +34,8 @@ #include #include +#include + /* The test function is normally called `do_test' and it is called with argc and argv as the arguments. We nevertheless provide the possibility to overwrite this name. @@ -85,94 +87,6 @@ static pid_t pid; /* Directory to place temporary files in. */ static const char *test_dir; -#define _FAIL(...) \ - printf ("error: %s:%d: ", __FILE__, __LINE__); \ - printf (__VA_ARGS__); \ - printf ("\n"); \ - -#define FAIL_RET(...) \ - ({ \ - _FAIL (__VA_ARGS__); \ - return 1; \ - }) - -#define FAIL_EXIT(value, ...) \ - ({ \ - _FAIL (__VA_ARGS__); \ - exit (value); \ - }) - -#define FAIL_EXIT1(...) FAIL_EXIT(1, __VA_ARGS__) - -static void -oom_error (const char *fn, size_t size) -{ - printf ("%s: unable to allocate %zu bytes: %m\n", fn, size); - exit (1); -} - -/* Allocate N bytes of memory dynamically, with error checking. */ -__attribute__ ((unused)) -static void * -xmalloc (size_t n) -{ - void *p; - - p = malloc (n); - if (p == NULL) - oom_error ("malloc", n); - return p; -} - -/* Allocate memory for N elements of S bytes, with error checking. */ -__attribute__ ((unused)) -static void * -xcalloc (size_t n, size_t s) -{ - void *p; - - p = calloc (n, s); - if (p == NULL) - oom_error ("calloc", n * s); - return p; -} - -/* Change the size of an allocated block of memory P to N bytes, - with error checking. */ -__attribute__ ((unused)) -static void * -xrealloc (void *p, size_t n) -{ - void *result = realloc (p, n); - if (result == NULL && (n > 0 || p == NULL)) - oom_error ("realloc", n); - return result; -} - -/* Call asprintf with error checking. */ -__attribute__ ((always_inline, format (printf, 1, 2))) -static __inline__ char * -xasprintf (const char *format, ...) -{ - char *result; - if (asprintf (&result, format, __builtin_va_arg_pack ()) < 0) - { - printf ("error: asprintf: %m\n"); - exit (1); - } - return result; -} - -/* Write a message to standard output. Can be used in signal - handlers. */ -static void -__attribute__ ((unused)) -write_message (const char *message) -{ - ssize_t unused __attribute__ ((unused)); - unused = write (STDOUT_FILENO, message, strlen (message)); -} - /* List of temporary files. */ struct temp_name_list { @@ -317,38 +231,6 @@ signal_handler (int sig __attribute__ ((unused))) exit (1); } -/* Avoid all the buffer overflow messages on stderr. */ -static void -__attribute__ ((unused)) -ignore_stderr (void) -{ - int fd = open (_PATH_DEVNULL, O_WRONLY); - if (fd == -1) - close (STDERR_FILENO); - else - { - dup2 (fd, STDERR_FILENO); - close (fd); - } - setenv ("LIBC_FATAL_STDERR_", "1", 1); -} - -/* Set fortification error handler. Used when tests want to verify that bad - code is caught by the library. */ -static void -__attribute__ ((unused)) -set_fortify_handler (void (*handler) (int sig)) -{ - struct sigaction sa; - - sa.sa_handler = handler; - sa.sa_flags = 0; - sigemptyset (&sa.sa_mask); - - sigaction (SIGABRT, &sa, NULL); - ignore_stderr (); -} - /* Show people how to run the program. */ static void usage (void)