fifo_create.c revision 149959
16448Sache/*-
26448Sache * Copyright (c) 2005 Robert N. M. Watson
36448Sache * All rights reserved.
46448Sache *
58857Srgrimes * Redistribution and use in source and binary forms, with or without
66448Sache * modification, are permitted provided that the following conditions
76448Sache * are met:
86448Sache * 1. Redistributions of source code must retain the above copyright
96448Sache *    notice, this list of conditions and the following disclaimer.
1029612Sjmg * 2. Redistributions in binary form must reproduce the above copyright
1129612Sjmg *    notice, this list of conditions and the following disclaimer in the
126448Sache *    documentation and/or other materials provided with the distribution.
136448Sache *
14114601Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15114601Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1629963Scharnier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1729963Scharnier * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1829963Scharnier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
196448Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
206448Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2129612Sjmg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2229612Sjmg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
236448Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
246448Sache * SUCH DAMAGE.
2578778Sdd *
266448Sache * $FreeBSD: head/tools/regression/fifo/fifo_create/fifo_create.c 149959 2005-09-10 21:09:26Z rwatson $
2729612Sjmg */
2829612Sjmg
2929612Sjmg#include <sys/stat.h>
306448Sache
3129612Sjmg#include <err.h>
3229612Sjmg#include <errno.h>
336448Sache#include <limits.h>
3429612Sjmg#include <stdio.h>
356448Sache#include <stdlib.h>
36113299Smdodd#include <string.h>
37113299Smdodd#include <unistd.h>
38113299Smdodd
3929753Sache/*
4029612Sjmg * Simple regression test for the creation and destruction of POSIX fifos in
416448Sache * the file system name space.  Using a specially created directory, create
426448Sache * a fifo in it and check that the following properties are present, as
4329612Sjmg * specified in IEEE Std 1003.1, 2004 Edition:
4469258Skris *
456448Sache * - When mkfifo() is called, on success, a fifo is created.
468857Srgrimes *
4729753Sache * - On an error, no fifo is created. (XXX: Not tested)
4829612Sjmg *
4929612Sjmg * - The mode bits on the fifo are a product of combining the umask and
5029612Sjmg *   requested mode.
5129612Sjmg *
5269258Skris * - The fifo's owner will be the processes effective user ID. (XXX: Not
5329612Sjmg *   tested)
5429612Sjmg *
5529612Sjmg * - The fifo's group will be the parent directory's group or the effective
566448Sache *   group ID of the process.  For historical reasons, BSD prefers the group
576448Sache *   ID of the process, so we will generate an error if it's not that. (XXX:
586448Sache *   Not tested)
5929612Sjmg *
6029612Sjmg * - The st_atime, st_ctime, st_mtime of the fifo will be set appropriately,
616448Sache *   and st_ctime and st_mtime on the directory will be updated. (XXX: We
6229612Sjmg *   test they are updated, not correct)
6329612Sjmg *
6429612Sjmg * - EEXIST is returned if the named file already exists.
6529612Sjmg *
6629612Sjmg * In addition, we check that we can unlink the fifo, and that if we do, it
6729612Sjmg * disappears.
6829612Sjmg *
6929612Sjmg * This test must run as root in order to usefully frob the process
7029612Sjmg * credential to test permission parts.
7129612Sjmg */
7229612Sjmg
7329612Sjmg/*
746448Sache * All activity occurs within a temporary directory created early in the
756448Sache * test.
766448Sache */
776448Sachechar	temp_dir[PATH_MAX];
786448Sache
796448Sachestatic void __unused
806448Sacheatexit_temp_dir(void)
8169258Skris{
826448Sache
836448Sache	rmdir(temp_dir);
846448Sache}
856448Sache
866448Sache/*
878857Srgrimes * Basic creation tests: verify that mkfifo() creates a fifo, that the time
886448Sache * stamps on the directory are updated, that if we try twice we get EEXIST,
896448Sache * and that we can unlink it.
906448Sache */
9129612Sjmgstatic void
9260741Sjkhfifo_create_test(void)
9375334Sgreid{
94113299Smdodd	struct stat old_dirsb, dirsb, fifosb;
95113299Smdodd	char path[PATH_MAX];
9664657Ssobomax	int error;
976448Sache
9829612Sjmg	/*
996448Sache	 * Sleep to make sure that the time stamp on the directory will be
10029612Sjmg	 * updated.
10129612Sjmg	 */
1026448Sache	sleep(2);
10329612Sjmg
10429612Sjmg	if (stat(temp_dir, &old_dirsb) < 0)
10529612Sjmg		err(-1, "basic_create_test: stat: %s", temp_dir);
1066448Sache
10764657Ssobomax	snprintf(path, PATH_MAX, "%s/testfifo", temp_dir);
10864657Ssobomax
10964657Ssobomax	if (mkfifo(path, 0600) < 0)
11064657Ssobomax		err(-1, "basic_create_test: mkfifo: %s", path);
11164657Ssobomax
11264657Ssobomax	if (stat(path, &fifosb) < 0) {
11364657Ssobomax		error = errno;
11464657Ssobomax		(void)unlink(path);
11564657Ssobomax		errno = error;
11664657Ssobomax		err(-1, "basic_create_test: stat: %s", path);
11764657Ssobomax	}
11864657Ssobomax
11964657Ssobomax	if (!(S_ISFIFO(fifosb.st_mode))) {
12029612Sjmg		(void)unlink(path);
12129963Scharnier		errx(-1, "basic_create_test: mkfifo produced non-fifo");
12229963Scharnier	}
12329612Sjmg
12429963Scharnier	if (mkfifo(path, 0600) == 0)
12530028Scharnier		errx(-1, "basic_create_test: dup mkfifo succeeded");
12629963Scharnier
12730028Scharnier	if (errno != EEXIST)
12829963Scharnier		err(-1, "basic_create_test: dup mkfifo unexpected error");
12930028Scharnier
13029612Sjmg	if (stat(temp_dir, &dirsb) < 0) {
1316448Sache		error = errno;
13264657Ssobomax		(void)unlink(path);
13313803Smpp		errno = error;
13413803Smpp		err(-1, "basic_create_test: stat: %s", temp_dir);
13513803Smpp	}
13613803Smpp
13729963Scharnier	if (old_dirsb.st_ctime == dirsb.st_ctime) {
13813803Smpp		(void)unlink(path);
13913803Smpp		errx(-1, "basic_create_test: old_dirsb.st_ctime == "
14060741Sjkh		    "dirsb.st_ctime");
14160741Sjkh	}
14260741Sjkh
14360741Sjkh	if (old_dirsb.st_mtime == dirsb.st_mtime) {
14413803Smpp		(void)unlink(path);
14513803Smpp		errx(-1, "basic_create_test: old_dirsb.st_mtime == "
14613803Smpp		    "dirsb.st_mtime");
14713803Smpp	}
14829612Sjmg
1496448Sache	if (unlink(path) < 0)
15075334Sgreid		err(-1, "basic_create_test: unlink: %s", path);
15129612Sjmg
15229612Sjmg	if (stat(path, &fifosb) == 0)
15329612Sjmg		errx(-1, "basic_create_test: unlink failed to unlink");
15429612Sjmg	if (errno != ENOENT)
15529612Sjmg		err(-1, "basic_create_test: unlink unexpected error");
15629612Sjmg}
15729612Sjmg
15864657Ssobomax/*
15929612Sjmg * Having determined that basic create/remove/etc functionality is present
16064657Ssobomax * for fifos, now make sure that the umask, requested permissions, and
16113435Smpp * resulting mode are handled properly.
16229612Sjmg */
16364657Ssobomaxstatic const struct permission_test {
16429612Sjmg	mode_t	pt_umask;
16564657Ssobomax	mode_t	pt_reqmode;
1666448Sache	mode_t	pt_mode;
16729612Sjmg} permission_test[] = {
16829612Sjmg	{0000, 0, S_IFIFO},
1696448Sache	{0000, S_IRWXU, S_IFIFO | S_IRWXU},
17029612Sjmg	{0000, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU | S_IRWXG |
17129612Sjmg	    S_IRWXO },
1726448Sache	{0077, S_IRWXU, S_IFIFO | S_IRWXU},
17329612Sjmg	{0077, S_IRWXU | S_IRWXG | S_IRWXO, S_IFIFO | S_IRWXU},
17429612Sjmg};
17529612Sjmgstatic const int permission_test_count = sizeof(permission_test) /
17629612Sjmg    sizeof(struct permission_test);
17729612Sjmg
17829612Sjmgstatic void
17929612Sjmgfifo_permission_test(void)
18029612Sjmg{
18129612Sjmg	const struct permission_test *ptp;
18229612Sjmg	mode_t __unused old_umask;
18329612Sjmg	char path[PATH_MAX];
18429612Sjmg	struct stat sb;
1856448Sache	int error, i;
18675334Sgreid
18775334Sgreid	snprintf(path, PATH_MAX, "%s/testfifo", temp_dir);
18875334Sgreid	old_umask = umask(0022);
18975334Sgreid	for (i = 0; i < permission_test_count; i++) {
19064657Ssobomax		ptp = &permission_test[i];
19129612Sjmg
19264657Ssobomax		umask(ptp->pt_umask);
19329612Sjmg		if (mkfifo(path, ptp->pt_reqmode) < 0)
19429612Sjmg			err(-1, "fifo_permission_test: %08o %08o %08o\n",
195113299Smdodd			    ptp->pt_umask, ptp->pt_reqmode, ptp->pt_mode);
196113299Smdodd
197113299Smdodd		if (stat(path, &sb) < 0) {
198113299Smdodd			error = errno;
199113299Smdodd			(void)unlink(path);
200113299Smdodd			errno = error;
201113299Smdodd			err(-1, "fifo_permission_test: %s", path);
202113299Smdodd		}
203113299Smdodd
204113299Smdodd		if (sb.st_mode != ptp->pt_mode) {
205113299Smdodd			(void)unlink(path);
206113299Smdodd			errx(-1, "fifo_permission_test: %08o %08o %08o "
207113299Smdodd			    "got %08o", ptp->pt_umask, ptp->pt_reqmode,
208113299Smdodd			    ptp->pt_mode, sb.st_mode);
209113299Smdodd		}
210113299Smdodd
211113299Smdodd		if (unlink(path) < 0)
212113299Smdodd			err(-1, "fifo_permission_test: unlink: %s", path);
21329612Sjmg	}
21429612Sjmg	umask(old_umask);
21529963Scharnier}
21629612Sjmg
21729612Sjmgint
2186448Sachemain(int argc, char *argv[])
21960741Sjkh{
22060741Sjkh
22160741Sjkh	if (geteuid() != 0)
22260741Sjkh		errx(-1, "must be run as root");
22360741Sjkh
2246448Sache	strcpy(temp_dir, "/tmp/fifo_create.XXXXXXXXXXX");
22529612Sjmg	if (mkdtemp(temp_dir) == NULL)
22629612Sjmg		err(-1, "mkdtemp");
22729612Sjmg	atexit(atexit_temp_dir);
22829612Sjmg
22929612Sjmg	if (chdir(temp_dir) < 0)
230113299Smdodd		err(-1, "chdir");
231113299Smdodd
232113299Smdodd	fifo_create_test();
233113299Smdodd
234113299Smdodd	fifo_permission_test();
235113299Smdodd
236113299Smdodd	return (0);
237113299Smdodd}
238113299Smdodd