diff options
author | ngie <ngie@FreeBSD.org> | 2015-05-13 10:24:23 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-05-13 10:24:23 +0000 |
commit | 51336e1434aa7ef0425fba7c65b82593035fb8cb (patch) | |
tree | 91dca85fbc24e37f3dae30fcbe5c23f50c4ba156 /tools | |
parent | 559871946b1e0e49c7548d9e828172705cbb4f57 (diff) | |
download | FreeBSD-src-51336e1434aa7ef0425fba7c65b82593035fb8cb.zip FreeBSD-src-51336e1434aa7ef0425fba7c65b82593035fb8cb.tar.gz |
MFC r282067:
Integrate tools/regression/fifo into the FreeBSD test suite as tests/sys/fifo
and tools/regression/file into the FreeBSD test suite as tests/sys/file
Diffstat (limited to 'tools')
20 files changed, 0 insertions, 4984 deletions
diff --git a/tools/regression/fifo/fifo_create/Makefile b/tools/regression/fifo/fifo_create/Makefile deleted file mode 100644 index 10e2b14..0000000 --- a/tools/regression/fifo/fifo_create/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= fifo_create -MAN= -WARNS?= 3 - -.include <bsd.prog.mk> diff --git a/tools/regression/fifo/fifo_create/fifo_create.c b/tools/regression/fifo/fifo_create/fifo_create.c deleted file mode 100644 index 4e8a8a4..0000000 --- a/tools/regression/fifo/fifo_create/fifo_create.c +++ /dev/null @@ -1,285 +0,0 @@ -/*- - * Copyright (c) 2005-2008 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. - * - * $FreeBSD$ - */ - -#include <sys/stat.h> - -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* - * Simple regression test for the creation and destruction of POSIX fifos in - * the file system name space. Using a specially created directory, create - * a fifo in it and check that the following properties are present, as - * specified in IEEE Std 1003.1, 2004 Edition: - * - * - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is - * created. - * - * - On an error, no fifo is created. (XXX: Not tested) - * - * - The mode bits on the fifo are a product of combining the umask and - * requested mode. - * - * - The fifo's owner will be the processes effective user ID. (XXX: Not - * tested) - * - * - The fifo's group will be the parent directory's group or the effective - * group ID of the process. For historical reasons, BSD prefers the group - * ID of the process, so we will generate an error if it's not that. (XXX: - * Not tested) - * - * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately, - * and st_ctime and st_mtime on the directory will be updated. (XXX: We - * test they are updated, not correct) - * - * - EEXIST is returned if the named file already exists. - * - * In addition, we check that we can unlink the fifo, and that if we do, it - * disappears. - * - * This test must run as root in order to usefully frob the process - * credential to test permission parts. - */ - -/* - * All activity occurs within a temporary directory created early in the - * test. - */ -char temp_dir[PATH_MAX]; - -static void __unused -atexit_temp_dir(void) -{ - - rmdir(temp_dir); -} - -/* - * Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo, - * that the time stamps on the directory are updated, that if we try twice we - * get EEXIST, and that we can unlink it. - */ -static void -fifo_create_test(int use_mkfifo) -{ - struct stat old_dirsb, dirsb, fifosb; - const char *testname; - char path[PATH_MAX]; - int error; - - if (use_mkfifo) - testname = "mkfifo"; - else - testname = "mknod"; - - /* - * Sleep to make sure that the time stamp on the directory will be - * updated. - */ - if (stat(temp_dir, &old_dirsb) < 0) - err(-1, "basic_create_test: %s: stat: %s", testname, - temp_dir); - - sleep(2); - - snprintf(path, PATH_MAX, "%s/testfifo", temp_dir); - - if (use_mkfifo) { - if (mkfifo(path, 0600) < 0) - err(-1, "basic_create_test: %s: %s", testname, path); - } else { - if (mknod(path, S_IFIFO | 0600, 0) < 0) - err(-1, "basic_create_test: %s: %s", testname, path); - } - - if (stat(path, &fifosb) < 0) { - error = errno; - (void)unlink(path); - errno = error; - err(-1, "basic_create_test: %s: stat: %s", testname, path); - } - - if (!(S_ISFIFO(fifosb.st_mode))) { - (void)unlink(path); - errx(-1, "basic_create_test: %s produced non-fifo", - testname); - } - - if (use_mkfifo) { - if (mkfifo(path, 0600) == 0) - errx(-1, "basic_create_test: dup %s succeeded", - testname); - } else { - if (mknod(path, S_IFIFO | 0600, 0) == 0) - errx(-1, "basic_create_test: dup %s succeeded", - testname); - } - - if (errno != EEXIST) - err(-1, "basic_create_test: dup %s unexpected error", - testname); - - if (stat(temp_dir, &dirsb) < 0) { - error = errno; - (void)unlink(path); - errno = error; - err(-1, "basic_create_test: %s: stat: %s", testname, - temp_dir); - } - - if (old_dirsb.st_ctime == dirsb.st_ctime) { - (void)unlink(path); - errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == " - "dirsb.st_ctime", testname); - } - - if (old_dirsb.st_mtime == dirsb.st_mtime) { - (void)unlink(path); - errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == " - "dirsb.st_mtime", testname); - } - - if (unlink(path) < 0) - err(-1, "basic_create_test: %s: unlink: %s", testname, path); - - if (stat(path, &fifosb) == 0) - errx(-1, "basic_create_test: %s: unlink failed to unlink", - testname); - if (errno != ENOENT) - err(-1, "basic_create_test: %s: unlink unexpected error", - testname); -} - -/* - * Having determined that basic create/remove/etc functionality is present - * for fifos, now make sure that the umask, requested permissions, and - * resulting mode are handled properly. - */ -static const struct permission_test { - mode_t pt_umask; - mode_t pt_reqmode; - mode_t pt_mode; -} permission_test[] = { - {0000, 0, S_IFIFO}, - {0000, S_IRWXU, S_IFIFO | S_IRWXU}, - {0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG | - S_IRWXO }, - {0077, S_IRWXU, S_IFIFO | S_IRWXU}, - {0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU}, -}; -static const int permission_test_count = sizeof(permission_test) / - sizeof(struct permission_test); - -static void -fifo_permission_test(int use_mkfifo) -{ - const struct permission_test *ptp; - mode_t __unused old_umask; - char path[PATH_MAX]; - const char *testname; - struct stat sb; - int error, i; - - if (use_mkfifo) - testname = "mkfifo"; - else - testname = "mknod"; - - snprintf(path, PATH_MAX, "%s/testfifo", temp_dir); - old_umask = umask(0022); - for (i = 0; i < permission_test_count; i++) { - ptp = &permission_test[i]; - - umask(ptp->pt_umask); - if (use_mkfifo) { - if (mkfifo(path, ptp->pt_reqmode) < 0) - err(-1, "fifo_permission_test: %s: %08o " - "%08o %08o\n", testname, ptp->pt_umask, - ptp->pt_reqmode, ptp->pt_mode); - } else { - if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0) - err(-1, "fifo_permission_test: %s: %08o " - "%08o %08o\n", testname, ptp->pt_umask, - ptp->pt_reqmode, ptp->pt_mode); - } - - if (stat(path, &sb) < 0) { - error = errno; - (void)unlink(path); - errno = error; - err(-1, "fifo_permission_test: %s: %s", testname, - path); - } - - if (sb.st_mode != ptp->pt_mode) { - (void)unlink(path); - errx(-1, "fifo_permission_test: %s: %08o %08o %08o " - "got %08o", testname, ptp->pt_umask, - ptp->pt_reqmode, ptp->pt_mode, sb.st_mode); - } - - if (unlink(path) < 0) - err(-1, "fifo_permission_test: %s: unlink: %s", - testname, path); - } - umask(old_umask); -} - -int -main(int argc, char *argv[]) -{ - int i; - - if (geteuid() != 0) - errx(-1, "must be run as root"); - - strcpy(temp_dir, "/tmp/fifo_create.XXXXXXXXXXX"); - if (mkdtemp(temp_dir) == NULL) - err(-1, "mkdtemp"); - atexit(atexit_temp_dir); - - if (chdir(temp_dir) < 0) - err(-1, "chdir"); - - /* - * Run each test twice, once with mknod(2) and a second time with - * mkfifo(2). Historically, BSD has not allowed mknod(2) to be used - * to create fifos, but the Single UNIX Specification requires it. - */ - for (i = 0; i < 2; i++) { - fifo_create_test(i); - fifo_permission_test(i); - } - - return (0); -} diff --git a/tools/regression/fifo/fifo_io/Makefile b/tools/regression/fifo/fifo_io/Makefile deleted file mode 100644 index 49bf5bd..0000000 --- a/tools/regression/fifo/fifo_io/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= fifo_io -MAN= -WARNS?= 3 - -.include <bsd.prog.mk> diff --git a/tools/regression/fifo/fifo_io/fifo_io.c b/tools/regression/fifo/fifo_io/fifo_io.c deleted file mode 100644 index 4d3c54e..0000000 --- a/tools/regression/fifo/fifo_io/fifo_io.c +++ /dev/null @@ -1,1409 +0,0 @@ -/*- - * Copyright (c) 2005 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. - * - * $FreeBSD$ - */ - -#include <sys/types.h> -#include <sys/event.h> -#include <sys/ioctl.h> -#include <sys/select.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* - * Regression test to exercise POSIX fifo I/O. - * - * We test a number of aspect of behavior, including: - * - * - If there's no data to read, then for blocking fifos, we block, and for - * non-blocking, we return EAGAIN. - * - * - If we write ten bytes, ten bytes can be read, and they're the same - * bytes, in the same order. - * - * - If we write two batches of five bytes, we can read the same ten bytes in - * one read of ten bytes. - * - * - If we write ten bytes, we can read the same ten bytes in two reads of - * five bytes each. - * - * - If we over-fill a buffer (by writing 512k, which we take to be a large - * number above default buffer sizes), we block if there is no reader. - * - * - That once 512k (ish) is read from the other end, the blocked writer - * wakes up. - * - * - When a fifo is empty, poll, select, kqueue, and fionread report it is - * writable but not readable. - * - * - When a fifo has data in it, poll, select, and kqueue report that it is - * writable. - * - * - XXX: blocked reader semantics? - * - * - XXX: event behavior on remote close? - * - * Although behavior of O_RDWR isn't defined for fifos by POSIX, we expect - * "reasonable" behavior, and run some additional tests relating to event - * management on O_RDWR fifo descriptors. - */ - -#define KQUEUE_MAX_EVENT 8 - -/* - * All activity occurs within a temporary directory created early in the - * test. - */ -char temp_dir[PATH_MAX]; - -static void __unused -atexit_temp_dir(void) -{ - - rmdir(temp_dir); -} - -static void -makefifo(const char *fifoname, const char *testname) -{ - - if (mkfifo(fifoname, 0700) < 0) - err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); -} - -static void -cleanfifo2(const char *fifoname, int fd1, int fd2) -{ - - if (fd1 != -1) - close(fd1); - if (fd2 != -1) - close(fd2); - (void)unlink(fifoname); -} - -static void -cleanfifo3(const char *fifoname, int fd1, int fd2, int fd3) -{ - - if (fd3 != -1) - close(fd3); - cleanfifo2(fifoname, fd1, fd2); -} - -/* - * Open two different file descriptors for a fifo: one read, one write. Do - * so using non-blocking opens in order to avoid deadlocking the process. - */ -static int -openfifo(const char *fifoname, const char *testname, int *reader_fdp, - int *writer_fdp) -{ - int error, fd1, fd2; - - fd1 = open(fifoname, O_RDONLY | O_NONBLOCK); - if (fd1 < 0) - return (-1); - fd2 = open(fifoname, O_WRONLY | O_NONBLOCK); - if (fd2 < 0) { - error = errno; - close(fd1); - errno = error; - return (-1); - } - *reader_fdp = fd1; - *writer_fdp = fd2; - - return (0); -} - -/* - * Open one file descriptor for the fifo, supporting both read and write. - */ -static int -openfifo_rw(const char *fifoname, const char *testname, int *fdp) -{ - int fd; - - fd = open(fifoname, O_RDWR); - if (fd < 0) - return (-1); - *fdp = fd; - - return (0); -} - -static int -set_nonblocking(int fd, const char *testname) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - if (flags < 0) { - warn("%s: fcntl(fd, F_GETFL)", testname); - return(-1); - } - - flags |= O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) < 0) { - warn("%s: fcntl(fd, 0x%x)", testname, flags); - return (-1); - } - - return (0); -} - -static int -set_blocking(int fd, const char *testname) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - if (flags < 0) { - warn("%s: fcntl(fd, F_GETFL)", testname); - return(-1); - } - - flags &= ~O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) < 0) { - warn("%s: fcntl(fd, 0x%x)", testname, flags); - return (-1); - } - - return (0); -} - -/* - * Drain a file descriptor (fifo) of any readable data. Note: resets the - * blocking state. - */ -static int -drain_fd(int fd, const char *testname) -{ - ssize_t len; - u_char ch; - - if (set_nonblocking(fd, testname) < 0) - return (-1); - - while ((len = read(fd, &ch, sizeof(ch))) > 0); - if (len < 0) { - switch (errno) { - case EAGAIN: - return (0); - default: - warn("%s: drain_fd: read", testname); - return (-1); - } - } - warn("%s: drain_fd: read: returned 0 bytes", testname); - return (-1); -} - -/* - * Simple I/O test: write ten integers, and make sure we get back the same - * integers in the same order. This assumes a minimum fifo buffer > 10 - * bytes in order to not block and deadlock. - */ -static void -test_simpleio(void) -{ - int i, reader_fd, writer_fd; - u_char buffer[10]; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", "test_simpleio", &reader_fd, &writer_fd) - < 0) { - warn("test_simpleio: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - for (i = 0; i < 10; i++) - buffer[i] = i; - - len = write(writer_fd, (char *)buffer, sizeof(buffer)); - if (len < 0) { - warn("test_simpleio: write"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(buffer)) { - warnx("test_simplio: tried %zu but wrote %zd", sizeof(buffer), - len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - len = read(reader_fd, (char *)buffer, sizeof(buffer)); - if (len < 0) { - warn("test_simpleio: read"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(buffer)) { - warnx("test_simpleio: tried %zu but read %zd", sizeof(buffer), - len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - for (i = 0; i < 10; i++) { - if (buffer[i] == i) - continue; - warnx("test_simpleio: write byte %d as 0x%02x, but read " - "0x%02x", i, i, buffer[i]); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -static int alarm_fired; -/* - * Non-destructive SIGALRM handler. - */ -static void -sigalarm(int signum) -{ - - alarm_fired = 1; -} - -/* - * Wrapper function for write, which uses a timer to interrupt any blocking. - * Because we can't reliably detect EINTR for blocking I/O, we also track - * whether or not our timeout fired. - */ -static int __unused -timed_write(int fd, void *data, size_t len, ssize_t *written_lenp, - int timeout, int *timedoutp, const char *testname) -{ - struct sigaction act, oact; - ssize_t written_len; - int error; - - alarm_fired = 0; - bzero(&act, sizeof(oact)); - act.sa_handler = sigalarm; - if (sigaction(SIGALRM, &act, &oact) < 0) { - warn("%s: timed_write: sigaction", testname); - return (-1); - } - alarm(timeout); - written_len = write(fd, data, len); - error = errno; - alarm(0); - if (sigaction(SIGALRM, &oact, NULL) < 0) { - warn("%s: timed_write: sigaction", testname); - return (-1); - } - if (alarm_fired) - *timedoutp = 1; - else - *timedoutp = 0; - - errno = error; - if (written_len < 0) - return (-1); - *written_lenp = written_len; - return (0); -} - -/* - * Wrapper function for read, which uses a timer to interrupt any blocking. - * Because we can't reliably detect EINTR for blocking I/O, we also track - * whether or not our timeout fired. - */ -static int -timed_read(int fd, void *data, size_t len, ssize_t *read_lenp, - int timeout, int *timedoutp, const char *testname) -{ - struct sigaction act, oact; - ssize_t read_len; - int error; - - alarm_fired = 0; - bzero(&act, sizeof(oact)); - act.sa_handler = sigalarm; - if (sigaction(SIGALRM, &act, &oact) < 0) { - warn("%s: timed_write: sigaction", testname); - return (-1); - } - alarm(timeout); - read_len = read(fd, data, len); - error = errno; - alarm(0); - if (sigaction(SIGALRM, &oact, NULL) < 0) { - warn("%s: timed_write: sigaction", testname); - return (-1); - } - if (alarm_fired) - *timedoutp = 1; - else - *timedoutp = 0; - - errno = error; - if (read_len < 0) - return (-1); - *read_lenp = read_len; - return (0); -} - -/* - * This test operates on blocking and non-blocking fifo file descriptors, in - * order to determine whether they block at good moments or not. By good we - * mean: don't block for non-blocking sockets, and do block for blocking - * ones, assuming there isn't I/O buffer to satisfy the request. - * - * We use a timeout of 5 seconds, concluding that in 5 seconds either all I/O - * that can take place will, and that if we reach the end of the timeout, - * then blocking has occurred. - * - * We assume that the buffer size on a fifo is <512K, and as such, that - * writing that much data without an active reader will result in blocking. - */ -static void -test_blocking_read_empty(void) -{ - int reader_fd, ret, timedout, writer_fd; - ssize_t len; - u_char ch; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_blocking_read_empty: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - /* - * Read one byte from an empty blocking fifo, block as there is no - * data. - */ - if (set_blocking(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret != -1) { - warnx("test_blocking_read_empty: timed_read: returned " - "success"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (errno != EINTR) { - warn("test_blocking_read_empty: timed_read"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - /* - * Read one byte from an empty non-blocking fifo, return EAGAIN as - * there is no data. - */ - if (set_nonblocking(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret != -1) { - warnx("test_blocking_read_empty: timed_read: returned " - "success"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (errno != EAGAIN) { - warn("test_blocking_read_empty: timed_read"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -/* - * Write one byte to an empty fifo, then try to read one byte and make sure - * we don't block in either the write or the read. This tests both for - * improper blocking in the send and receive code. - */ -static void -test_blocking_one_byte(void) -{ - int reader_fd, ret, timedout, writer_fd; - ssize_t len; - u_char ch; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_blocking: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - if (set_blocking(writer_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (set_blocking(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ch = 0xfe; - ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_blocking_one_byte: timed_write"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(ch)) { - warnx("test_blocking_one_byte: timed_write: tried to write " - "%zu, wrote %zd", sizeof(ch), len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ch = 0xab; - ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_blocking_one_byte: timed_read"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(ch)) { - warnx("test_blocking_one_byte: timed_read: wanted %zu, " - "read %zd", sizeof(ch), len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (ch != 0xfe) { - warnx("test_blocking_one_byte: timed_read: expected to read " - "0x%02x, read 0x%02x", 0xfe, ch); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -/* - * Write one byte to an empty fifo, then try to read one byte and make sure - * we don't get back EAGAIN. - */ -static void -test_nonblocking_one_byte(void) -{ - int reader_fd, ret, timedout, writer_fd; - ssize_t len; - u_char ch; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_nonblocking: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - if (set_nonblocking(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ch = 0xfe; - ret = timed_write(writer_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_nonblocking_one_byte: timed_write"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(ch)) { - warnx("test_nonblocking_one_byte: timed_write: tried to write " - "%zu, wrote %zd", sizeof(ch), len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - ch = 0xab; - ret = timed_read(reader_fd, &ch, sizeof(ch), &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_nonblocking_one_byte: timed_read"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != sizeof(ch)) { - warnx("test_nonblocking_one_byte: timed_read: wanted %zu, read " - "%zd", sizeof(ch), len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (ch != 0xfe) { - warnx("test_nonblocking_one_byte: timed_read: expected to read " - "0x%02x, read 0x%02x", 0xfe, ch); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -/* - * First of two test cases involving a 512K buffer: write the buffer into a - * blocking file descriptor. We'd like to know it blocks, but the closest we - * can get is to see if SIGALRM fired during the I/O resulting in a partial - * write. - */ -static void -test_blocking_partial_write(void) -{ - int reader_fd, ret, timedout, writer_fd; - u_char *buffer; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_blocking_partial_write: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - if (set_blocking(writer_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - buffer = malloc(512*1024); - if (buffer == NULL) { - warn("test_blocking_partial_write: malloc"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - bzero(buffer, 512*1024); - - ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_blocking_partial_write: timed_write"); - free(buffer); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (!timedout) { - warnx("test_blocking_partial_write: timed_write: blocking " - "socket didn't time out"); - free(buffer); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - free(buffer); - - if (drain_fd(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -/* - * Write a 512K buffer to an empty fifo using a non-blocking file descriptor, - * and make sure it doesn't block. - */ -static void -test_nonblocking_partial_write(void) -{ - int reader_fd, ret, timedout, writer_fd; - u_char *buffer; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_blocking_partial_write: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - if (set_nonblocking(writer_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - buffer = malloc(512*1024); - if (buffer == NULL) { - warn("test_blocking_partial_write: malloc"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - bzero(buffer, 512*1024); - - ret = timed_write(writer_fd, buffer, 512*1024, &len, 5, &timedout, - __func__); - if (ret < 0) { - warn("test_blocking_partial_write: timed_write"); - free(buffer); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (timedout) { - warnx("test_blocking_partial_write: timed_write: " - "non-blocking socket timed out"); - free(buffer); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (len == 0 || len >= 512*1024) { - warnx("test_blocking_partial_write: timed_write: requested " - "%d, sent %zd", 512*1024, len); - free(buffer); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - free(buffer); - - if (drain_fd(reader_fd, __func__) < 0) { - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", reader_fd, writer_fd); -} - -/* - * test_coalesce_big_read() verifies that data mingles in the fifo across - * message boundaries by performing two small writes, then a bigger read - * that should return data from both writes. - */ -static void -test_coalesce_big_read(void) -{ - int i, reader_fd, writer_fd; - u_char buffer[10]; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_coalesce_big_read: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - /* Write five, write five, read ten. */ - for (i = 0; i < 10; i++) - buffer[i] = i; - - len = write(writer_fd, buffer, 5); - if (len < 0) { - warn("test_coalesce_big_read: write 5"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 5) { - warnx("test_coalesce_big_read: write 5 wrote %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - len = write(writer_fd, buffer + 5, 5); - if (len < 0) { - warn("test_coalesce_big_read: write 5"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 5) { - warnx("test_coalesce_big_read: write 5 wrote %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - len = read(reader_fd, buffer, 10); - if (len < 0) { - warn("test_coalesce_big_read: read 10"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 10) { - warnx("test_coalesce_big_read: read 10 read %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - for (i = 0; i < 10; i++) { - if (buffer[i] == i) - continue; - warnx("test_coalesce_big_read: expected to read 0x%02x, " - "read 0x%02x", i, buffer[i]); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", -1, -1); -} - -/* - * test_coalesce_big_write() verifies that data mingles in the fifo across - * message boundaries by performing one big write, then two smaller reads - * that should return sequential elements of data from the write. - */ -static void -test_coalesce_big_write(void) -{ - int i, reader_fd, writer_fd; - u_char buffer[10]; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_coalesce_big_write: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - /* Write ten, read five, read five. */ - for (i = 0; i < 10; i++) - buffer[i] = i; - - len = write(writer_fd, buffer, 10); - if (len < 0) { - warn("test_coalesce_big_write: write 10"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 10) { - warnx("test_coalesce_big_write: write 10 wrote %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - len = read(reader_fd, buffer, 5); - if (len < 0) { - warn("test_coalesce_big_write: read 5"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 5) { - warnx("test_coalesce_big_write: read 5 read %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - len = read(reader_fd, buffer + 5, 5); - if (len < 0) { - warn("test_coalesce_big_write: read 5"); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (len != 5) { - warnx("test_coalesce_big_write: read 5 read %zd", len); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - for (i = 0; i < 10; i++) { - if (buffer[i] == i) - continue; - warnx("test_coalesce_big_write: expected to read 0x%02x, " - "read 0x%02x", i, buffer[i]); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo2("testfifo", -1, -1); -} - -static int -poll_status(int fd, int *readable, int *writable, int *exception, - const char *testname) -{ - struct pollfd fds[1]; - - fds[0].fd = fd; - fds[0].events = POLLIN | POLLOUT | POLLERR; - fds[0].revents = 0; - - if (poll(fds, 1, 0) < 0) { - warn("%s: poll", testname); - return (-1); - } - *readable = (fds[0].revents & POLLIN) ? 1 : 0; - *writable = (fds[0].revents & POLLOUT) ? 1 : 0; - *exception = (fds[0].revents & POLLERR) ? 1 : 0; - return (0); -} - -static int -select_status(int fd, int *readable, int *writable, int *exception, - const char *testname) -{ - struct fd_set readfds, writefds, exceptfds; - struct timeval timeout; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - FD_SET(fd, &readfds); - FD_SET(fd, &writefds); - FD_SET(fd, &exceptfds); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - if (select(fd+1, &readfds, &writefds, &exceptfds, &timeout) < 0) { - warn("%s: select", testname); - return (-1); - } - *readable = FD_ISSET(fd, &readfds) ? 1 : 0; - *writable = FD_ISSET(fd, &writefds) ? 1 : 0; - *exception = FD_ISSET(fd, &exceptfds) ? 1 : 0; - return (0); -} - -/* - * Given an existing kqueue, set up read and write event filters for the - * passed file descriptor. Typically called once for the read endpoint, and - * once for the write endpoint. - */ -static int -kqueue_setup(int kqueue_fd, int fd, const char *testname) -{ - struct kevent kevent_changelist[2]; - struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp; - struct timespec timeout; - int i, ret; - - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - - bzero(&kevent_changelist, sizeof(kevent_changelist)); - EV_SET(&kevent_changelist[0], fd, EVFILT_READ, EV_ADD, 0, 0, 0); - EV_SET(&kevent_changelist[1], fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); - - bzero(&kevent_eventlist, sizeof(kevent_eventlist)); - ret = kevent(kqueue_fd, kevent_changelist, 2, kevent_eventlist, - KQUEUE_MAX_EVENT, &timeout); - if (ret < 0) { - warn("%s:%s: kevent initial register", testname, __func__); - return (-1); - } - - /* - * Verify that the events registered alright. - */ - for (i = 0; i < ret; i++) { - kp = &kevent_eventlist[i]; - if (kp->flags != EV_ERROR) - continue; - errno = kp->data; - warn("%s:%s: kevent register index %d", testname, __func__, - i); - return (-1); - } - - return (0); -} - -static int -kqueue_status(int kqueue_fd, int fd, int *readable, int *writable, - int *exception, const char *testname) -{ - struct kevent kevent_eventlist[KQUEUE_MAX_EVENT], *kp; - struct timespec timeout; - int i, ret; - - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - - ret = kevent(kqueue_fd, NULL, 0, kevent_eventlist, KQUEUE_MAX_EVENT, - &timeout); - if (ret < 0) { - warn("%s: %s: kevent", testname, __func__); - return (-1); - } - - *readable = *writable = *exception = 0; - for (i = 0; i < ret; i++) { - kp = &kevent_eventlist[i]; - if (kp->ident != (u_int)fd) - continue; - if (kp->filter == EVFILT_READ) - *readable = 1; - if (kp->filter == EVFILT_WRITE) - *writable = 1; - } - - return (0); -} - -static int -fionread_status(int fd, int *readable, const char *testname) -{ - int i; - - if (ioctl(fd, FIONREAD, &i) < 0) { - warn("%s: ioctl(FIONREAD)", testname); - return (-1); - } - - if (i > 0) - *readable = 1; - else - *readable = 0; - return (0); -} - -#define READABLE 1 -#define WRITABLE 1 -#define EXCEPTION 1 - -#define NOT_READABLE 0 -#define NOT_WRITABLE 0 -#define NOT_EXCEPTION 0 - -static int -assert_status(int fd, int kqueue_fd, int assert_readable, - int assert_writable, int assert_exception, const char *testname, - const char *conditionname, const char *fdname) -{ - int readable, writable, exception; - - if (poll_status(fd, &readable, &writable, &exception, testname) < 0) - return (-1); - - if (readable != assert_readable || writable != assert_writable || - exception != assert_exception) { - warnx("%s: %s polls r:%d, w:%d, e:%d on %s", testname, - fdname, readable, writable, exception, conditionname); - return (-1); - } - - if (select_status(fd, &readable, &writable, &exception, testname) < 0) - return (-1); - - if (readable != assert_readable || writable != assert_writable || - exception != assert_exception) { - warnx("%s: %s selects r:%d, w:%d, e:%d on %s", testname, - fdname, readable, writable, exception, conditionname); - return (-1); - } - - if (kqueue_status(kqueue_fd, fd, &readable, &writable, &exception, - testname) < 0) - return (-1); - - if (readable != assert_readable || writable != assert_writable || - exception != assert_exception) { - warnx("%s: %s kevent r:%d, w:%d, e:%d on %s", testname, - fdname, readable, writable, exception, conditionname); - return (-1); - } - - if (fionread_status(fd, &readable, __func__) < 0) - return (-1); - - if (readable != assert_readable) { - warnx("%s: %s fionread r:%d on %s", testname, fdname, - readable, conditionname); - return (-1); - } - - return (0); -} - -/* - * test_events() uses poll(), select(), and kevent() to query the status of - * fifo file descriptors and determine whether they match expected state - * based on earlier semantic tests: specifically, whether or not poll/select/ - * kevent will correctly inform on readable/writable state following I/O. - * - * It would be nice to also test status changes as a result of closing of one - * or another fifo endpoint. - */ -static void -test_events_outofbox(void) -{ - int kqueue_fd, reader_fd, writer_fd; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { - warn("test_events_outofbox: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - kqueue_fd = kqueue(); - if (kqueue_fd < 0) { - warn("%s: kqueue", __func__); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * Make sure that fresh, out-of-the-box fifo file descriptors have - * good initial states. The reader_fd should have no active state, - * since it will not be readable (no data in pipe), writable (it's - * a read-only descriptor), and there's no reason for error yet. - */ - if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE, - NOT_EXCEPTION, __func__, "create", "reader_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * Make sure that fresh, out-of-the-box fifo file descriptors have - * good initial states. The writer_fd should be ready to write. - */ - if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "create", "writer_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); -} - -static void -test_events_write_read_byte(void) -{ - int kqueue_fd, reader_fd, writer_fd; - ssize_t len; - u_char ch; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_events_write_read_byte: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - kqueue_fd = kqueue(); - if (kqueue_fd < 0) { - warn("%s: kqueue", __func__); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * Write a byte to the fifo, and make sure that the read end becomes - * readable, and that the write end remains writable (small write). - */ - ch = 0x00; - len = write(writer_fd, &ch, sizeof(ch)); - if (len < 0) { - warn("%s: write", __func__); - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (assert_status(reader_fd, kqueue_fd, READABLE, NOT_WRITABLE, - NOT_EXCEPTION, __func__, "write", "reader_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * the writer_fd should remain writable. - */ - if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "write", "writer_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * Read the byte from the reader_fd, and now confirm that that fifo - * becomes unreadable. - */ - len = read(reader_fd, &ch, sizeof(ch)); - if (len < 0) { - warn("%s: read", __func__); - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (assert_status(reader_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE, - NOT_EXCEPTION, __func__, "write+read", "reader_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * The writer_fd should remain writable. - */ - if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "write+read", "writer_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); -} - -/* - * Write a 512k buffer to the fifo in non-blocking mode, and make sure that - * the write end becomes un-writable as a result of a partial write that - * fills the fifo buffer. - */ -static void -test_events_partial_write(void) -{ - int kqueue_fd, reader_fd, writer_fd; - u_char *buffer; - ssize_t len; - - makefifo("testfifo", __func__); - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) - < 0) { - warn("test_events_partial_write: openfifo: testfifo"); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - kqueue_fd = kqueue(); - if (kqueue_fd < 0) { - warn("%s: kqueue", __func__); - cleanfifo2("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, reader_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, writer_fd, __func__) < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (set_nonblocking(writer_fd, "test_events") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - buffer = malloc(512*1024); - if (buffer == NULL) { - warn("test_events_partial_write: malloc"); - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - bzero(buffer, 512*1024); - - len = write(writer_fd, buffer, 512*1024); - if (len < 0) { - warn("test_events_partial_write: write"); - free(buffer); - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - free(buffer); - - if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, NOT_WRITABLE, - NOT_EXCEPTION, __func__, "big write", "writer_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - if (drain_fd(reader_fd, "test_events") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - /* - * Test that the writer_fd has been restored to writable state after - * draining. - */ - if (assert_status(writer_fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "big write + drain", "writer_fd") < 0) { - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); - exit(-1); - } - - cleanfifo3("testfifo", reader_fd, writer_fd, kqueue_fd); -} - -/* - * We don't comprehensively test O_RDWR file descriptors, but do run a couple - * of event tests to make sure that the fifo implementation doesn't mixed up - * status checks. In particular, at least one past FreeBSD bug exists in - * which the FIONREAD test was performed on the wrong socket implementing the - * fifo, resulting in the fifo never returning readable. - */ -static void -test_events_rdwr(void) -{ - int fd, kqueue_fd; - ssize_t len; - char ch; - - makefifo("testfifo", __func__); - if (openfifo_rw("testfifo", __func__, &fd) - < 0) { - warn("%s: openfifo_rw: testfifo", __func__); - cleanfifo2("testfifo", -1, -1); - exit(-1); - } - - kqueue_fd = kqueue(); - if (kqueue_fd < 0) { - warn("%s: kqueue", __func__); - cleanfifo2("testifo", fd, -1); - exit(-1); - } - - if (kqueue_setup(kqueue_fd, fd, __func__) < 0) { - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - /* - * On first creation, the O_RDWR descriptor should be writable but - * not readable. - */ - if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "create", "fd") < 0) { - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - /* - * Write a byte, which should cause the file descriptor to become - * readable and writable. - */ - ch = 0x00; - len = write(fd, &ch, sizeof(ch)); - if (len < 0) { - warn("%s: write", __func__); - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - if (assert_status(fd, kqueue_fd, READABLE, WRITABLE, NOT_EXCEPTION, - __func__, "write", "fd") < 0) { - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - /* - * Read a byte, which should cause the file descriptor to return to - * simply being writable. - */ - len = read(fd, &ch, sizeof(ch)); - if (len < 0) { - warn("%s: read", __func__); - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - if (assert_status(fd, kqueue_fd, NOT_READABLE, WRITABLE, - NOT_EXCEPTION, __func__, "write+read", "fd") < 0) { - cleanfifo2("testfifo", fd, kqueue_fd); - exit(-1); - } - - cleanfifo2("testfifo", fd, kqueue_fd); -} - -int -main(int argc, char *argv[]) -{ - - strcpy(temp_dir, "/tmp/fifo_io.XXXXXXXXXXX"); - if (mkdtemp(temp_dir) == NULL) - err(-1, "mkdtemp"); - atexit(atexit_temp_dir); - - if (chdir(temp_dir) < 0) - err(-1, "chdir %s", temp_dir); - - test_simpleio(); - test_blocking_read_empty(); - test_blocking_one_byte(); - test_nonblocking_one_byte(); - test_blocking_partial_write(); - test_nonblocking_partial_write(); - test_coalesce_big_read(); - test_coalesce_big_write(); - test_events_outofbox(); - test_events_write_read_byte(); - test_events_partial_write(); - test_events_rdwr(); - - return (0); -} diff --git a/tools/regression/fifo/fifo_misc/Makefile b/tools/regression/fifo/fifo_misc/Makefile deleted file mode 100644 index 97f85ec..0000000 --- a/tools/regression/fifo/fifo_misc/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= fifo_misc -MAN= -WARNS?= 3 - -.include <bsd.prog.mk> diff --git a/tools/regression/fifo/fifo_misc/fifo_misc.c b/tools/regression/fifo/fifo_misc/fifo_misc.c deleted file mode 100644 index 4215212..0000000 --- a/tools/regression/fifo/fifo_misc/fifo_misc.c +++ /dev/null @@ -1,336 +0,0 @@ -/*- - * Copyright (c) 2005 Robert N. M. Watson - * Copyright (c) 2012 Jilles Tjoelker - * 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. - * - * $FreeBSD$ - */ - -#include <sys/types.h> -#include <sys/event.h> -#include <sys/filio.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* - * Regression test for piddling details of fifos. - */ - -/* - * All activity occurs within a temporary directory created early in the - * test. - */ -char temp_dir[PATH_MAX]; - -static void __unused -atexit_temp_dir(void) -{ - - rmdir(temp_dir); -} - -static void -makefifo(const char *fifoname, const char *testname) -{ - - if (mkfifo(fifoname, 0700) < 0) - err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); -} - -static void -cleanfifo(const char *fifoname, int fd1, int fd2) -{ - - if (fd1 != -1) - close(fd1); - if (fd2 != -1) - close(fd2); - (void)unlink(fifoname); -} - -static int -openfifo(const char *fifoname, const char *testname, int *reader_fdp, - int *writer_fdp) -{ - int error, fd1, fd2; - - fd1 = open(fifoname, O_RDONLY | O_NONBLOCK); - if (fd1 < 0) - return (-1); - fd2 = open(fifoname, O_WRONLY | O_NONBLOCK); - if (fd2 < 0) { - error = errno; - close(fd1); - errno = error; - return (-1); - } - *reader_fdp = fd1; - *writer_fdp = fd2; - - return (0); -} - -/* - * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result. - */ -static void -test_lseek(void) -{ - int reader_fd, writer_fd; - - makefifo("testfifo", __func__); - - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { - warn("%s: openfifo", __func__); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - if (lseek(reader_fd, 1, SEEK_CUR) >= 0) { - warnx("%s: lseek succeeded instead of returning ESPIPE", - __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (errno != ESPIPE) { - warn("%s: lseek returned instead of ESPIPE", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo("testfifo", reader_fd, writer_fd); -} - -/* - * truncate(2) on FIFO should silently return success. - */ -static void -test_truncate(void) -{ - - makefifo("testfifo", __func__); - - if (truncate("testfifo", 1024) != 0) { - warn("%s: truncate", __func__); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - cleanfifo("testfifo", -1, -1); -} - -static int -test_ioctl_setclearflag(int fd, int flag, const char *testname, - const char *fdname, const char *flagname) -{ - int i; - - i = 1; - if (ioctl(fd, flag, &i) < 0) { - warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname, - flagname); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - i = 0; - if (ioctl(fd, flag, &i) < 0) { - warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname, - flagname); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - return (0); -} - -/* - * Test that various ioctls can be issued against the file descriptor. We - * don't currently test the semantics of these changes here. - */ -static void -test_ioctl(void) -{ - int reader_fd, writer_fd; - - makefifo("testfifo", __func__); - - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { - warn("%s: openfifo", __func__); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - /* - * Set and remove the non-blocking I/O flag. - */ - if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__, - "reader_fd", "FIONBIO") < 0) { - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__, - "writer_fd", "FIONBIO") < 0) { - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - /* - * Set and remove the async I/O flag. - */ - if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__, - "reader_fd", "FIOASYNC") < 0) { - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__, - "writer_fd", "FIONASYNC") < 0) { - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo("testfifo", reader_fd, writer_fd); -} - -/* - * fchmod(2)/fchown(2) on FIFO should work. - */ -static void -test_chmodchown(void) -{ - struct stat sb; - int reader_fd, writer_fd; - uid_t u; - gid_t g; - - makefifo("testfifo", __func__); - - if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { - warn("%s: openfifo", __func__); - cleanfifo("testfifo", -1, -1); - exit(-1); - } - - if (fchmod(reader_fd, 0666) != 0) { - warn("%s: fchmod", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (stat("testfifo", &sb) != 0) { - warn("%s: stat", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if ((sb.st_mode & 0777) != 0666) { - warnx("%s: stat chmod result", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (fstat(writer_fd, &sb) != 0) { - warn("%s: fstat", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if ((sb.st_mode & 0777) != 0666) { - warnx("%s: fstat chmod result", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (fchown(reader_fd, -1, -1) != 0) { - warn("%s: fchown 1", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - u = geteuid(); - if (u == 0) - u = 1; - g = getegid(); - if (fchown(reader_fd, u, g) != 0) { - warn("%s: fchown 2", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - if (stat("testfifo", &sb) != 0) { - warn("%s: stat", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (sb.st_uid != u || sb.st_gid != g) { - warnx("%s: stat chown result", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (fstat(writer_fd, &sb) != 0) { - warn("%s: fstat", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - if (sb.st_uid != u || sb.st_gid != g) { - warnx("%s: fstat chown result", __func__); - cleanfifo("testfifo", reader_fd, writer_fd); - exit(-1); - } - - cleanfifo("testfifo", -1, -1); -} - -int -main(int argc, char *argv[]) -{ - - strcpy(temp_dir, "/tmp/fifo_misc.XXXXXXXXXXX"); - if (mkdtemp(temp_dir) == NULL) - err(-1, "mkdtemp"); - atexit(atexit_temp_dir); - - if (chdir(temp_dir) < 0) - err(-1, "chdir %s", temp_dir); - - test_lseek(); - test_truncate(); - test_ioctl(); - test_chmodchown(); - - return (0); -} diff --git a/tools/regression/fifo/fifo_open/Makefile b/tools/regression/fifo/fifo_open/Makefile deleted file mode 100644 index d90811c..0000000 --- a/tools/regression/fifo/fifo_open/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= fifo_open -MAN= -WARNS?= 3 - -.include <bsd.prog.mk> diff --git a/tools/regression/fifo/fifo_open/fifo_open.c b/tools/regression/fifo/fifo_open/fifo_open.c deleted file mode 100644 index 6899a3a..0000000 --- a/tools/regression/fifo/fifo_open/fifo_open.c +++ /dev/null @@ -1,476 +0,0 @@ -/*- - * Copyright (c) 2005 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. - * - * $FreeBSD$ - */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -/* - * Regression test to exercise various POSIX-defined parts of fifo behavior - * described for open(2): - * - * O_NONBLOCK - * When opening a FIFO with O_RDONLY or O_WRONLY set: - * - * - If O_NONBLOCK is set, an open() for reading-only shall return without - * delay. An open() for writing-only shall return an error if no process - * currently has the file open for reading. - * - * - If O_NONBLOCK is clear, an open() for reading-only shall block the - * calling thread until a thread opens the file for writing. An open() - * for writing-only shall block the calling thread until a thread opens - * the file for reading. - * - * When opening a block special or character special file that supports - * non-blocking opens: - * - * - If O_NONBLOCK is set, the open() function shall return without blocking - * for the device to be ready or available. Subsequent behavior of the - * device is device-specific. - * - * - If O_NONBLOCK is clear, the open() function shall block the calling - * thread until the device is ready or available before returning. - * - * Special errors: - * - * [ENXIO] - * O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is set, and no - * process has the file open for reading. - */ - -/* - * In order to test blocking/non-blocking behavior, test processes must - * potentially block themselves until released. As bugs in blocking result - * in processes that won't un-block, we must sacrifice a process to the task, - * watching and potentially killing it after a time-out. The main test - * process is never used to open or act directly on a fifo (other than to - * create or unlink it) in order to avoid the main test process being - * blocked. - */ - -/* - * All activity occurs within a temporary directory created early in the - * test. - */ -char temp_dir[PATH_MAX]; - -static void __unused -atexit_temp_dir(void) -{ - - rmdir(temp_dir); -} - -/* - * Run a function in a particular test process. - */ -static int -run_in_process(int (*func)(void), pid_t *pidp, const char *errstr) -{ - pid_t pid; - - pid = fork(); - if (pid < 0) { - warn("%s: run_in_process: fork", errstr); - return (-1); - } - - if (pid == 0) - exit(func()); - - if (pidp != NULL) - *pidp = pid; - - return (0); -} - -/* - * Wait for a process on a timeout, and if the timeout expires, kill the - * process. Test each second rather than waiting the full timeout at once to - * minimize the amount of time spent hanging around unnecessarily. - */ -static int -wait_and_timeout(pid_t pid, int timeout, int *status, const char *errstr) -{ - pid_t wpid; - int i; - - /* - * Count up to the timeout, but do a non-hanging waitpid() after each - * second so we can avoid waiting a lot of extra time. - */ - for (i = 0; i < timeout; i++) { - wpid = waitpid(pid, status, WNOHANG); - if (wpid < 0) { - warn("%s: wait_and_timeout: waitpid %d", errstr, pid); - return (-1); - } - - if (wpid == pid) - return (0); - - sleep(1); - } - - wpid = waitpid(pid, status, WNOHANG); - if (wpid < 0) { - warn("%s: wait_and_timeout: waitpid %d", errstr, pid); - return (-1); - } - - if (wpid == pid) - return (0); - - if (kill(pid, SIGTERM) < 0) { - warn("%s: wait_and_timeout: kill %d", errstr, pid); - return (-1); - } - - wpid = waitpid(pid, status, 0); - if (wpid < 0) { - warn("%s: wait_and_timeout: waitpid %d", errstr, pid); - return (-1); - } - - if (wpid != pid) { - warn("%s: waitpid: returned %d not %d", errstr, wpid, pid); - return (-1); - } - - warnx("%s: process blocked", errstr); - return (-1); -} - -static int -non_blocking_open_reader(void) -{ - int fd; - - fd = open("testfifo", O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (errno); - close(fd); - - return (0); -} - -static int -non_blocking_open_writer(void) -{ - int fd; - - fd = open("testfifo", O_WRONLY | O_NONBLOCK); - if (fd < 0) - return (errno); - close(fd); - - return (0); -} - -static int -blocking_open_reader(void) -{ - int fd; - - fd = open("testfifo", O_RDONLY); - if (fd < 0) - return (errno); - close(fd); - - return (0); -} - -static int -blocking_open_writer(void) -{ - int fd; - - fd = open("testfifo", O_WRONLY); - if (fd < 0) - return (errno); - close(fd); - - return (0); -} - -static void -test_blocking_reader(void) -{ - pid_t reader_pid, writer_pid, wpid; - int error, status; - - if (mkfifo("testfifo", 0600) < 0) - err(-1, "test_blocking_reader: mkfifo: testfifo"); - - /* - * Block a process in opening the fifo. - */ - if (run_in_process(blocking_open_reader, &reader_pid, - "test_blocking_reader: blocking_open_reader") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - /* - * Test that it blocked. - */ - sleep(5); - wpid = waitpid(reader_pid, &status, WNOHANG); - if (wpid < 0) { - error = errno; - (void)unlink("testfifo"); - errno = error; - err(-1, "test_blocking_reader: waitpid %d", reader_pid); - } - - if (wpid != 0 && wpid != reader_pid) { - (void)unlink("testfifo"); - errx(-1, "test_blocking_reader: waitpid %d returned %d", - reader_pid, wpid); - } - - if (wpid == reader_pid) { - (void)unlink("testfifo"); - errx(-1, "test_blocking_reader: blocking child didn't " - "block"); - } - - /* - * Unblock the blocking reader. - */ - if (run_in_process(blocking_open_writer, &writer_pid, - "test_blocking_reader: blocking_open_writer") < 0) { - (void)unlink("testfifo"); - (void)kill(reader_pid, SIGTERM); - (void)waitpid(reader_pid, &status, 0); - exit(-1); - } - - /* - * Make sure both processes exited quickly (<1 second) to make sure - * they didn't block, and GC. - */ - if (wait_and_timeout(reader_pid, 1, &status, - "test_blocking_reader: blocking_open_reader") < 0) { - (void)unlink("testinfo"); - (void)kill(reader_pid, SIGTERM); - (void)kill(writer_pid, SIGTERM); - exit(-1); - } - - if (wait_and_timeout(writer_pid, 1, &status, - "test_blocking_reader: blocking_open_writer") < 0) { - (void)unlink("testinfo"); - (void)kill(writer_pid, SIGTERM); - exit(-1); - } - - if (unlink("testfifo") < 0) - err(-1, "test_blocking_reader: unlink: testfifo"); -} -static void -test_blocking_writer(void) -{ - pid_t reader_pid, writer_pid, wpid; - int error, status; - - if (mkfifo("testfifo", 0600) < 0) - err(-1, "test_blocking_writer: mkfifo: testfifo"); - - /* - * Block a process in opening the fifo. - */ - if (run_in_process(blocking_open_writer, &writer_pid, - "test_blocking_writer: blocking_open_writer") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - /* - * Test that it blocked. - */ - sleep(5); - wpid = waitpid(writer_pid, &status, WNOHANG); - if (wpid < 0) { - error = errno; - (void)unlink("testfifo"); - errno = error; - err(-1, "test_blocking_writer: waitpid %d", writer_pid); - } - - if (wpid != 0 && wpid != writer_pid) { - (void)unlink("testfifo"); - errx(-1, "test_blocking_writer: waitpid %d returned %d", - writer_pid, wpid); - } - - if (wpid == writer_pid) { - (void)unlink("testfifo"); - errx(-1, "test_blocking_writer: blocking child didn't " - "block"); - } - - /* - * Unblock the blocking writer. - */ - if (run_in_process(blocking_open_reader, &reader_pid, - "test_blocking_writer: blocking_open_reader") < 0) { - (void)unlink("testfifo"); - (void)kill(writer_pid, SIGTERM); - (void)waitpid(writer_pid, &status, 0); - exit(-1); - } - - /* - * Make sure both processes exited quickly (<1 second) to make sure - * they didn't block, and GC. - */ - if (wait_and_timeout(writer_pid, 1, &status, - "test_blocking_writer: blocking_open_writer") < 0) { - (void)unlink("testinfo"); - (void)kill(writer_pid, SIGTERM); - (void)kill(reader_pid, SIGTERM); - (void)waitpid(writer_pid, &status, 0); - (void)waitpid(reader_pid, &status, 0); - exit(-1); - } - - if (wait_and_timeout(reader_pid, 1, &status, - "test_blocking_writer: blocking_open_reader") < 0) { - (void)unlink("testinfo"); - (void)kill(reader_pid, SIGTERM); - (void)waitpid(reader_pid, &status, 0); - exit(-1); - } - - if (unlink("testfifo") < 0) - err(-1, "test_blocking_writer: unlink: testfifo"); -} - -static void -test_non_blocking_reader(void) -{ - int status; - pid_t pid; - - if (mkfifo("testfifo", 0600) < 0) - err(-1, "test_non_blocking_reader: mkfifo: testfifo"); - - if (run_in_process(non_blocking_open_reader, &pid, - "test_non_blocking_reader: non_blocking_open_reader") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - status = -1; - if (wait_and_timeout(pid, 5, &status, - "test_non_blocking_reader: non_blocking_open_reader") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - if (WEXITSTATUS(status) != 0) { - (void)unlink("testfifo"); - errno = WEXITSTATUS(status); - err(-1, "test_non_blocking_reader: " - "non_blocking_open_reader: open: testfifo"); - } - - if (unlink("testfifo") < 0) - err(-1, "test_non_blocking_reader: unlink: testfifo"); -} - -static void -test_non_blocking_writer(void) -{ - int status; - pid_t pid; - - if (mkfifo("testfifo", 0600) < 0) - err(-1, "test_non_blocking_writer: mkfifo: testfifo"); - - if (run_in_process(non_blocking_open_writer, &pid, - "test_non_blocking_writer: non_blocking_open_writer") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - status = -1; - if (wait_and_timeout(pid, 5, &status, - "test_non_blocking_writer: non_blocking_open_writer") < 0) { - (void)unlink("testfifo"); - exit(-1); - } - - if (WEXITSTATUS(status) != ENXIO) { - (void)unlink("testfifo"); - - errno = WEXITSTATUS(status); - if (errno == 0) - errx(-1, "test_non_blocking_writer: " - "non_blocking_open_writer: open succeeded"); - err(-1, "test_non_blocking_writer: " - "non_blocking_open_writer: open: testfifo"); - } - - if (unlink("testfifo") < 0) - err(-1, "test_non_blocking_writer: unlink: testfifo"); -} - -int -main(int argc, char *argv[]) -{ - - if (geteuid() != 0) - errx(-1, "must be run as root"); - - strcpy(temp_dir, "/tmp/fifo_open.XXXXXXXXXXX"); - if (mkdtemp(temp_dir) == NULL) - err(-1, "mkdtemp"); - if (chdir(temp_dir) < 0) - err(-1, "chdir: %s", temp_dir); - atexit(atexit_temp_dir); - - test_non_blocking_reader(); - test_non_blocking_writer(); - - test_blocking_reader(); - test_blocking_writer(); - - return (0); -} diff --git a/tools/regression/file/dup/Makefile b/tools/regression/file/dup/Makefile deleted file mode 100644 index 225c2e2..0000000 --- a/tools/regression/file/dup/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= dup -MAN= -WARNS?= 6 - -.include <bsd.prog.mk> diff --git a/tools/regression/file/dup/dup.c b/tools/regression/file/dup/dup.c deleted file mode 100644 index 8173818..0000000 --- a/tools/regression/file/dup/dup.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * $OpenBSD: dup2test.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ - * $OpenBSD: dup2_self.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ - * $OpenBSD: fcntl_dup.c,v 1.2 2003/07/31 21:48:08 deraadt Exp $ - * - * Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain. - * - * $FreeBSD$ - */ - -/* - * Test #1: check if dup(2) works. - * Test #2: check if dup2(2) works. - * Test #3: check if dup2(2) returned a fd we asked for. - * Test #4: check if dup2(2) cleared close-on-exec flag for duped fd. - * Test #5: check if dup2(2) allows to dup fd to itself. - * Test #6: check if dup2(2) returned a fd we asked for. - * Test #7: check if dup2(2) did not clear close-on-exec flag for duped fd. - * Test #8: check if fcntl(F_DUPFD) works. - * Test #9: check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd. - * Test #10: check if dup2() to a fd > current maximum number of open files - * limit work. - * Test #11: check if fcntl(F_DUP2FD) works. - * Test #12: check if fcntl(F_DUP2FD) returned a fd we asked for. - * Test #13: check if fcntl(F_DUP2FD) cleared close-on-exec flag for duped fd. - * Test #14: check if fcntl(F_DUP2FD) allows to dup fd to itself. - * Test #15: check if fcntl(F_DUP2FD) returned a fd we asked for. - * Test #16: check if fcntl(F_DUP2FD) did not clear close-on-exec flag for - * duped fd. - * Test #17: check if fcntl(F_DUP2FD) to a fd > current maximum number of open - * files limit work. - * Test #18: check if fcntl(F_DUPFD_CLOEXEC) works. - * Test #19: check if fcntl(F_DUPFD_CLOEXEC) set close-on-exec flag for duped - * fd. - * Test #20: check if fcntl(F_DUP2FD_CLOEXEC) works. - * Test #21: check if fcntl(F_DUP2FD_CLOEXEC) returned a fd we asked for. - * Test #22: check if fcntl(F_DUP2FD_CLOEXEC) set close-on-exec flag for duped - * fd. - * Test #23: check if fcntl(F_DUP2FD_CLOEXEC) to a fd > current maximum number - * of open files limit work. - * Test #24: check if dup3(O_CLOEXEC) works. - * Test #25: check if dup3(O_CLOEXEC) returned a fd we asked for. - * Test #26: check if dup3(O_CLOEXEC) set close-on-exec flag for duped fd. - * Test #27: check if dup3(0) works. - * Test #28: check if dup3(0) returned a fd we asked for. - * Test #29: check if dup3(0) cleared close-on-exec flag for duped fd. - * Test #30: check if dup3(O_CLOEXEC) fails if oldfd == newfd. - * Test #31: check if dup3(0) fails if oldfd == newfd. - * Test #32: check if dup3(O_CLOEXEC) to a fd > current maximum number of - * open files limit work. - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> - -#include <err.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -static int getafile(void); - -static int -getafile(void) -{ - int fd; - - char temp[] = "/tmp/dup2XXXXXXXXX"; - if ((fd = mkstemp(temp)) < 0) - err(1, "mkstemp"); - remove(temp); - if (ftruncate(fd, 1024) != 0) - err(1, "ftruncate"); - return (fd); -} - -int -main(int __unused argc, char __unused *argv[]) -{ - struct rlimit rlp; - int orgfd, fd1, fd2, test = 0; - - orgfd = getafile(); - - printf("1..32\n"); - - /* If dup(2) ever work? */ - if ((fd1 = dup(orgfd)) < 0) - err(1, "dup"); - printf("ok %d - dup(2) works\n", ++test); - - /* Set close-on-exec */ - if (fcntl(fd1, F_SETFD, 1) != 0) - err(1, "fcntl(F_SETFD)"); - - /* If dup2(2) ever work? */ - if ((fd2 = dup2(fd1, fd1 + 1)) < 0) - err(1, "dup2"); - printf("ok %d - dup2(2) works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1 + 1) - printf("no ok %d - dup2(2) didn't give us the right fd\n", - test); - else - printf("ok %d - dup2(2) returned a correct fd\n", test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) != 0) - printf("not ok %d - dup2(2) didn't clear close-on-exec\n", - test); - else - printf("ok %d - dup2(2) cleared close-on-exec\n", test); - - /* - * Dup to itself. - * - * We're testing a small tweak in dup2 semantics. - * Normally dup and dup2 will clear the close-on-exec - * flag on the new fd (which appears to be an implementation - * mistake from start and not some planned behavior). - * In today's implementations of dup and dup2 we have to make - * an effort to really clear that flag. But all tested - * implementations of dup2 have another tweak. If we - * dup2(old, new) when old == new, the syscall short-circuits - * and returns early (because there is no need to do all the - * work (and there is a risk for serious mistakes)). - * So although the docs say that dup2 should "take 'old', - * close 'new' perform a dup(2) of 'old' into 'new'" - * the docs are not really followed because close-on-exec - * is not cleared on 'new'. - * - * Since everyone has this bug, we pretend that this is - * the way it is supposed to be and test here that it really - * works that way. - * - * This is a fine example on where two separate implementation - * fuckups take out each other and make the end-result the way - * it was meant to be. - */ - if ((fd2 = dup2(fd1, fd1)) < 0) - err(1, "dup2"); - printf("ok %d - dup2(2) to itself works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1) - printf("not ok %d - dup2(2) didn't give us the right fd\n", - test); - else - printf("ok %d - dup2(2) to itself returned a correct fd\n", - test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) == 0) - printf("not ok %d - dup2(2) cleared close-on-exec\n", test); - else - printf("ok %d - dup2(2) didn't clear close-on-exec\n", test); - - /* Does fcntl(F_DUPFD) work? */ - if ((fd2 = fcntl(fd1, F_DUPFD, 10)) < 0) - err(1, "fcntl(F_DUPFD)"); - if (fd2 < 10) - printf("not ok %d - fcntl(F_DUPFD) returned wrong fd %d\n", - ++test, fd2); - else - printf("ok %d - fcntl(F_DUPFD) works\n", ++test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) != 0) - printf( - "not ok %d - fcntl(F_DUPFD) didn't clear close-on-exec\n", - test); - else - printf("ok %d - fcntl(F_DUPFD) cleared close-on-exec\n", test); - - ++test; - if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) - err(1, "getrlimit"); - if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) >= 0) - printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test); - else - printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test); - - /* If fcntl(F_DUP2FD) ever work? */ - if ((fd2 = fcntl(fd1, F_DUP2FD, fd1 + 1)) < 0) - err(1, "fcntl(F_DUP2FD)"); - printf("ok %d - fcntl(F_DUP2FD) works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1 + 1) - printf( - "no ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD) returned a correct fd\n", - test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) != 0) - printf( - "not ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", - test); - - /* Dup to itself */ - if ((fd2 = fcntl(fd1, F_DUP2FD, fd1)) < 0) - err(1, "fcntl(F_DUP2FD)"); - printf("ok %d - fcntl(F_DUP2FD) to itself works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1) - printf( - "not ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", - test); - else - printf( - "ok %d - fcntl(F_DUP2FD) to itself returned a correct fd\n", - test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) == 0) - printf("not ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", - test); - - ++test; - if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) - err(1, "getrlimit"); - if ((fd2 = fcntl(fd1, F_DUP2FD, rlp.rlim_cur + 1)) >= 0) - printf("not ok %d - fcntl(F_DUP2FD) bypassed NOFILE limit\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD) didn't bypass NOFILE limit\n", - test); - - /* Does fcntl(F_DUPFD_CLOEXEC) work? */ - if ((fd2 = fcntl(fd1, F_DUPFD_CLOEXEC, 10)) < 0) - err(1, "fcntl(F_DUPFD_CLOEXEC)"); - if (fd2 < 10) - printf("not ok %d - fcntl(F_DUPFD_CLOEXEC) returned wrong fd %d\n", - ++test, fd2); - else - printf("ok %d - fcntl(F_DUPFD_CLOEXEC) works\n", ++test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) != 1) - printf( - "not ok %d - fcntl(F_DUPFD_CLOEXEC) didn't set close-on-exec\n", - test); - else - printf("ok %d - fcntl(F_DUPFD_CLOEXEC) set close-on-exec\n", - test); - - /* If fcntl(F_DUP2FD_CLOEXEC) ever work? */ - if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, fd1 + 1)) < 0) - err(1, "fcntl(F_DUP2FD_CLOEXEC)"); - printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1 + 1) - printf( - "no ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't give us the right fd\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) returned a correct fd\n", - test); - - /* Was close-on-exec set? */ - ++test; - if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) - printf( - "not ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't set close-on-exec\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) set close-on-exec\n", - test); - - /* - * It is unclear what F_DUP2FD_CLOEXEC should do when duplicating a - * file descriptor onto itself. - */ - - ++test; - if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) - err(1, "getrlimit"); - if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, rlp.rlim_cur + 1)) >= 0) - printf("not ok %d - fcntl(F_DUP2FD_CLOEXEC) bypassed NOFILE limit\n", - test); - else - printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't bypass NOFILE limit\n", - test); - - /* Does dup3(O_CLOEXEC) ever work? */ - if ((fd2 = dup3(fd1, fd1 + 1, O_CLOEXEC)) < 0) - err(1, "dup3(O_CLOEXEC)"); - printf("ok %d - dup3(O_CLOEXEC) works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1 + 1) - printf( - "no ok %d - dup3(O_CLOEXEC) didn't give us the right fd\n", - test); - else - printf("ok %d - dup3(O_CLOEXEC) returned a correct fd\n", - test); - - /* Was close-on-exec set? */ - ++test; - if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) - printf( - "not ok %d - dup3(O_CLOEXEC) didn't set close-on-exec\n", - test); - else - printf("ok %d - dup3(O_CLOEXEC) set close-on-exec\n", - test); - - /* Does dup3(0) ever work? */ - if ((fd2 = dup3(fd1, fd1 + 1, 0)) < 0) - err(1, "dup3(0)"); - printf("ok %d - dup3(0) works\n", ++test); - - /* Do we get the right fd? */ - ++test; - if (fd2 != fd1 + 1) - printf( - "no ok %d - dup3(0) didn't give us the right fd\n", - test); - else - printf("ok %d - dup3(0) returned a correct fd\n", - test); - - /* Was close-on-exec cleared? */ - ++test; - if (fcntl(fd2, F_GETFD) != 0) - printf( - "not ok %d - dup3(0) didn't clear close-on-exec\n", - test); - else - printf("ok %d - dup3(0) cleared close-on-exec\n", - test); - - /* dup3() does not allow duplicating to the same fd */ - ++test; - if (dup3(fd1, fd1, O_CLOEXEC) != -1) - printf( - "not ok %d - dup3(fd1, fd1, O_CLOEXEC) succeeded\n", test); - else - printf("ok %d - dup3(fd1, fd1, O_CLOEXEC) failed\n", test); - - ++test; - if (dup3(fd1, fd1, 0) != -1) - printf( - "not ok %d - dup3(fd1, fd1, 0) succeeded\n", test); - else - printf("ok %d - dup3(fd1, fd1, 0) failed\n", test); - - ++test; - if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) - err(1, "getrlimit"); - if ((fd2 = dup3(fd1, rlp.rlim_cur + 1, O_CLOEXEC)) >= 0) - printf("not ok %d - dup3(O_CLOEXEC) bypassed NOFILE limit\n", - test); - else - printf("ok %d - dup3(O_CLOEXEC) didn't bypass NOFILE limit\n", - test); - - return (0); -} diff --git a/tools/regression/file/dup/dup.t b/tools/regression/file/dup/dup.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/file/dup/dup.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/file/fcntlflags/Makefile b/tools/regression/file/fcntlflags/Makefile deleted file mode 100644 index 9e7fc3e..0000000 --- a/tools/regression/file/fcntlflags/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= fcntlflags -MAN= -WARNS?= 6 - -.include <bsd.prog.mk> diff --git a/tools/regression/file/fcntlflags/fcntlflags.c b/tools/regression/file/fcntlflags/fcntlflags.c deleted file mode 100644 index bcb3b54..0000000 --- a/tools/regression/file/fcntlflags/fcntlflags.c +++ /dev/null @@ -1,110 +0,0 @@ -/*- - * Copyright (c) 2013 Jilles Tjoelker - * 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. - * - * $FreeBSD$ - */ - -#include <sys/cdefs.h> - -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> - -/* - * O_ACCMODE is currently defined incorrectly. This is what it should be. - * Various code depends on the incorrect value. - */ -#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC) - -static int testnum; - -static void -subtests(const char *path, int omode, const char *omodetext) -{ - int fd, flags1, flags2, flags3; - - fd = open(path, omode); - if (fd == -1) - printf("not ok %d - open(\"%s\", %s) failed\n", - testnum++, path, omodetext); - else - printf("ok %d - open(\"%s\", %s) succeeded\n", - testnum++, path, omodetext); - flags1 = fcntl(fd, F_GETFL); - if (flags1 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if ((flags1 & CORRECT_O_ACCMODE) == omode) - printf("ok %d - fcntl(F_GETFL) gave correct result\n", - testnum++); - else - printf("not ok %d - fcntl(F_GETFL) gave incorrect result " - "(%#x & %#x != %#x)\n", - testnum++, flags1, CORRECT_O_ACCMODE, omode); - if (fcntl(fd, F_SETFL, flags1) == -1) - printf("not ok %d - fcntl(F_SETFL) same flags failed\n", - testnum++); - else - printf("ok %d - fcntl(F_SETFL) same flags succeeded\n", - testnum++); - flags2 = fcntl(fd, F_GETFL); - if (flags2 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if (flags2 == flags1) - printf("ok %d - fcntl(F_GETFL) gave same result\n", - testnum++); - else - printf("not ok %d - fcntl(F_SETFL) caused fcntl(F_GETFL) to " - "change from %#x to %#x\n", - testnum++, flags1, flags2); - if (fcntl(fd, F_SETFL, flags2 | O_NONBLOCK) == -1) - printf("not ok %d - fcntl(F_SETFL) O_NONBLOCK failed\n", - testnum++); - else - printf("ok %d - fcntl(F_SETFL) O_NONBLOCK succeeded\n", - testnum++); - flags3 = fcntl(fd, F_GETFL); - if (flags3 == -1) - printf("not ok %d - fcntl(F_GETFL) failed\n", testnum++); - else if (flags3 == (flags2 | O_NONBLOCK)) - printf("ok %d - fcntl(F_GETFL) gave expected result\n", - testnum++); - else - printf("not ok %d - fcntl(F_SETFL) gave unexpected result " - "(%#x != %#x)\n", - testnum++, flags3, flags2 | O_NONBLOCK); - (void)close(fd); -} - -int -main(int argc __unused, char **argv __unused) -{ - printf("1..24\n"); - testnum = 1; - subtests("/dev/null", O_RDONLY, "O_RDONLY"); - subtests("/dev/null", O_WRONLY, "O_WRONLY"); - subtests("/dev/null", O_RDWR, "O_RDWR"); - subtests("/bin/sh", O_EXEC, "O_EXEC"); - return (0); -} diff --git a/tools/regression/file/fcntlflags/fcntlflags.t b/tools/regression/file/fcntlflags/fcntlflags.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/file/fcntlflags/fcntlflags.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/file/flock/Makefile b/tools/regression/file/flock/Makefile deleted file mode 100644 index cd1a46d..0000000 --- a/tools/regression/file/flock/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -PROG= flock -MAN= -WARNS?= 6 -DPADD= ${LIBPTHREAD} -LDADD= -lpthread - -.include <bsd.prog.mk> diff --git a/tools/regression/file/flock/flock.c b/tools/regression/file/flock/flock.c deleted file mode 100644 index 49e47b8..0000000 --- a/tools/regression/file/flock/flock.c +++ /dev/null @@ -1,1598 +0,0 @@ -/*- - * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ - * Authors: Doug Rabson <dfr@rabson.org> - * Developed with Red Inc: Alfred Perlstein <alfred@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. - * - * 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$ - */ - -#include <sys/param.h> -#include <sys/file.h> -#include <sys/time.h> -#ifdef __FreeBSD__ -#include <sys/mount.h> -#endif -#include <sys/stat.h> -#include <sys/wait.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <signal.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifdef __FreeBSD__ -#if __FreeBSD_version >= 800028 -#define HAVE_SYSID -#endif -#include <sys/cdefs.h> -#else -#ifndef nitems -#define nitems(x) (sizeof((x)) / sizeof((x)[0])) -#endif - -#ifndef __unused -#ifdef __GNUC__ -#define __unused __attribute__((__unused__)) -#else -#define __unused -#endif -#endif -#endif - -static int verbose = 0; - -static int -make_file(const char *pathname, off_t sz) -{ - struct stat st; - const char *template = "/flocktempXXXXXX"; - size_t len; - char *filename; - int fd; - - if (stat(pathname, &st) == 0) { - if (S_ISREG(st.st_mode)) { - fd = open(pathname, O_RDWR); - if (fd < 0) - err(1, "open(%s)", pathname); - if (ftruncate(fd, sz) < 0) - err(1, "ftruncate"); - return (fd); - } - } - - len = strlen(pathname) + strlen(template) + 1; - filename = malloc(len); - strcpy(filename, pathname); - strcat(filename, template); - fd = mkstemp(filename); - if (fd < 0) - err(1, "mkstemp"); - if (ftruncate(fd, sz) < 0) - err(1, "ftruncate"); - if (unlink(filename) < 0) - err(1, "unlink"); - free(filename); - - return (fd); -} - -static void -ignore_alarm(int __unused sig) -{ -} - -static int -safe_waitpid(pid_t pid) -{ - int save_errno; - int status; - - save_errno = errno; - errno = 0; - while (waitpid(pid, &status, 0) != pid) { - if (errno == EINTR) - continue; - err(1, "waitpid"); - } - errno = save_errno; - - return (status); -} - -#define FAIL(test) \ - do { \ - if (test) { \ - printf("FAIL (%s)\n", #test); \ - return -1; \ - } \ - } while (0) - -#define SUCCEED \ - do { printf("SUCCEED\n"); return 0; } while (0) - -/* - * Test 1 - F_GETLK on unlocked region - * - * If no lock is found that would prevent this lock from being - * created, the structure is left unchanged by this function call - * except for the lock type which is set to F_UNLCK. - */ -static int -test1(int fd, __unused int argc, const __unused char **argv) -{ - struct flock fl1, fl2; - - memset(&fl1, 1, sizeof(fl1)); - fl1.l_type = F_WRLCK; - fl1.l_whence = SEEK_SET; - fl2 = fl1; - - if (fcntl(fd, F_GETLK, &fl1) < 0) - err(1, "F_GETLK"); - - printf("1 - F_GETLK on unlocked region: "); - FAIL(fl1.l_start != fl2.l_start); - FAIL(fl1.l_len != fl2.l_len); - FAIL(fl1.l_pid != fl2.l_pid); - FAIL(fl1.l_type != F_UNLCK); - FAIL(fl1.l_whence != fl2.l_whence); -#ifdef HAVE_SYSID - FAIL(fl1.l_sysid != fl2.l_sysid); -#endif - - SUCCEED; -} - -/* - * Test 2 - F_SETLK on locked region - * - * If a shared or exclusive lock cannot be set, fcntl returns - * immediately with EACCES or EAGAIN. - */ -static int -test2(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should return -1 with errno set to either EACCES or - * EAGAIN. - */ - printf("2 - F_SETLK on locked region: "); - res = fcntl(fd, F_SETLK, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - FAIL(res == 0); - FAIL(errno != EACCES && errno != EAGAIN); - - SUCCEED; -} - -/* - * Test 3 - F_SETLKW on locked region - * - * If a shared or exclusive lock is blocked by other locks, the - * process waits until the request can be satisfied. - * - * XXX this test hangs on FreeBSD NFS filesystems due to limitations - * in FreeBSD's client (and server) lockd implementation. - */ -static int -test3(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("3 - F_SETLKW on locked region: "); - - alarm(1); - - res = fcntl(fd, F_SETLKW, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - FAIL(res == 0); - FAIL(errno != EINTR); - - SUCCEED; -} - -/* - * Test 4 - F_GETLK on locked region - * - * Get the first lock that blocks the lock. - */ -static int -test4(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 99; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should return a lock structure reflecting the lock we - * made in the child process. - */ - if (fcntl(fd, F_GETLK, &fl) < 0) - err(1, "F_GETLK"); - - printf("4 - F_GETLK on locked region: "); - FAIL(fl.l_start != 0); - FAIL(fl.l_len != 99); - FAIL(fl.l_type != F_WRLCK); - FAIL(fl.l_pid != pid); -#ifdef HAVE_SYSID - FAIL(fl.l_sysid != 0); -#endif - - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - SUCCEED; -} - -/* - * Test 5 - F_SETLKW simple deadlock - * - * If a blocking shared lock request would cause a deadlock (i.e. the - * lock request is blocked by a process which is itself blocked on a - * lock currently owned by the process making the new request), - * EDEADLK is returned. - */ -static int -test5(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. Because our test relies on the child process being - * blocked on the parent's lock, we can't easily use a pipe to - * synchronize so we just sleep in the parent to given the - * child a chance to setup. - * - * To create the deadlock condition, we arrange for the parent - * to lock the first byte of the file and the child to lock - * the second byte. After locking the second byte, the child - * will attempt to lock the first byte of the file, and - * block. The parent will then attempt to lock the second byte - * (owned by the child) which should cause deadlock. - */ - int pid; - struct flock fl; - int res; - - /* - * Lock the first byte in the parent. - */ - fl.l_start = 0; - fl.l_len = 1; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK 1 (parent)"); - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * Lock the second byte in the child and then block on - * the parent's lock. - */ - fl.l_start = 1; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - fl.l_start = 0; - if (fcntl(fd, F_SETLKW, &fl) < 0) - err(1, "F_SETLKW (child)"); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - sleep(1); - - /* - * fcntl should immediately return -1 with errno set to - * EDEADLK. If the alarm fires, we failed to detect the - * deadlock. - */ - alarm(1); - printf("5 - F_SETLKW simple deadlock: "); - - fl.l_start = 1; - res = fcntl(fd, F_SETLKW, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - - FAIL(res == 0); - FAIL(errno != EDEADLK); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_UNLCK"); - - /* - * Cancel the alarm to avoid confusing later tests. - */ - alarm(0); - - SUCCEED; -} - -/* - * Test 6 - F_SETLKW complex deadlock. - * - * This test involves three process, P, C1 and C2. We set things up so - * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We - * also block C2 by attempting to lock byte zero. Lastly, P attempts - * to lock a range including byte 1 and 2. This represents a deadlock - * (due to C2's blocking attempt to lock byte zero). - */ -static int -test6(int fd, __unused int argc, const __unused char **argv) -{ - /* - * Because our test relies on the child process being blocked - * on the parent's lock, we can't easily use a pipe to - * synchronize so we just sleep in the parent to given the - * children a chance to setup. - */ - int pid1, pid2; - struct flock fl; - int res; - - /* - * Lock the first byte in the parent. - */ - fl.l_start = 0; - fl.l_len = 1; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK 1 (parent)"); - - pid1 = fork(); - if (pid1 < 0) - err(1, "fork"); - - if (pid1 == 0) { - /* - * C1 - * Lock the second byte in the child and then sleep - */ - fl.l_start = 1; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child1)"); - pause(); - exit(0); - } - - pid2 = fork(); - if (pid2 < 0) - err(1, "fork"); - - if (pid2 == 0) { - /* - * C2 - * Lock the third byte in the child and then block on - * the parent's lock. - */ - fl.l_start = 2; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child2)"); - fl.l_start = 0; - if (fcntl(fd, F_SETLKW, &fl) < 0) - err(1, "F_SETLKW (child2)"); - exit(0); - } - - /* - * Wait until the children have set their locks and then - * perform the test. - */ - sleep(1); - - /* - * fcntl should immediately return -1 with errno set to - * EDEADLK. If the alarm fires, we failed to detect the - * deadlock. - */ - alarm(1); - printf("6 - F_SETLKW complex deadlock: "); - - fl.l_start = 1; - fl.l_len = 2; - res = fcntl(fd, F_SETLKW, &fl); - kill(pid1, SIGTERM); - safe_waitpid(pid1); - kill(pid2, SIGTERM); - safe_waitpid(pid2); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_UNLCK"); - - FAIL(res == 0); - FAIL(errno != EDEADLK); - - /* - * Cancel the alarm to avoid confusing later tests. - */ - alarm(0); - - SUCCEED; -} - -/* - * Test 7 - F_SETLK shared lock on exclusive locked region - * - * If a shared or exclusive lock cannot be set, fcntl returns - * immediately with EACCES or EAGAIN. - */ -static int -test7(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("7 - F_SETLK shared lock on exclusive locked region: "); - - fl.l_type = F_RDLCK; - res = fcntl(fd, F_SETLK, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - FAIL(res == 0); - FAIL(errno != EACCES && errno != EAGAIN); - - SUCCEED; -} - -/* - * Test 8 - F_SETLK shared lock on share locked region - * - * When a shared lock is set on a segment of a file, other processes - * shall be able to set shared locks on that segment or a portion of - * it. - */ -static int -test8(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_RDLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("8 - F_SETLK shared lock on share locked region: "); - - fl.l_type = F_RDLCK; - res = fcntl(fd, F_SETLK, &fl); - - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_UNLCK"); - - FAIL(res != 0); - - SUCCEED; -} - -/* - * Test 9 - F_SETLK exclusive lock on share locked region - * - * If a shared or exclusive lock cannot be set, fcntl returns - * immediately with EACCES or EAGAIN. - */ -static int -test9(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_RDLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("9 - F_SETLK exclusive lock on share locked region: "); - - fl.l_type = F_WRLCK; - res = fcntl(fd, F_SETLK, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - FAIL(res == 0); - FAIL(errno != EACCES && errno != EAGAIN); - - SUCCEED; -} - -/* - * Test 10 - trying to set bogus pid or sysid values - * - * The l_pid and l_sysid fields are only used with F_GETLK to return - * the process ID of the process holding a blocking lock and the - * system ID of the system that owns that process - */ -static int -test10(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_pid = 9999; -#ifdef HAVE_SYSID - fl.l_sysid = 9999; -#endif - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - printf("10 - trying to set bogus pid or sysid values: "); - - if (fcntl(fd, F_GETLK, &fl) < 0) - err(1, "F_GETLK"); - - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - FAIL(fl.l_pid != pid); -#ifdef HAVE_SYSID - FAIL(fl.l_sysid != 0); -#endif - - SUCCEED; -} - -/* - * Test 11 - remote locks - * - * XXX temporary interface which will be removed when the kernel lockd - * is added. - */ -static int -test11(int fd, __unused int argc, const __unused char **argv) -{ -#ifdef F_SETLK_REMOTE - struct flock fl; - int res; - - if (geteuid() != 0) - return 0; - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_pid = 9999; - fl.l_sysid = 1001; - - printf("11 - remote locks: "); - - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - fl.l_sysid = 1002; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res == 0); - FAIL(errno != EACCES && errno != EAGAIN); - - res = fcntl(fd, F_GETLK, &fl); - FAIL(res != 0); - FAIL(fl.l_pid != 9999); - FAIL(fl.l_sysid != 1001); - - fl.l_type = F_UNLCK; - fl.l_sysid = 1001; - fl.l_start = 0; - fl.l_len = 0; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - fl.l_pid = 1234; - fl.l_sysid = 1001; - fl.l_start = 0; - fl.l_len = 1; - fl.l_whence = SEEK_SET; - fl.l_type = F_RDLCK; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - fl.l_sysid = 1002; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - fl.l_type = F_UNLCKSYS; - fl.l_sysid = 1001; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - fl.l_type = F_WRLCK; - res = fcntl(fd, F_GETLK, &fl); - FAIL(res != 0); - FAIL(fl.l_pid != 1234); - FAIL(fl.l_sysid != 1002); - - fl.l_type = F_UNLCKSYS; - fl.l_sysid = 1002; - res = fcntl(fd, F_SETLK_REMOTE, &fl); - FAIL(res != 0); - - SUCCEED; -#else - return 0; -#endif -} - -/* - * Test 12 - F_SETLKW on locked region which is then unlocked - * - * If a shared or exclusive lock is blocked by other locks, the - * process waits until the request can be satisfied. - */ -static int -test12(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - - sleep(1); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("12 - F_SETLKW on locked region which is then unlocked: "); - - //alarm(1); - - res = fcntl(fd, F_SETLKW, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - FAIL(res != 0); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_UNLCK"); - - SUCCEED; -} - -/* - * Test 13 - F_SETLKW on locked region, race with owner - * - * If a shared or exclusive lock is blocked by other locks, the - * process waits until the request can be satisfied. - */ -static int -test13(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int i; - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - struct itimerval itv; - - printf("13 - F_SETLKW on locked region, race with owner: "); - fflush(stdout); - - for (i = 0; i < 100; i++) { - if (pipe(pfd) < 0) - err(1, "pipe"); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - - usleep(1); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - while (read(pfd[0], &ch, 1) != 1) { - if (errno == EINTR) - continue; - err(1, "reading from pipe (child)"); - } - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 2; - setitimer(ITIMER_REAL, &itv, NULL); - - res = fcntl(fd, F_SETLKW, &fl); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - FAIL(!(res == 0 || (res == -1 && errno == EINTR))); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "F_UNLCK"); - } - SUCCEED; -} - -/* - * Test 14 - soak test - */ -static int -test14(int fd, int argc, const char **argv) -{ -#define CHILD_COUNT 20 - /* - * We create a set of child processes and let each one run - * through a random sequence of locks and unlocks. - */ - int i, j, id, id_base; - int pids[CHILD_COUNT], pid; - char buf[128]; - char tbuf[128]; - int map[128]; - char outbuf[512]; - struct flock fl; - struct itimerval itv; - int status; - - id_base = 0; - if (argc >= 2) - id_base = strtol(argv[1], NULL, 0); - - printf("14 - soak test: "); - fflush(stdout); - - for (i = 0; i < 128; i++) - map[i] = F_UNLCK; - - for (i = 0; i < CHILD_COUNT; i++) { - - pid = fork(); - if (pid < 0) - err(1, "fork"); - if (pid) { - /* - * Parent - record the pid and continue. - */ - pids[i] = pid; - continue; - } - - /* - * Child - do some work and exit. - */ - id = id_base + i; - srandom(getpid()); - - for (j = 0; j < 50; j++) { - int start, end, len; - int set, wrlock; - - do { - start = random() & 127; - end = random() & 127; - } while (end <= start); - - set = random() & 1; - wrlock = random() & 1; - - len = end - start; - fl.l_start = start; - fl.l_len = len; - fl.l_whence = SEEK_SET; - if (set) - fl.l_type = wrlock ? F_WRLCK : F_RDLCK; - else - fl.l_type = F_UNLCK; - - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 3000; - setitimer(ITIMER_REAL, &itv, NULL); - - if (fcntl(fd, F_SETLKW, &fl) < 0) { - if (errno == EDEADLK || errno == EINTR) { - if (verbose) { - snprintf(outbuf, sizeof(outbuf), - "%d[%d]: %s [%d .. %d] %s\n", - id, j, - set ? (wrlock ? "write lock" - : "read lock") - : "unlock", start, end, - errno == EDEADLK - ? "deadlock" - : "interrupted"); - write(1, outbuf, - strlen(outbuf)); - } - continue; - } else { - perror("fcntl"); - } - } - - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &itv, NULL); - - if (verbose) { - snprintf(outbuf, sizeof(outbuf), - "%d[%d]: %s [%d .. %d] succeeded\n", - id, j, - set ? (wrlock ? "write lock" : "read lock") - : "unlock", start, end); - write(1, outbuf, strlen(outbuf)); - } - - if (set) { - if (wrlock) { - /* - * We got a write lock - write - * our ID to each byte that we - * managed to claim. - */ - for (i = start; i < end; i++) - map[i] = F_WRLCK; - memset(&buf[start], id, len); - if (pwrite(fd, &buf[start], len, - start) != len) { - printf("%d: short write\n", id); - exit(1); - } - } else { - /* - * We got a read lock - read - * the bytes which we claimed - * so that we can check that - * they don't change - * unexpectedly. - */ - for (i = start; i < end; i++) - map[i] = F_RDLCK; - if (pread(fd, &buf[start], len, - start) != len) { - printf("%d: short read\n", id); - exit(1); - } - } - } else { - for (i = start; i < end; i++) - map[i] = F_UNLCK; - } - - usleep(1000); - - /* - * Read back the whole region so that we can - * check that all the bytes we have some kind - * of claim to have the correct value. - */ - if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) { - printf("%d: short read\n", id); - exit(1); - } - - for (i = 0; i < 128; i++) { - if (map[i] != F_UNLCK && buf[i] != tbuf[i]) { - snprintf(outbuf, sizeof(outbuf), - "%d: byte %d expected %d, " - "got %d\n", id, i, buf[i], tbuf[i]); - write(1, outbuf, strlen(outbuf)); - exit(1); - } - } - } - if (verbose) - printf("%d[%d]: done\n", id, j); - - exit(0); - } - - status = 0; - for (i = 0; i < CHILD_COUNT; i++) { - status += safe_waitpid(pids[i]); - } - if (status) - FAIL(status != 0); - - SUCCEED; -} - -/* - * Test 15 - flock(2) semantcs - * - * When a lock holder has a shared lock and attempts to upgrade that - * shared lock to exclusive, it must drop the shared lock before - * blocking on the exclusive lock. - * - * To test this, we first arrange for two shared locks on the file, - * and then attempt to upgrade one of them to exclusive. This should - * drop one of the shared locks and block. We interrupt the blocking - * lock request and examine the lock state of the file after dropping - * the other shared lock - there should be no active locks at this - * point. - */ -static int -test15(int fd, __unused int argc, const __unused char **argv) -{ -#ifdef LOCK_EX - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - * - * Since we only have one file descriptors and lock ownership - * for flock(2) goes with the file descriptor, we use fcntl to - * set the child's shared lock. - */ - int pid; - int pfd[2]; - struct flock fl; - char ch; - int res; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a shared lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_RDLCK; - fl.l_whence = SEEK_SET; - if (fcntl(fd, F_SETLK, &fl) < 0) - err(1, "fcntl(F_SETLK) (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - (void)dup(fd); - if (flock(fd, LOCK_SH) < 0) - err(1, "flock shared"); - - /* - * flock should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("15 - flock(2) semantics: "); - - alarm(1); - flock(fd, LOCK_EX); - - /* - * Kill the child to force it to drop its locks. - */ - kill(pid, SIGTERM); - safe_waitpid(pid); - - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - res = fcntl(fd, F_GETLK, &fl); - - close(pfd[0]); - close(pfd[1]); - FAIL(res != 0); - FAIL(fl.l_type != F_UNLCK); - - SUCCEED; -#else - return 0; -#endif -} - -struct test_ctx { - struct flock tc_fl; - int tc_fd; -}; - -static void * -test16_func(void *tc_in) -{ - uintptr_t error; - struct test_ctx *tc = tc_in; - - error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl); - - pthread_exit((void *)error); -} - -#define THREADS 10 - -/* - * Test 16 - F_SETLKW from two threads - * - * If two threads within a process are blocked on a lock and the lock - * is granted, make sure things are sane. - */ -static int -test16(int fd, __unused int argc, const __unused char **argv) -{ - /* - * We create a child process to hold the lock which we will - * test. We use a pipe to communicate with the child. - */ - int pid; - int pfd[2]; - struct test_ctx tc = { .tc_fd = fd }; - char ch; - int i; - int error; - pthread_t thr[THREADS]; - - if (pipe(pfd) < 0) - err(1, "pipe"); - - tc.tc_fl.l_start = 0; - tc.tc_fl.l_len = 0; - tc.tc_fl.l_type = F_WRLCK; - tc.tc_fl.l_whence = SEEK_SET; - - pid = fork(); - if (pid < 0) - err(1, "fork"); - - if (pid == 0) { - /* - * We are the child. We set a write lock and then - * write one byte back to the parent to tell it. The - * parent will kill us when its done. - */ - if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0) - err(1, "F_SETLK (child)"); - if (write(pfd[1], "a", 1) < 0) - err(1, "writing to pipe (child)"); - pause(); - exit(0); - } - - /* - * Wait until the child has set its lock and then perform the - * test. - */ - if (read(pfd[0], &ch, 1) != 1) - err(1, "reading from pipe (child)"); - - /* - * fcntl should wait until the alarm and then return -1 with - * errno set to EINTR. - */ - printf("16 - F_SETLKW on locked region by two threads: "); - - for (i = 0; i < THREADS; i++) { - error = pthread_create(&thr[i], NULL, test16_func, &tc); - if (error) - err(1, "pthread_create"); - } - - /* - * Sleep, then kill the child. This makes me a little sad, but it's - * tricky to tell whether the threads are all really blocked by this - * point. - */ - sleep(1); - kill(pid, SIGTERM); - safe_waitpid(pid); - close(pfd[0]); - close(pfd[1]); - - for (i = 0; i < THREADS; i++) { - void *res; - error = pthread_join(thr[i], &res); - if (error) - err(1, "pthread_join"); - FAIL((uintptr_t)res != 0); - } - - SUCCEED; -} - -struct test { - int (*testfn)(int, int, const char **); /* function to perform the test */ - int num; /* test number */ - int intr; /* non-zero if the test interrupts a lock */ -}; - -static struct test tests[] = { - { test1, 1, 0 }, - { test2, 2, 0 }, - { test3, 3, 1 }, - { test4, 4, 0 }, - { test5, 5, 1 }, - { test6, 6, 1 }, - { test7, 7, 0 }, - { test8, 8, 0 }, - { test9, 9, 0 }, - { test10, 10, 0 }, - { test11, 11, 1 }, - { test12, 12, 0 }, - { test13, 13, 1 }, - { test14, 14, 0 }, - { test15, 15, 1 }, - { test16, 16, 1 }, -}; - -int -main(int argc, const char *argv[]) -{ - int testnum; - int fd; - int nointr; - unsigned i; - struct sigaction sa; - int test_argc; - const char **test_argv; - - if (argc < 2) { - errx(1, "usage: flock <directory> [test number] ..."); - } - - fd = make_file(argv[1], 1024); - if (argc >= 3) { - testnum = strtol(argv[2], NULL, 0); - test_argc = argc - 2; - test_argv = argv + 2; - } else { - testnum = 0; - test_argc = 0; - test_argv = 0; - } - - sa.sa_handler = ignore_alarm; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGALRM, &sa, 0); - - nointr = 0; -#if defined(__FreeBSD__) && __FreeBSD_version < 800040 - { - /* - * FreeBSD with userland NLM can't interrupt a blocked - * lock request on an NFS mounted filesystem. - */ - struct statfs st; - fstatfs(fd, &st); - nointr = !strcmp(st.f_fstypename, "nfs"); - } -#endif - - for (i = 0; i < nitems(tests); i++) { - if (tests[i].intr && nointr) - continue; - if (!testnum || tests[i].num == testnum) - tests[i].testfn(fd, test_argc, test_argv); - } - - return 0; -} diff --git a/tools/regression/file/ftruncate/Makefile b/tools/regression/file/ftruncate/Makefile deleted file mode 100644 index 40b753e..0000000 --- a/tools/regression/file/ftruncate/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= ftruncate -MAN= -WARNS?= 2 - -.include <bsd.prog.mk> diff --git a/tools/regression/file/ftruncate/ftruncate.c b/tools/regression/file/ftruncate/ftruncate.c deleted file mode 100644 index aebcdcd..0000000 --- a/tools/regression/file/ftruncate/ftruncate.c +++ /dev/null @@ -1,177 +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. - * - * $FreeBSD$ - */ - -/* - * Very simple regression test. - * - * Future tests that might be of interest: - * - * - Make sure we get EISDIR on a directory. - */ - -#include <sys/types.h> -#include <sys/event.h> -#include <sys/socket.h> -#include <sys/stat.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <limits.h> -#include <stdio.h> -#include <unistd.h> - -/* - * Select various potentially interesting lengths at and around power of 2 - * edges. - */ -static off_t lengths[] = {0, 1, 2, 3, 4, 127, 128, 129, 511, 512, 513, 1023, - 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097, 8191, 8192, 8193, 16383, - 16384, 16385}; -static int lengths_count = sizeof(lengths) / sizeof(off_t); - -int -main(int argc, char *argv[]) -{ - int error, fd, fds[2], i, read_only_fd; - char path[PATH_MAX]; - struct stat sb; - size_t size; - off_t len; - char ch; - - /* - * Tests using a writable temporary file: grow and then shrink a file - * using ftruncate and various lengths. Make sure that a negative - * file length is rejected. Make sure that when we grow the file, - * bytes now in the range of the file size return 0. - * - * Save a read-only reference to the file to use later for read-only - * descriptor tests. - */ - snprintf(path, PATH_MAX, "/tmp/ftruncate.XXXXXXXXXXXXX"); - fd = mkstemp(path); - if (fd < 0) - err(-1, "makestemp"); - read_only_fd = open(path, O_RDONLY); - if (read_only_fd < 0) { - error = errno; - (void)unlink(path); - errno = error; - err(-1, "open(%s, O_RDONLY)", path); - } - (void)unlink(path); - - if (ftruncate(fd, -1) == 0) - errx(-1, "ftruncate(fd, -1) succeeded"); - if (errno != EINVAL) - err(-1, "ftruncate(fd, -1) returned wrong error"); - - for (i = 0; i < lengths_count; i++) { - len = lengths[i]; - if (ftruncate(fd, len) < 0) - err(-1, "ftruncate(%llu) up", len); - if (fstat(fd, &sb) < 0) - err(-1, "stat"); - if (sb.st_size != len) - errx(-1, "fstat(%llu) returned len %llu up", len, - sb.st_size); - if (len != 0) { - size = pread(fd, &ch, sizeof(ch), len - 1); - if (size < 0) - err(-1, "pread on len %llu up", len); - if (size != sizeof(ch)) - errx(-1, "pread len %llu size %jd up", - len, (intmax_t)size); - if (ch != 0) - errx(-1, - "pread length %llu size %jd ch %d up", - len, (intmax_t)size, ch); - } - } - - for (i = lengths_count - 1; i >= 0; i--) { - len = lengths[i]; - if (ftruncate(fd, len) < 0) - err(-1, "ftruncate(%llu) down", len); - if (fstat(fd, &sb) < 0) - err(-1, "stat"); - if (sb.st_size != len) - errx(-1, "fstat(%llu) returned %llu down", len, - sb.st_size); - } - close(fd); - - /* - * Make sure that a read-only descriptor can't be truncated. - */ - if (ftruncate(read_only_fd, 0) == 0) - errx(-1, "ftruncate(read_only_fd) succeeded"); - if (errno != EINVAL) - err(-1, "ftruncate(read_only_fd) returned wrong error"); - close(read_only_fd); - - /* - * Make sure that ftruncate on sockets doesn't work. - */ - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) - err(-1, "socket(PF_UNIX, SOCK_STREAM, 0)"); - if (ftruncate(fd, 0) == 0) - errx(-1, "ftruncate(socket) succeeded"); - if (errno != EINVAL) - err(-1, "ftruncate(socket) returned wrong error"); - close(fd); - - /* - * Make sure that ftruncate on pipes doesn't work. - */ - if (pipe(fds) < 0) - err(-1, "pipe"); - if (ftruncate(fds[0], 0) == 0) - errx(-1, "ftruncate(pipe) succeeded"); - if (errno != EINVAL) - err(-1, "ftruncate(pipe) returned wrong error"); - close(fds[0]); - close(fds[1]); - - /* - * Make sure that ftruncate on kqueues doesn't work. - */ - fd = kqueue(); - if (fd < 0) - err(-1, "kqueue"); - if (ftruncate(fds[0], 0) == 0) - errx(-1, "ftruncate(kqueue) succeeded"); - if (errno != EINVAL) - err(-1, "ftruncate(kqueue) returned wrong error"); - close(fd); - - return (0); -} diff --git a/tools/regression/file/newfileops_on_fork/Makefile b/tools/regression/file/newfileops_on_fork/Makefile deleted file mode 100644 index be0c5fe..0000000 --- a/tools/regression/file/newfileops_on_fork/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -PROG= newfileops_on_fork -MAN= -WARNS?= 6 -LDFLAGS= -lpthread - -.include <bsd.prog.mk> diff --git a/tools/regression/file/newfileops_on_fork/newfileops_on_fork.c b/tools/regression/file/newfileops_on_fork/newfileops_on_fork.c deleted file mode 100644 index 8713a82..0000000 --- a/tools/regression/file/newfileops_on_fork/newfileops_on_fork.c +++ /dev/null @@ -1,121 +0,0 @@ -/*- - * Copyright (c) 2009 Robert N. M. Watson - * All rights reserved. - * - * This software was developed at the University of Cambridge Computer - * Laboratory with support from a grant from Google, Inc. - * - * 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. - * - * $FreeBSD$ - */ - -/* - * When a multi-threaded application calls fork(2) from one thread while - * another thread is blocked in accept(2), we prefer that the file descriptor - * to be returned by accept(2) not appear in the child process. Test this by - * creating a thread blocked in accept(2), then forking a child and seeing if - * the fd it would have returned is defined in the child or not. - */ - -#include <sys/socket.h> -#include <sys/wait.h> - -#include <netinet/in.h> - -#include <err.h> -#include <errno.h> -#include <pthread.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define PORT 9000 - -static int listen_fd; - -static void * -do_accept(__unused void *arg) -{ - int accept_fd; - - accept_fd = accept(listen_fd, NULL, NULL); - if (accept_fd < 0) - err(-1, "accept"); - - return (NULL); -} - -static void -do_fork(void) -{ - int pid; - - pid = fork(); - if (pid < 0) - err(-1, "fork"); - if (pid > 0) { - waitpid(pid, NULL, 0); - exit(0); - } - - /* - * We will call ftruncate(2) on the next available file descriptor, - * listen_fd+1, and get back EBADF if it's not a valid descriptor, - * and EINVAL if it is. This (currently) works fine in practice. - */ - if (ftruncate(listen_fd + 1, 0 < 0)) { - if (errno == EBADF) - exit(0); - else if (errno == EINVAL) - errx(-1, "file descriptor still open in child"); - else - err(-1, "unexpected error"); - } else - errx(-1, "ftruncate succeeded"); -} - -int -main(__unused int argc, __unused char *argv[]) -{ - struct sockaddr_in sin; - pthread_t accept_thread; - - listen_fd = socket(PF_INET, SOCK_STREAM, 0); - if (listen_fd < 0) - err(-1, "socket"); - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_port = htons(PORT); - if (bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "bind"); - if (listen(listen_fd, -1) <0) - err(-1, "listen"); - if (pthread_create(&accept_thread, NULL, do_accept, NULL) != 0) - err(-1, "pthread_create"); - sleep(1); /* Easier than using a CV. */; - do_fork(); - exit(0); -} |