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