diff options
-rw-r--r-- | tests/sys/posixshm/Makefile | 6 | ||||
-rw-r--r-- | tests/sys/posixshm/posixshm.c | 627 | ||||
-rw-r--r-- | tests/sys/posixshm/posixshm_test.c | 739 | ||||
-rw-r--r-- | tests/sys/posixshm/shm_test.c | 164 | ||||
-rw-r--r-- | tests/sys/posixshm/test.c | 128 | ||||
-rw-r--r-- | tests/sys/posixshm/test.h | 59 |
6 files changed, 740 insertions, 983 deletions
diff --git a/tests/sys/posixshm/Makefile b/tests/sys/posixshm/Makefile index 7ddd7f0..2acdfa4 100644 --- a/tests/sys/posixshm/Makefile +++ b/tests/sys/posixshm/Makefile @@ -2,10 +2,6 @@ TESTSDIR= ${TESTSBASE}/sys/posixshm -TAP_TESTS_C+= posixshm_test -PLAIN_TESTS_C+= posixshm_test2 - -SRCS.posixshm_test= posixshm.c test.c -SRCS.posixshm_test2= shm_test.c +ATF_TESTS_C+= posixshm_test .include <bsd.test.mk> diff --git a/tests/sys/posixshm/posixshm.c b/tests/sys/posixshm/posixshm.c deleted file mode 100644 index 6f4c306..0000000 --- a/tests/sys/posixshm/posixshm.c +++ /dev/null @@ -1,627 +0,0 @@ -/*- - * Copyright (c) 2006 Robert N. M. Watson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/mman.h> -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/wait.h> - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "test.h" - -#define TEST_PATH "/tmp/posixshm_regression_test" - -/* - * Attempt a shm_open() that should fail with an expected error of 'error'. - */ -static void -shm_open_should_fail(const char *path, int flags, mode_t mode, int error) -{ - int fd; - - fd = shm_open(path, flags, mode); - if (fd >= 0) { - fail_err("shm_open() didn't fail"); - close(fd); - return; - } - if (errno != error) { - fail_errno("shm_open"); - return; - } - pass(); -} - -/* - * Attempt a shm_unlink() that should fail with an expected error of 'error'. - */ -static void -shm_unlink_should_fail(const char *path, int error) -{ - - if (shm_unlink(path) >= 0) { - fail_err("shm_unlink() didn't fail"); - return; - } - if (errno != error) { - fail_errno("shm_unlink"); - return; - } - pass(); -} - -/* - * Open the test object and write '1' to the first byte. Returns valid fd - * on success and -1 on failure. - */ -static int -scribble_object(void) -{ - char *page; - int fd; - - fd = shm_open(TEST_PATH, O_CREAT | O_EXCL | O_RDWR, 0777); - if (fd < 0 && errno == EEXIST) { - if (shm_unlink(TEST_PATH) < 0) { - fail_errno("shm_unlink"); - return (-1); - } - fd = shm_open(TEST_PATH, O_CREAT | O_EXCL | O_RDWR, 0777); - } - if (fd < 0) { - fail_errno("shm_open"); - return (-1); - } - if (ftruncate(fd, getpagesize()) < 0) { - fail_errno("ftruncate"); - close(fd); - shm_unlink(TEST_PATH); - return (-1); - } - - page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, - 0); - if (page == MAP_FAILED) { - fail_errno("mmap"); - close(fd); - shm_unlink(TEST_PATH); - return (-1); - } - - page[0] = '1'; - - if (munmap(page, getpagesize()) < 0) { - fail_errno("munmap"); - close(fd); - shm_unlink(TEST_PATH); - return (-1); - } - - return (fd); -} - -static void -remap_object(void) -{ - char *page; - int fd; - - fd = scribble_object(); - if (fd < 0) - return; - - page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, - 0); - if (page == MAP_FAILED) { - fail_errno("mmap(2)"); - close(fd); - shm_unlink(TEST_PATH); - return; - } - - if (page[0] != '1') { - fail_err("missing data"); - close(fd); - shm_unlink(TEST_PATH); - return; - } - - close(fd); - if (munmap(page, getpagesize()) < 0) { - fail_errno("munmap"); - shm_unlink(TEST_PATH); - return; - } - - if (shm_unlink(TEST_PATH) < 0) { - fail_errno("shm_unlink"); - return; - } - - pass(); -} -TEST(remap_object, "remap object"); - -static void -reopen_object(void) -{ - char *page; - int fd; - - fd = scribble_object(); - if (fd < 0) - return; - close(fd); - - fd = shm_open(TEST_PATH, O_RDONLY, 0777); - if (fd < 0) { - fail_errno("shm_open(2)"); - shm_unlink(TEST_PATH); - return; - } - page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); - if (page == MAP_FAILED) { - fail_errno("mmap(2)"); - close(fd); - shm_unlink(TEST_PATH); - return; - } - - if (page[0] != '1') { - fail_err("missing data"); - munmap(page, getpagesize()); - close(fd); - shm_unlink(TEST_PATH); - return; - } - - munmap(page, getpagesize()); - close(fd); - shm_unlink(TEST_PATH); - pass(); -} -TEST(reopen_object, "reopen object"); - -static void -readonly_mmap_write(void) -{ - char *page; - int fd; - - fd = shm_open(TEST_PATH, O_RDONLY | O_CREAT, 0777); - if (fd < 0) { - fail_errno("shm_open"); - return; - } - - /* PROT_WRITE should fail with EACCES. */ - page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, - 0); - if (page != MAP_FAILED) { - fail_err("mmap(PROT_WRITE) succeeded"); - munmap(page, getpagesize()); - close(fd); - shm_unlink(TEST_PATH); - return; - } - if (errno != EACCES) { - fail_errno("mmap"); - close(fd); - shm_unlink(TEST_PATH); - return; - } - - close(fd); - shm_unlink(TEST_PATH); - pass(); -} -TEST(readonly_mmap_write, "RDONLY object"); - -static void -open_after_unlink(void) -{ - int fd; - - fd = shm_open(TEST_PATH, O_RDONLY | O_CREAT, 0777); - if (fd < 0) { - fail_errno("shm_open(1)"); - return; - } - close(fd); - - if (shm_unlink(TEST_PATH) < 0) { - fail_errno("shm_unlink"); - return; - } - - shm_open_should_fail(TEST_PATH, O_RDONLY, 0777, ENOENT); -} -TEST(open_after_unlink, "open after unlink"); - -static void -open_invalid_path(void) -{ - - shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL); -} -TEST(open_invalid_path, "open invalid path"); - -static void -open_write_only(void) -{ - - shm_open_should_fail(TEST_PATH, O_WRONLY, 0777, EINVAL); -} -TEST(open_write_only, "open with O_WRONLY"); - -static void -open_extra_flags(void) -{ - - shm_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, EINVAL); -} -TEST(open_extra_flags, "open with extra flags"); - -static void -open_anon(void) -{ - int fd; - - fd = shm_open(SHM_ANON, O_RDWR, 0777); - if (fd < 0) { - fail_errno("shm_open"); - return; - } - close(fd); - pass(); -} -TEST(open_anon, "open anonymous object"); - -static void -open_anon_readonly(void) -{ - - shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL); -} -TEST(open_anon_readonly, "open SHM_ANON with O_RDONLY"); - -static void -open_bad_path_pointer(void) -{ - - shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT); -} -TEST(open_bad_path_pointer, "open bad path pointer"); - -static void -open_path_too_long(void) -{ - char *page; - - page = malloc(MAXPATHLEN + 1); - memset(page, 'a', MAXPATHLEN); - page[MAXPATHLEN] = '\0'; - shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG); - free(page); -} -TEST(open_path_too_long, "open pathname too long"); - -static void -open_nonexisting_object(void) -{ - - shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT); -} -TEST(open_nonexisting_object, "open nonexistent object"); - -static void -exclusive_create_existing_object(void) -{ - int fd; - - fd = shm_open("/tmp/notreallythere", O_RDONLY | O_CREAT, 0777); - if (fd < 0) { - fail_errno("shm_open(O_CREAT)"); - return; - } - close(fd); - - shm_open_should_fail("/tmp/notreallythere", O_RDONLY | O_CREAT | O_EXCL, - 0777, EEXIST); - - shm_unlink("/tmp/notreallythere"); -} -TEST(exclusive_create_existing_object, "O_EXCL of existing object"); - -static void -trunc_resets_object(void) -{ - struct stat sb; - int fd; - - /* Create object and set size to 1024. */ - fd = shm_open(TEST_PATH, O_RDWR | O_CREAT, 0777); - if (fd < 0) { - fail_errno("shm_open(1)"); - return; - } - if (ftruncate(fd, 1024) < 0) { - fail_errno("ftruncate"); - close(fd); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(1)"); - close(fd); - return; - } - if (sb.st_size != 1024) { - fail_err("size %d != 1024", (int)sb.st_size); - close(fd); - return; - } - close(fd); - - /* Open with O_TRUNC which should reset size to 0. */ - fd = shm_open(TEST_PATH, O_RDWR | O_TRUNC, 0777); - if (fd < 0) { - fail_errno("shm_open(2)"); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(2)"); - close(fd); - return; - } - if (sb.st_size != 0) { - fail_err("size after O_TRUNC %d != 0", (int)sb.st_size); - close(fd); - return; - } - close(fd); - if (shm_unlink(TEST_PATH) < 0) { - fail_errno("shm_unlink"); - return; - } - pass(); -} -TEST(trunc_resets_object, "O_TRUNC resets size"); - -static void -unlink_bad_path_pointer(void) -{ - - shm_unlink_should_fail((char *)1024, EFAULT); -} -TEST(unlink_bad_path_pointer, "unlink bad path pointer"); - -static void -unlink_path_too_long(void) -{ - char *page; - - page = malloc(MAXPATHLEN + 1); - memset(page, 'a', MAXPATHLEN); - page[MAXPATHLEN] = '\0'; - shm_unlink_should_fail(page, ENAMETOOLONG); - free(page); -} -TEST(unlink_path_too_long, "unlink pathname too long"); - -static void -test_object_resize(void) -{ - pid_t pid; - struct stat sb; - char *page; - int fd, status; - - /* Start off with a size of a single page. */ - fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0777); - if (fd < 0) { - fail_errno("shm_open"); - return; - } - if (ftruncate(fd, getpagesize()) < 0) { - fail_errno("ftruncate(1)"); - close(fd); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(1)"); - close(fd); - return; - } - if (sb.st_size != getpagesize()) { - fail_err("first resize failed"); - close(fd); - return; - } - - /* Write a '1' to the first byte. */ - page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, - 0); - if (page == MAP_FAILED) { - fail_errno("mmap(1)"); - close(fd); - return; - } - - page[0] = '1'; - - if (munmap(page, getpagesize()) < 0) { - fail_errno("munmap(1)"); - close(fd); - return; - } - - /* Grow the object to 2 pages. */ - if (ftruncate(fd, getpagesize() * 2) < 0) { - fail_errno("ftruncate(2)"); - close(fd); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(2)"); - close(fd); - return; - } - if (sb.st_size != getpagesize() * 2) { - fail_err("second resize failed"); - close(fd); - return; - } - - /* Check for '1' at the first byte. */ - page = mmap(0, getpagesize() * 2, PROT_READ | PROT_WRITE, MAP_SHARED, - fd, 0); - if (page == MAP_FAILED) { - fail_errno("mmap(2)"); - close(fd); - return; - } - - if (page[0] != '1') { - fail_err("missing data at 0"); - close(fd); - return; - } - - /* Write a '2' at the start of the second page. */ - page[getpagesize()] = '2'; - - /* Shrink the object back to 1 page. */ - if (ftruncate(fd, getpagesize()) < 0) { - fail_errno("ftruncate(3)"); - close(fd); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(3)"); - close(fd); - return; - } - if (sb.st_size != getpagesize()) { - fail_err("third resize failed"); - close(fd); - return; - } - - /* - * Fork a child process to make sure the second page is no - * longer valid. - */ - pid = fork(); - if (pid < 0) { - fail_errno("fork"); - close(fd); - return; - } - - if (pid == 0) { - struct rlimit lim; - char c; - - /* Don't generate a core dump. */ - getrlimit(RLIMIT_CORE, &lim); - lim.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &lim); - - /* - * The previous ftruncate(2) shrunk the backing object - * so that this address is no longer valid, so reading - * from it should trigger a SIGSEGV. - */ - c = page[getpagesize()]; - fprintf(stderr, "child: page 1: '%c'\n", c); - exit(0); - } - if (wait(&status) < 0) { - fail_errno("wait"); - close(fd); - return; - } - if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) { - fail_err("child terminated with status %x", status); - close(fd); - return; - } - - /* Grow the object back to 2 pages. */ - if (ftruncate(fd, getpagesize() * 2) < 0) { - fail_errno("ftruncate(4)"); - close(fd); - return; - } - if (fstat(fd, &sb) < 0) { - fail_errno("fstat(4)"); - close(fd); - return; - } - if (sb.st_size != getpagesize() * 2) { - fail_err("second resize failed"); - close(fd); - return; - } - - /* - * Note that the mapping at 'page' for the second page is - * still valid, and now that the shm object has been grown - * back up to 2 pages, there is now memory backing this page - * so the read will work. However, the data should be zero - * rather than '2' as the old data was thrown away when the - * object was shrunk and the new pages when an object are - * grown are zero-filled. - */ - if (page[getpagesize()] != 0) { - fail_err("invalid data at %d", getpagesize()); - close(fd); - return; - } - - close(fd); - pass(); -} -TEST(test_object_resize, "object resize"); - -int -main(int argc, char *argv[]) -{ - - run_tests(); - return (0); -} diff --git a/tests/sys/posixshm/posixshm_test.c b/tests/sys/posixshm/posixshm_test.c new file mode 100644 index 0000000..d7c32a8 --- /dev/null +++ b/tests/sys/posixshm/posixshm_test.c @@ -0,0 +1,739 @@ +/*- + * Copyright (c) 2006 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/wait.h> + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +#define TEST_PATH_LEN 256 +static char test_path[TEST_PATH_LEN]; + +static void +gen_test_path(void) +{ + char *tmpdir = getenv("TMPDIR"); + + if (tmpdir == NULL) + tmpdir = "/tmp"; + + snprintf(test_path, sizeof(test_path), "%s/tmp.XXXXXX", tmpdir); + test_path[sizeof(test_path) - 1] = '\0'; + ATF_REQUIRE_MSG(mkstemp(test_path) != -1, + "mkstemp failed; errno=%d", errno); + ATF_REQUIRE_MSG(unlink(test_path) == 0, + "unlink failed; errno=%d", errno); +} + +/* + * Attempt a shm_open() that should fail with an expected error of 'error'. + */ +static void +shm_open_should_fail(const char *path, int flags, mode_t mode, int error) +{ + int fd; + + fd = shm_open(path, flags, mode); + ATF_CHECK_MSG(fd == -1, "shm_open didn't fail"); + ATF_CHECK_MSG(error == errno, + "shm_open didn't fail with expected errno; errno=%d; expected " + "errno=%d", errno, error); +} + +/* + * Attempt a shm_unlink() that should fail with an expected error of 'error'. + */ +static void +shm_unlink_should_fail(const char *path, int error) +{ + + ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail"); + ATF_CHECK_MSG(error == errno, + "shm_unlink didn't fail with expected errno; errno=%d; expected " + "errno=%d", errno, error); +} + +/* + * Open the test object and write '1' to the first byte. Returns valid fd + * on success and -1 on failure. + */ +static int +scribble_object(void) +{ + char *page; + int fd; + + gen_test_path(); + + fd = shm_open(test_path, O_CREAT|O_EXCL|O_RDWR, 0777); + if (fd < 0 && errno == EEXIST) { + if (shm_unlink(test_path) < 0) + atf_tc_fail("shm_unlink"); + fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777); + } + if (fd < 0) + atf_tc_fail("shm_open"); + if (ftruncate(fd, getpagesize()) < 0) + atf_tc_fail("ftruncate"); + + page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, + 0); + if (page == MAP_FAILED) + atf_tc_fail("mmap"); + + page[0] = '1'; + if (munmap(page, getpagesize()) < 0) + atf_tc_fail("munmap"); + + return (fd); +} + +ATF_TC_WITHOUT_HEAD(remap_object); +ATF_TC_BODY(remap_object, tc) +{ + char *page; + int fd; + + fd = scribble_object(); + + page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, + 0); + if (page == MAP_FAILED) { + atf_tc_fail("mmap(2)"); + close(fd); + shm_unlink(test_path); + return; + } + + if (page[0] != '1') { + atf_tc_fail("missing data"); + close(fd); + shm_unlink(test_path); + return; + } + + close(fd); + if (munmap(page, getpagesize()) < 0) { + atf_tc_fail("munmap"); + shm_unlink(test_path); + return; + } + + if (shm_unlink(test_path) < 0) { + atf_tc_fail("shm_unlink"); + return; + } + +} + +ATF_TC_WITHOUT_HEAD(reopen_object); +ATF_TC_BODY(reopen_object, tc) +{ + char *page; + int fd; + + fd = scribble_object(); + close(fd); + + fd = shm_open(test_path, O_RDONLY, 0777); + if (fd < 0) { + atf_tc_fail("shm_open(2)"); + shm_unlink(test_path); + return; + } + page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); + if (page == MAP_FAILED) { + atf_tc_fail("mmap(2)"); + close(fd); + shm_unlink(test_path); + return; + } + + if (page[0] != '1') { + atf_tc_fail("missing data"); + munmap(page, getpagesize()); + close(fd); + shm_unlink(test_path); + return; + } + + munmap(page, getpagesize()); + close(fd); + shm_unlink(test_path); +} + +ATF_TC_WITHOUT_HEAD(readonly_mmap_write); +ATF_TC_BODY(readonly_mmap_write, tc) +{ + char *page; + int fd; + + gen_test_path(); + + fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); + if (fd < 0) { + atf_tc_fail("shm_open"); + return; + } + + /* PROT_WRITE should fail with EACCES. */ + page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, + 0); + if (page != MAP_FAILED) { + atf_tc_fail("mmap(PROT_WRITE) succeeded"); + munmap(page, getpagesize()); + close(fd); + shm_unlink(test_path); + return; + } + if (errno != EACCES) { + atf_tc_fail("mmap"); + close(fd); + shm_unlink(test_path); + return; + } + + close(fd); + shm_unlink(test_path); +} + +ATF_TC_WITHOUT_HEAD(open_after_link); +ATF_TC_BODY(open_after_link, tc) +{ + int fd; + + gen_test_path(); + + fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); + if (fd < 0) { + atf_tc_fail("shm_open(1)"); + return; + } + close(fd); + + if (shm_unlink(test_path) < 0) { + atf_tc_fail("shm_unlink"); + return; + } + + shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT); +} + +ATF_TC_WITHOUT_HEAD(open_invalid_path); +ATF_TC_BODY(open_invalid_path, tc) +{ + + shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL); +} + +ATF_TC_WITHOUT_HEAD(open_write_only); +ATF_TC_BODY(open_write_only, tc) +{ + + gen_test_path(); + + shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL); +} + +ATF_TC_WITHOUT_HEAD(open_extra_flags); +ATF_TC_BODY(open_extra_flags, tc) +{ + + gen_test_path(); + + shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL); +} + +ATF_TC_WITHOUT_HEAD(open_anon); +ATF_TC_BODY(open_anon, tc) +{ + int fd; + + fd = shm_open(SHM_ANON, O_RDWR, 0777); + if (fd < 0) { + atf_tc_fail("shm_open"); + return; + } + close(fd); +} + +ATF_TC_WITHOUT_HEAD(open_anon_readonly); +ATF_TC_BODY(open_anon_readonly, tc) +{ + + shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL); +} + +ATF_TC_WITHOUT_HEAD(open_bad_path_pointer); +ATF_TC_BODY(open_bad_path_pointer, tc) +{ + + shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT); +} + +ATF_TC_WITHOUT_HEAD(open_path_too_long); +ATF_TC_BODY(open_path_too_long, tc) +{ + char *page; + + page = malloc(MAXPATHLEN + 1); + memset(page, 'a', MAXPATHLEN); + page[MAXPATHLEN] = '\0'; + shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG); + free(page); +} + +ATF_TC_WITHOUT_HEAD(open_nonexisting_object); +ATF_TC_BODY(open_nonexisting_object, tc) +{ + + shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT); +} + +ATF_TC_WITHOUT_HEAD(open_create_existing_object); +ATF_TC_BODY(open_create_existing_object, tc) +{ + int fd; + + gen_test_path(); + + fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777); + ATF_REQUIRE_MSG(fd != -1, "shm_open(O_CREAT) failed; errno=%d", errno); + close(fd); + + shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL, + 0777, EEXIST); + + shm_unlink("shm_object"); +} + +ATF_TC_WITHOUT_HEAD(trunc_resets_object); +ATF_TC_BODY(trunc_resets_object, tc) +{ + struct stat sb; + int fd; + + gen_test_path(); + + /* Create object and set size to 1024. */ + fd = shm_open(test_path, O_RDWR | O_CREAT, 0777); + if (fd < 0) { + atf_tc_fail("shm_open(1)"); + return; + } + if (ftruncate(fd, 1024) < 0) { + atf_tc_fail("ftruncate"); + close(fd); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(1)"); + close(fd); + return; + } + if (sb.st_size != 1024) { + atf_tc_fail("size %d != 1024", (int)sb.st_size); + close(fd); + return; + } + close(fd); + + /* Open with O_TRUNC which should reset size to 0. */ + fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777); + if (fd < 0) { + atf_tc_fail("shm_open(2)"); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(2)"); + close(fd); + return; + } + if (sb.st_size != 0) { + atf_tc_fail("size after O_TRUNC %d != 0", (int)sb.st_size); + close(fd); + return; + } + close(fd); + if (shm_unlink(test_path) < 0) { + atf_tc_fail("shm_unlink"); + return; + } +} + +ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer); +ATF_TC_BODY(unlink_bad_path_pointer, tc) +{ + + shm_unlink_should_fail((char *)1024, EFAULT); +} + +ATF_TC_WITHOUT_HEAD(unlink_path_too_long); +ATF_TC_BODY(unlink_path_too_long, tc) +{ + char *page; + + page = malloc(MAXPATHLEN + 1); + memset(page, 'a', MAXPATHLEN); + page[MAXPATHLEN] = '\0'; + shm_unlink_should_fail(page, ENAMETOOLONG); + free(page); +} + +ATF_TC_WITHOUT_HEAD(object_resize); +ATF_TC_BODY(object_resize, tc) +{ + pid_t pid; + struct stat sb; + char *page; + int fd, status; + + /* Start off with a size of a single page. */ + fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0777); + if (fd < 0) { + atf_tc_fail("shm_open"); + return; + } + if (ftruncate(fd, getpagesize()) < 0) { + atf_tc_fail("ftruncate(1)"); + close(fd); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(1)"); + close(fd); + return; + } + if (sb.st_size != getpagesize()) { + atf_tc_fail("first resize failed"); + close(fd); + return; + } + + /* Write a '1' to the first byte. */ + page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, + 0); + if (page == MAP_FAILED) { + atf_tc_fail("mmap(1)"); + close(fd); + return; + } + + page[0] = '1'; + + if (munmap(page, getpagesize()) < 0) { + atf_tc_fail("munmap(1)"); + close(fd); + return; + } + + /* Grow the object to 2 pages. */ + if (ftruncate(fd, getpagesize() * 2) < 0) { + atf_tc_fail("ftruncate(2)"); + close(fd); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(2)"); + close(fd); + return; + } + if (sb.st_size != getpagesize() * 2) { + atf_tc_fail("second resize failed"); + close(fd); + return; + } + + /* Check for '1' at the first byte. */ + page = mmap(0, getpagesize() * 2, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + if (page == MAP_FAILED) { + atf_tc_fail("mmap(2)"); + close(fd); + return; + } + + if (page[0] != '1') { + atf_tc_fail("missing data at 0"); + close(fd); + return; + } + + /* Write a '2' at the start of the second page. */ + page[getpagesize()] = '2'; + + /* Shrink the object back to 1 page. */ + if (ftruncate(fd, getpagesize()) < 0) { + atf_tc_fail("ftruncate(3)"); + close(fd); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(3)"); + close(fd); + return; + } + if (sb.st_size != getpagesize()) { + atf_tc_fail("third resize failed"); + close(fd); + return; + } + + /* + * Fork a child process to make sure the second page is no + * longer valid. + */ + pid = fork(); + if (pid < 0) { + atf_tc_fail("fork"); + close(fd); + return; + } + + if (pid == 0) { + struct rlimit lim; + char c; + + /* Don't generate a core dump. */ + getrlimit(RLIMIT_CORE, &lim); + lim.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &lim); + + /* + * The previous ftruncate(2) shrunk the backing object + * so that this address is no longer valid, so reading + * from it should trigger a SIGSEGV. + */ + c = page[getpagesize()]; + fprintf(stderr, "child: page 1: '%c'\n", c); + exit(0); + } + if (wait(&status) < 0) { + atf_tc_fail("wait"); + close(fd); + return; + } + if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) { + atf_tc_fail("child terminated with status %x", status); + close(fd); + return; + } + + /* Grow the object back to 2 pages. */ + if (ftruncate(fd, getpagesize() * 2) < 0) { + atf_tc_fail("ftruncate(4)"); + close(fd); + return; + } + if (fstat(fd, &sb) < 0) { + atf_tc_fail("fstat(4)"); + close(fd); + return; + } + if (sb.st_size != getpagesize() * 2) { + atf_tc_fail("second resize failed"); + close(fd); + return; + } + + /* + * Note that the mapping at 'page' for the second page is + * still valid, and now that the shm object has been grown + * back up to 2 pages, there is now memory backing this page + * so the read will work. However, the data should be zero + * rather than '2' as the old data was thrown away when the + * object was shrunk and the new pages when an object are + * grown are zero-filled. + */ + if (page[getpagesize()] != 0) { + atf_tc_fail("invalid data at %d", getpagesize()); + close(fd); + return; + } + + close(fd); +} + +/* Signal handler which does nothing. */ +static void +ignoreit(int sig __unused) +{ + ; +} + +ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork); +ATF_TC_BODY(shm_functionality_across_fork, tc) +{ + char *cp, c; + int error, desc, rv; + long scval; + sigset_t ss; + struct sigaction sa; + void *region; + size_t i, psize; + +#ifndef _POSIX_SHARED_MEMORY_OBJECTS + printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n"); +#else + printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", + (long)_POSIX_SHARED_MEMORY_OBJECTS - 0); + if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1) + printf("***Indicates this feature may be unsupported!\n"); +#endif + errno = 0; + scval = sysconf(_SC_SHARED_MEMORY_OBJECTS); + if (scval == -1 && errno != 0) { + atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; " + "errno=%d", errno); + } else { + printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n", + scval); + if (scval == -1) + printf("***Indicates this feature is unsupported!\n"); + } + + errno = 0; + scval = sysconf(_SC_PAGESIZE); + if (scval == -1 && errno != 0) { + atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno); + } else if (scval <= 0 || (size_t)psize != psize) { + fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld", + scval); + psize = 4096; + } else { + printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval); + psize = scval; + } + + gen_test_path(); + desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600); + + ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno); + ATF_REQUIRE_MSG(shm_unlink(test_path) == 0, + "shm_unlink failed; errno=%d", errno); + ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1, + "ftruncate failed; errno=%d", errno); + + region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED, + desc, (off_t)0); + ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno); + memset(region, '\377', psize); + + sa.sa_flags = 0; + sa.sa_handler = ignoreit; + sigemptyset(&sa.sa_mask); + ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0, + "sigaction failed; errno=%d", errno); + + sigemptyset(&ss); + sigaddset(&ss, SIGUSR1); + ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0, + "sigprocmask failed; errno=%d", errno); + + rv = fork(); + ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno); + if (rv == 0) { + sigemptyset(&ss); + sigsuspend(&ss); + + for (cp = region; cp < (char *)region + psize; cp++) { + if (*cp != '\151') + _exit(1); + } + if (lseek(desc, 0, SEEK_SET) == -1) + _exit(1); + for (i = 0; i < psize; i++) { + error = read(desc, &c, 1); + if (c != '\151') + _exit(1); + } + _exit(0); + } else { + int status; + + memset(region, '\151', psize - 2); + error = pwrite(desc, region, 2, psize - 2); + if (error != 2) { + if (error >= 0) + atf_tc_fail("short write; %d bytes written", + error); + else + atf_tc_fail("shmfd write"); + } + kill(rv, SIGUSR1); + waitpid(rv, &status, 0); + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + printf("Functionality test successful\n"); + } else if (WIFEXITED(status)) { + atf_tc_fail("Child process exited with status %d", + WEXITSTATUS(status)); + } else { + atf_tc_fail("Child process terminated with %s", + strsignal(WTERMSIG(status))); + } + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, remap_object); + ATF_TP_ADD_TC(tp, reopen_object); + ATF_TP_ADD_TC(tp, readonly_mmap_write); + ATF_TP_ADD_TC(tp, open_after_link); + ATF_TP_ADD_TC(tp, open_invalid_path); + ATF_TP_ADD_TC(tp, open_write_only); + ATF_TP_ADD_TC(tp, open_extra_flags); + ATF_TP_ADD_TC(tp, open_anon); + ATF_TP_ADD_TC(tp, open_anon_readonly); + ATF_TP_ADD_TC(tp, open_bad_path_pointer); + ATF_TP_ADD_TC(tp, open_path_too_long); + ATF_TP_ADD_TC(tp, open_nonexisting_object); + ATF_TP_ADD_TC(tp, open_create_existing_object); + ATF_TP_ADD_TC(tp, shm_functionality_across_fork); + ATF_TP_ADD_TC(tp, trunc_resets_object); + ATF_TP_ADD_TC(tp, unlink_bad_path_pointer); + ATF_TP_ADD_TC(tp, unlink_path_too_long); + ATF_TP_ADD_TC(tp, object_resize); + + return (atf_no_error()); +} diff --git a/tests/sys/posixshm/shm_test.c b/tests/sys/posixshm/shm_test.c deleted file mode 100644 index a46fc0b..0000000 --- a/tests/sys/posixshm/shm_test.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Test the POSIX shared-memory API. - * Dedicated to the public domain by Garrett A. Wollman, 2000. - * $FreeBSD$ - */ - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/wait.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* - * Signal handler which does nothing. - */ -static void -ignoreit(int sig __unused) -{ - ; -} - -int -main(int argc, char **argv) -{ - char buf[1024], *cp, c; - int error, desc, rv; - long scval; - sigset_t ss; - struct sigaction sa; - void *region; - size_t i, psize; - -#ifndef _POSIX_SHARED_MEMORY_OBJECTS - printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n"); -#else - printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", - (long)_POSIX_SHARED_MEMORY_OBJECTS - 0); - if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1) - printf("***Indicates this feature may be unsupported!\n"); -#endif - errno = 0; - scval = sysconf(_SC_SHARED_MEMORY_OBJECTS); - if (scval == -1 && errno != 0) { - err(1, "sysconf(_SC_SHARED_MEMORY_OBJECTS)"); - } else { - printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n", - scval); - if (scval == -1) - printf("***Indicates this feature is unsupported!\n"); - } - - errno = 0; - scval = sysconf(_SC_PAGESIZE); - if (scval == -1 && errno != 0) { - err(1, "sysconf(_SC_PAGESIZE)"); - } else if (scval <= 0 || (size_t)psize != psize) { - warnx("bogus return from sysconf(_SC_PAGESIZE): %ld", - scval); - psize = 4096; - } else { - printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval); - psize = scval; - } - - argc--, argv++; - - if (*argv) { - strncat(buf, *argv, (sizeof buf) - 1); - desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600); - } else { - do { - /* - * Can't use mkstemp for obvious reasons... - */ - char *tmpdir = getenv("TMPDIR"); - if (tmpdir == NULL) - tmpdir = "/tmp"; - snprintf(buf, sizeof(buf) - 1, - "%s/shmtest.XXXXXXXXXXXX", tmpdir); - buf[sizeof(buf) - 1] = '\0'; - mktemp(buf); - desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600); - } while (desc < 0 && errno == EEXIST); - } - - if (desc < 0) - err(1, "shm_open"); - - if (shm_unlink(buf) < 0) - err(1, "shm_unlink"); - - if (ftruncate(desc, (off_t)psize) < 0) - err(1, "ftruncate"); - - region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED, - desc, (off_t)0); - if (region == MAP_FAILED) - err(1, "mmap"); - memset(region, '\377', psize); - - sa.sa_flags = 0; - sa.sa_handler = ignoreit; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGUSR1, &sa, (struct sigaction *)0) < 0) - err(1, "sigaction"); - - sigemptyset(&ss); - sigaddset(&ss, SIGUSR1); - if (sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) < 0) - err(1, "sigprocmask"); - - rv = fork(); - if (rv < 0) { - err(1, "fork"); - } else if (rv == 0) { - sigemptyset(&ss); - sigsuspend(&ss); - - for (cp = region; cp < (char *)region + psize; cp++) { - if (*cp != '\151') - _exit(1); - } - if (lseek(desc, 0, SEEK_SET) == -1) - _exit(1); - for (i = 0; i < psize; i++) { - error = read(desc, &c, 1); - if (c != '\151') - _exit(1); - } - _exit(0); - } else { - int status; - - memset(region, '\151', psize - 2); - error = pwrite(desc, region, 2, psize - 2); - if (error != 2) { - if (error >= 0) - errx(1, "short write %d", error); - else - err(1, "shmfd write"); - } - kill(rv, SIGUSR1); - waitpid(rv, &status, 0); - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - printf("Functionality test successful\n"); - exit(0); - } else if (WIFEXITED(status)) { - printf("Child process exited with status %d\n", - WEXITSTATUS(status)); - } else { - printf("Child process terminated with %s\n", - strsignal(WTERMSIG(status))); - } - } - exit(1); -} diff --git a/tests/sys/posixshm/test.c b/tests/sys/posixshm/test.c deleted file mode 100644 index 8583a0d..0000000 --- a/tests/sys/posixshm/test.c +++ /dev/null @@ -1,128 +0,0 @@ -/*- - * Copyright (c) 2008 Yahoo!, Inc. - * All rights reserved. - * Written by: John Baldwin <jhb@FreeBSD.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <stdarg.h> -#include <stdio.h> - -#include "test.h" - -static int test_index; -static struct regression_test *test; -static int test_acknowleged; - -SET_DECLARE(regression_tests_set, struct regression_test); - -/* - * Outputs a test summary of the following: - * - * <status> <test #> [name] [# <fmt> [fmt args]] - */ -static void -vprint_status(const char *status, const char *fmt, va_list ap) -{ - - printf("%s %d", status, test_index); - if (test->rt_name) - printf(" - %s", test->rt_name); - if (fmt) { - printf(" # "); - vprintf(fmt, ap); - } - printf("\n"); - test_acknowleged = 1; -} - -static void -print_status(const char *status, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vprint_status(status, fmt, ap); - va_end(ap); -} - -void -pass(void) -{ - - print_status("ok", NULL); -} - -void -fail(void) -{ - - print_status("not ok", NULL); -} - -void -fail_err(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vprint_status("not ok", fmt, ap); - va_end(ap); -} - -void -skip(const char *reason) -{ - - print_status("ok", "skip %s", reason); -} - -void -todo(const char *reason) -{ - - print_status("not ok", "TODO %s", reason); -} - -void -run_tests(void) -{ - struct regression_test **testp; - - printf("1..%td\n", SET_COUNT(regression_tests_set)); - test_index = 1; - SET_FOREACH(testp, regression_tests_set) { - test_acknowleged = 0; - test = *testp; - test->rt_function(); - if (!test_acknowleged) - print_status("not ok", "unknown status"); - test_index++; - } -} diff --git a/tests/sys/posixshm/test.h b/tests/sys/posixshm/test.h deleted file mode 100644 index 505679b..0000000 --- a/tests/sys/posixshm/test.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2008 Yahoo!, Inc. - * All rights reserved. - * Written by: John Baldwin <jhb@FreeBSD.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __TEST_H__ -#define __TEST_H__ - -#include <sys/linker_set.h> - -struct regression_test { - void (*rt_function)(void); - const char *rt_name; -}; - -#define TEST(function, name) \ - static struct regression_test _regtest_##function = { \ - (function), \ - (name) \ - }; \ - DATA_SET(regression_tests_set, _regtest_##function) - -void fail(void); -void fail_err(const char *fmt, ...); -void pass(void); -void run_tests(void); -void skip(const char *reason); -void todo(const char *reason); - -#define fail_errno(tag) fail_err("%s: %s", (tag), strerror(errno)) - -#endif /* !__TEST_H__ */ |