xref: /freebsd/tests/sys/fifo/fifo_misc.c (revision dfded4478da01f9c5d139b4453537ad29a7dd911)
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