fifo_create.c revision 302408
174462Salfred/*- 274462Salfred * Copyright (c) 2005-2008 Robert N. M. Watson 3261046Smav * All rights reserved. 4261046Smav * 5261046Smav * Redistribution and use in source and binary forms, with or without 68870Srgrimes * modification, are permitted provided that the following conditions 7261046Smav * are met: 8261046Smav * 1. Redistributions of source code must retain the above copyright 9261046Smav * notice, this list of conditions and the following disclaimer. 10261046Smav * 2. Redistributions in binary form must reproduce the above copyright 11261046Smav * notice, this list of conditions and the following disclaimer in the 12261046Smav * documentation and/or other materials provided with the distribution. 13261046Smav * 14261046Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15261046Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18261046Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19261046Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20261046Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21261046Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22261046Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23261046Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24261046Smav * SUCH DAMAGE. 25261046Smav * 26261046Smav * $FreeBSD: stable/11/tests/sys/fifo/fifo_create.c 281450 2015-04-12 06:18:24Z ngie $ 27261046Smav */ 28261046Smav 291901Swollman#include <sys/stat.h> 301901Swollman 311901Swollman#include <err.h> 32136581Sobrien#include <errno.h> 3374462Salfred#include <limits.h> 341901Swollman#include <stdio.h> 3592990Sobrien#include <stdlib.h> 3692990Sobrien#include <string.h> 371901Swollman#include <unistd.h> 381901Swollman 391901Swollman/* 401901Swollman * Simple regression test for the creation and destruction of POSIX fifos in 411901Swollman * the file system name space. Using a specially created directory, create 421901Swollman * a fifo in it and check that the following properties are present, as 431901Swollman * specified in IEEE Std 1003.1, 2004 Edition: 441901Swollman * 4574462Salfred * - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is 4674462Salfred * created. 4774462Salfred * 481901Swollman * - On an error, no fifo is created. (XXX: Not tested) 491901Swollman * 501901Swollman * - The mode bits on the fifo are a product of combining the umask and 5174462Salfred * requested mode. 521901Swollman * 531901Swollman * - The fifo's owner will be the processes effective user ID. (XXX: Not 548870Srgrimes * tested) 551901Swollman * 561901Swollman * - The fifo's group will be the parent directory's group or the effective 571901Swollman * group ID of the process. For historical reasons, BSD prefers the group 581901Swollman * ID of the process, so we will generate an error if it's not that. (XXX: 591901Swollman * Not tested) 601901Swollman * 611901Swollman * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately, 621901Swollman * and st_ctime and st_mtime on the directory will be updated. (XXX: We 638870Srgrimes * test they are updated, not correct) 641901Swollman * 651901Swollman * - EEXIST is returned if the named file already exists. 661901Swollman * 678870Srgrimes * In addition, we check that we can unlink the fifo, and that if we do, it 681901Swollman * disappears. 691901Swollman * 701901Swollman * This test must run as root in order to usefully frob the process 711901Swollman * credential to test permission parts. 721901Swollman */ 731901Swollman 741901Swollman/* 751901Swollman * All activity occurs within a temporary directory created early in the 761901Swollman * test. 771901Swollman */ 781901Swollmanstatic char temp_dir[PATH_MAX]; 791901Swollman 808870Srgrimesstatic void __unused 818870Srgrimesatexit_temp_dir(void) 821901Swollman{ 831901Swollman 841901Swollman rmdir(temp_dir); 851901Swollman} 861901Swollman 871901Swollman/* 881901Swollman * Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo, 891901Swollman * that the time stamps on the directory are updated, that if we try twice we 901901Swollman * get EEXIST, and that we can unlink it. 911901Swollman */ 921901Swollmanstatic void 931901Swollmanfifo_create_test(int use_mkfifo) 9474462Salfred{ 9574462Salfred struct stat old_dirsb, dirsb, fifosb; 961901Swollman const char *testname; 971901Swollman char path[] = "testfifo"; 981901Swollman int error; 991901Swollman 1001901Swollman if (use_mkfifo) 1011901Swollman testname = "mkfifo"; 1021901Swollman else 10374462Salfred testname = "mknod"; 10474462Salfred 1051901Swollman /* 10674462Salfred * Sleep to make sure that the time stamp on the directory will be 10774462Salfred * updated. 10874462Salfred */ 10974462Salfred if (stat(".", &old_dirsb) < 0) 11074462Salfred err(-1, "basic_create_test: %s: stat: %s", testname, 11174462Salfred temp_dir); 1121901Swollman 1131901Swollman sleep(2); 1141901Swollman 1151901Swollman if (use_mkfifo) { 1161901Swollman if (mkfifo(path, 0600) < 0) 1171901Swollman err(-1, "basic_create_test: %s: %s", testname, path); 1181901Swollman } else { 1191901Swollman if (mknod(path, S_IFIFO | 0600, 0) < 0) 1201901Swollman err(-1, "basic_create_test: %s: %s", testname, path); 1211901Swollman } 1221901Swollman 12374462Salfred if (stat(path, &fifosb) < 0) { 1241901Swollman error = errno; 12574462Salfred (void)unlink(path); 1261901Swollman errno = error; 1271901Swollman err(-1, "basic_create_test: %s: stat: %s", testname, path); 1281901Swollman } 1291901Swollman 13074462Salfred if (!(S_ISFIFO(fifosb.st_mode))) { 13174462Salfred (void)unlink(path); 13274462Salfred errx(-1, "basic_create_test: %s produced non-fifo", 13374462Salfred testname); 13474462Salfred } 13574462Salfred 13674462Salfred if (use_mkfifo) { 13774462Salfred if (mkfifo(path, 0600) == 0) 13874462Salfred errx(-1, "basic_create_test: dup %s succeeded", 13974462Salfred testname); 14074462Salfred } else { 14174462Salfred if (mknod(path, S_IFIFO | 0600, 0) == 0) 14274462Salfred 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 */ 186static 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}; 198static const int permission_test_count = sizeof(permission_test) / 199 sizeof(struct permission_test); 200 201static void 202fifo_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 255int 256main(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