1150032Srwatson/*-
2150032Srwatson * Copyright (c) 2005 Robert N. M. Watson
3232184Sjilles * Copyright (c) 2012 Jilles Tjoelker
4150032Srwatson * All rights reserved.
5150032Srwatson *
6150032Srwatson * Redistribution and use in source and binary forms, with or without
7150032Srwatson * modification, are permitted provided that the following conditions
8150032Srwatson * are met:
9150032Srwatson * 1. Redistributions of source code must retain the above copyright
10150032Srwatson *    notice, this list of conditions and the following disclaimer.
11150032Srwatson * 2. Redistributions in binary form must reproduce the above copyright
12150032Srwatson *    notice, this list of conditions and the following disclaimer in the
13150032Srwatson *    documentation and/or other materials provided with the distribution.
14150032Srwatson *
15150032Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16150032Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17150032Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18150032Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19150032Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20150032Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21150032Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22150032Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23150032Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24150032Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25150032Srwatson * SUCH DAMAGE.
26150032Srwatson *
27150032Srwatson * $FreeBSD$
28150032Srwatson */
29150032Srwatson
30150064Srwatson#include <sys/types.h>
31150064Srwatson#include <sys/event.h>
32150094Srwatson#include <sys/filio.h>
33286612Srodrigc#include <sys/ioctl.h>
34150032Srwatson#include <sys/stat.h>
35150064Srwatson#include <sys/time.h>
36150032Srwatson
37150032Srwatson#include <err.h>
38150032Srwatson#include <errno.h>
39150032Srwatson#include <fcntl.h>
40150032Srwatson#include <limits.h>
41150064Srwatson#include <stdio.h>
42150032Srwatson#include <stdlib.h>
43150032Srwatson#include <string.h>
44150032Srwatson#include <unistd.h>
45150032Srwatson
46150032Srwatson/*
47150032Srwatson * Regression test for piddling details of fifos.
48150032Srwatson */
49150032Srwatson
50150032Srwatson/*
51150032Srwatson * All activity occurs within a temporary directory created early in the
52150032Srwatson * test.
53150032Srwatson */
54281450Sngiestatic char	temp_dir[PATH_MAX];
55150032Srwatson
56150032Srwatsonstatic void __unused
57150032Srwatsonatexit_temp_dir(void)
58150032Srwatson{
59150032Srwatson
60150032Srwatson	rmdir(temp_dir);
61150032Srwatson}
62150032Srwatson
63150032Srwatsonstatic void
64150032Srwatsonmakefifo(const char *fifoname, const char *testname)
65150032Srwatson{
66150032Srwatson
67150032Srwatson	if (mkfifo(fifoname, 0700) < 0)
68150032Srwatson		err(-1, "%s: makefifo: mkfifo: %s", testname, fifoname);
69150032Srwatson}
70150032Srwatson
71150032Srwatsonstatic void
72150032Srwatsoncleanfifo(const char *fifoname, int fd1, int fd2)
73150032Srwatson{
74150032Srwatson
75150032Srwatson	if (fd1 != -1)
76150032Srwatson		close(fd1);
77150032Srwatson	if (fd2 != -1)
78150032Srwatson		close(fd2);
79150032Srwatson	(void)unlink(fifoname);
80150032Srwatson}
81150032Srwatson
82150032Srwatsonstatic int
83281450Sngieopenfifo(const char *fifoname, int *reader_fdp, int *writer_fdp)
84150032Srwatson{
85150032Srwatson	int error, fd1, fd2;
86150032Srwatson
87150032Srwatson	fd1 = open(fifoname, O_RDONLY | O_NONBLOCK);
88150032Srwatson	if (fd1 < 0)
89150032Srwatson		return (-1);
90150032Srwatson	fd2 = open(fifoname, O_WRONLY | O_NONBLOCK);
91150032Srwatson	if (fd2 < 0) {
92150032Srwatson		error = errno;
93150032Srwatson		close(fd1);
94150032Srwatson		errno = error;
95150032Srwatson		return (-1);
96150032Srwatson	}
97150032Srwatson	*reader_fdp = fd1;
98150032Srwatson	*writer_fdp = fd2;
99150032Srwatson
100150032Srwatson	return (0);
101150032Srwatson}
102150032Srwatson
103150064Srwatson/*
104150064Srwatson * POSIX does not allow lseek(2) on fifos, so we expect ESPIPE as a result.
105150064Srwatson */
106150032Srwatsonstatic void
107150032Srwatsontest_lseek(void)
108150032Srwatson{
109150032Srwatson	int reader_fd, writer_fd;
110150032Srwatson
111150032Srwatson	makefifo("testfifo", __func__);
112150032Srwatson
113281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
114150032Srwatson		warn("%s: openfifo", __func__);
115150032Srwatson		cleanfifo("testfifo", -1, -1);
116150032Srwatson		exit(-1);
117150032Srwatson	}
118150032Srwatson
119227124Sjilles	if (lseek(reader_fd, 1, SEEK_CUR) >= 0) {
120150032Srwatson		warnx("%s: lseek succeeded instead of returning ESPIPE",
121150032Srwatson		    __func__);
122150032Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
123150032Srwatson		exit(-1);
124150032Srwatson	}
125150032Srwatson	if (errno != ESPIPE) {
126150032Srwatson		warn("%s: lseek returned instead of ESPIPE", __func__);
127150032Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
128150032Srwatson		exit(-1);
129150032Srwatson	}
130150032Srwatson
131150032Srwatson	cleanfifo("testfifo", reader_fd, writer_fd);
132150032Srwatson}
133150032Srwatson
134159032Smaxim/*
135159032Smaxim * truncate(2) on FIFO should silently return success.
136159032Smaxim */
137159032Smaximstatic void
138159032Smaximtest_truncate(void)
139159032Smaxim{
140159032Smaxim
141159032Smaxim	makefifo("testfifo", __func__);
142159032Smaxim
143159032Smaxim	if (truncate("testfifo", 1024) != 0) {
144159032Smaxim		warn("%s: truncate", __func__);
145159032Smaxim		cleanfifo("testfifo", -1, -1);
146159032Smaxim		exit(-1);
147159032Smaxim	}
148159032Smaxim
149159032Smaxim	cleanfifo("testfifo", -1, -1);
150159032Smaxim}
151159032Smaxim
152150094Srwatsonstatic int
153286612Srodrigctest_ioctl_setclearflag(int fd, unsigned long flag, const char *testname,
154150094Srwatson    const char *fdname, const char *flagname)
155150094Srwatson{
156150094Srwatson	int i;
157150094Srwatson
158150094Srwatson	i = 1;
159150094Srwatson	if (ioctl(fd, flag, &i) < 0) {
160150094Srwatson		warn("%s:%s: ioctl(%s, %s, 1)", testname, __func__, fdname,
161150094Srwatson		    flagname);
162150094Srwatson		cleanfifo("testfifo", -1, -1);
163150094Srwatson		exit(-1);
164150094Srwatson	}
165150094Srwatson
166150094Srwatson	i = 0;
167150094Srwatson	if (ioctl(fd, flag, &i) < 0) {
168150094Srwatson		warn("%s:%s: ioctl(%s, %s, 0)", testname, __func__, fdname,
169150094Srwatson		    flagname);
170150094Srwatson		cleanfifo("testfifo", -1, -1);
171150094Srwatson		exit(-1);
172150094Srwatson	}
173150094Srwatson
174150094Srwatson	return (0);
175150094Srwatson}
176150094Srwatson
177150094Srwatson/*
178150094Srwatson * Test that various ioctls can be issued against the file descriptor.  We
179150094Srwatson * don't currently test the semantics of these changes here.
180150094Srwatson */
181150094Srwatsonstatic void
182150094Srwatsontest_ioctl(void)
183150094Srwatson{
184150094Srwatson	int reader_fd, writer_fd;
185150094Srwatson
186150094Srwatson	makefifo("testfifo", __func__);
187150094Srwatson
188281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
189150094Srwatson		warn("%s: openfifo", __func__);
190150094Srwatson		cleanfifo("testfifo", -1, -1);
191150094Srwatson		exit(-1);
192150094Srwatson	}
193150094Srwatson
194150094Srwatson	/*
195150094Srwatson	 * Set and remove the non-blocking I/O flag.
196150094Srwatson	 */
197150094Srwatson	if (test_ioctl_setclearflag(reader_fd, FIONBIO, __func__,
198150094Srwatson	    "reader_fd", "FIONBIO") < 0) {
199150094Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
200150094Srwatson		exit(-1);
201150094Srwatson	}
202150094Srwatson
203150094Srwatson	if (test_ioctl_setclearflag(writer_fd, FIONBIO, __func__,
204150094Srwatson	    "writer_fd", "FIONBIO") < 0) {
205150094Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
206150094Srwatson		exit(-1);
207150094Srwatson	}
208150094Srwatson
209150094Srwatson	/*
210150094Srwatson	 * Set and remove the async I/O flag.
211150094Srwatson	 */
212150094Srwatson	if (test_ioctl_setclearflag(reader_fd, FIOASYNC, __func__,
213150094Srwatson	    "reader_fd", "FIOASYNC") < 0) {
214150094Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
215150094Srwatson		exit(-1);
216150094Srwatson	}
217150094Srwatson
218150094Srwatson	if (test_ioctl_setclearflag(writer_fd, FIOASYNC, __func__,
219150094Srwatson	    "writer_fd", "FIONASYNC") < 0) {
220150094Srwatson		cleanfifo("testfifo", reader_fd, writer_fd);
221150094Srwatson		exit(-1);
222150094Srwatson	}
223150094Srwatson
224150094Srwatson	cleanfifo("testfifo", reader_fd, writer_fd);
225150094Srwatson}
226150094Srwatson
227232184Sjilles/*
228232184Sjilles * fchmod(2)/fchown(2) on FIFO should work.
229232184Sjilles */
230232184Sjillesstatic void
231232184Sjillestest_chmodchown(void)
232232184Sjilles{
233232184Sjilles	struct stat sb;
234232184Sjilles	int reader_fd, writer_fd;
235232184Sjilles	uid_t u;
236232184Sjilles	gid_t g;
237232184Sjilles
238232184Sjilles	makefifo("testfifo", __func__);
239232184Sjilles
240281450Sngie	if (openfifo("testfifo", &reader_fd, &writer_fd) < 0) {
241232184Sjilles		warn("%s: openfifo", __func__);
242232184Sjilles		cleanfifo("testfifo", -1, -1);
243232184Sjilles		exit(-1);
244232184Sjilles	}
245232184Sjilles
246232184Sjilles	if (fchmod(reader_fd, 0666) != 0) {
247232184Sjilles		warn("%s: fchmod", __func__);
248232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
249232184Sjilles		exit(-1);
250232184Sjilles	}
251232184Sjilles
252232184Sjilles	if (stat("testfifo", &sb) != 0) {
253232184Sjilles		warn("%s: stat", __func__);
254232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
255232184Sjilles		exit(-1);
256232184Sjilles	}
257232184Sjilles
258232184Sjilles	if ((sb.st_mode & 0777) != 0666) {
259232184Sjilles		warnx("%s: stat chmod result", __func__);
260232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
261232184Sjilles		exit(-1);
262232184Sjilles	}
263232184Sjilles
264232184Sjilles	if (fstat(writer_fd, &sb) != 0) {
265232184Sjilles		warn("%s: fstat", __func__);
266232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
267232184Sjilles		exit(-1);
268232184Sjilles	}
269232184Sjilles
270232184Sjilles	if ((sb.st_mode & 0777) != 0666) {
271232184Sjilles		warnx("%s: fstat chmod result", __func__);
272232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
273232184Sjilles		exit(-1);
274232184Sjilles	}
275232184Sjilles
276232184Sjilles	if (fchown(reader_fd, -1, -1) != 0) {
277232184Sjilles		warn("%s: fchown 1", __func__);
278232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
279232184Sjilles		exit(-1);
280232184Sjilles	}
281232184Sjilles
282232184Sjilles	u = geteuid();
283232184Sjilles	if (u == 0)
284232184Sjilles		u = 1;
285232184Sjilles	g = getegid();
286232184Sjilles	if (fchown(reader_fd, u, g) != 0) {
287232184Sjilles		warn("%s: fchown 2", __func__);
288232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
289232184Sjilles		exit(-1);
290232184Sjilles	}
291232184Sjilles	if (stat("testfifo", &sb) != 0) {
292232184Sjilles		warn("%s: stat", __func__);
293232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
294232184Sjilles		exit(-1);
295232184Sjilles	}
296232184Sjilles
297232184Sjilles	if (sb.st_uid != u || sb.st_gid != g) {
298232184Sjilles		warnx("%s: stat chown result", __func__);
299232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
300232184Sjilles		exit(-1);
301232184Sjilles	}
302232184Sjilles
303232184Sjilles	if (fstat(writer_fd, &sb) != 0) {
304232184Sjilles		warn("%s: fstat", __func__);
305232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
306232184Sjilles		exit(-1);
307232184Sjilles	}
308232184Sjilles
309232184Sjilles	if (sb.st_uid != u || sb.st_gid != g) {
310232184Sjilles		warnx("%s: fstat chown result", __func__);
311232184Sjilles		cleanfifo("testfifo", reader_fd, writer_fd);
312232184Sjilles		exit(-1);
313232184Sjilles	}
314232184Sjilles
315232184Sjilles	cleanfifo("testfifo", -1, -1);
316232184Sjilles}
317232184Sjilles
318150032Srwatsonint
319281450Sngiemain(void)
320150032Srwatson{
321150032Srwatson
322281450Sngie	strcpy(temp_dir, "fifo_misc.XXXXXXXXXXX");
323150032Srwatson	if (mkdtemp(temp_dir) == NULL)
324150032Srwatson		err(-1, "mkdtemp");
325150032Srwatson	atexit(atexit_temp_dir);
326150032Srwatson
327150032Srwatson	if (chdir(temp_dir) < 0)
328150032Srwatson		err(-1, "chdir %s", temp_dir);
329150032Srwatson
330150032Srwatson	test_lseek();
331159032Smaxim	test_truncate();
332150094Srwatson	test_ioctl();
333232184Sjilles	test_chmodchown();
334150032Srwatson
335150032Srwatson	return (0);
336150032Srwatson}
337