diff options
Diffstat (limited to 'tests/sys/file')
| -rw-r--r-- | tests/sys/file/Makefile | 2 | ||||
| -rw-r--r-- | tests/sys/file/closefrom_test.c | 490 | 
2 files changed, 236 insertions, 256 deletions
| diff --git a/tests/sys/file/Makefile b/tests/sys/file/Makefile index beb4452359b7..c1fcef68d08e 100644 --- a/tests/sys/file/Makefile +++ b/tests/sys/file/Makefile @@ -3,7 +3,7 @@ TESTSDIR=	${TESTSBASE}/sys/file  BINDIR=		${TESTSDIR}  ATF_TESTS_C+=	path_test -TAP_TESTS_C+=	closefrom_test +ATF_TESTS_C+=	closefrom_test  TAP_TESTS_C+=	dup_test  ATF_TESTS_C+=	fcntlflags_test  TAP_TESTS_SH+=	flock_test diff --git a/tests/sys/file/closefrom_test.c b/tests/sys/file/closefrom_test.c index 212d048d7566..a51e1630e24d 100644 --- a/tests/sys/file/closefrom_test.c +++ b/tests/sys/file/closefrom_test.c @@ -25,13 +25,13 @@   * SUCH DAMAGE.   */ -#include <sys/cdefs.h>  /*   * Regression tests for the closefrom(2) system call.   */  #include <sys/param.h>  #include <sys/mman.h> +#include <sys/stat.h>  #include <sys/user.h>  #include <sys/wait.h>  #include <errno.h> @@ -44,67 +44,57 @@  #include <string.h>  #include <unistd.h> -struct shared_info { -	int	failed; -	char	tag[64]; -	char	message[0]; -}; +#include <atf-c.h> -static int test = 1; +static char *shared_page; -static void -ok(const char *descr) +/* + * A variant of ATF_REQUIRE that is suitable for use in child + * processes.  Since these tests close stderr, errors are reported to + * a shared page of memory checked by the parent process. + */ +#define	CHILD_REQUIRE(exp) do {				\ +	if (!(exp))					\ +		child_fail_require(__FILE__, __LINE__,	\ +		    #exp " not met");			\ +} while (0) + +static __dead2 __printflike(3, 4) void +child_fail_require(const char *file, int line, const char *fmt, ...)  { +	FILE *fp; +	va_list ap; -	printf("ok %d - %s\n", test, descr); -	test++; -} +	fp = fmemopen(shared_page, PAGE_SIZE - 1, "w"); +	if (fp == NULL) +		exit(1); -static void -fail(const char *descr, const char *fmt, ...) -{ -	va_list ap; +	fprintf(fp, "%s:%d: ", file, line); +	va_start(ap, fmt); +	vfprintf(fp, fmt, ap); +	va_end(ap); +	fclose(fp); -	printf("not ok %d - %s", test, descr); -	test++; -	if (fmt) { -		va_start(ap, fmt); -		printf(" # "); -		vprintf(fmt, ap); -		va_end(ap); -	} -	printf("\n"); -	exit(1); +	exit(0);  } -#define	fail_err(descr)		fail((descr), "%s", strerror(errno)) - -static void -cok(struct shared_info *info, const char *descr) +static pid_t +child_fork(void)  { - -	info->failed = 0; -	strlcpy(info->tag, descr, sizeof(info->tag)); -	exit(0); +	shared_page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | +	    MAP_SHARED, -1, 0); +	ATF_REQUIRE_MSG(shared_page != MAP_FAILED, "mmap: %s", strerror(errno)); +	return (atf_utils_fork());  }  static void -cfail(struct shared_info *info, const char *descr, const char *fmt, ...) +child_wait(pid_t pid)  { -	va_list ap; - -	info->failed = 1; -	strlcpy(info->tag, descr, sizeof(info->tag)); -	if (fmt) { -		va_start(ap, fmt); -		vsprintf(info->message, fmt, ap); -		va_end(ap); -	} -	exit(0); +	atf_utils_wait(pid, 0, "", ""); +	if (shared_page[0] != '\0') +		atf_tc_fail("%s", shared_page);  } -#define	cfail_err(info, descr)	cfail((info), (descr), "%s", strerror(errno)) -  /*   * Use kinfo_getfile() to fetch the list of file descriptors and figure out   * the highest open file descriptor. @@ -116,9 +106,8 @@ highest_fd(void)  	int cnt, i, highest;  	kif = kinfo_getfile(getpid(), &cnt); -	if (kif == NULL) -		fail_err("kinfo_getfile"); -	highest = INT_MIN; +	ATF_REQUIRE_MSG(kif != NULL, "kinfo_getfile: %s", strerror(errno)); +	highest = -1;  	for (i = 0; i < cnt; i++)  		if (kif[i].kf_fd > highest)  			highest = kif[i].kf_fd; @@ -132,262 +121,253 @@ devnull(void)  	int fd;  	fd = open(_PATH_DEVNULL, O_RDONLY); -	if (fd < 0) -		fail_err("open(\" "_PATH_DEVNULL" \")"); +	ATF_REQUIRE_MSG(fd != -1, "open(\" "_PATH_DEVNULL" \"): %s", +	    strerror(errno));  	return (fd);  } -int -main(void) +ATF_TC_WITHOUT_HEAD(closefrom_simple); +ATF_TC_BODY(closefrom_simple, tc)  { -	struct shared_info *info; -	pid_t pid; -	int fd, flags, i, start; - -	printf("1..22\n"); +	int fd, start;  	/* We'd better start up with fd's 0, 1, and 2 open. */ -	start = devnull(); -	if (start < 3) -		fail("open", "bad descriptor %d", start); -	ok("open"); +	start = highest_fd(); +	ATF_REQUIRE(start >= 2); + +	fd = devnull(); +	ATF_REQUIRE(fd > start);  	/* Make sure highest_fd() works. */ -	fd = highest_fd(); -	if (start != fd) -		fail("highest_fd", "bad descriptor %d != %d", start, fd); -	ok("highest_fd"); - -	/* Try to use closefrom() for just closing fd 3. */ -	closefrom(start); -	fd = highest_fd(); -	if (fd != start - 1) -		fail("closefrom", "highest fd %d", fd); -	ok("closefrom"); +	ATF_REQUIRE_INTEQ(fd, highest_fd()); + +	/* Try to use closefrom() to close just the new fd. */ +	closefrom(fd); +	ATF_REQUIRE_INTEQ(start, highest_fd()); +} + +ATF_TC_WITHOUT_HEAD(closefrom_with_holes); +ATF_TC_BODY(closefrom_with_holes, tc) +{ +	int i, start; +	 +	start = highest_fd();  	/* Eat up 16 descriptors. */  	for (i = 0; i < 16; i++)  		(void)devnull(); -	fd = highest_fd(); -	if (fd != start + 15) -		fail("open 16", "highest fd %d", fd); -	ok("open 16"); + +	ATF_REQUIRE_INTEQ(start + 16, highest_fd());  	/* Close half of them. */ -	closefrom(11); -	fd = highest_fd(); -	if (fd != 10) -		fail("closefrom", "highest fd %d", fd); -	ok("closefrom"); - -	/* Explicitly close descriptors 6 and 8 to create holes. */ -	if (close(6) < 0 || close(8) < 0) -		fail_err("close2 "); -	ok("close 2"); - -	/* Verify that close on 6 and 8 fails with EBADF. */ -	if (close(6) == 0) -		fail("close(6)", "did not fail"); -	if (errno != EBADF) -		fail_err("close(6)"); -	ok("close(6)"); -	if (close(8) == 0) -		fail("close(8)", "did not fail"); -	if (errno != EBADF) -		fail_err("close(8)"); -	ok("close(8)"); - -	/* Close from 4 on. */ -	closefrom(4); -	fd = highest_fd(); -	if (fd != 3) -		fail("closefrom", "highest fd %d", fd); -	ok("closefrom"); - -	/* Allocate a small SHM region for IPC with our child. */ -	info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | -	    MAP_SHARED, -1, 0); -	if (info == MAP_FAILED) -		fail_err("mmap"); -	ok("mmap"); - -	/* Fork a child process to test closefrom(0). */ -	pid = fork(); -	if (pid < 0) -		fail_err("fork"); +	closefrom(start + 9); +	ATF_REQUIRE_INTEQ(start + 8, highest_fd()); + +	/* Explicitly close two descriptors to create holes. */ +	ATF_REQUIRE_MSG(close(start + 3) == 0, "close(start + 3): %s", +	    strerror(errno)); +	ATF_REQUIRE_MSG(close(start + 5) == 0, "close(start + 5): %s", +	    strerror(errno)); + +	/* Verify that close on the closed descriptors fails with EBADF. */ +	ATF_REQUIRE_ERRNO(EBADF, close(start + 3) == -1); +	ATF_REQUIRE_ERRNO(EBADF, close(start + 5) == -1); + +	/* Close most remaining descriptors. */ +	closefrom(start + 2); +	ATF_REQUIRE_INTEQ(start + 1, highest_fd()); +} + +ATF_TC_WITHOUT_HEAD(closefrom_zero); +ATF_TC_BODY(closefrom_zero, tc) +{ +	pid_t pid; +	int fd; + +	/* Ensure standard descriptors are open. */ +	ATF_REQUIRE(highest_fd() >= 2); + +	pid = child_fork();  	if (pid == 0) {  		/* Child. */  		closefrom(0);  		fd = highest_fd(); -		if (fd >= 0) -			cfail(info, "closefrom(0)", "highest fd %d", fd); -		cok(info, "closefrom(0)"); +		CHILD_REQUIRE(fd == -1); +		exit(0);  	} -	if (wait(NULL) < 0) -		fail_err("wait"); -	if (info->failed) -		fail(info->tag, "%s", info->message); -	ok(info->tag); - -	/* Fork a child process to test closefrom(-1). */ -	pid = fork(); -	if (pid < 0) -		fail_err("fork"); + +	child_wait(pid); +} + +ATF_TC_WITHOUT_HEAD(closefrom_negative_one); +ATF_TC_BODY(closefrom_negative_one, tc) +{ +	pid_t pid; +	int fd; + +	/* Ensure standard descriptors are open. */ +	ATF_REQUIRE(highest_fd() >= 2); + +	pid = child_fork();  	if (pid == 0) {  		/* Child. */  		closefrom(-1);  		fd = highest_fd(); -		if (fd >= 0) -			cfail(info, "closefrom(-1)", "highest fd %d", fd); -		cok(info, "closefrom(-1)"); +		CHILD_REQUIRE(fd == -1); +		exit(0);  	} -	if (wait(NULL) < 0) -		fail_err("wait"); -	if (info->failed) -		fail(info->tag, "%s", info->message); -	ok(info->tag); - -	/* Dup stdout to 6. */ -	if (dup2(1, 6) < 0) -		fail_err("dup2"); -	fd = highest_fd(); -	if (fd != 6) -		fail("dup2", "highest fd %d", fd); -	ok("dup2"); + +	child_wait(pid); +} + +ATF_TC_WITHOUT_HEAD(closefrom_in_holes); +ATF_TC_BODY(closefrom_in_holes, tc) +{ +	int start; + +	start = highest_fd(); +	ATF_REQUIRE(start >= 2); + +	/* Dup stdout to a higher fd. */ +	ATF_REQUIRE_INTEQ(start + 4, dup2(1, start + 4)); +	ATF_REQUIRE_INTEQ(start + 4, highest_fd());  	/* Do a closefrom() starting in a hole. */ -	closefrom(4); -	fd = highest_fd(); -	if (fd != 3) -		fail("closefrom", "highest fd %d", fd); -	ok("closefrom"); +	closefrom(start + 2); +	ATF_REQUIRE_INTEQ(start, highest_fd());  	/* Do a closefrom() beyond our highest open fd. */ -	closefrom(32); -	fd = highest_fd(); -	if (fd != 3) -		fail("closefrom", "highest fd %d", fd); -	ok("closefrom"); +	closefrom(start + 32); +	ATF_REQUIRE_INTEQ(start, highest_fd()); +} + +ATF_TC_WITHOUT_HEAD(closerange_basic); +ATF_TC_BODY(closerange_basic, tc) +{ +	struct stat sb; +	int i, start; -	/* Chew up another 8 fd */ +	start = highest_fd(); + +	/* Open 8 file descriptors */  	for (i = 0; i < 8; i++)  		(void)devnull(); -	fd = highest_fd(); -	start = fd - 7; +	ATF_REQUIRE_INTEQ(start + 8, highest_fd());  	/* close_range() a hole in the middle */ -	close_range(start + 3, start + 5, 0); -	for (i = start + 3; i < start + 6; ++i) { -		if (close(i) == 0 || errno != EBADF) { -			--i; -			break; -		} -	} -	if (i != start + 6) -		fail("close_range", "failed to close at %d in %d - %d", i + 1, -		    start + 3, start + 6); -	ok("close_range"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 3, start + 5, 0)); +	for (i = start + 3; i < start + 6; ++i) +		ATF_REQUIRE_ERRNO(EBADF, fstat(i, &sb) == -1);  	/* close_range from the middle of the hole */ -	close_range(start + 4, start + 6, 0); -	if ((i = highest_fd()) != fd) -		fail("close_range", "highest fd %d", i); -	ok("close_range"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 4, start + 6, 0)); +	ATF_REQUIRE_INTEQ(start + 8, highest_fd());  	/* close_range to the end; effectively closefrom(2) */ -	close_range(start + 3, ~0L, 0); -	if ((i = highest_fd()) != start + 2) -		fail("close_range", "highest fd %d", i); -	ok("close_range"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 3, ~0L, 0)); +	ATF_REQUIRE_INTEQ(start + 2, highest_fd());  	/* Now close the rest */ -	close_range(start, start + 4, 0); -	fd = highest_fd(); -	if (fd != 3) -		fail("close_range", "highest fd %d", fd); -	ok("close_range"); - -	/* Fork a child process to test closefrom(0) twice. */ -	pid = fork(); -	if (pid < 0) -		fail_err("fork"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 1, start + 4, 0)); +	ATF_REQUIRE_INTEQ(start, highest_fd()); +} + +ATF_TC_WITHOUT_HEAD(closefrom_zero_twice); +ATF_TC_BODY(closefrom_zero_twice, tc) +{ +	pid_t pid; +	int fd; + +	/* Ensure standard descriptors are open. */ +	ATF_REQUIRE(highest_fd() >= 2); + +	pid = child_fork();  	if (pid == 0) {  		/* Child. */  		closefrom(0); +		fd = highest_fd(); +		CHILD_REQUIRE(fd == -1);  		closefrom(0); -		cok(info, "closefrom(0)"); +		fd = highest_fd(); +		CHILD_REQUIRE(fd == -1); +		exit(0);  	} -	if (wait(NULL) < 0) -		fail_err("wait"); -	if (info->failed) -		fail(info->tag, "%s", info->message); -	ok(info->tag); -	/* test CLOSE_RANGE_CLOEXEC */ +	child_wait(pid); +} + +static void +require_fd_flag(int fd, const char *descr, const char *descr2, int flag, +    bool set) +{ +	int flags; + +	flags = fcntl(fd, F_GETFD); +	ATF_REQUIRE_MSG(flags >= 0, "fcntl(.., F_GETFD): %s", strerror(errno)); + +	if (set) { +		ATF_REQUIRE_MSG((flags & flag) == flag, +		    "%s did not set %s on fd %d", descr, descr2, fd); +	} else { +		ATF_REQUIRE_MSG((flags & flag) == 0, +		    "%s set %s when it should not have on fd %d", descr, descr2, +		    fd); +	} +} + +ATF_TC_WITHOUT_HEAD(closerange_CLOEXEC); +ATF_TC_BODY(closerange_CLOEXEC, tc) +{ +	int i, start; + +	start = highest_fd(); +	ATF_REQUIRE(start >= 2); +  	for (i = 0; i < 8; i++)  		(void)devnull(); -	fd = highest_fd(); -	start = fd - 8; -	if (close_range(start + 1, start + 4, CLOSE_RANGE_CLOEXEC) < 0) -		fail_err("close_range(..., CLOSE_RANGE_CLOEXEC)"); -	flags = fcntl(start, F_GETFD); -	if (flags < 0) -		fail_err("fcntl(.., F_GETFD)"); -	if ((flags & FD_CLOEXEC) != 0) -		fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec " -		    "when it should not have on fd %d", start); -	for (i = start + 1; i <= start + 4; i++) { -		flags = fcntl(i, F_GETFD); -		if (flags < 0) -			fail_err("fcntl(.., F_GETFD)"); -		if ((flags & FD_CLOEXEC) == 0) -			fail("close_range", "CLOSE_RANGE_CLOEXEC did not set " -			    "close-on-exec on fd %d", i); -	} -	for (; i < start + 8; i++) { -		flags = fcntl(i, F_GETFD); -		if (flags < 0) -			fail_err("fcntl(.., F_GETFD)"); -		if ((flags & FD_CLOEXEC) != 0) -			fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec " -			    "when it should not have on fd %d", i); +	ATF_REQUIRE_INTEQ(start + 8, highest_fd()); + +	ATF_REQUIRE_INTEQ(0, close_range(start + 2, start + 5, +	    CLOSE_RANGE_CLOEXEC)); +	for (i = 1; i < 9; i++) { +		require_fd_flag(start + i, "CLOSE_RANGE_CLOEXEC", +		    "close-on-exec", FD_CLOEXEC, i >= 2 && i <= 5);  	} -	if (close_range(start, start + 8, 0) < 0) -		fail_err("close_range"); -	ok("close_range(..., CLOSE_RANGE_CLOEXEC)"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 1, start + 8, 0)); +} + +ATF_TC_WITHOUT_HEAD(closerange_CLOFORK); +ATF_TC_BODY(closerange_CLOFORK, tc) +{ +	int i, start; + +	start = highest_fd(); +	ATF_REQUIRE(start >= 2); -	/* test CLOSE_RANGE_CLOFORK */  	for (i = 0; i < 8; i++)  		(void)devnull(); -	fd = highest_fd(); -	start = fd - 8; -	if (close_range(start + 1, start + 4, CLOSE_RANGE_CLOFORK) < 0) -		fail_err("close_range(..., CLOSE_RANGE_CLOFORK)"); -	flags = fcntl(start, F_GETFD); -	if (flags < 0) -		fail_err("fcntl(.., F_GETFD)"); -	if ((flags & FD_CLOFORK) != 0) -		fail("close_range", "CLOSE_RANGE_CLOFORK set close-on-exec " -		    "when it should not have on fd %d", start); -	for (i = start + 1; i <= start + 4; i++) { -		flags = fcntl(i, F_GETFD); -		if (flags < 0) -			fail_err("fcntl(.., F_GETFD)"); -		if ((flags & FD_CLOFORK) == 0) -			fail("close_range", "CLOSE_RANGE_CLOFORK did not set " -			    "close-on-exec on fd %d", i); -	} -	for (; i < start + 8; i++) { -		flags = fcntl(i, F_GETFD); -		if (flags < 0) -			fail_err("fcntl(.., F_GETFD)"); -		if ((flags & FD_CLOFORK) != 0) -			fail("close_range", "CLOSE_RANGE_CLOFORK set close-on-exec " -			    "when it should not have on fd %d", i); +	ATF_REQUIRE_INTEQ(start + 8, highest_fd()); + +	ATF_REQUIRE_INTEQ(0, close_range(start + 2, start + 5, +	    CLOSE_RANGE_CLOFORK)); +	for (i = 1; i < 9; i++) { +		require_fd_flag(start + i, "CLOSE_RANGE_CLOFORK", +		    "close-on-fork", FD_CLOFORK, i >= 2 && i <= 5);  	} -	if (close_range(start, start + 8, 0) < 0) -		fail_err("close_range"); -	ok("close_range(..., CLOSE_RANGE_CLOFORK)"); +	ATF_REQUIRE_INTEQ(0, close_range(start + 1, start + 8, 0)); +} -	return (0); +ATF_TP_ADD_TCS(tp) +{ +	ATF_TP_ADD_TC(tp, closefrom_simple); +	ATF_TP_ADD_TC(tp, closefrom_with_holes); +	ATF_TP_ADD_TC(tp, closefrom_zero); +	ATF_TP_ADD_TC(tp, closefrom_negative_one); +	ATF_TP_ADD_TC(tp, closefrom_in_holes); +	ATF_TP_ADD_TC(tp, closerange_basic); +	ATF_TP_ADD_TC(tp, closefrom_zero_twice); +	ATF_TP_ADD_TC(tp, closerange_CLOEXEC); +	ATF_TP_ADD_TC(tp, closerange_CLOFORK); + +	return (atf_no_error());  } | 
