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