/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2020 Robert Mustacchi */ /* * Test different O_DIRECTORY open cases. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static uint_t odir_failures; static char odir_fpath[PATH_MAX]; static char odir_dpath[PATH_MAX]; static char odir_doorpath[PATH_MAX]; static char odir_enoent[PATH_MAX]; static char odir_udspath[PATH_MAX]; static int odir_did = -1; static int odir_uds = -1; static void odir_test_one(const char *test, const char *path, int flags, int err) { int fd = open(path, flags | O_DIRECTORY | O_RDONLY, 0644); if (fd >= 0) { (void) close(fd); if (err != 0) { odir_failures++; warnx("TEST FAILED: %s: opened %s, but expected error: " "%d", test, path, err); } } else { if (err == 0) { odir_failures++; warnx("TEST FAILED: %s: failed to open %s, error: %d", test, path, err); } else if (err != errno) { odir_failures++; warnx("TEST FAILED: %s: wrong error for path %s, " "found %d, expected %d", test, path, errno, err); } } } static void odir_door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, uint_t ndesc) { (void) door_return(NULL, 0, NULL, 0); } static boolean_t odir_setup(void) { int fd; struct stat st; struct sockaddr_un un; pid_t pid = getpid(); (void) snprintf(odir_fpath, sizeof (odir_fpath), "/tmp/odir.%d.file", pid); if ((fd = creat(odir_fpath, 0644)) < 0) { warn("failed to create temp file %s", odir_fpath); odir_fpath[0] = '\0'; return (B_FALSE); } (void) close(fd); (void) snprintf(odir_dpath, sizeof (odir_dpath), "/tmp/odir.%d.dir", pid); if (mkdir(odir_dpath, 0755) != 0) { warn("failed to create temp directory %s", odir_dpath); odir_dpath[0] = '\0'; return (B_FALSE); } odir_did = door_create(odir_door_server, NULL, 0); if (odir_did == -1) { warnx("failed to create door"); return (B_FALSE); } (void) snprintf(odir_doorpath, sizeof (odir_doorpath), "/tmp/odir.%d.door", pid); if ((fd = creat(odir_doorpath, 0644)) < 0) { warn("failed to create %s", odir_doorpath); odir_doorpath[0] = '\0'; return (B_FALSE); } (void) close(fd); if (fattach(odir_did, odir_doorpath) != 0) { warn("failed to attach door to %s", odir_doorpath); (void) unlink(odir_doorpath); odir_doorpath[0] = '\0'; return (B_FALSE); } (void) snprintf(odir_enoent, sizeof (odir_enoent), "/tmp/odir.%d.enoent", pid); if (stat(odir_enoent, &st) == 0) { warnx("somehow random file %s exists!", odir_enoent); } odir_uds = socket(PF_UNIX, SOCK_STREAM, 0); if (odir_uds == -1) { warn("failed to create UDS"); return (B_FALSE); } (void) snprintf(odir_udspath, sizeof (odir_udspath), "/tmp/odir.%d.uds", pid); (void) memset(&un, '\0', sizeof (un)); un.sun_family = AF_UNIX; if (strlcpy(un.sun_path, odir_udspath, sizeof (un.sun_path)) >= sizeof (un.sun_path)) { warnx("%s overflows AF_UNIX path", odir_udspath); odir_udspath[0] = '\0'; return (B_FALSE); } if (bind(odir_uds, (struct sockaddr *)&un, SUN_LEN(&un)) != 0) { warn("failed to bind %s", odir_udspath); odir_udspath[0] = '\0'; return (B_FALSE); } if (listen(odir_uds, 1) != 0) { warn("failed to listen on %s", odir_udspath); return (B_FALSE); } return (B_TRUE); } static void odir_verify_enoent(void) { struct stat st; if (stat(odir_enoent, &st) == 0) { warnx("TEST FAILED: %s was created", odir_enoent); odir_failures++; } else if (errno != ENOENT) { warn("TEST FAILED: stat on %s failed", odir_enoent); odir_failures++; } } static void odir_cleanup(void) { if (odir_udspath[0] != '\0') { if (unlink(odir_udspath) != 0) { warn("failed to unlink %s", odir_udspath); } } if (odir_uds != -1) { if (close(odir_uds) != 0) { warn("failed to close UDS"); } } if (odir_doorpath[0] != '\0') { if (fdetach(odir_doorpath) != 0) { warn("failed to detach door %s", odir_doorpath); } if (unlink(odir_doorpath) != 0) { warn("failed to unlink %s", odir_doorpath); } } if (odir_did != -1) { if (door_revoke(odir_did) != 0) { warn("failed to revoke door"); } } if (odir_dpath[0] != '\0') { if (rmdir(odir_dpath) != 0) { warn("failed to clean up %s", odir_dpath); } } if (odir_fpath[0] != '\0') { if (unlink(odir_fpath) != 0) { warn("failed to clean up %s", odir_fpath); } } } int main(void) { if (!odir_setup()) { odir_cleanup(); return (EXIT_FAILURE); } odir_test_one("regular file", odir_fpath, 0, ENOTDIR); odir_test_one("directory", odir_dpath, 0, 0); odir_test_one("character device", "/dev/null", 0, ENOTDIR); odir_test_one("door server", odir_doorpath, 0, ENOTDIR); odir_test_one("missing file", odir_enoent, 0, ENOENT); odir_test_one("UDS", odir_udspath, 0, ENOTDIR); odir_test_one("O_CREAT | O_DIRECTORY on a regular file", odir_fpath, O_CREAT, ENOTDIR); odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a regular file", odir_fpath, O_CREAT | O_EXCL, EINVAL); odir_test_one("O_CREAT | O_DIRECTORY on a directory", odir_dpath, O_CREAT, 0); odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a directory", odir_dpath, O_CREAT | O_EXCL, EINVAL); odir_test_one("O_CREAT | O_DIRECTORY on a missing file", odir_enoent, O_CREAT, ENOENT); odir_verify_enoent(); odir_test_one("O_CREAT | O_DIRECTORY | O_EXCL on a missing file", odir_enoent, O_CREAT | O_EXCL, EINVAL); odir_verify_enoent(); odir_cleanup(); if (odir_failures > 0) { warnx("%u tests failed", odir_failures); } return (odir_failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); }