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