1/*-
2 * Copyright (c) 2005 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#include <sys/types.h>
30#include <sys/event.h>
31#include <sys/filio.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <limits.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44/*
45 * Regression test for piddling details of fifos.
46 */
47
48/*
49 * All activity occurs within a temporary directory created early in the
50 * test.
51 */
52char	temp_dir[PATH_MAX];
53
54static void __unused
55atexit_temp_dir(void)
56{
57
58	rmdir(temp_dir);
59}
60
61static void
62makefifo(const char *fifoname, const char *testname)
63{
64
65	if (mkfifo(fifoname, 0700) < 0)
66		err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname);
67}
68
69static void
70cleanfifo(const char *fifoname, int fd1, int fd2)
71{
72
73	if (fd1 != -1)
74		close(fd1);
75	if (fd2 != -1)
76		close(fd2);
77	(void)unlink(fifoname);
78}
79
80static int
81openfifo(const char *fifoname, const char *testname, int *reader_fdp,
82    int *writer_fdp)
83{
84	int error, fd1, fd2;
85
86	fd1 = open(fifoname, O_RDONLY | O_NONBLOCK);
87	if (fd1 < 0)
88		return (-1);
89	fd2 = open(fifoname, O_WRONLY | O_NONBLOCK);
90	if (fd2 < 0) {
91		error = errno;
92		close(fd1);
93		errno = error;
94		return (-1);
95	}
96	*reader_fdp = fd1;
97	*writer_fdp = fd2;
98
99	return (0);
100}
101
102/*
103 * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result.
104 */
105static void
106test_lseek(void)
107{
108	int reader_fd, writer_fd;
109
110	makefifo("testfifo", __func__);
111
112	if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
113		warn("%s: openfifo", __func__);
114		cleanfifo("testfifo", -1, -1);
115		exit(-1);
116	}
117
118	if (lseek(reader_fd, 1, SEEK_CUR) >= 0) {
119		warnx("%s: lseek succeeded instead of returning ESPIPE",
120		    __func__);
121		cleanfifo("testfifo", reader_fd, writer_fd);
122		exit(-1);
123	}
124	if (errno != ESPIPE) {
125		warn("%s: lseek returned instead of ESPIPE", __func__);
126		cleanfifo("testfifo", reader_fd, writer_fd);
127		exit(-1);
128	}
129
130	cleanfifo("testfifo", reader_fd, writer_fd);
131}
132
133/*
134 * truncate(2) on FIFO should silently return success.
135 */
136static void
137test_truncate(void)
138{
139
140	makefifo("testfifo", __func__);
141
142	if (truncate("testfifo", 1024) != 0) {
143		warn("%s: truncate", __func__);
144		cleanfifo("testfifo", -1, -1);
145		exit(-1);
146	}
147
148	cleanfifo("testfifo", -1, -1);
149}
150
151static int
152test_ioctl_setclearflag(int fd, int flag, const char *testname,
153    const char *fdname, const char *flagname)
154{
155	int i;
156
157	i = 1;
158	if (ioctl(fd, flag, &i) < 0) {
159		warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname,
160		    flagname);
161		cleanfifo("testfifo", -1, -1);
162		exit(-1);
163	}
164
165	i = 0;
166	if (ioctl(fd, flag, &i) < 0) {
167		warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname,
168		    flagname);
169		cleanfifo("testfifo", -1, -1);
170		exit(-1);
171	}
172
173	return (0);
174}
175
176/*
177 * Test that various ioctls can be issued against the file descriptor.  We
178 * don't currently test the semantics of these changes here.
179 */
180static void
181test_ioctl(void)
182{
183	int reader_fd, writer_fd;
184
185	makefifo("testfifo", __func__);
186
187	if (openfifo("testfifo", __func__, &reader_fd, &writer_fd) < 0) {
188		warn("%s: openfifo", __func__);
189		cleanfifo("testfifo", -1, -1);
190		exit(-1);
191	}
192
193	/*
194	 * Set and remove the non-blocking I/O flag.
195	 */
196	if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__,
197	    "reader_fd", "FIONBIO") < 0) {
198		cleanfifo("testfifo", reader_fd, writer_fd);
199		exit(-1);
200	}
201
202	if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__,
203	    "writer_fd", "FIONBIO") < 0) {
204		cleanfifo("testfifo", reader_fd, writer_fd);
205		exit(-1);
206	}
207
208	/*
209	 * Set and remove the async I/O flag.
210	 */
211	if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__,
212	    "reader_fd", "FIOASYNC") < 0) {
213		cleanfifo("testfifo", reader_fd, writer_fd);
214		exit(-1);
215	}
216
217	if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__,
218	    "writer_fd", "FIONASYNC") < 0) {
219		cleanfifo("testfifo", reader_fd, writer_fd);
220		exit(-1);
221	}
222
223	cleanfifo("testfifo", reader_fd, writer_fd);
224}
225
226int
227main(int argc, char *argv[])
228{
229
230	strcpy(temp_dir, "/tmp/fifo_misc.XXXXXXXXXXX");
231	if (mkdtemp(temp_dir) == NULL)
232		err(-1, "mkdtemp");
233	atexit(atexit_temp_dir);
234
235	if (chdir(temp_dir) < 0)
236		err(-1, "chdir %s", temp_dir);
237
238	test_lseek();
239	test_truncate();
240	test_ioctl();
241
242	return (0);
243}
244