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 * $FreeBSD$ 27 */ 28 29 #include <sys/stat.h> 30 31 #include <err.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 /* 40 * Simple regression test for the creation and destruction of POSIX fifos in 41 * the file system name space. Using a specially created directory, create 42 * a fifo in it and check that the following properties are present, as 43 * specified in IEEE Std 1003.1, 2004 Edition: 44 * 45 * - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is 46 * created. 47 * 48 * - On an error, no fifo is created. (XXX: Not tested) 49 * 50 * - The mode bits on the fifo are a product of combining the umask and 51 * requested mode. 52 * 53 * - The fifo's owner will be the processes effective user ID. (XXX: Not 54 * tested) 55 * 56 * - The fifo's group will be the parent directory's group or the effective 57 * group ID of the process. For historical reasons, BSD prefers the group 58 * ID of the process, so we will generate an error if it's not that. (XXX: 59 * Not tested) 60 * 61 * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately, 62 * and st_ctime and st_mtime on the directory will be updated. (XXX: We 63 * test they are updated, not correct) 64 * 65 * - EEXIST is returned if the named file already exists. 66 * 67 * In addition, we check that we can unlink the fifo, and that if we do, it 68 * disappears. 69 * 70 * This test must run as root in order to usefully frob the process 71 * credential to test permission parts. 72 */ 73 74 /* 75 * All activity occurs within a temporary directory created early in the 76 * test. 77 */ 78 static char temp_dir[PATH_MAX]; 79 80 static void __unused 81 atexit_temp_dir(void) 82 { 83 84 rmdir(temp_dir); 85 } 86 87 /* 88 * Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo, 89 * that the time stamps on the directory are updated, that if we try twice we 90 * get EEXIST, and that we can unlink it. 91 */ 92 static void 93 fifo_create_test(int use_mkfifo) 94 { 95 struct stat old_dirsb, dirsb, fifosb; 96 const char *testname; 97 char path[] = "testfifo"; 98 int error; 99 100 if (use_mkfifo) 101 testname = "mkfifo"; 102 else 103 testname = "mknod"; 104 105 /* 106 * Sleep to make sure that the time stamp on the directory will be 107 * updated. 108 */ 109 if (stat(".", &old_dirsb) < 0) 110 err(-1, "basic_create_test: %s: stat: %s", testname, 111 temp_dir); 112 113 sleep(2); 114 115 if (use_mkfifo) { 116 if (mkfifo(path, 0600) < 0) 117 err(-1, "basic_create_test: %s: %s", testname, path); 118 } else { 119 if (mknod(path, S_IFIFO | 0600, 0) < 0) 120 err(-1, "basic_create_test: %s: %s", testname, path); 121 } 122 123 if (stat(path, &fifosb) < 0) { 124 error = errno; 125 (void)unlink(path); 126 errno = error; 127 err(-1, "basic_create_test: %s: stat: %s", testname, path); 128 } 129 130 if (!(S_ISFIFO(fifosb.st_mode))) { 131 (void)unlink(path); 132 errx(-1, "basic_create_test: %s produced non-fifo", 133 testname); 134 } 135 136 if (use_mkfifo) { 137 if (mkfifo(path, 0600) == 0) 138 errx(-1, "basic_create_test: dup %s succeeded", 139 testname); 140 } else { 141 if (mknod(path, S_IFIFO | 0600, 0) == 0) 142 errx(-1, "basic_create_test: dup %s succeeded", 143 testname); 144 } 145 146 if (errno != EEXIST) 147 err(-1, "basic_create_test: dup %s unexpected error", 148 testname); 149 150 if (stat(".", &dirsb) < 0) { 151 error = errno; 152 (void)unlink(path); 153 errno = error; 154 err(-1, "basic_create_test: %s: stat: %s", testname, 155 temp_dir); 156 } 157 158 if (old_dirsb.st_ctime == dirsb.st_ctime) { 159 (void)unlink(path); 160 errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == " 161 "dirsb.st_ctime", testname); 162 } 163 164 if (old_dirsb.st_mtime == dirsb.st_mtime) { 165 (void)unlink(path); 166 errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == " 167 "dirsb.st_mtime", testname); 168 } 169 170 if (unlink(path) < 0) 171 err(-1, "basic_create_test: %s: unlink: %s", testname, path); 172 173 if (stat(path, &fifosb) == 0) 174 errx(-1, "basic_create_test: %s: unlink failed to unlink", 175 testname); 176 if (errno != ENOENT) 177 err(-1, "basic_create_test: %s: unlink unexpected error", 178 testname); 179 } 180 181 /* 182 * Having determined that basic create/remove/etc functionality is present 183 * for fifos, now make sure that the umask, requested permissions, and 184 * resulting mode are handled properly. 185 */ 186 static const struct permission_test { 187 mode_t pt_umask; 188 mode_t pt_reqmode; 189 mode_t pt_mode; 190 } permission_test[] = { 191 {0000, 0, S_IFIFO}, 192 {0000, S_IRWXU, S_IFIFO | S_IRWXU}, 193 {0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG | 194 S_IRWXO }, 195 {0077, S_IRWXU, S_IFIFO | S_IRWXU}, 196 {0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU}, 197 }; 198 static const int permission_test_count = sizeof(permission_test) / 199 sizeof(struct permission_test); 200 201 static void 202 fifo_permission_test(int use_mkfifo) 203 { 204 const struct permission_test *ptp; 205 mode_t __unused old_umask; 206 char path[] = "testfifo"; 207 const char *testname; 208 struct stat sb; 209 int error, i; 210 211 if (use_mkfifo) 212 testname = "mkfifo"; 213 else 214 testname = "mknod"; 215 216 old_umask = umask(0022); 217 for (i = 0; i < permission_test_count; i++) { 218 ptp = &permission_test[i]; 219 220 umask(ptp->pt_umask); 221 if (use_mkfifo) { 222 if (mkfifo(path, ptp->pt_reqmode) < 0) 223 err(-1, "fifo_permission_test: %s: %08o " 224 "%08o %08o\n", testname, ptp->pt_umask, 225 ptp->pt_reqmode, ptp->pt_mode); 226 } else { 227 if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0) 228 err(-1, "fifo_permission_test: %s: %08o " 229 "%08o %08o\n", testname, ptp->pt_umask, 230 ptp->pt_reqmode, ptp->pt_mode); 231 } 232 233 if (stat(path, &sb) < 0) { 234 error = errno; 235 (void)unlink(path); 236 errno = error; 237 err(-1, "fifo_permission_test: %s: %s", testname, 238 path); 239 } 240 241 if (sb.st_mode != ptp->pt_mode) { 242 (void)unlink(path); 243 errx(-1, "fifo_permission_test: %s: %08o %08o %08o " 244 "got %08o", testname, ptp->pt_umask, 245 ptp->pt_reqmode, ptp->pt_mode, sb.st_mode); 246 } 247 248 if (unlink(path) < 0) 249 err(-1, "fifo_permission_test: %s: unlink: %s", 250 testname, path); 251 } 252 umask(old_umask); 253 } 254 255 int 256 main(void) 257 { 258 int i; 259 260 if (geteuid() != 0) 261 errx(-1, "must be run as root"); 262 263 strcpy(temp_dir, "fifo_create.XXXXXXXXXXX"); 264 if (mkdtemp(temp_dir) == NULL) 265 err(-1, "mkdtemp"); 266 atexit(atexit_temp_dir); 267 268 if (chdir(temp_dir) < 0) 269 err(-1, "chdir"); 270 271 /* 272 * Run each test twice, once with mknod(2) and a second time with 273 * mkfifo(2). Historically, BSD has not allowed mknod(2) to be used 274 * to create fifos, but the Single UNIX Specification requires it. 275 */ 276 for (i = 0; i < 2; i++) { 277 fifo_create_test(i); 278 fifo_permission_test(i); 279 } 280 281 return (0); 282 } 283