/*-1* Copyright (c) 2005-2008 Robert N. M. Watson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/stat.h>2728#include <err.h>29#include <errno.h>30#include <limits.h>31#include <stdio.h>32#include <stdlib.h>33#include <string.h>34#include <unistd.h>3536/*37* Simple regression test for the creation and destruction of POSIX fifos in38* the file system name space. Using a specially created directory, create39* a fifo in it and check that the following properties are present, as40* specified in IEEE Std 1003.1, 2004 Edition:41*42* - When mkfifo() or mknod(S_IFIFO) is called, on success, a fifo is43* created.44*45* - On an error, no fifo is created. (XXX: Not tested)46*47* - The mode bits on the fifo are a product of combining the umask and48* requested mode.49*50* - The fifo's owner will be the processes effective user ID. (XXX: Not51* tested)52*53* - The fifo's group will be the parent directory's group or the effective54* group ID of the process. For historical reasons, BSD prefers the group55* ID of the process, so we will generate an error if it's not that. (XXX:56* Not tested)57*58* - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately,59* and st_ctime and st_mtime on the directory will be updated. (XXX: We60* test they are updated, not correct)61*62* - EEXIST is returned if the named file already exists.63*64* In addition, we check that we can unlink the fifo, and that if we do, it65* disappears.66*67* This test must run as root in order to usefully frob the process68* credential to test permission parts.69*/7071/*72* All activity occurs within a temporary directory created early in the73* test.74*/75static char temp_dir[PATH_MAX];7677static void __unused78atexit_temp_dir(void)79{8081rmdir(temp_dir);82}8384/*85* Basic creation tests: verify that mkfifo(2) (or mknod(2)) creates a fifo,86* that the time stamps on the directory are updated, that if we try twice we87* get EEXIST, and that we can unlink it.88*/89static void90fifo_create_test(int use_mkfifo)91{92struct stat old_dirsb, dirsb, fifosb;93const char *testname;94char path[] = "testfifo";95int error;9697if (use_mkfifo)98testname = "mkfifo";99else100testname = "mknod";101102/*103* Sleep to make sure that the time stamp on the directory will be104* updated.105*/106if (stat(".", &old_dirsb) < 0)107err(-1, "basic_create_test: %s: stat: %s", testname,108temp_dir);109110sleep(2);111112if (use_mkfifo) {113if (mkfifo(path, 0600) < 0)114err(-1, "basic_create_test: %s: %s", testname, path);115} else {116if (mknod(path, S_IFIFO | 0600, 0) < 0)117err(-1, "basic_create_test: %s: %s", testname, path);118}119120if (stat(path, &fifosb) < 0) {121error = errno;122(void)unlink(path);123errno = error;124err(-1, "basic_create_test: %s: stat: %s", testname, path);125}126127if (!(S_ISFIFO(fifosb.st_mode))) {128(void)unlink(path);129errx(-1, "basic_create_test: %s produced non-fifo",130testname);131}132133if (use_mkfifo) {134if (mkfifo(path, 0600) == 0)135errx(-1, "basic_create_test: dup %s succeeded",136testname);137} else {138if (mknod(path, S_IFIFO | 0600, 0) == 0)139errx(-1, "basic_create_test: dup %s succeeded",140testname);141}142143if (errno != EEXIST)144err(-1, "basic_create_test: dup %s unexpected error",145testname);146147if (stat(".", &dirsb) < 0) {148error = errno;149(void)unlink(path);150errno = error;151err(-1, "basic_create_test: %s: stat: %s", testname,152temp_dir);153}154155if (old_dirsb.st_ctime == dirsb.st_ctime) {156(void)unlink(path);157errx(-1, "basic_create_test: %s: old_dirsb.st_ctime == "158"dirsb.st_ctime", testname);159}160161if (old_dirsb.st_mtime == dirsb.st_mtime) {162(void)unlink(path);163errx(-1, "basic_create_test: %s: old_dirsb.st_mtime == "164"dirsb.st_mtime", testname);165}166167if (unlink(path) < 0)168err(-1, "basic_create_test: %s: unlink: %s", testname, path);169170if (stat(path, &fifosb) == 0)171errx(-1, "basic_create_test: %s: unlink failed to unlink",172testname);173if (errno != ENOENT)174err(-1, "basic_create_test: %s: unlink unexpected error",175testname);176}177178/*179* Having determined that basic create/remove/etc functionality is present180* for fifos, now make sure that the umask, requested permissions, and181* resulting mode are handled properly.182*/183static const struct permission_test {184mode_t pt_umask;185mode_t pt_reqmode;186mode_t pt_mode;187} permission_test[] = {188{0000, 0, S_IFIFO},189{0000, S_IRWXU, S_IFIFO | S_IRWXU},190{0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG |191S_IRWXO },192{0077, S_IRWXU, S_IFIFO | S_IRWXU},193{0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU},194};195static const int permission_test_count = sizeof(permission_test) /196sizeof(struct permission_test);197198static void199fifo_permission_test(int use_mkfifo)200{201const struct permission_test *ptp;202mode_t __unused old_umask;203char path[] = "testfifo";204const char *testname;205struct stat sb;206int error, i;207208if (use_mkfifo)209testname = "mkfifo";210else211testname = "mknod";212213old_umask = umask(0022);214for (i = 0; i < permission_test_count; i++) {215ptp = &permission_test[i];216217umask(ptp->pt_umask);218if (use_mkfifo) {219if (mkfifo(path, ptp->pt_reqmode) < 0)220err(-1, "fifo_permission_test: %s: %08o "221"%08o %08o\n", testname, ptp->pt_umask,222ptp->pt_reqmode, ptp->pt_mode);223} else {224if (mknod(path, S_IFIFO | ptp->pt_reqmode, 0) < 0)225err(-1, "fifo_permission_test: %s: %08o "226"%08o %08o\n", testname, ptp->pt_umask,227ptp->pt_reqmode, ptp->pt_mode);228}229230if (stat(path, &sb) < 0) {231error = errno;232(void)unlink(path);233errno = error;234err(-1, "fifo_permission_test: %s: %s", testname,235path);236}237238if (sb.st_mode != ptp->pt_mode) {239(void)unlink(path);240errx(-1, "fifo_permission_test: %s: %08o %08o %08o "241"got %08o", testname, ptp->pt_umask,242ptp->pt_reqmode, ptp->pt_mode, sb.st_mode);243}244245if (unlink(path) < 0)246err(-1, "fifo_permission_test: %s: unlink: %s",247testname, path);248}249umask(old_umask);250}251252int253main(void)254{255int i;256257if (geteuid() != 0)258errx(-1, "must be run as root");259260strcpy(temp_dir, "fifo_create.XXXXXXXXXXX");261if (mkdtemp(temp_dir) == NULL)262err(-1, "mkdtemp");263atexit(atexit_temp_dir);264265if (chdir(temp_dir) < 0)266err(-1, "chdir");267268/*269* Run each test twice, once with mknod(2) and a second time with270* mkfifo(2). Historically, BSD has not allowed mknod(2) to be used271* to create fifos, but the Single UNIX Specification requires it.272*/273for (i = 0; i < 2; i++) {274fifo_create_test(i);275fifo_permission_test(i);276}277278return (0);279}280281282