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/stat.h> 34 #include <sys/time.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 /* 46 * Regression test for piddling details of fifos. 47 */ 48 49 /* 50 * All activity occurs within a temporary directory created early in the 51 * test. 52 */ 53 static char temp_dir[PATH_MAX]; 54 55 static void __unused 56 atexit_temp_dir(void) 57 { 58 59 rmdir(temp_dir); 60 } 61 62 static void 63 makefifo(const char *fifoname, const char *testname) 64 { 65 66 if (mkfifo(fifoname, 0700) < 0) 67 err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); 68 } 69 70 static void 71 cleanfifo(const char *fifoname, int fd1, int fd2) 72 { 73 74 if (fd1 != -1) 75 close(fd1); 76 if (fd2 != -1) 77 close(fd2); 78 (void)unlink(fifoname); 79 } 80 81 static int 82 openfifo(const char *fifoname, int *reader_fdp, 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 */ 105 static void 106 test_lseek(void) 107 { 108 int reader_fd, writer_fd; 109 110 makefifo("testfifo", __func__); 111 112 if (openfifo("testfifo", &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 */ 136 static void 137 test_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 151 static int 152 test_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 */ 180 static void 181 test_ioctl(void) 182 { 183 int reader_fd, writer_fd; 184 185 makefifo("testfifo", __func__); 186 187 if (openfifo("testfifo", &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 226 /* 227 * fchmod(2)/fchown(2) on FIFO should work. 228 */ 229 static void 230 test_chmodchown(void) 231 { 232 struct stat sb; 233 int reader_fd, writer_fd; 234 uid_t u; 235 gid_t g; 236 237 makefifo("testfifo", __func__); 238 239 if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 240 warn("%s: openfifo", __func__); 241 cleanfifo("testfifo", -1, -1); 242 exit(-1); 243 } 244 245 if (fchmod(reader_fd, 0666) != 0) { 246 warn("%s: fchmod", __func__); 247 cleanfifo("testfifo", reader_fd, writer_fd); 248 exit(-1); 249 } 250 251 if (stat("testfifo", &sb) != 0) { 252 warn("%s: stat", __func__); 253 cleanfifo("testfifo", reader_fd, writer_fd); 254 exit(-1); 255 } 256 257 if ((sb.st_mode & 0777) != 0666) { 258 warnx("%s: stat chmod result", __func__); 259 cleanfifo("testfifo", reader_fd, writer_fd); 260 exit(-1); 261 } 262 263 if (fstat(writer_fd, &sb) != 0) { 264 warn("%s: fstat", __func__); 265 cleanfifo("testfifo", reader_fd, writer_fd); 266 exit(-1); 267 } 268 269 if ((sb.st_mode & 0777) != 0666) { 270 warnx("%s: fstat chmod result", __func__); 271 cleanfifo("testfifo", reader_fd, writer_fd); 272 exit(-1); 273 } 274 275 if (fchown(reader_fd, -1, -1) != 0) { 276 warn("%s: fchown 1", __func__); 277 cleanfifo("testfifo", reader_fd, writer_fd); 278 exit(-1); 279 } 280 281 u = geteuid(); 282 if (u == 0) 283 u = 1; 284 g = getegid(); 285 if (fchown(reader_fd, u, g) != 0) { 286 warn("%s: fchown 2", __func__); 287 cleanfifo("testfifo", reader_fd, writer_fd); 288 exit(-1); 289 } 290 if (stat("testfifo", &sb) != 0) { 291 warn("%s: stat", __func__); 292 cleanfifo("testfifo", reader_fd, writer_fd); 293 exit(-1); 294 } 295 296 if (sb.st_uid != u || sb.st_gid != g) { 297 warnx("%s: stat chown result", __func__); 298 cleanfifo("testfifo", reader_fd, writer_fd); 299 exit(-1); 300 } 301 302 if (fstat(writer_fd, &sb) != 0) { 303 warn("%s: fstat", __func__); 304 cleanfifo("testfifo", reader_fd, writer_fd); 305 exit(-1); 306 } 307 308 if (sb.st_uid != u || sb.st_gid != g) { 309 warnx("%s: fstat chown result", __func__); 310 cleanfifo("testfifo", reader_fd, writer_fd); 311 exit(-1); 312 } 313 314 cleanfifo("testfifo", -1, -1); 315 } 316 317 int 318 main(void) 319 { 320 321 strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX"); 322 if (mkdtemp(temp_dir) == NULL) 323 err(-1, "mkdtemp"); 324 atexit(atexit_temp_dir); 325 326 if (chdir(temp_dir) < 0) 327 err(-1, "chdir %s", temp_dir); 328 329 test_lseek(); 330 test_truncate(); 331 test_ioctl(); 332 test_chmodchown(); 333 334 return (0); 335 } 336