1 /*- 2 * Copyright (c) 2005-2008 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/stat.h> 28 29 #include <err.h> 30 #include <errno.h> 31 #include <limits.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 /* 38 * Simple regression test for the creation and destruction of POSIX fifos in 39 * the file system name space. Using a specially created directory, create 40 * a fifo in it and check that the following properties are present, as 41 * specified in IEEE Std 1003.1, 2004 Edition: 42 * 43 * - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is 44 * created. 45 * 46 * - On an error, no fifo is created. (XXX: Not tested) 47 * 48 * - The mode bits on the fifo are a product of combining the umask and 49 * requested mode. 50 * 51 * - The fifo's owner will be the processes effective user ID. (XXX: Not 52 * tested) 53 * 54 * - The fifo's group will be the parent directory's group or the effective 55 * group ID of the process. For historical reasons, BSD prefers the group 56 * ID of the process, so we will generate an error if it's not that. (XXX: 57 * Not tested) 58 * 59 * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately, 60 * and st_ctime and st_mtime on the directory will be updated. (XXX: We 61 * test they are updated, not correct) 62 * 63 * - EEXIST is returned if the named file already exists. 64 * 65 * In addition, we check that we can unlink the fifo, and that if we do, it 66 * disappears. 67 * 68 * This test must run as root in order to usefully frob the process 69 * credential to test permission parts. 70 */ 71 72 /* 73 * All activity occurs within a temporary directory created early in the 74 * test. 75 */ 76 static char temp_dir[PATH_MAX]; 77 78 static void __unused 79 atexit_temp_dir(void) 80 { 81 82 rmdir(temp_dir); 83 } 84 85 /* 86 * Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo, 87 * that the time stamps on the directory are updated, that if we try twice we 88 * get EEXIST, and that we can unlink it. 89 */ 90 static void 91 fifo_create_test(int use_mkfifo) 92 { 93 struct stat old_dirsb, dirsb, fifosb; 94 const char *testname; 95 char path[] = "testfifo"; 96 int error; 97 98 if (use_mkfifo) 99 testname = "mkfifo"; 100 else 101 testname = "mknod"; 102 103 /* 104 * Sleep to make sure that the time stamp on the directory will be 105 * updated. 106 */ 107 if (stat(".", &old_dirsb) < 0) 108 err(-1, "basic_create_test: %s: stat: %s", testname, 109 temp_dir); 110 111 sleep(2); 112 113 if (use_mkfifo) { 114 if (mkfifo(path, 0600) < 0) 115 err(-1, "basic_create_test: %s: %s", testname, path); 116 } else { 117 if (mknod(path, S_IFIFO | 0600, 0) < 0) 118 err(-1, "basic_create_test: %s: %s", testname, path); 119 } 120 121 if (stat(path, &fifosb) < 0) { 122 error = errno; 123 (void)unlink(path); 124 errno = error; 125 err(-1, "basic_create_test: %s: stat: %s", testname, path); 126 } 127 128 if (!(S_ISFIFO(fifosb.st_mode))) { 129 (void)unlink(path); 130 errx(-1, "basic_create_test: %s produced non-fifo", 131 testname); 132 } 133 134 if (use_mkfifo) { 135 if (mkfifo(path, 0600) == 0) 136 errx(-1, "basic_create_test: dup %s succeeded", 137 testname); 138 } else { 139 if (mknod(path, S_IFIFO | 0600, 0) == 0) 140 errx(-1, "basic_create_test: dup %s succeeded", 141 testname); 142 } 143 144 if (errno != EEXIST) 145 err(-1, "basic_create_test: dup %s unexpected error", 146 testname); 147 148 if (stat(".", &dirsb) < 0) { 149 error = errno; 150 (void)unlink(path); 151 errno = error; 152 err(-1, "basic_create_test: %s: stat: %s", testname, 153 temp_dir); 154 } 155 156 if (old_dirsb.st_ctime == dirsb.st_ctime) { 157 (void)unlink(path); 158 errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == " 159 "dirsb.st_ctime", testname); 160 } 161 162 if (old_dirsb.st_mtime == dirsb.st_mtime) { 163 (void)unlink(path); 164 errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == " 165 "dirsb.st_mtime", testname); 166 } 167 168 if (unlink(path) < 0) 169 err(-1, "basic_create_test: %s: unlink: %s", testname, path); 170 171 if (stat(path, &fifosb) == 0) 172 errx(-1, "basic_create_test: %s: unlink failed to unlink", 173 testname); 174 if (errno != ENOENT) 175 err(-1, "basic_create_test: %s: unlink unexpected error", 176 testname); 177 } 178 179 /* 180 * Having determined that basic create/remove/etc functionality is present 181 * for fifos, now make sure that the umask, requested permissions, and 182 * resulting mode are handled properly. 183 */ 184 static const struct permission_test { 185 mode_t pt_umask; 186 mode_t pt_reqmode; 187 mode_t pt_mode; 188 } permission_test[] = { 189 {0000, 0, S_IFIFO}, 190 {0000, S_IRWXU, S_IFIFO | S_IRWXU}, 191 {0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG | 192 S_IRWXO }, 193 {0077, S_IRWXU, S_IFIFO | S_IRWXU}, 194 {0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU}, 195 }; 196 static const int permission_test_count = sizeof(permission_test) / 197 sizeof(struct permission_test); 198 199 static void 200 fifo_permission_test(int use_mkfifo) 201 { 202 const struct permission_test *ptp; 203 mode_t __unused old_umask; 204 char path[] = "testfifo"; 205 const char *testname; 206 struct stat sb; 207 int error, i; 208 209 if (use_mkfifo) 210 testname = "mkfifo"; 211 else 212 testname = "mknod"; 213 214 old_umask = umask(0022); 215 for (i = 0; i < permission_test_count; i++) { 216 ptp = &permission_test[i]; 217 218 umask(ptp->pt_umask); 219 if (use_mkfifo) { 220 if (mkfifo(path, ptp->pt_reqmode) < 0) 221 err(-1, "fifo_permission_test: %s: %08o " 222 "%08o %08o\n", testname, ptp->pt_umask, 223 ptp->pt_reqmode, ptp->pt_mode); 224 } else { 225 if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0) 226 err(-1, "fifo_permission_test: %s: %08o " 227 "%08o %08o\n", testname, ptp->pt_umask, 228 ptp->pt_reqmode, ptp->pt_mode); 229 } 230 231 if (stat(path, &sb) < 0) { 232 error = errno; 233 (void)unlink(path); 234 errno = error; 235 err(-1, "fifo_permission_test: %s: %s", testname, 236 path); 237 } 238 239 if (sb.st_mode != ptp->pt_mode) { 240 (void)unlink(path); 241 errx(-1, "fifo_permission_test: %s: %08o %08o %08o " 242 "got %08o", testname, ptp->pt_umask, 243 ptp->pt_reqmode, ptp->pt_mode, sb.st_mode); 244 } 245 246 if (unlink(path) < 0) 247 err(-1, "fifo_permission_test: %s: unlink: %s", 248 testname, path); 249 } 250 umask(old_umask); 251 } 252 253 int 254 main(void) 255 { 256 int i; 257 258 if (geteuid() != 0) 259 errx(-1, "must be run as root"); 260 261 strcpy(temp_dir, "fifo_create.XXXXXXXXXXX"); 262 if (mkdtemp(temp_dir) == NULL) 263 err(-1, "mkdtemp"); 264 atexit(atexit_temp_dir); 265 266 if (chdir(temp_dir) < 0) 267 err(-1, "chdir"); 268 269 /* 270 * Run each test twice, once with mknod(2) and a second time with 271 * mkfifo(2). Historically, BSD has not allowed mknod(2) to be used 272 * to create fifos, but the Single UNIX Specification requires it. 273 */ 274 for (i = 0; i < 2; i++) { 275 fifo_create_test(i); 276 fifo_permission_test(i); 277 } 278 279 return (0); 280 } 281