diff options
author | ngie <ngie@FreeBSD.org> | 2015-04-12 06:18:24 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-04-12 06:18:24 +0000 |
commit | 86baa7f8f13214ab47e5f9f56c93259959f06615 (patch) | |
tree | 41281d1eacda8804076c58bb7a66d3dd50b84c89 /tools | |
parent | 3ffff028af4665eff539b7753046527e8db659b3 (diff) | |
download | FreeBSD-src-86baa7f8f13214ab47e5f9f56c93259959f06615.zip FreeBSD-src-86baa7f8f13214ab47e5f9f56c93259959f06615.tar.gz |
Integrate tools/regression/fifo into the FreeBSD test suite as tests/sys/fifo
Diffstat (limited to 'tools')
-rw-r--r-- | tools/regression/fifo/fifo_create/Makefile | 7 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_create/fifo_create.c | 285 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_io/Makefile | 7 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_io/fifo_io.c | 1409 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_misc/Makefile | 7 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_misc/fifo_misc.c | 336 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_open/Makefile | 7 | ||||
-rw-r--r-- | tools/regression/fifo/fifo_open/fifo_open.c | 476 |
8 files changed, 0 insertions, 2534 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); -} |