static void docheckservice (void) { struct stat st; char *reason = "maintenance"; char buf[256]; char *p; if (0 == stat(".noservice", &st)) { if (st.st_size) if (-1 != topline(NULL, ".noservice", buf, sizeof (buf))) reason = buf; args_write(1, "400 Service going down: %s\r\n", reason); cleanup(); _exit(0); } if (0 == stat(".nopost", &st)) posting_ok = FALSE; else if ((p = getenv("POSTING_OK"))) posting_ok = TRUE; else posting_ok = FALSE; openfifo(); checkservice = FALSE; }
/* * 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); }
/* * 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); }
/* * 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", &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); }
/* * 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); }
/* * 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", &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); }
/* * 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); }
/* * 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", &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); }
/* * 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", &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); }
/* * 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", &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 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", &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); }
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", &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); }