1*69c811abSRobert Mustacchi /*
2*69c811abSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*69c811abSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*69c811abSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*69c811abSRobert Mustacchi  * 1.0 of the CDDL.
6*69c811abSRobert Mustacchi  *
7*69c811abSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*69c811abSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*69c811abSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*69c811abSRobert Mustacchi  */
11*69c811abSRobert Mustacchi 
12*69c811abSRobert Mustacchi /*
13*69c811abSRobert Mustacchi  * Copyright 2020 Robert Mustacchi
14*69c811abSRobert Mustacchi  */
15*69c811abSRobert Mustacchi 
16*69c811abSRobert Mustacchi /*
17*69c811abSRobert Mustacchi  * Test different O_DIRECTORY open cases.
18*69c811abSRobert Mustacchi  */
19*69c811abSRobert Mustacchi 
20*69c811abSRobert Mustacchi #include <sys/types.h>
21*69c811abSRobert Mustacchi #include <sys/stat.h>
22*69c811abSRobert Mustacchi #include <fcntl.h>
23*69c811abSRobert Mustacchi #include <stdio.h>
24*69c811abSRobert Mustacchi #include <errno.h>
25*69c811abSRobert Mustacchi #include <unistd.h>
26*69c811abSRobert Mustacchi #include <err.h>
27*69c811abSRobert Mustacchi #include <string.h>
28*69c811abSRobert Mustacchi #include <stdlib.h>
29*69c811abSRobert Mustacchi #include <limits.h>
30*69c811abSRobert Mustacchi #include <door.h>
31*69c811abSRobert Mustacchi #include <stropts.h>
32*69c811abSRobert Mustacchi #include <sys/socket.h>
33*69c811abSRobert Mustacchi 
34*69c811abSRobert Mustacchi static uint_t odir_failures;
35*69c811abSRobert Mustacchi static char odir_fpath[PATH_MAX];
36*69c811abSRobert Mustacchi static char odir_dpath[PATH_MAX];
37*69c811abSRobert Mustacchi static char odir_doorpath[PATH_MAX];
38*69c811abSRobert Mustacchi static char odir_enoent[PATH_MAX];
39*69c811abSRobert Mustacchi static char odir_udspath[PATH_MAX];
40*69c811abSRobert Mustacchi static int odir_did = -1;
41*69c811abSRobert Mustacchi static int odir_uds = -1;
42*69c811abSRobert Mustacchi 
43*69c811abSRobert Mustacchi static void
44*69c811abSRobert Mustacchi odir_test_one(const char *test, const char *path, int flags, int err)
45*69c811abSRobert Mustacchi {
46*69c811abSRobert Mustacchi 	int fd = open(path, flags | O_DIRECTORY | O_RDONLY, 0644);
47*69c811abSRobert Mustacchi 	if (fd >= 0) {
48*69c811abSRobert Mustacchi 		(void) close(fd);
49*69c811abSRobert Mustacchi 		if (err != 0) {
50*69c811abSRobert Mustacchi 			odir_failures++;
51*69c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: opened %s, but expected error: "
52*69c811abSRobert Mustacchi 			    "%d", test, path, err);
53*69c811abSRobert Mustacchi 		}
54*69c811abSRobert Mustacchi 	} else {
55*69c811abSRobert Mustacchi 		if (err == 0) {
56*69c811abSRobert Mustacchi 			odir_failures++;
57*69c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: failed to open %s, error: %d",
58*69c811abSRobert Mustacchi 			    test, path, err);
59*69c811abSRobert Mustacchi 		} else if (err != errno) {
60*69c811abSRobert Mustacchi 			odir_failures++;
61*69c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: wrong error for path %s, "
62*69c811abSRobert Mustacchi 			    "found %d, expected %d", test, path, errno, err);
63*69c811abSRobert Mustacchi 		}
64*69c811abSRobert Mustacchi 	}
65*69c811abSRobert Mustacchi }
66*69c811abSRobert Mustacchi 
67*69c811abSRobert Mustacchi static void
68*69c811abSRobert Mustacchi odir_door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
69*69c811abSRobert Mustacchi     uint_t ndesc)
70*69c811abSRobert Mustacchi {
71*69c811abSRobert Mustacchi 	(void) door_return(NULL, 0, NULL, 0);
72*69c811abSRobert Mustacchi }
73*69c811abSRobert Mustacchi 
74*69c811abSRobert Mustacchi static boolean_t
75*69c811abSRobert Mustacchi odir_setup(void)
76*69c811abSRobert Mustacchi {
77*69c811abSRobert Mustacchi 	int fd;
78*69c811abSRobert Mustacchi 	struct stat st;
79*69c811abSRobert Mustacchi 	struct sockaddr_un un;
80*69c811abSRobert Mustacchi 	pid_t pid = getpid();
81*69c811abSRobert Mustacchi 
82*69c811abSRobert Mustacchi 	(void) snprintf(odir_fpath, sizeof (odir_fpath),
83*69c811abSRobert Mustacchi 	    "/tmp/odir.%d.file", pid);
84*69c811abSRobert Mustacchi 	if ((fd = creat(odir_fpath, 0644)) < 0) {
85*69c811abSRobert Mustacchi 		warn("failed to create temp file %s", odir_fpath);
86*69c811abSRobert Mustacchi 		odir_fpath[0] = '\0';
87*69c811abSRobert Mustacchi 		return (B_FALSE);
88*69c811abSRobert Mustacchi 	}
89*69c811abSRobert Mustacchi 	(void) close(fd);
90*69c811abSRobert Mustacchi 
91*69c811abSRobert Mustacchi 	(void) snprintf(odir_dpath, sizeof (odir_dpath),
92*69c811abSRobert Mustacchi 	    "/tmp/odir.%d.dir", pid);
93*69c811abSRobert Mustacchi 	if (mkdir(odir_dpath, 0755) != 0) {
94*69c811abSRobert Mustacchi 		warn("failed to create temp directory %s", odir_dpath);
95*69c811abSRobert Mustacchi 		odir_dpath[0] = '\0';
96*69c811abSRobert Mustacchi 		return (B_FALSE);
97*69c811abSRobert Mustacchi 	}
98*69c811abSRobert Mustacchi 
99*69c811abSRobert Mustacchi 	odir_did = door_create(odir_door_server, NULL, 0);
100*69c811abSRobert Mustacchi 	if (odir_did == -1) {
101*69c811abSRobert Mustacchi 		warnx("failed to create door");
102*69c811abSRobert Mustacchi 		return (B_FALSE);
103*69c811abSRobert Mustacchi 	}
104*69c811abSRobert Mustacchi 	(void) snprintf(odir_doorpath, sizeof (odir_doorpath),
105*69c811abSRobert Mustacchi 	    "/tmp/odir.%d.door", pid);
106*69c811abSRobert Mustacchi 	if ((fd = creat(odir_doorpath, 0644)) < 0) {
107*69c811abSRobert Mustacchi 		warn("failed to create %s", odir_doorpath);
108*69c811abSRobert Mustacchi 		odir_doorpath[0] = '\0';
109*69c811abSRobert Mustacchi 		return (B_FALSE);
110*69c811abSRobert Mustacchi 	}
111*69c811abSRobert Mustacchi 	(void) close(fd);
112*69c811abSRobert Mustacchi 	if (fattach(odir_did, odir_doorpath) != 0) {
113*69c811abSRobert Mustacchi 		warn("failed to attach door to %s", odir_doorpath);
114*69c811abSRobert Mustacchi 		(void) unlink(odir_doorpath);
115*69c811abSRobert Mustacchi 		odir_doorpath[0] = '\0';
116*69c811abSRobert Mustacchi 		return (B_FALSE);
117*69c811abSRobert Mustacchi 	}
118*69c811abSRobert Mustacchi 
119*69c811abSRobert Mustacchi 	(void) snprintf(odir_enoent, sizeof (odir_enoent),
120*69c811abSRobert Mustacchi 	    "/tmp/odir.%d.enoent", pid);
121*69c811abSRobert Mustacchi 	if (stat(odir_enoent, &st) == 0) {
122*69c811abSRobert Mustacchi 		warnx("somehow random file %s exists!", odir_enoent);
123*69c811abSRobert Mustacchi 	}
124*69c811abSRobert Mustacchi 
125*69c811abSRobert Mustacchi 	odir_uds = socket(PF_UNIX, SOCK_STREAM, 0);
126*69c811abSRobert Mustacchi 	if (odir_uds == -1) {
127*69c811abSRobert Mustacchi 		warn("failed to create UDS");
128*69c811abSRobert Mustacchi 		return (B_FALSE);
129*69c811abSRobert Mustacchi 	}
130*69c811abSRobert Mustacchi 	(void) snprintf(odir_udspath, sizeof (odir_udspath),
131*69c811abSRobert Mustacchi 	    "/tmp/odir.%d.uds", pid);
132*69c811abSRobert Mustacchi 	(void) memset(&un, '\0', sizeof (un));
133*69c811abSRobert Mustacchi 	un.sun_family = AF_UNIX;
134*69c811abSRobert Mustacchi 	if (strlcpy(un.sun_path, odir_udspath, sizeof (un.sun_path)) >=
135*69c811abSRobert Mustacchi 	    sizeof (un.sun_path)) {
136*69c811abSRobert Mustacchi 		warnx("%s overflows AF_UNIX path", odir_udspath);
137*69c811abSRobert Mustacchi 		odir_udspath[0] = '\0';
138*69c811abSRobert Mustacchi 		return (B_FALSE);
139*69c811abSRobert Mustacchi 	}
140*69c811abSRobert Mustacchi 
141*69c811abSRobert Mustacchi 	if (bind(odir_uds, (struct sockaddr *)&un, SUN_LEN(&un)) != 0) {
142*69c811abSRobert Mustacchi 		warn("failed to bind %s", odir_udspath);
143*69c811abSRobert Mustacchi 		odir_udspath[0] = '\0';
144*69c811abSRobert Mustacchi 		return (B_FALSE);
145*69c811abSRobert Mustacchi 	}
146*69c811abSRobert Mustacchi 
147*69c811abSRobert Mustacchi 	if (listen(odir_uds, 1) != 0) {
148*69c811abSRobert Mustacchi 		warn("failed to listen on %s", odir_udspath);
149*69c811abSRobert Mustacchi 		return (B_FALSE);
150*69c811abSRobert Mustacchi 	}
151*69c811abSRobert Mustacchi 
152*69c811abSRobert Mustacchi 	return (B_TRUE);
153*69c811abSRobert Mustacchi }
154*69c811abSRobert Mustacchi 
155*69c811abSRobert Mustacchi static void
156*69c811abSRobert Mustacchi odir_verify_enoent(void)
157*69c811abSRobert Mustacchi {
158*69c811abSRobert Mustacchi 	struct stat st;
159*69c811abSRobert Mustacchi 
160*69c811abSRobert Mustacchi 	if (stat(odir_enoent, &st) == 0) {
161*69c811abSRobert Mustacchi 		warnx("TEST FAILED: %s was created", odir_enoent);
162*69c811abSRobert Mustacchi 		odir_failures++;
163*69c811abSRobert Mustacchi 	} else if (errno != ENOENT) {
164*69c811abSRobert Mustacchi 		warn("TEST FAILED: stat on %s failed", odir_enoent);
165*69c811abSRobert Mustacchi 		odir_failures++;
166*69c811abSRobert Mustacchi 	}
167*69c811abSRobert Mustacchi }
168*69c811abSRobert Mustacchi 
169*69c811abSRobert Mustacchi static void
170*69c811abSRobert Mustacchi odir_cleanup(void)
171*69c811abSRobert Mustacchi {
172*69c811abSRobert Mustacchi 	if (odir_udspath[0] != '\0') {
173*69c811abSRobert Mustacchi 		if (unlink(odir_udspath) != 0) {
174*69c811abSRobert Mustacchi 			warn("failed to unlink %s", odir_udspath);
175*69c811abSRobert Mustacchi 		}
176*69c811abSRobert Mustacchi 	}
177*69c811abSRobert Mustacchi 
178*69c811abSRobert Mustacchi 	if (odir_uds != -1) {
179*69c811abSRobert Mustacchi 		if (close(odir_uds) != 0) {
180*69c811abSRobert Mustacchi 			warn("failed to close UDS");
181*69c811abSRobert Mustacchi 		}
182*69c811abSRobert Mustacchi 	}
183*69c811abSRobert Mustacchi 
184*69c811abSRobert Mustacchi 	if (odir_doorpath[0] != '\0') {
185*69c811abSRobert Mustacchi 		if (fdetach(odir_doorpath) != 0) {
186*69c811abSRobert Mustacchi 			warn("failed to detach door %s", odir_doorpath);
187*69c811abSRobert Mustacchi 		}
188*69c811abSRobert Mustacchi 	}
189*69c811abSRobert Mustacchi 
190*69c811abSRobert Mustacchi 	if (odir_did != -1) {
191*69c811abSRobert Mustacchi 		if (door_revoke(odir_did) != 0) {
192*69c811abSRobert Mustacchi 			warn("failed to revoke door");
193*69c811abSRobert Mustacchi 		}
194*69c811abSRobert Mustacchi 	}
195*69c811abSRobert Mustacchi 
196*69c811abSRobert Mustacchi 	if (odir_dpath[0] != '\0') {
197*69c811abSRobert Mustacchi 		if (rmdir(odir_dpath) != 0) {
198*69c811abSRobert Mustacchi 			warn("failed to clean up %s", odir_dpath);
199*69c811abSRobert Mustacchi 		}
200*69c811abSRobert Mustacchi 	}
201*69c811abSRobert Mustacchi 
202*69c811abSRobert Mustacchi 	if (odir_fpath[0] != '\0') {
203*69c811abSRobert Mustacchi 		if (unlink(odir_fpath) != 0) {
204*69c811abSRobert Mustacchi 			warn("failed to clean up %s", odir_fpath);
205*69c811abSRobert Mustacchi 		}
206*69c811abSRobert Mustacchi 	}
207*69c811abSRobert Mustacchi }
208*69c811abSRobert Mustacchi 
209*69c811abSRobert Mustacchi int
210*69c811abSRobert Mustacchi main(void)
211*69c811abSRobert Mustacchi {
212*69c811abSRobert Mustacchi 	if (!odir_setup()) {
213*69c811abSRobert Mustacchi 		odir_cleanup();
214*69c811abSRobert Mustacchi 		return (EXIT_FAILURE);
215*69c811abSRobert Mustacchi 	}
216*69c811abSRobert Mustacchi 
217*69c811abSRobert Mustacchi 	odir_test_one("regular file", odir_fpath, 0, ENOTDIR);
218*69c811abSRobert Mustacchi 	odir_test_one("directory", odir_dpath, 0, 0);
219*69c811abSRobert Mustacchi 	odir_test_one("character device", "/dev/null", 0, ENOTDIR);
220*69c811abSRobert Mustacchi 	odir_test_one("door server", odir_doorpath, 0, ENOTDIR);
221*69c811abSRobert Mustacchi 	odir_test_one("missing file", odir_enoent, 0, ENOENT);
222*69c811abSRobert Mustacchi 	odir_test_one("UDS", odir_udspath, 0, ENOTDIR);
223*69c811abSRobert Mustacchi 
224*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a regular file", odir_fpath,
225*69c811abSRobert Mustacchi 	    O_CREAT, ENOTDIR);
226*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a regular file",
227*69c811abSRobert Mustacchi 	    odir_fpath, O_CREAT | O_EXCL, EINVAL);
228*69c811abSRobert Mustacchi 
229*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a directory", odir_dpath,
230*69c811abSRobert Mustacchi 	    O_CREAT, 0);
231*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a directory",
232*69c811abSRobert Mustacchi 	    odir_dpath, O_CREAT | O_EXCL, EINVAL);
233*69c811abSRobert Mustacchi 
234*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a missing file", odir_enoent,
235*69c811abSRobert Mustacchi 	    O_CREAT, ENOENT);
236*69c811abSRobert Mustacchi 	odir_verify_enoent();
237*69c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a missing file",
238*69c811abSRobert Mustacchi 	    odir_enoent, O_CREAT | O_EXCL, EINVAL);
239*69c811abSRobert Mustacchi 	odir_verify_enoent();
240*69c811abSRobert Mustacchi 
241*69c811abSRobert Mustacchi 	odir_cleanup();
242*69c811abSRobert Mustacchi 	if (odir_failures > 0) {
243*69c811abSRobert Mustacchi 		warnx("%u tests failed", odir_failures);
244*69c811abSRobert Mustacchi 	}
245*69c811abSRobert Mustacchi 
246*69c811abSRobert Mustacchi 	return (odir_failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
247*69c811abSRobert Mustacchi }
248