13cedbec3SEnji Cooper /*- 23cedbec3SEnji Cooper * Copyright (c) 2005 Robert N. M. Watson 33cedbec3SEnji Cooper * Copyright (c) 2012 Jilles Tjoelker 43cedbec3SEnji Cooper * All rights reserved. 53cedbec3SEnji Cooper * 63cedbec3SEnji Cooper * Redistribution and use in source and binary forms, with or without 73cedbec3SEnji Cooper * modification, are permitted provided that the following conditions 83cedbec3SEnji Cooper * are met: 93cedbec3SEnji Cooper * 1. Redistributions of source code must retain the above copyright 103cedbec3SEnji Cooper * notice, this list of conditions and the following disclaimer. 113cedbec3SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 123cedbec3SEnji Cooper * notice, this list of conditions and the following disclaimer in the 133cedbec3SEnji Cooper * documentation and/or other materials provided with the distribution. 143cedbec3SEnji Cooper * 153cedbec3SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 163cedbec3SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 173cedbec3SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 183cedbec3SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 193cedbec3SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 203cedbec3SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 213cedbec3SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 223cedbec3SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 233cedbec3SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 243cedbec3SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 253cedbec3SEnji Cooper * SUCH DAMAGE. 263cedbec3SEnji Cooper * 273cedbec3SEnji Cooper * $FreeBSD$ 283cedbec3SEnji Cooper */ 293cedbec3SEnji Cooper 303cedbec3SEnji Cooper #include <sys/types.h> 313cedbec3SEnji Cooper #include <sys/event.h> 323cedbec3SEnji Cooper #include <sys/filio.h> 33*dfded447SCraig Rodrigues #include <sys/ioctl.h> 343cedbec3SEnji Cooper #include <sys/stat.h> 353cedbec3SEnji Cooper #include <sys/time.h> 363cedbec3SEnji Cooper 373cedbec3SEnji Cooper #include <err.h> 383cedbec3SEnji Cooper #include <errno.h> 393cedbec3SEnji Cooper #include <fcntl.h> 403cedbec3SEnji Cooper #include <limits.h> 413cedbec3SEnji Cooper #include <stdio.h> 423cedbec3SEnji Cooper #include <stdlib.h> 433cedbec3SEnji Cooper #include <string.h> 443cedbec3SEnji Cooper #include <unistd.h> 453cedbec3SEnji Cooper 463cedbec3SEnji Cooper /* 473cedbec3SEnji Cooper * Regression test for piddling details of fifos. 483cedbec3SEnji Cooper */ 493cedbec3SEnji Cooper 503cedbec3SEnji Cooper /* 513cedbec3SEnji Cooper * All activity occurs within a temporary directory created early in the 523cedbec3SEnji Cooper * test. 533cedbec3SEnji Cooper */ 543cedbec3SEnji Cooper static char temp_dir[PATH_MAX]; 553cedbec3SEnji Cooper 563cedbec3SEnji Cooper static void __unused 573cedbec3SEnji Cooper atexit_temp_dir(void) 583cedbec3SEnji Cooper { 593cedbec3SEnji Cooper 603cedbec3SEnji Cooper rmdir(temp_dir); 613cedbec3SEnji Cooper } 623cedbec3SEnji Cooper 633cedbec3SEnji Cooper static void 643cedbec3SEnji Cooper makefifo(const char *fifoname, const char *testname) 653cedbec3SEnji Cooper { 663cedbec3SEnji Cooper 673cedbec3SEnji Cooper if (mkfifo(fifoname, 0700) < 0) 683cedbec3SEnji Cooper err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname); 693cedbec3SEnji Cooper } 703cedbec3SEnji Cooper 713cedbec3SEnji Cooper static void 723cedbec3SEnji Cooper cleanfifo(const char *fifoname, int fd1, int fd2) 733cedbec3SEnji Cooper { 743cedbec3SEnji Cooper 753cedbec3SEnji Cooper if (fd1 != -1) 763cedbec3SEnji Cooper close(fd1); 773cedbec3SEnji Cooper if (fd2 != -1) 783cedbec3SEnji Cooper close(fd2); 793cedbec3SEnji Cooper (void)unlink(fifoname); 803cedbec3SEnji Cooper } 813cedbec3SEnji Cooper 823cedbec3SEnji Cooper static int 833cedbec3SEnji Cooper openfifo(const char *fifoname, int *reader_fdp, int *writer_fdp) 843cedbec3SEnji Cooper { 853cedbec3SEnji Cooper int error, fd1, fd2; 863cedbec3SEnji Cooper 873cedbec3SEnji Cooper fd1 = open(fifoname, O_RDONLY | O_NONBLOCK); 883cedbec3SEnji Cooper if (fd1 < 0) 893cedbec3SEnji Cooper return (-1); 903cedbec3SEnji Cooper fd2 = open(fifoname, O_WRONLY | O_NONBLOCK); 913cedbec3SEnji Cooper if (fd2 < 0) { 923cedbec3SEnji Cooper error = errno; 933cedbec3SEnji Cooper close(fd1); 943cedbec3SEnji Cooper errno = error; 953cedbec3SEnji Cooper return (-1); 963cedbec3SEnji Cooper } 973cedbec3SEnji Cooper *reader_fdp = fd1; 983cedbec3SEnji Cooper *writer_fdp = fd2; 993cedbec3SEnji Cooper 1003cedbec3SEnji Cooper return (0); 1013cedbec3SEnji Cooper } 1023cedbec3SEnji Cooper 1033cedbec3SEnji Cooper /* 1043cedbec3SEnji Cooper * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result. 1053cedbec3SEnji Cooper */ 1063cedbec3SEnji Cooper static void 1073cedbec3SEnji Cooper test_lseek(void) 1083cedbec3SEnji Cooper { 1093cedbec3SEnji Cooper int reader_fd, writer_fd; 1103cedbec3SEnji Cooper 1113cedbec3SEnji Cooper makefifo("testfifo", __func__); 1123cedbec3SEnji Cooper 1133cedbec3SEnji Cooper if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 1143cedbec3SEnji Cooper warn("%s: openfifo", __func__); 1153cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1163cedbec3SEnji Cooper exit(-1); 1173cedbec3SEnji Cooper } 1183cedbec3SEnji Cooper 1193cedbec3SEnji Cooper if (lseek(reader_fd, 1, SEEK_CUR) >= 0) { 1203cedbec3SEnji Cooper warnx("%s: lseek succeeded instead of returning ESPIPE", 1213cedbec3SEnji Cooper __func__); 1223cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 1233cedbec3SEnji Cooper exit(-1); 1243cedbec3SEnji Cooper } 1253cedbec3SEnji Cooper if (errno != ESPIPE) { 1263cedbec3SEnji Cooper warn("%s: lseek returned instead of ESPIPE", __func__); 1273cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 1283cedbec3SEnji Cooper exit(-1); 1293cedbec3SEnji Cooper } 1303cedbec3SEnji Cooper 1313cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 1323cedbec3SEnji Cooper } 1333cedbec3SEnji Cooper 1343cedbec3SEnji Cooper /* 1353cedbec3SEnji Cooper * truncate(2) on FIFO should silently return success. 1363cedbec3SEnji Cooper */ 1373cedbec3SEnji Cooper static void 1383cedbec3SEnji Cooper test_truncate(void) 1393cedbec3SEnji Cooper { 1403cedbec3SEnji Cooper 1413cedbec3SEnji Cooper makefifo("testfifo", __func__); 1423cedbec3SEnji Cooper 1433cedbec3SEnji Cooper if (truncate("testfifo", 1024) != 0) { 1443cedbec3SEnji Cooper warn("%s: truncate", __func__); 1453cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1463cedbec3SEnji Cooper exit(-1); 1473cedbec3SEnji Cooper } 1483cedbec3SEnji Cooper 1493cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1503cedbec3SEnji Cooper } 1513cedbec3SEnji Cooper 1523cedbec3SEnji Cooper static int 153*dfded447SCraig Rodrigues test_ioctl_setclearflag(int fd, unsigned long flag, const char *testname, 1543cedbec3SEnji Cooper const char *fdname, const char *flagname) 1553cedbec3SEnji Cooper { 1563cedbec3SEnji Cooper int i; 1573cedbec3SEnji Cooper 1583cedbec3SEnji Cooper i = 1; 1593cedbec3SEnji Cooper if (ioctl(fd, flag, &i) < 0) { 1603cedbec3SEnji Cooper warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname, 1613cedbec3SEnji Cooper flagname); 1623cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1633cedbec3SEnji Cooper exit(-1); 1643cedbec3SEnji Cooper } 1653cedbec3SEnji Cooper 1663cedbec3SEnji Cooper i = 0; 1673cedbec3SEnji Cooper if (ioctl(fd, flag, &i) < 0) { 1683cedbec3SEnji Cooper warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname, 1693cedbec3SEnji Cooper flagname); 1703cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1713cedbec3SEnji Cooper exit(-1); 1723cedbec3SEnji Cooper } 1733cedbec3SEnji Cooper 1743cedbec3SEnji Cooper return (0); 1753cedbec3SEnji Cooper } 1763cedbec3SEnji Cooper 1773cedbec3SEnji Cooper /* 1783cedbec3SEnji Cooper * Test that various ioctls can be issued against the file descriptor. We 1793cedbec3SEnji Cooper * don't currently test the semantics of these changes here. 1803cedbec3SEnji Cooper */ 1813cedbec3SEnji Cooper static void 1823cedbec3SEnji Cooper test_ioctl(void) 1833cedbec3SEnji Cooper { 1843cedbec3SEnji Cooper int reader_fd, writer_fd; 1853cedbec3SEnji Cooper 1863cedbec3SEnji Cooper makefifo("testfifo", __func__); 1873cedbec3SEnji Cooper 1883cedbec3SEnji Cooper if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 1893cedbec3SEnji Cooper warn("%s: openfifo", __func__); 1903cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 1913cedbec3SEnji Cooper exit(-1); 1923cedbec3SEnji Cooper } 1933cedbec3SEnji Cooper 1943cedbec3SEnji Cooper /* 1953cedbec3SEnji Cooper * Set and remove the non-blocking I/O flag. 1963cedbec3SEnji Cooper */ 1973cedbec3SEnji Cooper if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__, 1983cedbec3SEnji Cooper "reader_fd", "FIONBIO") < 0) { 1993cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2003cedbec3SEnji Cooper exit(-1); 2013cedbec3SEnji Cooper } 2023cedbec3SEnji Cooper 2033cedbec3SEnji Cooper if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__, 2043cedbec3SEnji Cooper "writer_fd", "FIONBIO") < 0) { 2053cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2063cedbec3SEnji Cooper exit(-1); 2073cedbec3SEnji Cooper } 2083cedbec3SEnji Cooper 2093cedbec3SEnji Cooper /* 2103cedbec3SEnji Cooper * Set and remove the async I/O flag. 2113cedbec3SEnji Cooper */ 2123cedbec3SEnji Cooper if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__, 2133cedbec3SEnji Cooper "reader_fd", "FIOASYNC") < 0) { 2143cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2153cedbec3SEnji Cooper exit(-1); 2163cedbec3SEnji Cooper } 2173cedbec3SEnji Cooper 2183cedbec3SEnji Cooper if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__, 2193cedbec3SEnji Cooper "writer_fd", "FIONASYNC") < 0) { 2203cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2213cedbec3SEnji Cooper exit(-1); 2223cedbec3SEnji Cooper } 2233cedbec3SEnji Cooper 2243cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2253cedbec3SEnji Cooper } 2263cedbec3SEnji Cooper 2273cedbec3SEnji Cooper /* 2283cedbec3SEnji Cooper * fchmod(2)/fchown(2) on FIFO should work. 2293cedbec3SEnji Cooper */ 2303cedbec3SEnji Cooper static void 2313cedbec3SEnji Cooper test_chmodchown(void) 2323cedbec3SEnji Cooper { 2333cedbec3SEnji Cooper struct stat sb; 2343cedbec3SEnji Cooper int reader_fd, writer_fd; 2353cedbec3SEnji Cooper uid_t u; 2363cedbec3SEnji Cooper gid_t g; 2373cedbec3SEnji Cooper 2383cedbec3SEnji Cooper makefifo("testfifo", __func__); 2393cedbec3SEnji Cooper 2403cedbec3SEnji Cooper if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) { 2413cedbec3SEnji Cooper warn("%s: openfifo", __func__); 2423cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 2433cedbec3SEnji Cooper exit(-1); 2443cedbec3SEnji Cooper } 2453cedbec3SEnji Cooper 2463cedbec3SEnji Cooper if (fchmod(reader_fd, 0666) != 0) { 2473cedbec3SEnji Cooper warn("%s: fchmod", __func__); 2483cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2493cedbec3SEnji Cooper exit(-1); 2503cedbec3SEnji Cooper } 2513cedbec3SEnji Cooper 2523cedbec3SEnji Cooper if (stat("testfifo", &sb) != 0) { 2533cedbec3SEnji Cooper warn("%s: stat", __func__); 2543cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2553cedbec3SEnji Cooper exit(-1); 2563cedbec3SEnji Cooper } 2573cedbec3SEnji Cooper 2583cedbec3SEnji Cooper if ((sb.st_mode & 0777) != 0666) { 2593cedbec3SEnji Cooper warnx("%s: stat chmod result", __func__); 2603cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2613cedbec3SEnji Cooper exit(-1); 2623cedbec3SEnji Cooper } 2633cedbec3SEnji Cooper 2643cedbec3SEnji Cooper if (fstat(writer_fd, &sb) != 0) { 2653cedbec3SEnji Cooper warn("%s: fstat", __func__); 2663cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2673cedbec3SEnji Cooper exit(-1); 2683cedbec3SEnji Cooper } 2693cedbec3SEnji Cooper 2703cedbec3SEnji Cooper if ((sb.st_mode & 0777) != 0666) { 2713cedbec3SEnji Cooper warnx("%s: fstat chmod result", __func__); 2723cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2733cedbec3SEnji Cooper exit(-1); 2743cedbec3SEnji Cooper } 2753cedbec3SEnji Cooper 2763cedbec3SEnji Cooper if (fchown(reader_fd, -1, -1) != 0) { 2773cedbec3SEnji Cooper warn("%s: fchown 1", __func__); 2783cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2793cedbec3SEnji Cooper exit(-1); 2803cedbec3SEnji Cooper } 2813cedbec3SEnji Cooper 2823cedbec3SEnji Cooper u = geteuid(); 2833cedbec3SEnji Cooper if (u == 0) 2843cedbec3SEnji Cooper u = 1; 2853cedbec3SEnji Cooper g = getegid(); 2863cedbec3SEnji Cooper if (fchown(reader_fd, u, g) != 0) { 2873cedbec3SEnji Cooper warn("%s: fchown 2", __func__); 2883cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2893cedbec3SEnji Cooper exit(-1); 2903cedbec3SEnji Cooper } 2913cedbec3SEnji Cooper if (stat("testfifo", &sb) != 0) { 2923cedbec3SEnji Cooper warn("%s: stat", __func__); 2933cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 2943cedbec3SEnji Cooper exit(-1); 2953cedbec3SEnji Cooper } 2963cedbec3SEnji Cooper 2973cedbec3SEnji Cooper if (sb.st_uid != u || sb.st_gid != g) { 2983cedbec3SEnji Cooper warnx("%s: stat chown result", __func__); 2993cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 3003cedbec3SEnji Cooper exit(-1); 3013cedbec3SEnji Cooper } 3023cedbec3SEnji Cooper 3033cedbec3SEnji Cooper if (fstat(writer_fd, &sb) != 0) { 3043cedbec3SEnji Cooper warn("%s: fstat", __func__); 3053cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 3063cedbec3SEnji Cooper exit(-1); 3073cedbec3SEnji Cooper } 3083cedbec3SEnji Cooper 3093cedbec3SEnji Cooper if (sb.st_uid != u || sb.st_gid != g) { 3103cedbec3SEnji Cooper warnx("%s: fstat chown result", __func__); 3113cedbec3SEnji Cooper cleanfifo("testfifo", reader_fd, writer_fd); 3123cedbec3SEnji Cooper exit(-1); 3133cedbec3SEnji Cooper } 3143cedbec3SEnji Cooper 3153cedbec3SEnji Cooper cleanfifo("testfifo", -1, -1); 3163cedbec3SEnji Cooper } 3173cedbec3SEnji Cooper 3183cedbec3SEnji Cooper int 3193cedbec3SEnji Cooper main(void) 3203cedbec3SEnji Cooper { 3213cedbec3SEnji Cooper 3223cedbec3SEnji Cooper strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX"); 3233cedbec3SEnji Cooper if (mkdtemp(temp_dir) == NULL) 3243cedbec3SEnji Cooper err(-1, "mkdtemp"); 3253cedbec3SEnji Cooper atexit(atexit_temp_dir); 3263cedbec3SEnji Cooper 3273cedbec3SEnji Cooper if (chdir(temp_dir) < 0) 3283cedbec3SEnji Cooper err(-1, "chdir %s", temp_dir); 3293cedbec3SEnji Cooper 3303cedbec3SEnji Cooper test_lseek(); 3313cedbec3SEnji Cooper test_truncate(); 3323cedbec3SEnji Cooper test_ioctl(); 3333cedbec3SEnji Cooper test_chmodchown(); 3343cedbec3SEnji Cooper 3353cedbec3SEnji Cooper return (0); 3363cedbec3SEnji Cooper } 337