1*3cedbec3SEnji Cooper /*-
2*3cedbec3SEnji Cooper * Copyright (c) 2005-2008 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/stat.h>
28*3cedbec3SEnji Cooper
29*3cedbec3SEnji Cooper #include <err.h>
30*3cedbec3SEnji Cooper #include <errno.h>
31*3cedbec3SEnji Cooper #include <limits.h>
32*3cedbec3SEnji Cooper #include <stdio.h>
33*3cedbec3SEnji Cooper #include <stdlib.h>
34*3cedbec3SEnji Cooper #include <string.h>
35*3cedbec3SEnji Cooper #include <unistd.h>
36*3cedbec3SEnji Cooper
37*3cedbec3SEnji Cooper /*
38*3cedbec3SEnji Cooper * Simple regression test for the creation and destruction of POSIX fifos in
39*3cedbec3SEnji Cooper * the file system name space. Using a specially created directory, create
40*3cedbec3SEnji Cooper * a fifo in it and check that the following properties are present, as
41*3cedbec3SEnji Cooper * specified in IEEE Std 1003.1, 2004 Edition:
42*3cedbec3SEnji Cooper *
43*3cedbec3SEnji Cooper * - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is
44*3cedbec3SEnji Cooper * created.
45*3cedbec3SEnji Cooper *
46*3cedbec3SEnji Cooper * - On an error, no fifo is created. (XXX: Not tested)
47*3cedbec3SEnji Cooper *
48*3cedbec3SEnji Cooper * - The mode bits on the fifo are a product of combining the umask and
49*3cedbec3SEnji Cooper * requested mode.
50*3cedbec3SEnji Cooper *
51*3cedbec3SEnji Cooper * - The fifo's owner will be the processes effective user ID. (XXX: Not
52*3cedbec3SEnji Cooper * tested)
53*3cedbec3SEnji Cooper *
54*3cedbec3SEnji Cooper * - The fifo's group will be the parent directory's group or the effective
55*3cedbec3SEnji Cooper * group ID of the process. For historical reasons, BSD prefers the group
56*3cedbec3SEnji Cooper * ID of the process, so we will generate an error if it's not that. (XXX:
57*3cedbec3SEnji Cooper * Not tested)
58*3cedbec3SEnji Cooper *
59*3cedbec3SEnji Cooper * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately,
60*3cedbec3SEnji Cooper * and st_ctime and st_mtime on the directory will be updated. (XXX: We
61*3cedbec3SEnji Cooper * test they are updated, not correct)
62*3cedbec3SEnji Cooper *
63*3cedbec3SEnji Cooper * - EEXIST is returned if the named file already exists.
64*3cedbec3SEnji Cooper *
65*3cedbec3SEnji Cooper * In addition, we check that we can unlink the fifo, and that if we do, it
66*3cedbec3SEnji Cooper * disappears.
67*3cedbec3SEnji Cooper *
68*3cedbec3SEnji Cooper * This test must run as root in order to usefully frob the process
69*3cedbec3SEnji Cooper * credential to test permission parts.
70*3cedbec3SEnji Cooper */
71*3cedbec3SEnji Cooper
72*3cedbec3SEnji Cooper /*
73*3cedbec3SEnji Cooper * All activity occurs within a temporary directory created early in the
74*3cedbec3SEnji Cooper * test.
75*3cedbec3SEnji Cooper */
76*3cedbec3SEnji Cooper static char temp_dir[PATH_MAX];
77*3cedbec3SEnji Cooper
78*3cedbec3SEnji Cooper static void __unused
atexit_temp_dir(void)79*3cedbec3SEnji Cooper atexit_temp_dir(void)
80*3cedbec3SEnji Cooper {
81*3cedbec3SEnji Cooper
82*3cedbec3SEnji Cooper rmdir(temp_dir);
83*3cedbec3SEnji Cooper }
84*3cedbec3SEnji Cooper
85*3cedbec3SEnji Cooper /*
86*3cedbec3SEnji Cooper * Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo,
87*3cedbec3SEnji Cooper * that the time stamps on the directory are updated, that if we try twice we
88*3cedbec3SEnji Cooper * get EEXIST, and that we can unlink it.
89*3cedbec3SEnji Cooper */
90*3cedbec3SEnji Cooper static void
fifo_create_test(int use_mkfifo)91*3cedbec3SEnji Cooper fifo_create_test(int use_mkfifo)
92*3cedbec3SEnji Cooper {
93*3cedbec3SEnji Cooper struct stat old_dirsb, dirsb, fifosb;
94*3cedbec3SEnji Cooper const char *testname;
95*3cedbec3SEnji Cooper char path[] = "testfifo";
96*3cedbec3SEnji Cooper int error;
97*3cedbec3SEnji Cooper
98*3cedbec3SEnji Cooper if (use_mkfifo)
99*3cedbec3SEnji Cooper testname = "mkfifo";
100*3cedbec3SEnji Cooper else
101*3cedbec3SEnji Cooper testname = "mknod";
102*3cedbec3SEnji Cooper
103*3cedbec3SEnji Cooper /*
104*3cedbec3SEnji Cooper * Sleep to make sure that the time stamp on the directory will be
105*3cedbec3SEnji Cooper * updated.
106*3cedbec3SEnji Cooper */
107*3cedbec3SEnji Cooper if (stat(".", &old_dirsb) < 0)
108*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: stat: %s", testname,
109*3cedbec3SEnji Cooper temp_dir);
110*3cedbec3SEnji Cooper
111*3cedbec3SEnji Cooper sleep(2);
112*3cedbec3SEnji Cooper
113*3cedbec3SEnji Cooper if (use_mkfifo) {
114*3cedbec3SEnji Cooper if (mkfifo(path, 0600) < 0)
115*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: %s", testname, path);
116*3cedbec3SEnji Cooper } else {
117*3cedbec3SEnji Cooper if (mknod(path, S_IFIFO | 0600, 0) < 0)
118*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: %s", testname, path);
119*3cedbec3SEnji Cooper }
120*3cedbec3SEnji Cooper
121*3cedbec3SEnji Cooper if (stat(path, &fifosb) < 0) {
122*3cedbec3SEnji Cooper error = errno;
123*3cedbec3SEnji Cooper (void)unlink(path);
124*3cedbec3SEnji Cooper errno = error;
125*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: stat: %s", testname, path);
126*3cedbec3SEnji Cooper }
127*3cedbec3SEnji Cooper
128*3cedbec3SEnji Cooper if (!(S_ISFIFO(fifosb.st_mode))) {
129*3cedbec3SEnji Cooper (void)unlink(path);
130*3cedbec3SEnji Cooper errx(-1, "basic_create_test: %s produced non-fifo",
131*3cedbec3SEnji Cooper testname);
132*3cedbec3SEnji Cooper }
133*3cedbec3SEnji Cooper
134*3cedbec3SEnji Cooper if (use_mkfifo) {
135*3cedbec3SEnji Cooper if (mkfifo(path, 0600) == 0)
136*3cedbec3SEnji Cooper errx(-1, "basic_create_test: dup %s succeeded",
137*3cedbec3SEnji Cooper testname);
138*3cedbec3SEnji Cooper } else {
139*3cedbec3SEnji Cooper if (mknod(path, S_IFIFO | 0600, 0) == 0)
140*3cedbec3SEnji Cooper errx(-1, "basic_create_test: dup %s succeeded",
141*3cedbec3SEnji Cooper testname);
142*3cedbec3SEnji Cooper }
143*3cedbec3SEnji Cooper
144*3cedbec3SEnji Cooper if (errno != EEXIST)
145*3cedbec3SEnji Cooper err(-1, "basic_create_test: dup %s unexpected error",
146*3cedbec3SEnji Cooper testname);
147*3cedbec3SEnji Cooper
148*3cedbec3SEnji Cooper if (stat(".", &dirsb) < 0) {
149*3cedbec3SEnji Cooper error = errno;
150*3cedbec3SEnji Cooper (void)unlink(path);
151*3cedbec3SEnji Cooper errno = error;
152*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: stat: %s", testname,
153*3cedbec3SEnji Cooper temp_dir);
154*3cedbec3SEnji Cooper }
155*3cedbec3SEnji Cooper
156*3cedbec3SEnji Cooper if (old_dirsb.st_ctime == dirsb.st_ctime) {
157*3cedbec3SEnji Cooper (void)unlink(path);
158*3cedbec3SEnji Cooper errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == "
159*3cedbec3SEnji Cooper "dirsb.st_ctime", testname);
160*3cedbec3SEnji Cooper }
161*3cedbec3SEnji Cooper
162*3cedbec3SEnji Cooper if (old_dirsb.st_mtime == dirsb.st_mtime) {
163*3cedbec3SEnji Cooper (void)unlink(path);
164*3cedbec3SEnji Cooper errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == "
165*3cedbec3SEnji Cooper "dirsb.st_mtime", testname);
166*3cedbec3SEnji Cooper }
167*3cedbec3SEnji Cooper
168*3cedbec3SEnji Cooper if (unlink(path) < 0)
169*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: unlink: %s", testname, path);
170*3cedbec3SEnji Cooper
171*3cedbec3SEnji Cooper if (stat(path, &fifosb) == 0)
172*3cedbec3SEnji Cooper errx(-1, "basic_create_test: %s: unlink failed to unlink",
173*3cedbec3SEnji Cooper testname);
174*3cedbec3SEnji Cooper if (errno != ENOENT)
175*3cedbec3SEnji Cooper err(-1, "basic_create_test: %s: unlink unexpected error",
176*3cedbec3SEnji Cooper testname);
177*3cedbec3SEnji Cooper }
178*3cedbec3SEnji Cooper
179*3cedbec3SEnji Cooper /*
180*3cedbec3SEnji Cooper * Having determined that basic create/remove/etc functionality is present
181*3cedbec3SEnji Cooper * for fifos, now make sure that the umask, requested permissions, and
182*3cedbec3SEnji Cooper * resulting mode are handled properly.
183*3cedbec3SEnji Cooper */
184*3cedbec3SEnji Cooper static const struct permission_test {
185*3cedbec3SEnji Cooper mode_t pt_umask;
186*3cedbec3SEnji Cooper mode_t pt_reqmode;
187*3cedbec3SEnji Cooper mode_t pt_mode;
188*3cedbec3SEnji Cooper } permission_test[] = {
189*3cedbec3SEnji Cooper {0000, 0, S_IFIFO},
190*3cedbec3SEnji Cooper {0000, S_IRWXU, S_IFIFO | S_IRWXU},
191*3cedbec3SEnji Cooper {0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG |
192*3cedbec3SEnji Cooper S_IRWXO },
193*3cedbec3SEnji Cooper {0077, S_IRWXU, S_IFIFO | S_IRWXU},
194*3cedbec3SEnji Cooper {0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU},
195*3cedbec3SEnji Cooper };
196*3cedbec3SEnji Cooper static const int permission_test_count = sizeof(permission_test) /
197*3cedbec3SEnji Cooper sizeof(struct permission_test);
198*3cedbec3SEnji Cooper
199*3cedbec3SEnji Cooper static void
fifo_permission_test(int use_mkfifo)200*3cedbec3SEnji Cooper fifo_permission_test(int use_mkfifo)
201*3cedbec3SEnji Cooper {
202*3cedbec3SEnji Cooper const struct permission_test *ptp;
203*3cedbec3SEnji Cooper mode_t __unused old_umask;
204*3cedbec3SEnji Cooper char path[] = "testfifo";
205*3cedbec3SEnji Cooper const char *testname;
206*3cedbec3SEnji Cooper struct stat sb;
207*3cedbec3SEnji Cooper int error, i;
208*3cedbec3SEnji Cooper
209*3cedbec3SEnji Cooper if (use_mkfifo)
210*3cedbec3SEnji Cooper testname = "mkfifo";
211*3cedbec3SEnji Cooper else
212*3cedbec3SEnji Cooper testname = "mknod";
213*3cedbec3SEnji Cooper
214*3cedbec3SEnji Cooper old_umask = umask(0022);
215*3cedbec3SEnji Cooper for (i = 0; i < permission_test_count; i++) {
216*3cedbec3SEnji Cooper ptp = &permission_test[i];
217*3cedbec3SEnji Cooper
218*3cedbec3SEnji Cooper umask(ptp->pt_umask);
219*3cedbec3SEnji Cooper if (use_mkfifo) {
220*3cedbec3SEnji Cooper if (mkfifo(path, ptp->pt_reqmode) < 0)
221*3cedbec3SEnji Cooper err(-1, "fifo_permission_test: %s: %08o "
222*3cedbec3SEnji Cooper "%08o %08o\n", testname, ptp->pt_umask,
223*3cedbec3SEnji Cooper ptp->pt_reqmode, ptp->pt_mode);
224*3cedbec3SEnji Cooper } else {
225*3cedbec3SEnji Cooper if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0)
226*3cedbec3SEnji Cooper err(-1, "fifo_permission_test: %s: %08o "
227*3cedbec3SEnji Cooper "%08o %08o\n", testname, ptp->pt_umask,
228*3cedbec3SEnji Cooper ptp->pt_reqmode, ptp->pt_mode);
229*3cedbec3SEnji Cooper }
230*3cedbec3SEnji Cooper
231*3cedbec3SEnji Cooper if (stat(path, &sb) < 0) {
232*3cedbec3SEnji Cooper error = errno;
233*3cedbec3SEnji Cooper (void)unlink(path);
234*3cedbec3SEnji Cooper errno = error;
235*3cedbec3SEnji Cooper err(-1, "fifo_permission_test: %s: %s", testname,
236*3cedbec3SEnji Cooper path);
237*3cedbec3SEnji Cooper }
238*3cedbec3SEnji Cooper
239*3cedbec3SEnji Cooper if (sb.st_mode != ptp->pt_mode) {
240*3cedbec3SEnji Cooper (void)unlink(path);
241*3cedbec3SEnji Cooper errx(-1, "fifo_permission_test: %s: %08o %08o %08o "
242*3cedbec3SEnji Cooper "got %08o", testname, ptp->pt_umask,
243*3cedbec3SEnji Cooper ptp->pt_reqmode, ptp->pt_mode, sb.st_mode);
244*3cedbec3SEnji Cooper }
245*3cedbec3SEnji Cooper
246*3cedbec3SEnji Cooper if (unlink(path) < 0)
247*3cedbec3SEnji Cooper err(-1, "fifo_permission_test: %s: unlink: %s",
248*3cedbec3SEnji Cooper testname, path);
249*3cedbec3SEnji Cooper }
250*3cedbec3SEnji Cooper umask(old_umask);
251*3cedbec3SEnji Cooper }
252*3cedbec3SEnji Cooper
253*3cedbec3SEnji Cooper int
main(void)254*3cedbec3SEnji Cooper main(void)
255*3cedbec3SEnji Cooper {
256*3cedbec3SEnji Cooper int i;
257*3cedbec3SEnji Cooper
258*3cedbec3SEnji Cooper if (geteuid() != 0)
259*3cedbec3SEnji Cooper errx(-1, "must be run as root");
260*3cedbec3SEnji Cooper
261*3cedbec3SEnji Cooper strcpy(temp_dir, "fifo_create.XXXXXXXXXXX");
262*3cedbec3SEnji Cooper if (mkdtemp(temp_dir) == NULL)
263*3cedbec3SEnji Cooper err(-1, "mkdtemp");
264*3cedbec3SEnji Cooper atexit(atexit_temp_dir);
265*3cedbec3SEnji Cooper
266*3cedbec3SEnji Cooper if (chdir(temp_dir) < 0)
267*3cedbec3SEnji Cooper err(-1, "chdir");
268*3cedbec3SEnji Cooper
269*3cedbec3SEnji Cooper /*
270*3cedbec3SEnji Cooper * Run each test twice, once with mknod(2) and a second time with
271*3cedbec3SEnji Cooper * mkfifo(2). Historically, BSD has not allowed mknod(2) to be used
272*3cedbec3SEnji Cooper * to create fifos, but the Single UNIX Specification requires it.
273*3cedbec3SEnji Cooper */
274*3cedbec3SEnji Cooper for (i = 0; i < 2; i++) {
275*3cedbec3SEnji Cooper fifo_create_test(i);
276*3cedbec3SEnji Cooper fifo_permission_test(i);
277*3cedbec3SEnji Cooper }
278*3cedbec3SEnji Cooper
279*3cedbec3SEnji Cooper return (0);
280*3cedbec3SEnji Cooper }
281