xref: /freebsd/tests/sys/fifo/fifo_misc.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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 
283cedbec3SEnji Cooper #include <sys/types.h>
293cedbec3SEnji Cooper #include <sys/event.h>
303cedbec3SEnji Cooper #include <sys/filio.h>
31*dfded447SCraig Rodrigues #include <sys/ioctl.h>
323cedbec3SEnji Cooper #include <sys/stat.h>
333cedbec3SEnji Cooper #include <sys/time.h>
343cedbec3SEnji Cooper 
353cedbec3SEnji Cooper #include <err.h>
363cedbec3SEnji Cooper #include <errno.h>
373cedbec3SEnji Cooper #include <fcntl.h>
383cedbec3SEnji Cooper #include <limits.h>
393cedbec3SEnji Cooper #include <stdio.h>
403cedbec3SEnji Cooper #include <stdlib.h>
413cedbec3SEnji Cooper #include <string.h>
423cedbec3SEnji Cooper #include <unistd.h>
433cedbec3SEnji Cooper 
443cedbec3SEnji Cooper /*
453cedbec3SEnji Cooper  * Regression test for piddling details of fifos.
463cedbec3SEnji Cooper  */
473cedbec3SEnji Cooper 
483cedbec3SEnji Cooper /*
493cedbec3SEnji Cooper  * All activity occurs within a temporary directory created early in the
503cedbec3SEnji Cooper  * test.
513cedbec3SEnji Cooper  */
523cedbec3SEnji Cooper static char	temp_dir[PATH_MAX];
533cedbec3SEnji Cooper 
543cedbec3SEnji Cooper static void __unused
atexit_temp_dir(void)553cedbec3SEnji Cooper atexit_temp_dir(void)
563cedbec3SEnji Cooper {
573cedbec3SEnji Cooper 
583cedbec3SEnji Cooper 	rmdir(temp_dir);
593cedbec3SEnji Cooper }
603cedbec3SEnji Cooper 
613cedbec3SEnji Cooper static void
makefifo(const char * fifoname,const char * testname)623cedbec3SEnji Cooper makefifo(const char *fifoname, const char *testname)
633cedbec3SEnji Cooper {
643cedbec3SEnji Cooper 
653cedbec3SEnji Cooper 	if (mkfifo(fifoname, 0700) < 0)
663cedbec3SEnji Cooper 		err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname);
673cedbec3SEnji Cooper }
683cedbec3SEnji Cooper 
693cedbec3SEnji Cooper static void
cleanfifo(const char * fifoname,int fd1,int fd2)703cedbec3SEnji Cooper cleanfifo(const char *fifoname, int fd1, int fd2)
713cedbec3SEnji Cooper {
723cedbec3SEnji Cooper 
733cedbec3SEnji Cooper 	if (fd1 != -1)
743cedbec3SEnji Cooper 		close(fd1);
753cedbec3SEnji Cooper 	if (fd2 != -1)
763cedbec3SEnji Cooper 		close(fd2);
773cedbec3SEnji Cooper 	(void)unlink(fifoname);
783cedbec3SEnji Cooper }
793cedbec3SEnji Cooper 
803cedbec3SEnji Cooper static int
openfifo(const char * fifoname,int * reader_fdp,int * writer_fdp)813cedbec3SEnji Cooper openfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
823cedbec3SEnji Cooper {
833cedbec3SEnji Cooper 	int error, fd1, fd2;
843cedbec3SEnji Cooper 
853cedbec3SEnji Cooper 	fd1 = open(fifoname, O_RDONLY | O_NONBLOCK);
863cedbec3SEnji Cooper 	if (fd1 < 0)
873cedbec3SEnji Cooper 		return (-1);
883cedbec3SEnji Cooper 	fd2 = open(fifoname, O_WRONLY | O_NONBLOCK);
893cedbec3SEnji Cooper 	if (fd2 < 0) {
903cedbec3SEnji Cooper 		error = errno;
913cedbec3SEnji Cooper 		close(fd1);
923cedbec3SEnji Cooper 		errno = error;
933cedbec3SEnji Cooper 		return (-1);
943cedbec3SEnji Cooper 	}
953cedbec3SEnji Cooper 	*reader_fdp = fd1;
963cedbec3SEnji Cooper 	*writer_fdp = fd2;
973cedbec3SEnji Cooper 
983cedbec3SEnji Cooper 	return (0);
993cedbec3SEnji Cooper }
1003cedbec3SEnji Cooper 
1013cedbec3SEnji Cooper /*
1023cedbec3SEnji Cooper  * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result.
1033cedbec3SEnji Cooper  */
1043cedbec3SEnji Cooper static void
test_lseek(void)1053cedbec3SEnji Cooper test_lseek(void)
1063cedbec3SEnji Cooper {
1073cedbec3SEnji Cooper 	int reader_fd, writer_fd;
1083cedbec3SEnji Cooper 
1093cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
1103cedbec3SEnji Cooper 
1113cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
1123cedbec3SEnji Cooper 		warn("%s: openfifo", __func__);
1133cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
1143cedbec3SEnji Cooper 		exit(-1);
1153cedbec3SEnji Cooper 	}
1163cedbec3SEnji Cooper 
1173cedbec3SEnji Cooper 	if (lseek(reader_fd, 1, SEEK_CUR) >= 0) {
1183cedbec3SEnji Cooper 		warnx("%s: lseek succeeded instead of returning ESPIPE",
1193cedbec3SEnji Cooper 		    __func__);
1203cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
1213cedbec3SEnji Cooper 		exit(-1);
1223cedbec3SEnji Cooper 	}
1233cedbec3SEnji Cooper 	if (errno != ESPIPE) {
1243cedbec3SEnji Cooper 		warn("%s: lseek returned instead of ESPIPE", __func__);
1253cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
1263cedbec3SEnji Cooper 		exit(-1);
1273cedbec3SEnji Cooper 	}
1283cedbec3SEnji Cooper 
1293cedbec3SEnji Cooper 	cleanfifo("testfifo", reader_fd, writer_fd);
1303cedbec3SEnji Cooper }
1313cedbec3SEnji Cooper 
1323cedbec3SEnji Cooper /*
1333cedbec3SEnji Cooper  * truncate(2) on FIFO should silently return success.
1343cedbec3SEnji Cooper  */
1353cedbec3SEnji Cooper static void
test_truncate(void)1363cedbec3SEnji Cooper test_truncate(void)
1373cedbec3SEnji Cooper {
1383cedbec3SEnji Cooper 
1393cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
1403cedbec3SEnji Cooper 
1413cedbec3SEnji Cooper 	if (truncate("testfifo", 1024) != 0) {
1423cedbec3SEnji Cooper 		warn("%s: truncate", __func__);
1433cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
1443cedbec3SEnji Cooper 		exit(-1);
1453cedbec3SEnji Cooper 	}
1463cedbec3SEnji Cooper 
1473cedbec3SEnji Cooper 	cleanfifo("testfifo", -1, -1);
1483cedbec3SEnji Cooper }
1493cedbec3SEnji Cooper 
1503cedbec3SEnji Cooper static int
test_ioctl_setclearflag(int fd,unsigned long flag,const char * testname,const char * fdname,const char * flagname)151*dfded447SCraig Rodrigues test_ioctl_setclearflag(int fd, unsigned long flag, const char *testname,
1523cedbec3SEnji Cooper     const char *fdname, const char *flagname)
1533cedbec3SEnji Cooper {
1543cedbec3SEnji Cooper 	int i;
1553cedbec3SEnji Cooper 
1563cedbec3SEnji Cooper 	i = 1;
1573cedbec3SEnji Cooper 	if (ioctl(fd, flag, &i) < 0) {
1583cedbec3SEnji Cooper 		warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname,
1593cedbec3SEnji Cooper 		    flagname);
1603cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
1613cedbec3SEnji Cooper 		exit(-1);
1623cedbec3SEnji Cooper 	}
1633cedbec3SEnji Cooper 
1643cedbec3SEnji Cooper 	i = 0;
1653cedbec3SEnji Cooper 	if (ioctl(fd, flag, &i) < 0) {
1663cedbec3SEnji Cooper 		warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname,
1673cedbec3SEnji Cooper 		    flagname);
1683cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
1693cedbec3SEnji Cooper 		exit(-1);
1703cedbec3SEnji Cooper 	}
1713cedbec3SEnji Cooper 
1723cedbec3SEnji Cooper 	return (0);
1733cedbec3SEnji Cooper }
1743cedbec3SEnji Cooper 
1753cedbec3SEnji Cooper /*
1763cedbec3SEnji Cooper  * Test that various ioctls can be issued against the file descriptor.  We
1773cedbec3SEnji Cooper  * don't currently test the semantics of these changes here.
1783cedbec3SEnji Cooper  */
1793cedbec3SEnji Cooper static void
test_ioctl(void)1803cedbec3SEnji Cooper test_ioctl(void)
1813cedbec3SEnji Cooper {
1823cedbec3SEnji Cooper 	int reader_fd, writer_fd;
1833cedbec3SEnji Cooper 
1843cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
1853cedbec3SEnji Cooper 
1863cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
1873cedbec3SEnji Cooper 		warn("%s: openfifo", __func__);
1883cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
1893cedbec3SEnji Cooper 		exit(-1);
1903cedbec3SEnji Cooper 	}
1913cedbec3SEnji Cooper 
1923cedbec3SEnji Cooper 	/*
1933cedbec3SEnji Cooper 	 * Set and remove the non-blocking I/O flag.
1943cedbec3SEnji Cooper 	 */
1953cedbec3SEnji Cooper 	if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__,
1963cedbec3SEnji Cooper 	    "reader_fd", "FIONBIO") < 0) {
1973cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
1983cedbec3SEnji Cooper 		exit(-1);
1993cedbec3SEnji Cooper 	}
2003cedbec3SEnji Cooper 
2013cedbec3SEnji Cooper 	if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__,
2023cedbec3SEnji Cooper 	    "writer_fd", "FIONBIO") < 0) {
2033cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2043cedbec3SEnji Cooper 		exit(-1);
2053cedbec3SEnji Cooper 	}
2063cedbec3SEnji Cooper 
2073cedbec3SEnji Cooper 	/*
2083cedbec3SEnji Cooper 	 * Set and remove the async I/O flag.
2093cedbec3SEnji Cooper 	 */
2103cedbec3SEnji Cooper 	if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__,
2113cedbec3SEnji Cooper 	    "reader_fd", "FIOASYNC") < 0) {
2123cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2133cedbec3SEnji Cooper 		exit(-1);
2143cedbec3SEnji Cooper 	}
2153cedbec3SEnji Cooper 
2163cedbec3SEnji Cooper 	if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__,
2173cedbec3SEnji Cooper 	    "writer_fd", "FIONASYNC") < 0) {
2183cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2193cedbec3SEnji Cooper 		exit(-1);
2203cedbec3SEnji Cooper 	}
2213cedbec3SEnji Cooper 
2223cedbec3SEnji Cooper 	cleanfifo("testfifo", reader_fd, writer_fd);
2233cedbec3SEnji Cooper }
2243cedbec3SEnji Cooper 
2253cedbec3SEnji Cooper /*
2263cedbec3SEnji Cooper  * fchmod(2)/fchown(2) on FIFO should work.
2273cedbec3SEnji Cooper  */
2283cedbec3SEnji Cooper static void
test_chmodchown(void)2293cedbec3SEnji Cooper test_chmodchown(void)
2303cedbec3SEnji Cooper {
2313cedbec3SEnji Cooper 	struct stat sb;
2323cedbec3SEnji Cooper 	int reader_fd, writer_fd;
2333cedbec3SEnji Cooper 	uid_t u;
2343cedbec3SEnji Cooper 	gid_t g;
2353cedbec3SEnji Cooper 
2363cedbec3SEnji Cooper 	makefifo("testfifo", __func__);
2373cedbec3SEnji Cooper 
2383cedbec3SEnji Cooper 	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
2393cedbec3SEnji Cooper 		warn("%s: openfifo", __func__);
2403cedbec3SEnji Cooper 		cleanfifo("testfifo", -1, -1);
2413cedbec3SEnji Cooper 		exit(-1);
2423cedbec3SEnji Cooper 	}
2433cedbec3SEnji Cooper 
2443cedbec3SEnji Cooper 	if (fchmod(reader_fd, 0666) != 0) {
2453cedbec3SEnji Cooper 		warn("%s: fchmod", __func__);
2463cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2473cedbec3SEnji Cooper 		exit(-1);
2483cedbec3SEnji Cooper 	}
2493cedbec3SEnji Cooper 
2503cedbec3SEnji Cooper 	if (stat("testfifo", &sb) != 0) {
2513cedbec3SEnji Cooper 		warn("%s: stat", __func__);
2523cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2533cedbec3SEnji Cooper 		exit(-1);
2543cedbec3SEnji Cooper 	}
2553cedbec3SEnji Cooper 
2563cedbec3SEnji Cooper 	if ((sb.st_mode & 0777) != 0666) {
2573cedbec3SEnji Cooper 		warnx("%s: stat chmod result", __func__);
2583cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2593cedbec3SEnji Cooper 		exit(-1);
2603cedbec3SEnji Cooper 	}
2613cedbec3SEnji Cooper 
2623cedbec3SEnji Cooper 	if (fstat(writer_fd, &sb) != 0) {
2633cedbec3SEnji Cooper 		warn("%s: fstat", __func__);
2643cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2653cedbec3SEnji Cooper 		exit(-1);
2663cedbec3SEnji Cooper 	}
2673cedbec3SEnji Cooper 
2683cedbec3SEnji Cooper 	if ((sb.st_mode & 0777) != 0666) {
2693cedbec3SEnji Cooper 		warnx("%s: fstat chmod result", __func__);
2703cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2713cedbec3SEnji Cooper 		exit(-1);
2723cedbec3SEnji Cooper 	}
2733cedbec3SEnji Cooper 
2743cedbec3SEnji Cooper 	if (fchown(reader_fd, -1, -1) != 0) {
2753cedbec3SEnji Cooper 		warn("%s: fchown 1", __func__);
2763cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2773cedbec3SEnji Cooper 		exit(-1);
2783cedbec3SEnji Cooper 	}
2793cedbec3SEnji Cooper 
2803cedbec3SEnji Cooper 	u = geteuid();
2813cedbec3SEnji Cooper 	if (u == 0)
2823cedbec3SEnji Cooper 		u = 1;
2833cedbec3SEnji Cooper 	g = getegid();
2843cedbec3SEnji Cooper 	if (fchown(reader_fd, u, g) != 0) {
2853cedbec3SEnji Cooper 		warn("%s: fchown 2", __func__);
2863cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2873cedbec3SEnji Cooper 		exit(-1);
2883cedbec3SEnji Cooper 	}
2893cedbec3SEnji Cooper 	if (stat("testfifo", &sb) != 0) {
2903cedbec3SEnji Cooper 		warn("%s: stat", __func__);
2913cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2923cedbec3SEnji Cooper 		exit(-1);
2933cedbec3SEnji Cooper 	}
2943cedbec3SEnji Cooper 
2953cedbec3SEnji Cooper 	if (sb.st_uid != u || sb.st_gid != g) {
2963cedbec3SEnji Cooper 		warnx("%s: stat chown result", __func__);
2973cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
2983cedbec3SEnji Cooper 		exit(-1);
2993cedbec3SEnji Cooper 	}
3003cedbec3SEnji Cooper 
3013cedbec3SEnji Cooper 	if (fstat(writer_fd, &sb) != 0) {
3023cedbec3SEnji Cooper 		warn("%s: fstat", __func__);
3033cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
3043cedbec3SEnji Cooper 		exit(-1);
3053cedbec3SEnji Cooper 	}
3063cedbec3SEnji Cooper 
3073cedbec3SEnji Cooper 	if (sb.st_uid != u || sb.st_gid != g) {
3083cedbec3SEnji Cooper 		warnx("%s: fstat chown result", __func__);
3093cedbec3SEnji Cooper 		cleanfifo("testfifo", reader_fd, writer_fd);
3103cedbec3SEnji Cooper 		exit(-1);
3113cedbec3SEnji Cooper 	}
3123cedbec3SEnji Cooper 
3133cedbec3SEnji Cooper 	cleanfifo("testfifo", -1, -1);
3143cedbec3SEnji Cooper }
3153cedbec3SEnji Cooper 
3163cedbec3SEnji Cooper int
main(void)3173cedbec3SEnji Cooper main(void)
3183cedbec3SEnji Cooper {
3193cedbec3SEnji Cooper 
3203cedbec3SEnji Cooper 	strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX");
3213cedbec3SEnji Cooper 	if (mkdtemp(temp_dir) == NULL)
3223cedbec3SEnji Cooper 		err(-1, "mkdtemp");
3233cedbec3SEnji Cooper 	atexit(atexit_temp_dir);
3243cedbec3SEnji Cooper 
3253cedbec3SEnji Cooper 	if (chdir(temp_dir) < 0)
3263cedbec3SEnji Cooper 		err(-1, "chdir %s", temp_dir);
3273cedbec3SEnji Cooper 
3283cedbec3SEnji Cooper 	test_lseek();
3293cedbec3SEnji Cooper 	test_truncate();
3303cedbec3SEnji Cooper 	test_ioctl();
3313cedbec3SEnji Cooper 	test_chmodchown();
3323cedbec3SEnji Cooper 
3333cedbec3SEnji Cooper 	return (0);
3343cedbec3SEnji Cooper }
335