fifo_create.c revision 179934
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: head/tools/regression/fifo/fifo_create/fifo_create.c 179934 2008-06-22 21:03:26Z rwatson $ 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 */ 78char temp_dir[PATH_MAX]; 79 80static void __unused 81atexit_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 */ 92static void 93fifo_create_test(int use_mkfifo) 94{ 95 struct stat old_dirsb, dirsb, fifosb; 96 const char *testname; 97 char path[PATH_MAX]; 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(temp_dir, &old_dirsb) < 0) 110 err(-1, "basic_create_test: %s: stat: %s", testname, 111 temp_dir); 112 113 sleep(2); 114 115 snprintf(path, PATH_MAX, "%s/testfifo", temp_dir); 116 117 if (use_mkfifo) { 118 if (mkfifo(path, 0600) < 0) 119 err(-1, "basic_create_test: %s: %s", testname, path); 120 } else { 121 if (mknod(path, S_IFIFO | 0600, 0) < 0) 122 err(-1, "basic_create_test: %s: %s", testname, path); 123 } 124 125 if (stat(path, &fifosb) < 0) { 126 error = errno; 127 (void)unlink(path); 128 errno = error; 129 err(-1, "basic_create_test: %s: stat: %s", testname, path); 130 } 131 132 if (!(S_ISFIFO(fifosb.st_mode))) { 133 (void)unlink(path); 134 errx(-1, "basic_create_test: %s produced non-fifo", 135 testname); 136 } 137 138 if (use_mkfifo) { 139 if (mkfifo(path, 0600) == 0) 140 errx(-1, "basic_create_test: dup %s succeeded", 141 testname); 142 } else { 143 if (mknod(path, S_IFIFO | 0600, 0) == 0) 144 errx(-1, "basic_create_test: dup %s succeeded", 145 testname); 146 } 147 148 if (errno != EEXIST) 149 err(-1, "basic_create_test: dup %s unexpected error", 150 testname); 151 152 if (stat(temp_dir, &dirsb) < 0) { 153 error = errno; 154 (void)unlink(path); 155 errno = error; 156 err(-1, "basic_create_test: %s: stat: %s", testname, 157 temp_dir); 158 } 159 160 if (old_dirsb.st_ctime == dirsb.st_ctime) { 161 (void)unlink(path); 162 errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == " 163 "dirsb.st_ctime", testname); 164 } 165 166 if (old_dirsb.st_mtime == dirsb.st_mtime) { 167 (void)unlink(path); 168 errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == " 169 "dirsb.st_mtime", testname); 170 } 171 172 if (unlink(path) < 0) 173 err(-1, "basic_create_test: %s: unlink: %s", testname, path); 174 175 if (stat(path, &fifosb) == 0) 176 errx(-1, "basic_create_test: %s: unlink failed to unlink", 177 testname); 178 if (errno != ENOENT) 179 err(-1, "basic_create_test: %s: unlink unexpected error", 180 testname); 181} 182 183/* 184 * Having determined that basic create/remove/etc functionality is present 185 * for fifos, now make sure that the umask, requested permissions, and 186 * resulting mode are handled properly. 187 */ 188static const struct permission_test { 189 mode_t pt_umask; 190 mode_t pt_reqmode; 191 mode_t pt_mode; 192} permission_test[] = { 193 {0000, 0, S_IFIFO}, 194 {0000, S_IRWXU, S_IFIFO | S_IRWXU}, 195 {0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG | 196 S_IRWXO }, 197 {0077, S_IRWXU, S_IFIFO | S_IRWXU}, 198 {0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU}, 199}; 200static const int permission_test_count = sizeof(permission_test) / 201 sizeof(struct permission_test); 202 203static void 204fifo_permission_test(int use_mkfifo) 205{ 206 const struct permission_test *ptp; 207 mode_t __unused old_umask; 208 char path[PATH_MAX]; 209 const char *testname; 210 struct stat sb; 211 int error, i; 212 213 if (use_mkfifo) 214 testname = "mkfifo"; 215 else 216 testname = "mknod"; 217 218 snprintf(path, PATH_MAX, "%s/testfifo", temp_dir); 219 old_umask = umask(0022); 220 for (i = 0; i < permission_test_count; i++) { 221 ptp = &permission_test[i]; 222 223 umask(ptp->pt_umask); 224 if (use_mkfifo) { 225 if (mkfifo(path, ptp->pt_reqmode) < 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 } else { 230 if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0) 231 err(-1, "fifo_permission_test: %s: %08o " 232 "%08o %08o\n", testname, ptp->pt_umask, 233 ptp->pt_reqmode, ptp->pt_mode); 234 } 235 236 if (stat(path, &sb) < 0) { 237 error = errno; 238 (void)unlink(path); 239 errno = error; 240 err(-1, "fifo_permission_test: %s: %s", testname, 241 path); 242 } 243 244 if (sb.st_mode != ptp->pt_mode) { 245 (void)unlink(path); 246 errx(-1, "fifo_permission_test: %s: %08o %08o %08o " 247 "got %08o", testname, ptp->pt_umask, 248 ptp->pt_reqmode, ptp->pt_mode, sb.st_mode); 249 } 250 251 if (unlink(path) < 0) 252 err(-1, "fifo_permission_test: %s: unlink: %s", 253 testname, path); 254 } 255 umask(old_umask); 256} 257 258int 259main(int argc, char *argv[]) 260{ 261 int i; 262 263 if (geteuid() != 0) 264 errx(-1, "must be run as root"); 265 266 strcpy(temp_dir, "/tmp/fifo_create.XXXXXXXXXXX"); 267 if (mkdtemp(temp_dir) == NULL) 268 err(-1, "mkdtemp"); 269 atexit(atexit_temp_dir); 270 271 if (chdir(temp_dir) < 0) 272 err(-1, "chdir"); 273 274 /* 275 * Run each test twice, once with mknod(2) and a second time with 276 * mkfifo(2). Historically, BSD has not allowed mknod(2) to be used 277 * to create fifos, but the Single UNIX Specification requires it. 278 */ 279 for (i = 0; i < 2; i++) { 280 fifo_create_test(i); 281 fifo_permission_test(i); 282 } 283 284 return (0); 285} 286