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: releng/10.2/tests/sys/fifo/fifo_misc.c 281450 2015-04-12 06:18:24Z ngie $ 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 */ 53static char temp_dir[PATH_MAX]; 54 55static void __unused 56atexit_temp_dir(void) 57{ 58 59 rmdir(temp_dir); 60} 61 62static void 63makefifo(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 70static void 71cleanfifo(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 81static int 82openfifo(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 */ 105static void 106test_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 */ 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", &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 */ 229static void 230test_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 317int 318main(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