1/*- 2 * Copyright (c) 2005 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29#include <sys/types.h> 30#include <sys/event.h> 31#include <sys/filio.h> 32#include <sys/stat.h> 33#include <sys/time.h> 34 35#include <err.h> 36#include <errno.h> 37#include <fcntl.h> 38#include <limits.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 44/* 45 * Regression test for piddling details of fifos. 46 */ 47 48/* 49 * All activity occurs within a temporary directory created early in the 50 * test. 51 */ 52char temp_dir[PATH_MAX]; 53 54static void __unused 55atexit_temp_dir(void) 56{ 57 58 rmdir(temp_dir); 59} 60 61static void 62makefifo(const char *fifoname, const char *testname) 63{ 64 65 if (mkfifo(fifoname, 0700) < 0) 66 err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); 67} 68 69static void 70cleanfifo(const char *fifoname, int fd1, int fd2) 71{ 72 73 if (fd1 != -1) 74 close(fd1); 75 if (fd2 != -1) 76 close(fd2); 77 (void)unlink(fifoname); 78} 79 80static int 81openfifo(const char *fifoname, const char *testname, int *reader_fdp, 82 int *writer_fdp) 83{ 84 int error, fd1, fd2; 85 86 fd1 = open(fifoname, O_RDONLY | O_NONBLOCK); 87 if (fd1 < 0) 88 return (-1); 89 fd2 = open(fifoname, O_WRONLY | O_NONBLOCK); 90 if (fd2 < 0) { 91 error = errno; 92 close(fd1); 93 errno = error; 94 return (-1); 95 } 96 *reader_fdp = fd1; 97 *writer_fdp = fd2; 98 99 return (0); 100} 101 102/* 103 * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result. 104 */ 105static void 106test_lseek(void) 107{ 108 int reader_fd, writer_fd; 109 110 makefifo("testfifo", __func__); 111 112 if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { 113 warn("%s: openfifo", __func__); 114 cleanfifo("testfifo", -1, -1); 115 exit(-1); 116 } 117 118 if (lseek(reader_fd, 1, SEEK_CUR) >= 0) { 119 warnx("%s: lseek succeeded instead of returning ESPIPE", 120 __func__); 121 cleanfifo("testfifo", reader_fd, writer_fd); 122 exit(-1); 123 } 124 if (errno != ESPIPE) { 125 warn("%s: lseek returned instead of ESPIPE", __func__); 126 cleanfifo("testfifo", reader_fd, writer_fd); 127 exit(-1); 128 } 129 130 cleanfifo("testfifo", reader_fd, writer_fd); 131} 132 133/* 134 * truncate(2) on FIFO should silently return success. 135 */ 136static void 137test_truncate(void) 138{ 139 140 makefifo("testfifo", __func__); 141 142 if (truncate("testfifo", 1024) != 0) { 143 warn("%s: truncate", __func__); 144 cleanfifo("testfifo", -1, -1); 145 exit(-1); 146 } 147 148 cleanfifo("testfifo", -1, -1); 149} 150 151static int 152test_ioctl_setclearflag(int fd, int flag, const char *testname, 153 const char *fdname, const char *flagname) 154{ 155 int i; 156 157 i = 1; 158 if (ioctl(fd, flag, &i) < 0) { 159 warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname, 160 flagname); 161 cleanfifo("testfifo", -1, -1); 162 exit(-1); 163 } 164 165 i = 0; 166 if (ioctl(fd, flag, &i) < 0) { 167 warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname, 168 flagname); 169 cleanfifo("testfifo", -1, -1); 170 exit(-1); 171 } 172 173 return (0); 174} 175 176/* 177 * Test that various ioctls can be issued against the file descriptor. We 178 * don't currently test the semantics of these changes here. 179 */ 180static void 181test_ioctl(void) 182{ 183 int reader_fd, writer_fd; 184 185 makefifo("testfifo", __func__); 186 187 if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) { 188 warn("%s: openfifo", __func__); 189 cleanfifo("testfifo", -1, -1); 190 exit(-1); 191 } 192 193 /* 194 * Set and remove the non-blocking I/O flag. 195 */ 196 if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__, 197 "reader_fd", "FIONBIO") < 0) { 198 cleanfifo("testfifo", reader_fd, writer_fd); 199 exit(-1); 200 } 201 202 if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__, 203 "writer_fd", "FIONBIO") < 0) { 204 cleanfifo("testfifo", reader_fd, writer_fd); 205 exit(-1); 206 } 207 208 /* 209 * Set and remove the async I/O flag. 210 */ 211 if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__, 212 "reader_fd", "FIOASYNC") < 0) { 213 cleanfifo("testfifo", reader_fd, writer_fd); 214 exit(-1); 215 } 216 217 if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__, 218 "writer_fd", "FIONASYNC") < 0) { 219 cleanfifo("testfifo", reader_fd, writer_fd); 220 exit(-1); 221 } 222 223 cleanfifo("testfifo", reader_fd, writer_fd); 224} 225 226int 227main(int argc, char *argv[]) 228{ 229 230 strcpy(temp_dir, "/tmp/fifo_misc.XXXXXXXXXXX"); 231 if (mkdtemp(temp_dir) == NULL) 232 err(-1, "mkdtemp"); 233 atexit(atexit_temp_dir); 234 235 if (chdir(temp_dir) < 0) 236 err(-1, "chdir %s", temp_dir); 237 238 test_lseek(); 239 test_truncate(); 240 test_ioctl(); 241 242 return (0); 243} 244