xref: /freebsd-src/contrib/netbsd-tests/lib/libc/sys/t_stat.c (revision 63d1fd5970ec814904aa0f4580b10a0d302d08b2)
1*63d1fd59SEnji Cooper /* $NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 christos Exp $ */
257718be8SEnji Cooper 
357718be8SEnji Cooper /*-
457718be8SEnji Cooper  * Copyright (c) 2011 The NetBSD Foundation, Inc.
557718be8SEnji Cooper  * All rights reserved.
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper  * by Jukka Ruohonen.
957718be8SEnji Cooper  *
1057718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
1157718be8SEnji Cooper  * modification, are permitted provided that the following conditions
1257718be8SEnji Cooper  * are met:
1357718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1457718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1557718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1657718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1757718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
1857718be8SEnji Cooper  *
1957718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2057718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2157718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2257718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2357718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2457718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2557718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2657718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2757718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2857718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2957718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
3057718be8SEnji Cooper  */
3157718be8SEnji Cooper #include <sys/cdefs.h>
32*63d1fd59SEnji Cooper __RCSID("$NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 christos Exp $");
3357718be8SEnji Cooper 
3457718be8SEnji Cooper #include <sys/stat.h>
3557718be8SEnji Cooper #include <sys/socket.h>
3657718be8SEnji Cooper #include <sys/types.h>
3757718be8SEnji Cooper 
3857718be8SEnji Cooper #include <arpa/inet.h>
39*63d1fd59SEnji Cooper #include <netinet/in.h>
4057718be8SEnji Cooper 
4157718be8SEnji Cooper #include <atf-c.h>
4257718be8SEnji Cooper #include <errno.h>
4357718be8SEnji Cooper #include <fcntl.h>
4457718be8SEnji Cooper #include <fts.h>
4557718be8SEnji Cooper #include <limits.h>
4657718be8SEnji Cooper #include <string.h>
4757718be8SEnji Cooper #include <unistd.h>
4857718be8SEnji Cooper 
4957718be8SEnji Cooper #include <stdio.h>
5057718be8SEnji Cooper 
51ff0ba872SEnji Cooper #ifdef __FreeBSD__
52a39196afSEnji Cooper #include <netinet/in.h>
53a39196afSEnji Cooper #endif
54a39196afSEnji Cooper 
5557718be8SEnji Cooper static const char *path = "stat";
5657718be8SEnji Cooper 
5757718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_chflags);
5857718be8SEnji Cooper ATF_TC_HEAD(stat_chflags, tc)
5957718be8SEnji Cooper {
6057718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)");
6157718be8SEnji Cooper }
6257718be8SEnji Cooper 
6357718be8SEnji Cooper ATF_TC_BODY(stat_chflags, tc)
6457718be8SEnji Cooper {
6557718be8SEnji Cooper 	struct stat sa, sb;
6657718be8SEnji Cooper 	int fd;
6757718be8SEnji Cooper 
6857718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
6957718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
7057718be8SEnji Cooper 
7157718be8SEnji Cooper 	fd = open(path, O_RDONLY | O_CREAT);
7257718be8SEnji Cooper 
7357718be8SEnji Cooper 	ATF_REQUIRE(fd != -1);
7457718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sa) == 0);
7557718be8SEnji Cooper 	ATF_REQUIRE(chflags(path, UF_NODUMP) == 0);
7657718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sb) == 0);
7757718be8SEnji Cooper 
7857718be8SEnji Cooper 	if (sa.st_flags == sb.st_flags)
7957718be8SEnji Cooper 		atf_tc_fail("stat(2) did not detect chflags(2)");
8057718be8SEnji Cooper 
8157718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
8257718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
8357718be8SEnji Cooper }
8457718be8SEnji Cooper 
8557718be8SEnji Cooper ATF_TC_CLEANUP(stat_chflags, tc)
8657718be8SEnji Cooper {
8757718be8SEnji Cooper 	(void)unlink(path);
8857718be8SEnji Cooper }
8957718be8SEnji Cooper 
9057718be8SEnji Cooper ATF_TC(stat_dir);
9157718be8SEnji Cooper ATF_TC_HEAD(stat_dir, tc)
9257718be8SEnji Cooper {
9357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories");
9457718be8SEnji Cooper }
9557718be8SEnji Cooper 
9657718be8SEnji Cooper ATF_TC_BODY(stat_dir, tc)
9757718be8SEnji Cooper {
9857718be8SEnji Cooper 	const short depth = 2;
9957718be8SEnji Cooper 	struct stat sa, sb;
10057718be8SEnji Cooper 	char *argv[2];
10157718be8SEnji Cooper 	FTSENT *ftse;
10257718be8SEnji Cooper 	FTS *fts;
10357718be8SEnji Cooper 	int ops;
10457718be8SEnji Cooper 
10557718be8SEnji Cooper 	argv[1] = NULL;
10657718be8SEnji Cooper 	argv[0] = __UNCONST("/");
10757718be8SEnji Cooper 
10857718be8SEnji Cooper 	ops = FTS_NOCHDIR;
10957718be8SEnji Cooper 	ops |= FTS_PHYSICAL;
11057718be8SEnji Cooper 
11157718be8SEnji Cooper 	fts = fts_open(argv, ops, NULL);
11257718be8SEnji Cooper 	ATF_REQUIRE(fts != NULL);
11357718be8SEnji Cooper 
11457718be8SEnji Cooper 	while ((ftse = fts_read(fts)) != NULL) {
11557718be8SEnji Cooper 
11657718be8SEnji Cooper 		if (ftse->fts_level < 1)
11757718be8SEnji Cooper 			continue;
11857718be8SEnji Cooper 
11957718be8SEnji Cooper 		if (ftse->fts_level > depth) {
12057718be8SEnji Cooper 			(void)fts_set(fts, ftse, FTS_SKIP);
12157718be8SEnji Cooper 			continue;
12257718be8SEnji Cooper 		}
12357718be8SEnji Cooper 
12457718be8SEnji Cooper 		switch(ftse->fts_info) {
12557718be8SEnji Cooper 
12657718be8SEnji Cooper 		case FTS_DP:
12757718be8SEnji Cooper 
12857718be8SEnji Cooper 			(void)memset(&sa, 0, sizeof(struct stat));
12957718be8SEnji Cooper 			(void)memset(&sb, 0, sizeof(struct stat));
13057718be8SEnji Cooper 
13157718be8SEnji Cooper 			ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0);
13257718be8SEnji Cooper 			ATF_REQUIRE(chdir(ftse->fts_path) == 0);
13357718be8SEnji Cooper 			ATF_REQUIRE(stat(".", &sb) == 0);
13457718be8SEnji Cooper 
13557718be8SEnji Cooper 			/*
13657718be8SEnji Cooper 			 * The previous two stat(2) calls
13757718be8SEnji Cooper 			 * should be for the same directory.
13857718be8SEnji Cooper 			 */
13957718be8SEnji Cooper 			if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino)
14057718be8SEnji Cooper 				atf_tc_fail("inconsistent stat(2)");
14157718be8SEnji Cooper 
14257718be8SEnji Cooper 			/*
14357718be8SEnji Cooper 			 * Check that fts(3)'s stat(2)
14457718be8SEnji Cooper 			 * call equals the manual one.
14557718be8SEnji Cooper 			 */
14657718be8SEnji Cooper 			if (sb.st_ino != ftse->fts_statp->st_ino)
14757718be8SEnji Cooper 				atf_tc_fail("stat(2) and fts(3) differ");
14857718be8SEnji Cooper 
14957718be8SEnji Cooper 			break;
15057718be8SEnji Cooper 
15157718be8SEnji Cooper 		default:
15257718be8SEnji Cooper 			break;
15357718be8SEnji Cooper 		}
15457718be8SEnji Cooper 	}
15557718be8SEnji Cooper 
15657718be8SEnji Cooper 	(void)fts_close(fts);
15757718be8SEnji Cooper }
15857718be8SEnji Cooper 
15957718be8SEnji Cooper ATF_TC(stat_err);
16057718be8SEnji Cooper ATF_TC_HEAD(stat_err, tc)
16157718be8SEnji Cooper {
16257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family");
16357718be8SEnji Cooper }
16457718be8SEnji Cooper 
16557718be8SEnji Cooper ATF_TC_BODY(stat_err, tc)
16657718be8SEnji Cooper {
16757718be8SEnji Cooper 	char buf[NAME_MAX + 1];
16857718be8SEnji Cooper 	struct stat st;
16957718be8SEnji Cooper 
17057718be8SEnji Cooper 	(void)memset(buf, 'x', sizeof(buf));
17157718be8SEnji Cooper 
17257718be8SEnji Cooper 	errno = 0;
17357718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1);
17457718be8SEnji Cooper 
17557718be8SEnji Cooper 	errno = 0;
17657718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1);
17757718be8SEnji Cooper 
17857718be8SEnji Cooper 	errno = 0;
17957718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1);
18057718be8SEnji Cooper 
18157718be8SEnji Cooper 	errno = 0;
18257718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1);
18357718be8SEnji Cooper 
18457718be8SEnji Cooper 	errno = 0;
18557718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1);
18657718be8SEnji Cooper 
18757718be8SEnji Cooper 	errno = 0;
18857718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1);
18957718be8SEnji Cooper 
19057718be8SEnji Cooper 	errno = 0;
19157718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1);
19257718be8SEnji Cooper 
19357718be8SEnji Cooper 	errno = 0;
19457718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
19557718be8SEnji Cooper 
19657718be8SEnji Cooper 	errno = 0;
19757718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
19857718be8SEnji Cooper }
19957718be8SEnji Cooper 
20057718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_mtime);
20157718be8SEnji Cooper ATF_TC_HEAD(stat_mtime, tc)
20257718be8SEnji Cooper {
20357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)");
20457718be8SEnji Cooper }
20557718be8SEnji Cooper 
20657718be8SEnji Cooper ATF_TC_BODY(stat_mtime, tc)
20757718be8SEnji Cooper {
20857718be8SEnji Cooper 	struct stat sa, sb;
20957718be8SEnji Cooper 	int fd[3];
21057718be8SEnji Cooper 	size_t i;
21157718be8SEnji Cooper 
21257718be8SEnji Cooper 	for (i = 0; i < __arraycount(fd); i++) {
21357718be8SEnji Cooper 
21457718be8SEnji Cooper 		(void)memset(&sa, 0, sizeof(struct stat));
21557718be8SEnji Cooper 		(void)memset(&sb, 0, sizeof(struct stat));
21657718be8SEnji Cooper 
21757718be8SEnji Cooper 		fd[i] = open(path, O_WRONLY | O_CREAT);
21857718be8SEnji Cooper 
21957718be8SEnji Cooper 		ATF_REQUIRE(fd[i] != -1);
22057718be8SEnji Cooper 		ATF_REQUIRE(write(fd[i], "X", 1) == 1);
22157718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sa) == 0);
22257718be8SEnji Cooper 
22357718be8SEnji Cooper 		(void)sleep(1);
22457718be8SEnji Cooper 
22557718be8SEnji Cooper 		ATF_REQUIRE(write(fd[i], "X", 1) == 1);
22657718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sb) == 0);
22757718be8SEnji Cooper 
22857718be8SEnji Cooper 		ATF_REQUIRE(close(fd[i]) == 0);
22957718be8SEnji Cooper 		ATF_REQUIRE(unlink(path) == 0);
23057718be8SEnji Cooper 
23157718be8SEnji Cooper 		if (sa.st_mtime == sb.st_mtime)
23257718be8SEnji Cooper 			atf_tc_fail("mtimes did not change");
23357718be8SEnji Cooper 	}
23457718be8SEnji Cooper }
23557718be8SEnji Cooper 
23657718be8SEnji Cooper ATF_TC_CLEANUP(stat_mtime, tc)
23757718be8SEnji Cooper {
23857718be8SEnji Cooper 	(void)unlink(path);
23957718be8SEnji Cooper }
24057718be8SEnji Cooper 
24157718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_perm);
24257718be8SEnji Cooper ATF_TC_HEAD(stat_perm, tc)
24357718be8SEnji Cooper {
24457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)");
24557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
24657718be8SEnji Cooper }
24757718be8SEnji Cooper 
24857718be8SEnji Cooper ATF_TC_BODY(stat_perm, tc)
24957718be8SEnji Cooper {
25057718be8SEnji Cooper 	struct stat sa, sb;
25157718be8SEnji Cooper 	gid_t gid;
25257718be8SEnji Cooper 	uid_t uid;
25357718be8SEnji Cooper 	int fd;
25457718be8SEnji Cooper 
25557718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
25657718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
25757718be8SEnji Cooper 
25857718be8SEnji Cooper 	uid = getuid();
25957718be8SEnji Cooper 	gid = getgid();
26057718be8SEnji Cooper 
26157718be8SEnji Cooper 	fd = open(path, O_RDONLY | O_CREAT);
26257718be8SEnji Cooper 
26357718be8SEnji Cooper 	ATF_REQUIRE(fd != -1);
26457718be8SEnji Cooper 	ATF_REQUIRE(fstat(fd, &sa) == 0);
26557718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sb) == 0);
26657718be8SEnji Cooper 
26757718be8SEnji Cooper 	if (gid != sa.st_gid || sa.st_gid != sb.st_gid)
26857718be8SEnji Cooper 		atf_tc_fail("invalid GID");
26957718be8SEnji Cooper 
27057718be8SEnji Cooper 	if (uid != sa.st_uid || sa.st_uid != sb.st_uid)
27157718be8SEnji Cooper 		atf_tc_fail("invalid UID");
27257718be8SEnji Cooper 
27357718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
27457718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
27557718be8SEnji Cooper }
27657718be8SEnji Cooper 
27757718be8SEnji Cooper ATF_TC_CLEANUP(stat_perm, tc)
27857718be8SEnji Cooper {
27957718be8SEnji Cooper 	(void)unlink(path);
28057718be8SEnji Cooper }
28157718be8SEnji Cooper 
28257718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_size);
28357718be8SEnji Cooper ATF_TC_HEAD(stat_size, tc)
28457718be8SEnji Cooper {
28557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)");
28657718be8SEnji Cooper }
28757718be8SEnji Cooper 
28857718be8SEnji Cooper ATF_TC_BODY(stat_size, tc)
28957718be8SEnji Cooper {
29057718be8SEnji Cooper 	struct stat sa, sb, sc;
29157718be8SEnji Cooper 	const size_t n = 10;
29257718be8SEnji Cooper 	size_t i;
29357718be8SEnji Cooper 	int fd;
29457718be8SEnji Cooper 
29557718be8SEnji Cooper 	fd = open(path, O_WRONLY | O_CREAT);
29657718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
29757718be8SEnji Cooper 
29857718be8SEnji Cooper 	for (i = 0; i < n; i++) {
29957718be8SEnji Cooper 
30057718be8SEnji Cooper 		(void)memset(&sa, 0, sizeof(struct stat));
30157718be8SEnji Cooper 		(void)memset(&sb, 0, sizeof(struct stat));
30257718be8SEnji Cooper 		(void)memset(&sc, 0, sizeof(struct stat));
30357718be8SEnji Cooper 
30457718be8SEnji Cooper 		ATF_REQUIRE(fstat(fd, &sa) == 0);
30557718be8SEnji Cooper 		ATF_REQUIRE(write(fd, "X", 1) == 1);
30657718be8SEnji Cooper 		ATF_REQUIRE(fstat(fd, &sb) == 0);
30757718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sc) == 0);
30857718be8SEnji Cooper 
30957718be8SEnji Cooper 		if (sa.st_size + 1 != sb.st_size)
31057718be8SEnji Cooper 			atf_tc_fail("invalid file size");
31157718be8SEnji Cooper 
31257718be8SEnji Cooper 		if (sb.st_size != sc.st_size)
31357718be8SEnji Cooper 			atf_tc_fail("stat(2) and fstat(2) mismatch");
31457718be8SEnji Cooper 	}
31557718be8SEnji Cooper 
31657718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
31757718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
31857718be8SEnji Cooper }
31957718be8SEnji Cooper 
32057718be8SEnji Cooper ATF_TC_CLEANUP(stat_size, tc)
32157718be8SEnji Cooper {
32257718be8SEnji Cooper 	(void)unlink(path);
32357718be8SEnji Cooper }
32457718be8SEnji Cooper 
32557718be8SEnji Cooper ATF_TC(stat_socket);
32657718be8SEnji Cooper ATF_TC_HEAD(stat_socket, tc)
32757718be8SEnji Cooper {
32857718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test fstat(2) with "
32957718be8SEnji Cooper 	    "a socket (PR kern/46077)");
33057718be8SEnji Cooper }
33157718be8SEnji Cooper 
33257718be8SEnji Cooper ATF_TC_BODY(stat_socket, tc)
33357718be8SEnji Cooper {
33457718be8SEnji Cooper 	struct sockaddr_in addr;
33557718be8SEnji Cooper 	struct stat st;
33657718be8SEnji Cooper 	uint32_t iaddr;
33757718be8SEnji Cooper 	int fd, flags;
33857718be8SEnji Cooper 
33957718be8SEnji Cooper 	(void)memset(&st, 0, sizeof(struct stat));
34057718be8SEnji Cooper 	(void)memset(&addr, 0, sizeof(struct sockaddr_in));
34157718be8SEnji Cooper 
34257718be8SEnji Cooper 	fd = socket(AF_INET, SOCK_STREAM, 0);
34357718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
34457718be8SEnji Cooper 
34557718be8SEnji Cooper 	flags = fcntl(fd, F_GETFL);
34657718be8SEnji Cooper 
34757718be8SEnji Cooper 	ATF_REQUIRE(flags != -1);
34857718be8SEnji Cooper 	ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
34957718be8SEnji Cooper 	ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1);
35057718be8SEnji Cooper 
35157718be8SEnji Cooper 	addr.sin_port = htons(42);
35257718be8SEnji Cooper 	addr.sin_family = AF_INET;
35357718be8SEnji Cooper 	addr.sin_addr.s_addr = iaddr;
35457718be8SEnji Cooper 
35557718be8SEnji Cooper 	errno = 0;
35657718be8SEnji Cooper 
35757718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EINPROGRESS,
35857718be8SEnji Cooper 	    connect(fd, (struct sockaddr *)&addr,
35957718be8SEnji Cooper 		sizeof(struct sockaddr_in)) == -1);
36057718be8SEnji Cooper 
36157718be8SEnji Cooper 	errno = 0;
36257718be8SEnji Cooper 
36357718be8SEnji Cooper 	if (fstat(fd, &st) != 0 || errno != 0)
36457718be8SEnji Cooper 		atf_tc_fail("fstat(2) failed for a EINPROGRESS socket");
36557718be8SEnji Cooper 
36657718be8SEnji Cooper 	(void)close(fd);
36757718be8SEnji Cooper }
36857718be8SEnji Cooper 
36957718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_symlink);
37057718be8SEnji Cooper ATF_TC_HEAD(stat_symlink, tc)
37157718be8SEnji Cooper {
37257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)");
37357718be8SEnji Cooper }
37457718be8SEnji Cooper 
37557718be8SEnji Cooper ATF_TC_BODY(stat_symlink, tc)
37657718be8SEnji Cooper {
37757718be8SEnji Cooper 	const char *pathlink = "pathlink";
37857718be8SEnji Cooper 	struct stat sa, sb;
37957718be8SEnji Cooper 	int fd;
38057718be8SEnji Cooper 
38157718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
38257718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
38357718be8SEnji Cooper 
38457718be8SEnji Cooper 	fd = open(path, O_WRONLY | O_CREAT);
38557718be8SEnji Cooper 
38657718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
38757718be8SEnji Cooper 	ATF_REQUIRE(symlink(path, pathlink) == 0);
38857718be8SEnji Cooper 	ATF_REQUIRE(stat(pathlink, &sa) == 0);
38957718be8SEnji Cooper 	ATF_REQUIRE(lstat(pathlink, &sb) == 0);
39057718be8SEnji Cooper 
39157718be8SEnji Cooper 	if (S_ISLNK(sa.st_mode) != 0)
39257718be8SEnji Cooper 		atf_tc_fail("stat(2) detected symbolic link");
39357718be8SEnji Cooper 
39457718be8SEnji Cooper 	if (S_ISLNK(sb.st_mode) == 0)
39557718be8SEnji Cooper 		atf_tc_fail("lstat(2) did not detect symbolic link");
39657718be8SEnji Cooper 
39757718be8SEnji Cooper 	if (sa.st_mode == sb.st_mode)
39857718be8SEnji Cooper 		atf_tc_fail("inconsistencies between stat(2) and lstat(2)");
39957718be8SEnji Cooper 
400*63d1fd59SEnji Cooper 	(void)close(fd);
40157718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
40257718be8SEnji Cooper 	ATF_REQUIRE(unlink(pathlink) == 0);
403621b0f13SEnji Cooper #ifdef	__FreeBSD__
404621b0f13SEnji Cooper 	(void)close(fd);
405621b0f13SEnji Cooper #endif
40657718be8SEnji Cooper }
40757718be8SEnji Cooper 
40857718be8SEnji Cooper ATF_TC_CLEANUP(stat_symlink, tc)
40957718be8SEnji Cooper {
41057718be8SEnji Cooper 	(void)unlink(path);
41157718be8SEnji Cooper }
41257718be8SEnji Cooper 
41357718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
41457718be8SEnji Cooper {
41557718be8SEnji Cooper 
41657718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_chflags);
41757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_dir);
41857718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_err);
41957718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_mtime);
42057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_perm);
42157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_size);
42257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_socket);
42357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_symlink);
42457718be8SEnji Cooper 
42557718be8SEnji Cooper 	return atf_no_error();
42657718be8SEnji Cooper }
427