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