1150032Srwatson/*- 2150032Srwatson * Copyright (c) 2005 Robert N. M. Watson 3232184Sjilles * Copyright (c) 2012 Jilles Tjoelker 4150032Srwatson * All rights reserved. 5150032Srwatson * 6150032Srwatson * Redistribution and use in source and binary forms, with or without 7150032Srwatson * modification, are permitted provided that the following conditions 8150032Srwatson * are met: 9150032Srwatson * 1. Redistributions of source code must retain the above copyright 10150032Srwatson * notice, this list of conditions and the following disclaimer. 11150032Srwatson * 2. Redistributions in binary form must reproduce the above copyright 12150032Srwatson * notice, this list of conditions and the following disclaimer in the 13150032Srwatson * documentation and/or other materials provided with the distribution. 14150032Srwatson * 15150032Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16150032Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17150032Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18150032Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19150032Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20150032Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21150032Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22150032Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23150032Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24150032Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25150032Srwatson * SUCH DAMAGE. 26150032Srwatson * 27150032Srwatson * $FreeBSD$ 28150032Srwatson */ 29150032Srwatson 30150064Srwatson#include <sys/types.h> 31150064Srwatson#include <sys/event.h> 32150094Srwatson#include <sys/filio.h> 33286612Srodrigc#include <sys/ioctl.h> 34150032Srwatson#include <sys/stat.h> 35150064Srwatson#include <sys/time.h> 36150032Srwatson 37150032Srwatson#include <err.h> 38150032Srwatson#include <errno.h> 39150032Srwatson#include <fcntl.h> 40150032Srwatson#include <limits.h> 41150064Srwatson#include <stdio.h> 42150032Srwatson#include <stdlib.h> 43150032Srwatson#include <string.h> 44150032Srwatson#include <unistd.h> 45150032Srwatson 46150032Srwatson/* 47150032Srwatson * Regression test for piddling details of fifos. 48150032Srwatson */ 49150032Srwatson 50150032Srwatson/* 51150032Srwatson * All activity occurs within a temporary directory created early in the 52150032Srwatson * test. 53150032Srwatson */ 54281450Sngiestatic char temp_dir[PATH_MAX]; 55150032Srwatson 56150032Srwatsonstatic void __unused 57150032Srwatsonatexit_temp_dir(void) 58150032Srwatson{ 59150032Srwatson 60150032Srwatson rmdir(temp_dir); 61150032Srwatson} 62150032Srwatson 63150032Srwatsonstatic void 64150032Srwatsonmakefifo(const char *fifoname, const char *testname) 65150032Srwatson{ 66150032Srwatson 67150032Srwatson if (mkfifo(fifoname, 0700) < 0) 68150032Srwatson err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); 69150032Srwatson} 70150032Srwatson 71150032Srwatsonstatic void 72150032Srwatsoncleanfifo(const char *fifoname, int fd1, int fd2) 73150032Srwatson{ 74150032Srwatson 75150032Srwatson if (fd1 != -1) 76150032Srwatson close(fd1); 77150032Srwatson if (fd2 != -1) 78150032Srwatson close(fd2); 79150032Srwatson (void)unlink(fifoname); 80150032Srwatson} 81150032Srwatson 82150032Srwatsonstatic int 83281450Sngieopenfifo(const char *fifoname, int *reader_fdp, int *writer_fdp) 84150032Srwatson{ 85150032Srwatson int error, fd1, fd2; 86150032Srwatson 87150032Srwatson fd1 = open(fifoname, O_RDONLY | O_NONBLOCK); 88150032Srwatson if (fd1 < 0) 89150032Srwatson return (-1); 90150032Srwatson fd2 = open(fifoname, O_WRONLY | O_NONBLOCK); 91150032Srwatson if (fd2 < 0) { 92150032Srwatson error = errno; 93150032Srwatson close(fd1); 94150032Srwatson errno = error; 95150032Srwatson return (-1); 96150032Srwatson } 97150032Srwatson *reader_fdp = fd1; 98150032Srwatson *writer_fdp = fd2; 99150032Srwatson 100150032Srwatson return (0); 101150032Srwatson} 102150032Srwatson 103150064Srwatson/* 104150064Srwatson * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result. 105150064Srwatson */ 106150032Srwatsonstatic void 107150032Srwatsontest_lseek(void) 108150032Srwatson{ 109150032Srwatson int reader_fd, writer_fd; 110150032Srwatson 111150032Srwatson makefifo("testfifo", __func__); 112150032Srwatson 113281450Sngie if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 114150032Srwatson warn("%s: openfifo", __func__); 115150032Srwatson cleanfifo("testfifo", -1, -1); 116150032Srwatson exit(-1); 117150032Srwatson } 118150032Srwatson 119227124Sjilles if (lseek(reader_fd, 1, SEEK_CUR) >= 0) { 120150032Srwatson warnx("%s: lseek succeeded instead of returning ESPIPE", 121150032Srwatson __func__); 122150032Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 123150032Srwatson exit(-1); 124150032Srwatson } 125150032Srwatson if (errno != ESPIPE) { 126150032Srwatson warn("%s: lseek returned instead of ESPIPE", __func__); 127150032Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 128150032Srwatson exit(-1); 129150032Srwatson } 130150032Srwatson 131150032Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 132150032Srwatson} 133150032Srwatson 134159032Smaxim/* 135159032Smaxim * truncate(2) on FIFO should silently return success. 136159032Smaxim */ 137159032Smaximstatic void 138159032Smaximtest_truncate(void) 139159032Smaxim{ 140159032Smaxim 141159032Smaxim makefifo("testfifo", __func__); 142159032Smaxim 143159032Smaxim if (truncate("testfifo", 1024) != 0) { 144159032Smaxim warn("%s: truncate", __func__); 145159032Smaxim cleanfifo("testfifo", -1, -1); 146159032Smaxim exit(-1); 147159032Smaxim } 148159032Smaxim 149159032Smaxim cleanfifo("testfifo", -1, -1); 150159032Smaxim} 151159032Smaxim 152150094Srwatsonstatic int 153286612Srodrigctest_ioctl_setclearflag(int fd, unsigned long flag, const char *testname, 154150094Srwatson const char *fdname, const char *flagname) 155150094Srwatson{ 156150094Srwatson int i; 157150094Srwatson 158150094Srwatson i = 1; 159150094Srwatson if (ioctl(fd, flag, &i) < 0) { 160150094Srwatson warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname, 161150094Srwatson flagname); 162150094Srwatson cleanfifo("testfifo", -1, -1); 163150094Srwatson exit(-1); 164150094Srwatson } 165150094Srwatson 166150094Srwatson i = 0; 167150094Srwatson if (ioctl(fd, flag, &i) < 0) { 168150094Srwatson warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname, 169150094Srwatson flagname); 170150094Srwatson cleanfifo("testfifo", -1, -1); 171150094Srwatson exit(-1); 172150094Srwatson } 173150094Srwatson 174150094Srwatson return (0); 175150094Srwatson} 176150094Srwatson 177150094Srwatson/* 178150094Srwatson * Test that various ioctls can be issued against the file descriptor. We 179150094Srwatson * don't currently test the semantics of these changes here. 180150094Srwatson */ 181150094Srwatsonstatic void 182150094Srwatsontest_ioctl(void) 183150094Srwatson{ 184150094Srwatson int reader_fd, writer_fd; 185150094Srwatson 186150094Srwatson makefifo("testfifo", __func__); 187150094Srwatson 188281450Sngie if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 189150094Srwatson warn("%s: openfifo", __func__); 190150094Srwatson cleanfifo("testfifo", -1, -1); 191150094Srwatson exit(-1); 192150094Srwatson } 193150094Srwatson 194150094Srwatson /* 195150094Srwatson * Set and remove the non-blocking I/O flag. 196150094Srwatson */ 197150094Srwatson if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__, 198150094Srwatson "reader_fd", "FIONBIO") < 0) { 199150094Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 200150094Srwatson exit(-1); 201150094Srwatson } 202150094Srwatson 203150094Srwatson if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__, 204150094Srwatson "writer_fd", "FIONBIO") < 0) { 205150094Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 206150094Srwatson exit(-1); 207150094Srwatson } 208150094Srwatson 209150094Srwatson /* 210150094Srwatson * Set and remove the async I/O flag. 211150094Srwatson */ 212150094Srwatson if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__, 213150094Srwatson "reader_fd", "FIOASYNC") < 0) { 214150094Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 215150094Srwatson exit(-1); 216150094Srwatson } 217150094Srwatson 218150094Srwatson if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__, 219150094Srwatson "writer_fd", "FIONASYNC") < 0) { 220150094Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 221150094Srwatson exit(-1); 222150094Srwatson } 223150094Srwatson 224150094Srwatson cleanfifo("testfifo", reader_fd, writer_fd); 225150094Srwatson} 226150094Srwatson 227232184Sjilles/* 228232184Sjilles * fchmod(2)/fchown(2) on FIFO should work. 229232184Sjilles */ 230232184Sjillesstatic void 231232184Sjillestest_chmodchown(void) 232232184Sjilles{ 233232184Sjilles struct stat sb; 234232184Sjilles int reader_fd, writer_fd; 235232184Sjilles uid_t u; 236232184Sjilles gid_t g; 237232184Sjilles 238232184Sjilles makefifo("testfifo", __func__); 239232184Sjilles 240281450Sngie if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 241232184Sjilles warn("%s: openfifo", __func__); 242232184Sjilles cleanfifo("testfifo", -1, -1); 243232184Sjilles exit(-1); 244232184Sjilles } 245232184Sjilles 246232184Sjilles if (fchmod(reader_fd, 0666) != 0) { 247232184Sjilles warn("%s: fchmod", __func__); 248232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 249232184Sjilles exit(-1); 250232184Sjilles } 251232184Sjilles 252232184Sjilles if (stat("testfifo", &sb) != 0) { 253232184Sjilles warn("%s: stat", __func__); 254232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 255232184Sjilles exit(-1); 256232184Sjilles } 257232184Sjilles 258232184Sjilles if ((sb.st_mode & 0777) != 0666) { 259232184Sjilles warnx("%s: stat chmod result", __func__); 260232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 261232184Sjilles exit(-1); 262232184Sjilles } 263232184Sjilles 264232184Sjilles if (fstat(writer_fd, &sb) != 0) { 265232184Sjilles warn("%s: fstat", __func__); 266232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 267232184Sjilles exit(-1); 268232184Sjilles } 269232184Sjilles 270232184Sjilles if ((sb.st_mode & 0777) != 0666) { 271232184Sjilles warnx("%s: fstat chmod result", __func__); 272232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 273232184Sjilles exit(-1); 274232184Sjilles } 275232184Sjilles 276232184Sjilles if (fchown(reader_fd, -1, -1) != 0) { 277232184Sjilles warn("%s: fchown 1", __func__); 278232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 279232184Sjilles exit(-1); 280232184Sjilles } 281232184Sjilles 282232184Sjilles u = geteuid(); 283232184Sjilles if (u == 0) 284232184Sjilles u = 1; 285232184Sjilles g = getegid(); 286232184Sjilles if (fchown(reader_fd, u, g) != 0) { 287232184Sjilles warn("%s: fchown 2", __func__); 288232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 289232184Sjilles exit(-1); 290232184Sjilles } 291232184Sjilles if (stat("testfifo", &sb) != 0) { 292232184Sjilles warn("%s: stat", __func__); 293232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 294232184Sjilles exit(-1); 295232184Sjilles } 296232184Sjilles 297232184Sjilles if (sb.st_uid != u || sb.st_gid != g) { 298232184Sjilles warnx("%s: stat chown result", __func__); 299232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 300232184Sjilles exit(-1); 301232184Sjilles } 302232184Sjilles 303232184Sjilles if (fstat(writer_fd, &sb) != 0) { 304232184Sjilles warn("%s: fstat", __func__); 305232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 306232184Sjilles exit(-1); 307232184Sjilles } 308232184Sjilles 309232184Sjilles if (sb.st_uid != u || sb.st_gid != g) { 310232184Sjilles warnx("%s: fstat chown result", __func__); 311232184Sjilles cleanfifo("testfifo", reader_fd, writer_fd); 312232184Sjilles exit(-1); 313232184Sjilles } 314232184Sjilles 315232184Sjilles cleanfifo("testfifo", -1, -1); 316232184Sjilles} 317232184Sjilles 318150032Srwatsonint 319281450Sngiemain(void) 320150032Srwatson{ 321150032Srwatson 322281450Sngie strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX"); 323150032Srwatson if (mkdtemp(temp_dir) == NULL) 324150032Srwatson err(-1, "mkdtemp"); 325150032Srwatson atexit(atexit_temp_dir); 326150032Srwatson 327150032Srwatson if (chdir(temp_dir) < 0) 328150032Srwatson err(-1, "chdir %s", temp_dir); 329150032Srwatson 330150032Srwatson test_lseek(); 331159032Smaxim test_truncate(); 332150094Srwatson test_ioctl(); 333232184Sjilles test_chmodchown(); 334150032Srwatson 335150032Srwatson return (0); 336150032Srwatson} 337