169c811abSRobert Mustacchi /*
269c811abSRobert Mustacchi  * This file and its contents are supplied under the terms of the
369c811abSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
469c811abSRobert Mustacchi  * You may only use this file in accordance with the terms of version
569c811abSRobert Mustacchi  * 1.0 of the CDDL.
669c811abSRobert Mustacchi  *
769c811abSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
869c811abSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
969c811abSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
1069c811abSRobert Mustacchi  */
1169c811abSRobert Mustacchi 
1269c811abSRobert Mustacchi /*
1369c811abSRobert Mustacchi  * Copyright 2020 Robert Mustacchi
1469c811abSRobert Mustacchi  */
1569c811abSRobert Mustacchi 
1669c811abSRobert Mustacchi /*
1769c811abSRobert Mustacchi  * Test different O_DIRECTORY open cases.
1869c811abSRobert Mustacchi  */
1969c811abSRobert Mustacchi 
2069c811abSRobert Mustacchi #include <sys/types.h>
2169c811abSRobert Mustacchi #include <sys/stat.h>
2269c811abSRobert Mustacchi #include <fcntl.h>
2369c811abSRobert Mustacchi #include <stdio.h>
2469c811abSRobert Mustacchi #include <errno.h>
2569c811abSRobert Mustacchi #include <unistd.h>
2669c811abSRobert Mustacchi #include <err.h>
2769c811abSRobert Mustacchi #include <string.h>
2869c811abSRobert Mustacchi #include <stdlib.h>
2969c811abSRobert Mustacchi #include <limits.h>
3069c811abSRobert Mustacchi #include <door.h>
3169c811abSRobert Mustacchi #include <stropts.h>
3269c811abSRobert Mustacchi #include <sys/socket.h>
3369c811abSRobert Mustacchi 
3469c811abSRobert Mustacchi static uint_t odir_failures;
3569c811abSRobert Mustacchi static char odir_fpath[PATH_MAX];
3669c811abSRobert Mustacchi static char odir_dpath[PATH_MAX];
3769c811abSRobert Mustacchi static char odir_doorpath[PATH_MAX];
3869c811abSRobert Mustacchi static char odir_enoent[PATH_MAX];
3969c811abSRobert Mustacchi static char odir_udspath[PATH_MAX];
4069c811abSRobert Mustacchi static int odir_did = -1;
4169c811abSRobert Mustacchi static int odir_uds = -1;
4269c811abSRobert Mustacchi 
4369c811abSRobert Mustacchi static void
odir_test_one(const char * test,const char * path,int flags,int err)4469c811abSRobert Mustacchi odir_test_one(const char *test, const char *path, int flags, int err)
4569c811abSRobert Mustacchi {
4669c811abSRobert Mustacchi 	int fd = open(path, flags | O_DIRECTORY | O_RDONLY, 0644);
4769c811abSRobert Mustacchi 	if (fd >= 0) {
4869c811abSRobert Mustacchi 		(void) close(fd);
4969c811abSRobert Mustacchi 		if (err != 0) {
5069c811abSRobert Mustacchi 			odir_failures++;
5169c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: opened %s, but expected error: "
5269c811abSRobert Mustacchi 			    "%d", test, path, err);
5369c811abSRobert Mustacchi 		}
5469c811abSRobert Mustacchi 	} else {
5569c811abSRobert Mustacchi 		if (err == 0) {
5669c811abSRobert Mustacchi 			odir_failures++;
5769c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: failed to open %s, error: %d",
5869c811abSRobert Mustacchi 			    test, path, err);
5969c811abSRobert Mustacchi 		} else if (err != errno) {
6069c811abSRobert Mustacchi 			odir_failures++;
6169c811abSRobert Mustacchi 			warnx("TEST FAILED: %s: wrong error for path %s, "
6269c811abSRobert Mustacchi 			    "found %d, expected %d", test, path, errno, err);
6369c811abSRobert Mustacchi 		}
6469c811abSRobert Mustacchi 	}
6569c811abSRobert Mustacchi }
6669c811abSRobert Mustacchi 
6769c811abSRobert Mustacchi static void
odir_door_server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t ndesc)6869c811abSRobert Mustacchi odir_door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
6969c811abSRobert Mustacchi     uint_t ndesc)
7069c811abSRobert Mustacchi {
7169c811abSRobert Mustacchi 	(void) door_return(NULL, 0, NULL, 0);
7269c811abSRobert Mustacchi }
7369c811abSRobert Mustacchi 
7469c811abSRobert Mustacchi static boolean_t
odir_setup(void)7569c811abSRobert Mustacchi odir_setup(void)
7669c811abSRobert Mustacchi {
7769c811abSRobert Mustacchi 	int fd;
7869c811abSRobert Mustacchi 	struct stat st;
7969c811abSRobert Mustacchi 	struct sockaddr_un un;
8069c811abSRobert Mustacchi 	pid_t pid = getpid();
8169c811abSRobert Mustacchi 
8269c811abSRobert Mustacchi 	(void) snprintf(odir_fpath, sizeof (odir_fpath),
8369c811abSRobert Mustacchi 	    "/tmp/odir.%d.file", pid);
8469c811abSRobert Mustacchi 	if ((fd = creat(odir_fpath, 0644)) < 0) {
8569c811abSRobert Mustacchi 		warn("failed to create temp file %s", odir_fpath);
8669c811abSRobert Mustacchi 		odir_fpath[0] = '\0';
8769c811abSRobert Mustacchi 		return (B_FALSE);
8869c811abSRobert Mustacchi 	}
8969c811abSRobert Mustacchi 	(void) close(fd);
9069c811abSRobert Mustacchi 
9169c811abSRobert Mustacchi 	(void) snprintf(odir_dpath, sizeof (odir_dpath),
9269c811abSRobert Mustacchi 	    "/tmp/odir.%d.dir", pid);
9369c811abSRobert Mustacchi 	if (mkdir(odir_dpath, 0755) != 0) {
9469c811abSRobert Mustacchi 		warn("failed to create temp directory %s", odir_dpath);
9569c811abSRobert Mustacchi 		odir_dpath[0] = '\0';
9669c811abSRobert Mustacchi 		return (B_FALSE);
9769c811abSRobert Mustacchi 	}
9869c811abSRobert Mustacchi 
9969c811abSRobert Mustacchi 	odir_did = door_create(odir_door_server, NULL, 0);
10069c811abSRobert Mustacchi 	if (odir_did == -1) {
10169c811abSRobert Mustacchi 		warnx("failed to create door");
10269c811abSRobert Mustacchi 		return (B_FALSE);
10369c811abSRobert Mustacchi 	}
10469c811abSRobert Mustacchi 	(void) snprintf(odir_doorpath, sizeof (odir_doorpath),
10569c811abSRobert Mustacchi 	    "/tmp/odir.%d.door", pid);
10669c811abSRobert Mustacchi 	if ((fd = creat(odir_doorpath, 0644)) < 0) {
10769c811abSRobert Mustacchi 		warn("failed to create %s", odir_doorpath);
10869c811abSRobert Mustacchi 		odir_doorpath[0] = '\0';
10969c811abSRobert Mustacchi 		return (B_FALSE);
11069c811abSRobert Mustacchi 	}
11169c811abSRobert Mustacchi 	(void) close(fd);
11269c811abSRobert Mustacchi 	if (fattach(odir_did, odir_doorpath) != 0) {
11369c811abSRobert Mustacchi 		warn("failed to attach door to %s", odir_doorpath);
11469c811abSRobert Mustacchi 		(void) unlink(odir_doorpath);
11569c811abSRobert Mustacchi 		odir_doorpath[0] = '\0';
11669c811abSRobert Mustacchi 		return (B_FALSE);
11769c811abSRobert Mustacchi 	}
11869c811abSRobert Mustacchi 
11969c811abSRobert Mustacchi 	(void) snprintf(odir_enoent, sizeof (odir_enoent),
12069c811abSRobert Mustacchi 	    "/tmp/odir.%d.enoent", pid);
12169c811abSRobert Mustacchi 	if (stat(odir_enoent, &st) == 0) {
12269c811abSRobert Mustacchi 		warnx("somehow random file %s exists!", odir_enoent);
12369c811abSRobert Mustacchi 	}
12469c811abSRobert Mustacchi 
12569c811abSRobert Mustacchi 	odir_uds = socket(PF_UNIX, SOCK_STREAM, 0);
12669c811abSRobert Mustacchi 	if (odir_uds == -1) {
12769c811abSRobert Mustacchi 		warn("failed to create UDS");
12869c811abSRobert Mustacchi 		return (B_FALSE);
12969c811abSRobert Mustacchi 	}
13069c811abSRobert Mustacchi 	(void) snprintf(odir_udspath, sizeof (odir_udspath),
13169c811abSRobert Mustacchi 	    "/tmp/odir.%d.uds", pid);
13269c811abSRobert Mustacchi 	(void) memset(&un, '\0', sizeof (un));
13369c811abSRobert Mustacchi 	un.sun_family = AF_UNIX;
13469c811abSRobert Mustacchi 	if (strlcpy(un.sun_path, odir_udspath, sizeof (un.sun_path)) >=
13569c811abSRobert Mustacchi 	    sizeof (un.sun_path)) {
13669c811abSRobert Mustacchi 		warnx("%s overflows AF_UNIX path", odir_udspath);
13769c811abSRobert Mustacchi 		odir_udspath[0] = '\0';
13869c811abSRobert Mustacchi 		return (B_FALSE);
13969c811abSRobert Mustacchi 	}
14069c811abSRobert Mustacchi 
14169c811abSRobert Mustacchi 	if (bind(odir_uds, (struct sockaddr *)&un, SUN_LEN(&un)) != 0) {
14269c811abSRobert Mustacchi 		warn("failed to bind %s", odir_udspath);
14369c811abSRobert Mustacchi 		odir_udspath[0] = '\0';
14469c811abSRobert Mustacchi 		return (B_FALSE);
14569c811abSRobert Mustacchi 	}
14669c811abSRobert Mustacchi 
14769c811abSRobert Mustacchi 	if (listen(odir_uds, 1) != 0) {
14869c811abSRobert Mustacchi 		warn("failed to listen on %s", odir_udspath);
14969c811abSRobert Mustacchi 		return (B_FALSE);
15069c811abSRobert Mustacchi 	}
15169c811abSRobert Mustacchi 
15269c811abSRobert Mustacchi 	return (B_TRUE);
15369c811abSRobert Mustacchi }
15469c811abSRobert Mustacchi 
15569c811abSRobert Mustacchi static void
odir_verify_enoent(void)15669c811abSRobert Mustacchi odir_verify_enoent(void)
15769c811abSRobert Mustacchi {
15869c811abSRobert Mustacchi 	struct stat st;
15969c811abSRobert Mustacchi 
16069c811abSRobert Mustacchi 	if (stat(odir_enoent, &st) == 0) {
16169c811abSRobert Mustacchi 		warnx("TEST FAILED: %s was created", odir_enoent);
16269c811abSRobert Mustacchi 		odir_failures++;
16369c811abSRobert Mustacchi 	} else if (errno != ENOENT) {
16469c811abSRobert Mustacchi 		warn("TEST FAILED: stat on %s failed", odir_enoent);
16569c811abSRobert Mustacchi 		odir_failures++;
16669c811abSRobert Mustacchi 	}
16769c811abSRobert Mustacchi }
16869c811abSRobert Mustacchi 
16969c811abSRobert Mustacchi static void
odir_cleanup(void)17069c811abSRobert Mustacchi odir_cleanup(void)
17169c811abSRobert Mustacchi {
17269c811abSRobert Mustacchi 	if (odir_udspath[0] != '\0') {
17369c811abSRobert Mustacchi 		if (unlink(odir_udspath) != 0) {
17469c811abSRobert Mustacchi 			warn("failed to unlink %s", odir_udspath);
17569c811abSRobert Mustacchi 		}
17669c811abSRobert Mustacchi 	}
17769c811abSRobert Mustacchi 
17869c811abSRobert Mustacchi 	if (odir_uds != -1) {
17969c811abSRobert Mustacchi 		if (close(odir_uds) != 0) {
18069c811abSRobert Mustacchi 			warn("failed to close UDS");
18169c811abSRobert Mustacchi 		}
18269c811abSRobert Mustacchi 	}
18369c811abSRobert Mustacchi 
18469c811abSRobert Mustacchi 	if (odir_doorpath[0] != '\0') {
18569c811abSRobert Mustacchi 		if (fdetach(odir_doorpath) != 0) {
18669c811abSRobert Mustacchi 			warn("failed to detach door %s", odir_doorpath);
18769c811abSRobert Mustacchi 		}
188*b36afad7SRobert Mustacchi 
189*b36afad7SRobert Mustacchi 		if (unlink(odir_doorpath) != 0) {
190*b36afad7SRobert Mustacchi 			warn("failed to unlink %s", odir_doorpath);
191*b36afad7SRobert Mustacchi 		}
19269c811abSRobert Mustacchi 	}
19369c811abSRobert Mustacchi 
19469c811abSRobert Mustacchi 	if (odir_did != -1) {
19569c811abSRobert Mustacchi 		if (door_revoke(odir_did) != 0) {
19669c811abSRobert Mustacchi 			warn("failed to revoke door");
19769c811abSRobert Mustacchi 		}
19869c811abSRobert Mustacchi 	}
19969c811abSRobert Mustacchi 
20069c811abSRobert Mustacchi 	if (odir_dpath[0] != '\0') {
20169c811abSRobert Mustacchi 		if (rmdir(odir_dpath) != 0) {
20269c811abSRobert Mustacchi 			warn("failed to clean up %s", odir_dpath);
20369c811abSRobert Mustacchi 		}
20469c811abSRobert Mustacchi 	}
20569c811abSRobert Mustacchi 
20669c811abSRobert Mustacchi 	if (odir_fpath[0] != '\0') {
20769c811abSRobert Mustacchi 		if (unlink(odir_fpath) != 0) {
20869c811abSRobert Mustacchi 			warn("failed to clean up %s", odir_fpath);
20969c811abSRobert Mustacchi 		}
21069c811abSRobert Mustacchi 	}
21169c811abSRobert Mustacchi }
21269c811abSRobert Mustacchi 
21369c811abSRobert Mustacchi int
main(void)21469c811abSRobert Mustacchi main(void)
21569c811abSRobert Mustacchi {
21669c811abSRobert Mustacchi 	if (!odir_setup()) {
21769c811abSRobert Mustacchi 		odir_cleanup();
21869c811abSRobert Mustacchi 		return (EXIT_FAILURE);
21969c811abSRobert Mustacchi 	}
22069c811abSRobert Mustacchi 
22169c811abSRobert Mustacchi 	odir_test_one("regular file", odir_fpath, 0, ENOTDIR);
22269c811abSRobert Mustacchi 	odir_test_one("directory", odir_dpath, 0, 0);
22369c811abSRobert Mustacchi 	odir_test_one("character device", "/dev/null", 0, ENOTDIR);
22469c811abSRobert Mustacchi 	odir_test_one("door server", odir_doorpath, 0, ENOTDIR);
22569c811abSRobert Mustacchi 	odir_test_one("missing file", odir_enoent, 0, ENOENT);
22669c811abSRobert Mustacchi 	odir_test_one("UDS", odir_udspath, 0, ENOTDIR);
22769c811abSRobert Mustacchi 
22869c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a regular file", odir_fpath,
22969c811abSRobert Mustacchi 	    O_CREAT, ENOTDIR);
23069c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a regular file",
23169c811abSRobert Mustacchi 	    odir_fpath, O_CREAT | O_EXCL, EINVAL);
23269c811abSRobert Mustacchi 
23369c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a directory", odir_dpath,
23469c811abSRobert Mustacchi 	    O_CREAT, 0);
23569c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a directory",
23669c811abSRobert Mustacchi 	    odir_dpath, O_CREAT | O_EXCL, EINVAL);
23769c811abSRobert Mustacchi 
23869c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY on a missing file", odir_enoent,
23969c811abSRobert Mustacchi 	    O_CREAT, ENOENT);
24069c811abSRobert Mustacchi 	odir_verify_enoent();
24169c811abSRobert Mustacchi 	odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a missing file",
24269c811abSRobert Mustacchi 	    odir_enoent, O_CREAT | O_EXCL, EINVAL);
24369c811abSRobert Mustacchi 	odir_verify_enoent();
24469c811abSRobert Mustacchi 
24569c811abSRobert Mustacchi 	odir_cleanup();
24669c811abSRobert Mustacchi 	if (odir_failures > 0) {
24769c811abSRobert Mustacchi 		warnx("%u tests failed", odir_failures);
24869c811abSRobert Mustacchi 	}
24969c811abSRobert Mustacchi 
25069c811abSRobert Mustacchi 	return (odir_failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
25169c811abSRobert Mustacchi }