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