xref: /freebsd/tests/sys/fifo/fifo_open.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1*3cedbec3SEnji Cooper /*-
2*3cedbec3SEnji Cooper  * Copyright (c) 2005 Robert N. M. Watson
3*3cedbec3SEnji Cooper  * All rights reserved.
4*3cedbec3SEnji Cooper  *
5*3cedbec3SEnji Cooper  * Redistribution and use in source and binary forms, with or without
6*3cedbec3SEnji Cooper  * modification, are permitted provided that the following conditions
7*3cedbec3SEnji Cooper  * are met:
8*3cedbec3SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
9*3cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
10*3cedbec3SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
11*3cedbec3SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
12*3cedbec3SEnji Cooper  *    documentation and/or other materials provided with the distribution.
13*3cedbec3SEnji Cooper  *
14*3cedbec3SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*3cedbec3SEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*3cedbec3SEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*3cedbec3SEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*3cedbec3SEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*3cedbec3SEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*3cedbec3SEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*3cedbec3SEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*3cedbec3SEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*3cedbec3SEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*3cedbec3SEnji Cooper  * SUCH DAMAGE.
25*3cedbec3SEnji Cooper  */
26*3cedbec3SEnji Cooper 
27*3cedbec3SEnji Cooper #include <sys/types.h>
28*3cedbec3SEnji Cooper #include <sys/stat.h>
29*3cedbec3SEnji Cooper #include <sys/wait.h>
30*3cedbec3SEnji Cooper 
31*3cedbec3SEnji Cooper #include <err.h>
32*3cedbec3SEnji Cooper #include <errno.h>
33*3cedbec3SEnji Cooper #include <fcntl.h>
34*3cedbec3SEnji Cooper #include <limits.h>
35*3cedbec3SEnji Cooper #include <signal.h>
36*3cedbec3SEnji Cooper #include <stdio.h>
37*3cedbec3SEnji Cooper #include <stdlib.h>
38*3cedbec3SEnji Cooper #include <string.h>
39*3cedbec3SEnji Cooper #include <unistd.h>
40*3cedbec3SEnji Cooper 
41*3cedbec3SEnji Cooper /*
42*3cedbec3SEnji Cooper  * Regression test to exercise various POSIX-defined parts of fifo behavior
43*3cedbec3SEnji Cooper  * described for open(2):
44*3cedbec3SEnji Cooper  *
45*3cedbec3SEnji Cooper  * O_NONBLOCK
46*3cedbec3SEnji Cooper  * When opening a FIFO with O_RDONLY or O_WRONLY set:
47*3cedbec3SEnji Cooper  *
48*3cedbec3SEnji Cooper  * - If O_NONBLOCK is set, an open() for reading-only shall return without
49*3cedbec3SEnji Cooper  *   delay. An open() for writing-only shall return an error if no process
50*3cedbec3SEnji Cooper  *   currently has the file open for reading.
51*3cedbec3SEnji Cooper  *
52*3cedbec3SEnji Cooper  * - If O_NONBLOCK is clear, an open() for reading-only shall block the
53*3cedbec3SEnji Cooper  *   calling thread until a thread opens the file for writing. An open()
54*3cedbec3SEnji Cooper  *   for writing-only shall block the calling thread until a thread opens
55*3cedbec3SEnji Cooper  *   the file for reading.
56*3cedbec3SEnji Cooper  *
57*3cedbec3SEnji Cooper  * When opening a block special or character special file that supports
58*3cedbec3SEnji Cooper  * non-blocking opens:
59*3cedbec3SEnji Cooper  *
60*3cedbec3SEnji Cooper  * - If O_NONBLOCK is set, the open() function shall return without blocking
61*3cedbec3SEnji Cooper  *   for the device to be ready or available. Subsequent behavior of the
62*3cedbec3SEnji Cooper  *   device is device-specific.
63*3cedbec3SEnji Cooper  *
64*3cedbec3SEnji Cooper  * - If O_NONBLOCK is clear, the open() function shall block the calling
65*3cedbec3SEnji Cooper  *   thread until the device is ready or available before returning.
66*3cedbec3SEnji Cooper  *
67*3cedbec3SEnji Cooper  * Special errors:
68*3cedbec3SEnji Cooper  *
69*3cedbec3SEnji Cooper  * [ENXIO]
70*3cedbec3SEnji Cooper  * O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is set, and no
71*3cedbec3SEnji Cooper  * process has the file open for reading.
72*3cedbec3SEnji Cooper  */
73*3cedbec3SEnji Cooper 
74*3cedbec3SEnji Cooper /*
75*3cedbec3SEnji Cooper  * In order to test blocking/non-blocking behavior, test processes must
76*3cedbec3SEnji Cooper  * potentially block themselves until released.  As bugs in blocking result
77*3cedbec3SEnji Cooper  * in processes that won't un-block, we must sacrifice a process to the task,
78*3cedbec3SEnji Cooper  * watching and potentially killing it after a time-out.  The main test
79*3cedbec3SEnji Cooper  * process is never used to open or act directly on a fifo (other than to
80*3cedbec3SEnji Cooper  * create or unlink it) in order to avoid the main test process being
81*3cedbec3SEnji Cooper  * blocked.
82*3cedbec3SEnji Cooper  */
83*3cedbec3SEnji Cooper 
84*3cedbec3SEnji Cooper /*
85*3cedbec3SEnji Cooper  * All activity occurs within a temporary directory created early in the
86*3cedbec3SEnji Cooper  * test.
87*3cedbec3SEnji Cooper  */
88*3cedbec3SEnji Cooper static char	temp_dir[PATH_MAX];
89*3cedbec3SEnji Cooper 
90*3cedbec3SEnji Cooper static void __unused
atexit_temp_dir(void)91*3cedbec3SEnji Cooper atexit_temp_dir(void)
92*3cedbec3SEnji Cooper {
93*3cedbec3SEnji Cooper 
94*3cedbec3SEnji Cooper 	rmdir(temp_dir);
95*3cedbec3SEnji Cooper }
96*3cedbec3SEnji Cooper 
97*3cedbec3SEnji Cooper /*
98*3cedbec3SEnji Cooper  * Run a function in a particular test process.
99*3cedbec3SEnji Cooper  */
100*3cedbec3SEnji Cooper static int
run_in_process(int (* func)(void),pid_t * pidp,const char * errstr)101*3cedbec3SEnji Cooper run_in_process(int (*func)(void), pid_t *pidp, const char *errstr)
102*3cedbec3SEnji Cooper {
103*3cedbec3SEnji Cooper 	pid_t pid;
104*3cedbec3SEnji Cooper 
105*3cedbec3SEnji Cooper 	pid = fork();
106*3cedbec3SEnji Cooper 	if (pid < 0) {
107*3cedbec3SEnji Cooper 		warn("%s: run_in_process: fork", errstr);
108*3cedbec3SEnji Cooper 		return (-1);
109*3cedbec3SEnji Cooper 	}
110*3cedbec3SEnji Cooper 
111*3cedbec3SEnji Cooper 	if (pid == 0)
112*3cedbec3SEnji Cooper 		exit(func());
113*3cedbec3SEnji Cooper 
114*3cedbec3SEnji Cooper 	if (pidp != NULL)
115*3cedbec3SEnji Cooper 		*pidp = pid;
116*3cedbec3SEnji Cooper 
117*3cedbec3SEnji Cooper 	return (0);
118*3cedbec3SEnji Cooper }
119*3cedbec3SEnji Cooper 
120*3cedbec3SEnji Cooper /*
121*3cedbec3SEnji Cooper  * Wait for a process on a timeout, and if the timeout expires, kill the
122*3cedbec3SEnji Cooper  * process.  Test each second rather than waiting the full timeout at once to
123*3cedbec3SEnji Cooper  * minimize the amount of time spent hanging around unnecessarily.
124*3cedbec3SEnji Cooper  */
125*3cedbec3SEnji Cooper static int
wait_and_timeout(pid_t pid,int timeout,int * status,const char * errstr)126*3cedbec3SEnji Cooper wait_and_timeout(pid_t pid, int timeout, int *status, const char *errstr)
127*3cedbec3SEnji Cooper {
128*3cedbec3SEnji Cooper 	pid_t wpid;
129*3cedbec3SEnji Cooper 	int i;
130*3cedbec3SEnji Cooper 
131*3cedbec3SEnji Cooper 	/*
132*3cedbec3SEnji Cooper 	 * Count up to the timeout, but do a non-hanging waitpid() after each
133*3cedbec3SEnji Cooper 	 * second so we can avoid waiting a lot of extra time.
134*3cedbec3SEnji Cooper 	 */
135*3cedbec3SEnji Cooper 	for (i = 0; i < timeout; i++) {
136*3cedbec3SEnji Cooper 		wpid = waitpid(pid, status, WNOHANG);
137*3cedbec3SEnji Cooper 		if (wpid < 0) {
138*3cedbec3SEnji Cooper 			warn("%s: wait_and_timeout: waitpid %d", errstr, pid);
139*3cedbec3SEnji Cooper 			return (-1);
140*3cedbec3SEnji Cooper 		}
141*3cedbec3SEnji Cooper 
142*3cedbec3SEnji Cooper 		if (wpid == pid)
143*3cedbec3SEnji Cooper 			return (0);
144*3cedbec3SEnji Cooper 
145*3cedbec3SEnji Cooper 		sleep(1);
146*3cedbec3SEnji Cooper 	}
147*3cedbec3SEnji Cooper 
148*3cedbec3SEnji Cooper 	wpid = waitpid(pid, status, WNOHANG);
149*3cedbec3SEnji Cooper 	if (wpid < 0) {
150*3cedbec3SEnji Cooper 		warn("%s: wait_and_timeout: waitpid %d", errstr, pid);
151*3cedbec3SEnji Cooper 		return (-1);
152*3cedbec3SEnji Cooper 	}
153*3cedbec3SEnji Cooper 
154*3cedbec3SEnji Cooper 	if (wpid == pid)
155*3cedbec3SEnji Cooper 		return (0);
156*3cedbec3SEnji Cooper 
157*3cedbec3SEnji Cooper 	if (kill(pid, SIGTERM) < 0) {
158*3cedbec3SEnji Cooper 		warn("%s: wait_and_timeout: kill %d", errstr, pid);
159*3cedbec3SEnji Cooper 		return (-1);
160*3cedbec3SEnji Cooper 	}
161*3cedbec3SEnji Cooper 
162*3cedbec3SEnji Cooper 	wpid = waitpid(pid, status, 0);
163*3cedbec3SEnji Cooper 	if (wpid < 0) {
164*3cedbec3SEnji Cooper 		warn("%s: wait_and_timeout: waitpid %d", errstr, pid);
165*3cedbec3SEnji Cooper 		return (-1);
166*3cedbec3SEnji Cooper 	}
167*3cedbec3SEnji Cooper 
168*3cedbec3SEnji Cooper 	if (wpid != pid) {
169*3cedbec3SEnji Cooper 		warn("%s: waitpid: returned %d not %d", errstr, wpid, pid);
170*3cedbec3SEnji Cooper 		return (-1);
171*3cedbec3SEnji Cooper 	}
172*3cedbec3SEnji Cooper 
173*3cedbec3SEnji Cooper 	warnx("%s: process blocked", errstr);
174*3cedbec3SEnji Cooper 	return (-1);
175*3cedbec3SEnji Cooper }
176*3cedbec3SEnji Cooper 
177*3cedbec3SEnji Cooper static int
non_blocking_open_reader(void)178*3cedbec3SEnji Cooper non_blocking_open_reader(void)
179*3cedbec3SEnji Cooper {
180*3cedbec3SEnji Cooper 	int fd;
181*3cedbec3SEnji Cooper 
182*3cedbec3SEnji Cooper 	fd = open("testfifo", O_RDONLY | O_NONBLOCK);
183*3cedbec3SEnji Cooper 	if (fd < 0)
184*3cedbec3SEnji Cooper 		return (errno);
185*3cedbec3SEnji Cooper 	close(fd);
186*3cedbec3SEnji Cooper 
187*3cedbec3SEnji Cooper 	return (0);
188*3cedbec3SEnji Cooper }
189*3cedbec3SEnji Cooper 
190*3cedbec3SEnji Cooper static int
non_blocking_open_writer(void)191*3cedbec3SEnji Cooper non_blocking_open_writer(void)
192*3cedbec3SEnji Cooper {
193*3cedbec3SEnji Cooper 	int fd;
194*3cedbec3SEnji Cooper 
195*3cedbec3SEnji Cooper 	fd = open("testfifo", O_WRONLY | O_NONBLOCK);
196*3cedbec3SEnji Cooper 	if (fd < 0)
197*3cedbec3SEnji Cooper 		return (errno);
198*3cedbec3SEnji Cooper 	close(fd);
199*3cedbec3SEnji Cooper 
200*3cedbec3SEnji Cooper 	return (0);
201*3cedbec3SEnji Cooper }
202*3cedbec3SEnji Cooper 
203*3cedbec3SEnji Cooper static int
blocking_open_reader(void)204*3cedbec3SEnji Cooper blocking_open_reader(void)
205*3cedbec3SEnji Cooper {
206*3cedbec3SEnji Cooper 	int fd;
207*3cedbec3SEnji Cooper 
208*3cedbec3SEnji Cooper 	fd = open("testfifo", O_RDONLY);
209*3cedbec3SEnji Cooper 	if (fd < 0)
210*3cedbec3SEnji Cooper 		return (errno);
211*3cedbec3SEnji Cooper 	close(fd);
212*3cedbec3SEnji Cooper 
213*3cedbec3SEnji Cooper 	return (0);
214*3cedbec3SEnji Cooper }
215*3cedbec3SEnji Cooper 
216*3cedbec3SEnji Cooper static int
blocking_open_writer(void)217*3cedbec3SEnji Cooper blocking_open_writer(void)
218*3cedbec3SEnji Cooper {
219*3cedbec3SEnji Cooper 	int fd;
220*3cedbec3SEnji Cooper 
221*3cedbec3SEnji Cooper 	fd = open("testfifo", O_WRONLY);
222*3cedbec3SEnji Cooper 	if (fd < 0)
223*3cedbec3SEnji Cooper 		return (errno);
224*3cedbec3SEnji Cooper 	close(fd);
225*3cedbec3SEnji Cooper 
226*3cedbec3SEnji Cooper 	return (0);
227*3cedbec3SEnji Cooper }
228*3cedbec3SEnji Cooper 
229*3cedbec3SEnji Cooper static void
test_blocking_reader(void)230*3cedbec3SEnji Cooper test_blocking_reader(void)
231*3cedbec3SEnji Cooper {
232*3cedbec3SEnji Cooper 	pid_t reader_pid, writer_pid, wpid;
233*3cedbec3SEnji Cooper 	int error, status;
234*3cedbec3SEnji Cooper 
235*3cedbec3SEnji Cooper 	if (mkfifo("testfifo", 0600) < 0)
236*3cedbec3SEnji Cooper 		err(-1, "test_blocking_reader: mkfifo: testfifo");
237*3cedbec3SEnji Cooper 
238*3cedbec3SEnji Cooper 	/*
239*3cedbec3SEnji Cooper 	 * Block a process in opening the fifo.
240*3cedbec3SEnji Cooper 	 */
241*3cedbec3SEnji Cooper 	if (run_in_process(blocking_open_reader, &reader_pid,
242*3cedbec3SEnji Cooper 	    "test_blocking_reader: blocking_open_reader") < 0) {
243*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
244*3cedbec3SEnji Cooper 		exit(-1);
245*3cedbec3SEnji Cooper 	}
246*3cedbec3SEnji Cooper 
247*3cedbec3SEnji Cooper 	/*
248*3cedbec3SEnji Cooper 	 * Test that it blocked.
249*3cedbec3SEnji Cooper 	 */
250*3cedbec3SEnji Cooper 	sleep(5);
251*3cedbec3SEnji Cooper 	wpid = waitpid(reader_pid, &status, WNOHANG);
252*3cedbec3SEnji Cooper 	if (wpid < 0) {
253*3cedbec3SEnji Cooper 		error = errno;
254*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
255*3cedbec3SEnji Cooper 		errno = error;
256*3cedbec3SEnji Cooper 		err(-1, "test_blocking_reader: waitpid %d", reader_pid);
257*3cedbec3SEnji Cooper 	}
258*3cedbec3SEnji Cooper 
259*3cedbec3SEnji Cooper 	if (wpid != 0 && wpid != reader_pid) {
260*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
261*3cedbec3SEnji Cooper 		errx(-1, "test_blocking_reader: waitpid %d returned %d",
262*3cedbec3SEnji Cooper 		    reader_pid, wpid);
263*3cedbec3SEnji Cooper 	}
264*3cedbec3SEnji Cooper 
265*3cedbec3SEnji Cooper 	if (wpid == reader_pid) {
266*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
267*3cedbec3SEnji Cooper 		errx(-1, "test_blocking_reader: blocking child didn't "
268*3cedbec3SEnji Cooper 		    "block");
269*3cedbec3SEnji Cooper 	}
270*3cedbec3SEnji Cooper 
271*3cedbec3SEnji Cooper 	/*
272*3cedbec3SEnji Cooper 	 * Unblock the blocking reader.
273*3cedbec3SEnji Cooper 	 */
274*3cedbec3SEnji Cooper 	if (run_in_process(blocking_open_writer, &writer_pid,
275*3cedbec3SEnji Cooper 	    "test_blocking_reader: blocking_open_writer") < 0) {
276*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
277*3cedbec3SEnji Cooper 		(void)kill(reader_pid, SIGTERM);
278*3cedbec3SEnji Cooper 		(void)waitpid(reader_pid, &status, 0);
279*3cedbec3SEnji Cooper 		exit(-1);
280*3cedbec3SEnji Cooper 	}
281*3cedbec3SEnji Cooper 
282*3cedbec3SEnji Cooper 	/*
283*3cedbec3SEnji Cooper 	 * Make sure both processes exited quickly (<1 second) to make sure
284*3cedbec3SEnji Cooper 	 * they didn't block, and GC.
285*3cedbec3SEnji Cooper 	 */
286*3cedbec3SEnji Cooper 	if (wait_and_timeout(reader_pid, 1, &status,
287*3cedbec3SEnji Cooper 	    "test_blocking_reader: blocking_open_reader") < 0) {
288*3cedbec3SEnji Cooper 		(void)unlink("testinfo");
289*3cedbec3SEnji Cooper 		(void)kill(reader_pid, SIGTERM);
290*3cedbec3SEnji Cooper 		(void)kill(writer_pid, SIGTERM);
291*3cedbec3SEnji Cooper 		exit(-1);
292*3cedbec3SEnji Cooper 	}
293*3cedbec3SEnji Cooper 
294*3cedbec3SEnji Cooper 	if (wait_and_timeout(writer_pid, 1, &status,
295*3cedbec3SEnji Cooper 	    "test_blocking_reader: blocking_open_writer") < 0) {
296*3cedbec3SEnji Cooper 		(void)unlink("testinfo");
297*3cedbec3SEnji Cooper 		(void)kill(writer_pid, SIGTERM);
298*3cedbec3SEnji Cooper 		exit(-1);
299*3cedbec3SEnji Cooper 	}
300*3cedbec3SEnji Cooper 
301*3cedbec3SEnji Cooper 	if (unlink("testfifo") < 0)
302*3cedbec3SEnji Cooper 		err(-1, "test_blocking_reader: unlink: testfifo");
303*3cedbec3SEnji Cooper }
304*3cedbec3SEnji Cooper static void
test_blocking_writer(void)305*3cedbec3SEnji Cooper test_blocking_writer(void)
306*3cedbec3SEnji Cooper {
307*3cedbec3SEnji Cooper 	pid_t reader_pid, writer_pid, wpid;
308*3cedbec3SEnji Cooper 	int error, status;
309*3cedbec3SEnji Cooper 
310*3cedbec3SEnji Cooper 	if (mkfifo("testfifo", 0600) < 0)
311*3cedbec3SEnji Cooper 		err(-1, "test_blocking_writer: mkfifo: testfifo");
312*3cedbec3SEnji Cooper 
313*3cedbec3SEnji Cooper 	/*
314*3cedbec3SEnji Cooper 	 * Block a process in opening the fifo.
315*3cedbec3SEnji Cooper 	 */
316*3cedbec3SEnji Cooper 	if (run_in_process(blocking_open_writer, &writer_pid,
317*3cedbec3SEnji Cooper 	    "test_blocking_writer: blocking_open_writer") < 0) {
318*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
319*3cedbec3SEnji Cooper 		exit(-1);
320*3cedbec3SEnji Cooper 	}
321*3cedbec3SEnji Cooper 
322*3cedbec3SEnji Cooper 	/*
323*3cedbec3SEnji Cooper 	 * Test that it blocked.
324*3cedbec3SEnji Cooper 	 */
325*3cedbec3SEnji Cooper 	sleep(5);
326*3cedbec3SEnji Cooper 	wpid = waitpid(writer_pid, &status, WNOHANG);
327*3cedbec3SEnji Cooper 	if (wpid < 0) {
328*3cedbec3SEnji Cooper 		error = errno;
329*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
330*3cedbec3SEnji Cooper 		errno = error;
331*3cedbec3SEnji Cooper 		err(-1, "test_blocking_writer: waitpid %d", writer_pid);
332*3cedbec3SEnji Cooper 	}
333*3cedbec3SEnji Cooper 
334*3cedbec3SEnji Cooper 	if (wpid != 0 && wpid != writer_pid) {
335*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
336*3cedbec3SEnji Cooper 		errx(-1, "test_blocking_writer: waitpid %d returned %d",
337*3cedbec3SEnji Cooper 		    writer_pid, wpid);
338*3cedbec3SEnji Cooper 	}
339*3cedbec3SEnji Cooper 
340*3cedbec3SEnji Cooper 	if (wpid == writer_pid) {
341*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
342*3cedbec3SEnji Cooper 		errx(-1, "test_blocking_writer: blocking child didn't "
343*3cedbec3SEnji Cooper 		    "block");
344*3cedbec3SEnji Cooper 	}
345*3cedbec3SEnji Cooper 
346*3cedbec3SEnji Cooper 	/*
347*3cedbec3SEnji Cooper 	 * Unblock the blocking writer.
348*3cedbec3SEnji Cooper 	 */
349*3cedbec3SEnji Cooper 	if (run_in_process(blocking_open_reader, &reader_pid,
350*3cedbec3SEnji Cooper 	    "test_blocking_writer: blocking_open_reader") < 0) {
351*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
352*3cedbec3SEnji Cooper 		(void)kill(writer_pid, SIGTERM);
353*3cedbec3SEnji Cooper 		(void)waitpid(writer_pid, &status, 0);
354*3cedbec3SEnji Cooper 		exit(-1);
355*3cedbec3SEnji Cooper 	}
356*3cedbec3SEnji Cooper 
357*3cedbec3SEnji Cooper 	/*
358*3cedbec3SEnji Cooper 	 * Make sure both processes exited quickly (<1 second) to make sure
359*3cedbec3SEnji Cooper 	 * they didn't block, and GC.
360*3cedbec3SEnji Cooper 	 */
361*3cedbec3SEnji Cooper 	if (wait_and_timeout(writer_pid, 1, &status,
362*3cedbec3SEnji Cooper 	    "test_blocking_writer: blocking_open_writer") < 0) {
363*3cedbec3SEnji Cooper 		(void)unlink("testinfo");
364*3cedbec3SEnji Cooper 		(void)kill(writer_pid, SIGTERM);
365*3cedbec3SEnji Cooper 		(void)kill(reader_pid, SIGTERM);
366*3cedbec3SEnji Cooper 		(void)waitpid(writer_pid, &status, 0);
367*3cedbec3SEnji Cooper 		(void)waitpid(reader_pid, &status, 0);
368*3cedbec3SEnji Cooper 		exit(-1);
369*3cedbec3SEnji Cooper 	}
370*3cedbec3SEnji Cooper 
371*3cedbec3SEnji Cooper 	if (wait_and_timeout(reader_pid, 1, &status,
372*3cedbec3SEnji Cooper 	    "test_blocking_writer: blocking_open_reader") < 0) {
373*3cedbec3SEnji Cooper 		(void)unlink("testinfo");
374*3cedbec3SEnji Cooper 		(void)kill(reader_pid, SIGTERM);
375*3cedbec3SEnji Cooper 		(void)waitpid(reader_pid, &status, 0);
376*3cedbec3SEnji Cooper 		exit(-1);
377*3cedbec3SEnji Cooper 	}
378*3cedbec3SEnji Cooper 
379*3cedbec3SEnji Cooper 	if (unlink("testfifo") < 0)
380*3cedbec3SEnji Cooper 		err(-1, "test_blocking_writer: unlink: testfifo");
381*3cedbec3SEnji Cooper }
382*3cedbec3SEnji Cooper 
383*3cedbec3SEnji Cooper static void
test_non_blocking_reader(void)384*3cedbec3SEnji Cooper test_non_blocking_reader(void)
385*3cedbec3SEnji Cooper {
386*3cedbec3SEnji Cooper 	int status;
387*3cedbec3SEnji Cooper 	pid_t pid;
388*3cedbec3SEnji Cooper 
389*3cedbec3SEnji Cooper 	if (mkfifo("testfifo", 0600) < 0)
390*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_reader: mkfifo: testfifo");
391*3cedbec3SEnji Cooper 
392*3cedbec3SEnji Cooper 	if (run_in_process(non_blocking_open_reader, &pid,
393*3cedbec3SEnji Cooper 	    "test_non_blocking_reader: non_blocking_open_reader") < 0) {
394*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
395*3cedbec3SEnji Cooper 		exit(-1);
396*3cedbec3SEnji Cooper 	}
397*3cedbec3SEnji Cooper 
398*3cedbec3SEnji Cooper 	status = -1;
399*3cedbec3SEnji Cooper 	if (wait_and_timeout(pid, 5, &status,
400*3cedbec3SEnji Cooper 	    "test_non_blocking_reader: non_blocking_open_reader") < 0) {
401*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
402*3cedbec3SEnji Cooper 		exit(-1);
403*3cedbec3SEnji Cooper 	}
404*3cedbec3SEnji Cooper 
405*3cedbec3SEnji Cooper 	if (WEXITSTATUS(status) != 0) {
406*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
407*3cedbec3SEnji Cooper 		errno = WEXITSTATUS(status);
408*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_reader: "
409*3cedbec3SEnji Cooper 		    "non_blocking_open_reader: open: testfifo");
410*3cedbec3SEnji Cooper 	}
411*3cedbec3SEnji Cooper 
412*3cedbec3SEnji Cooper 	if (unlink("testfifo") < 0)
413*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_reader: unlink: testfifo");
414*3cedbec3SEnji Cooper }
415*3cedbec3SEnji Cooper 
416*3cedbec3SEnji Cooper static void
test_non_blocking_writer(void)417*3cedbec3SEnji Cooper test_non_blocking_writer(void)
418*3cedbec3SEnji Cooper {
419*3cedbec3SEnji Cooper 	int status;
420*3cedbec3SEnji Cooper 	pid_t pid;
421*3cedbec3SEnji Cooper 
422*3cedbec3SEnji Cooper 	if (mkfifo("testfifo", 0600) < 0)
423*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_writer: mkfifo: testfifo");
424*3cedbec3SEnji Cooper 
425*3cedbec3SEnji Cooper 	if (run_in_process(non_blocking_open_writer, &pid,
426*3cedbec3SEnji Cooper 	    "test_non_blocking_writer: non_blocking_open_writer") < 0) {
427*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
428*3cedbec3SEnji Cooper 		exit(-1);
429*3cedbec3SEnji Cooper 	}
430*3cedbec3SEnji Cooper 
431*3cedbec3SEnji Cooper 	status = -1;
432*3cedbec3SEnji Cooper 	if (wait_and_timeout(pid, 5, &status,
433*3cedbec3SEnji Cooper 	    "test_non_blocking_writer: non_blocking_open_writer") < 0) {
434*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
435*3cedbec3SEnji Cooper 		exit(-1);
436*3cedbec3SEnji Cooper 	}
437*3cedbec3SEnji Cooper 
438*3cedbec3SEnji Cooper 	if (WEXITSTATUS(status) != ENXIO) {
439*3cedbec3SEnji Cooper 		(void)unlink("testfifo");
440*3cedbec3SEnji Cooper 
441*3cedbec3SEnji Cooper 		errno = WEXITSTATUS(status);
442*3cedbec3SEnji Cooper 		if (errno == 0)
443*3cedbec3SEnji Cooper 			errx(-1, "test_non_blocking_writer: "
444*3cedbec3SEnji Cooper 			    "non_blocking_open_writer: open succeeded");
445*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_writer: "
446*3cedbec3SEnji Cooper 		    "non_blocking_open_writer: open: testfifo");
447*3cedbec3SEnji Cooper 	}
448*3cedbec3SEnji Cooper 
449*3cedbec3SEnji Cooper 	if (unlink("testfifo") < 0)
450*3cedbec3SEnji Cooper 		err(-1, "test_non_blocking_writer: unlink: testfifo");
451*3cedbec3SEnji Cooper }
452*3cedbec3SEnji Cooper 
453*3cedbec3SEnji Cooper int
main(void)454*3cedbec3SEnji Cooper main(void)
455*3cedbec3SEnji Cooper {
456*3cedbec3SEnji Cooper 
457*3cedbec3SEnji Cooper 	if (geteuid() != 0)
458*3cedbec3SEnji Cooper 		errx(-1, "must be run as root");
459*3cedbec3SEnji Cooper 
460*3cedbec3SEnji Cooper 	strcpy(temp_dir, "fifo_open.XXXXXXXXXXX");
461*3cedbec3SEnji Cooper 	if (mkdtemp(temp_dir) == NULL)
462*3cedbec3SEnji Cooper 		err(-1, "mkdtemp");
463*3cedbec3SEnji Cooper 	if (chdir(temp_dir) < 0)
464*3cedbec3SEnji Cooper 		err(-1, "chdir: %s", temp_dir);
465*3cedbec3SEnji Cooper 	atexit(atexit_temp_dir);
466*3cedbec3SEnji Cooper 
467*3cedbec3SEnji Cooper 	test_non_blocking_reader();
468*3cedbec3SEnji Cooper 	test_non_blocking_writer();
469*3cedbec3SEnji Cooper 
470*3cedbec3SEnji Cooper 	test_blocking_reader();
471*3cedbec3SEnji Cooper 	test_blocking_writer();
472*3cedbec3SEnji Cooper 
473*3cedbec3SEnji Cooper 	return (0);
474*3cedbec3SEnji Cooper }
475