xref: /freebsd-src/contrib/netbsd-tests/lib/libc/sys/t_stat.c (revision a39196afea7225bf05c537d61912be47b026bba1)
157718be8SEnji Cooper /* $NetBSD: t_stat.c,v 1.4 2012/03/17 08:37:08 jruoho 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>
3257718be8SEnji Cooper __RCSID("$NetBSD: t_stat.c,v 1.4 2012/03/17 08:37:08 jruoho 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>
3957718be8SEnji Cooper 
4057718be8SEnji Cooper #include <atf-c.h>
4157718be8SEnji Cooper #include <errno.h>
4257718be8SEnji Cooper #include <fcntl.h>
4357718be8SEnji Cooper #include <fts.h>
4457718be8SEnji Cooper #include <limits.h>
4557718be8SEnji Cooper #include <string.h>
4657718be8SEnji Cooper #include <unistd.h>
4757718be8SEnji Cooper 
4857718be8SEnji Cooper #include <stdio.h>
4957718be8SEnji Cooper 
50*a39196afSEnji Cooper #if defined(__FreeBSD__)
51*a39196afSEnji Cooper #include <netinet/in.h>
52*a39196afSEnji Cooper #endif
53*a39196afSEnji Cooper 
5457718be8SEnji Cooper static const char *path = "stat";
5557718be8SEnji Cooper 
5657718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_chflags);
5757718be8SEnji Cooper ATF_TC_HEAD(stat_chflags, tc)
5857718be8SEnji Cooper {
5957718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)");
6057718be8SEnji Cooper }
6157718be8SEnji Cooper 
6257718be8SEnji Cooper ATF_TC_BODY(stat_chflags, tc)
6357718be8SEnji Cooper {
6457718be8SEnji Cooper 	struct stat sa, sb;
6557718be8SEnji Cooper 	int fd;
6657718be8SEnji Cooper 
6757718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
6857718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
6957718be8SEnji Cooper 
7057718be8SEnji Cooper 	fd = open(path, O_RDONLY | O_CREAT);
7157718be8SEnji Cooper 
7257718be8SEnji Cooper 	ATF_REQUIRE(fd != -1);
7357718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sa) == 0);
7457718be8SEnji Cooper 	ATF_REQUIRE(chflags(path, UF_NODUMP) == 0);
7557718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sb) == 0);
7657718be8SEnji Cooper 
7757718be8SEnji Cooper 	if (sa.st_flags == sb.st_flags)
7857718be8SEnji Cooper 		atf_tc_fail("stat(2) did not detect chflags(2)");
7957718be8SEnji Cooper 
8057718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
8157718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
8257718be8SEnji Cooper }
8357718be8SEnji Cooper 
8457718be8SEnji Cooper ATF_TC_CLEANUP(stat_chflags, tc)
8557718be8SEnji Cooper {
8657718be8SEnji Cooper 	(void)unlink(path);
8757718be8SEnji Cooper }
8857718be8SEnji Cooper 
8957718be8SEnji Cooper ATF_TC(stat_dir);
9057718be8SEnji Cooper ATF_TC_HEAD(stat_dir, tc)
9157718be8SEnji Cooper {
9257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories");
9357718be8SEnji Cooper }
9457718be8SEnji Cooper 
9557718be8SEnji Cooper ATF_TC_BODY(stat_dir, tc)
9657718be8SEnji Cooper {
9757718be8SEnji Cooper 	const short depth = 2;
9857718be8SEnji Cooper 	struct stat sa, sb;
9957718be8SEnji Cooper 	char *argv[2];
10057718be8SEnji Cooper 	FTSENT *ftse;
10157718be8SEnji Cooper 	FTS *fts;
10257718be8SEnji Cooper 	int ops;
10357718be8SEnji Cooper 
10457718be8SEnji Cooper 	argv[1] = NULL;
10557718be8SEnji Cooper 	argv[0] = __UNCONST("/");
10657718be8SEnji Cooper 
10757718be8SEnji Cooper 	ops = FTS_NOCHDIR;
10857718be8SEnji Cooper 	ops |= FTS_PHYSICAL;
10957718be8SEnji Cooper 
11057718be8SEnji Cooper 	fts = fts_open(argv, ops, NULL);
11157718be8SEnji Cooper 	ATF_REQUIRE(fts != NULL);
11257718be8SEnji Cooper 
11357718be8SEnji Cooper 	while ((ftse = fts_read(fts)) != NULL) {
11457718be8SEnji Cooper 
11557718be8SEnji Cooper 		if (ftse->fts_level < 1)
11657718be8SEnji Cooper 			continue;
11757718be8SEnji Cooper 
11857718be8SEnji Cooper 		if (ftse->fts_level > depth) {
11957718be8SEnji Cooper 			(void)fts_set(fts, ftse, FTS_SKIP);
12057718be8SEnji Cooper 			continue;
12157718be8SEnji Cooper 		}
12257718be8SEnji Cooper 
12357718be8SEnji Cooper 		switch(ftse->fts_info) {
12457718be8SEnji Cooper 
12557718be8SEnji Cooper 		case FTS_DP:
12657718be8SEnji Cooper 
12757718be8SEnji Cooper 			(void)memset(&sa, 0, sizeof(struct stat));
12857718be8SEnji Cooper 			(void)memset(&sb, 0, sizeof(struct stat));
12957718be8SEnji Cooper 
13057718be8SEnji Cooper 			ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0);
13157718be8SEnji Cooper 			ATF_REQUIRE(chdir(ftse->fts_path) == 0);
13257718be8SEnji Cooper 			ATF_REQUIRE(stat(".", &sb) == 0);
13357718be8SEnji Cooper 
13457718be8SEnji Cooper 			/*
13557718be8SEnji Cooper 			 * The previous two stat(2) calls
13657718be8SEnji Cooper 			 * should be for the same directory.
13757718be8SEnji Cooper 			 */
13857718be8SEnji Cooper 			if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino)
13957718be8SEnji Cooper 				atf_tc_fail("inconsistent stat(2)");
14057718be8SEnji Cooper 
14157718be8SEnji Cooper 			/*
14257718be8SEnji Cooper 			 * Check that fts(3)'s stat(2)
14357718be8SEnji Cooper 			 * call equals the manual one.
14457718be8SEnji Cooper 			 */
14557718be8SEnji Cooper 			if (sb.st_ino != ftse->fts_statp->st_ino)
14657718be8SEnji Cooper 				atf_tc_fail("stat(2) and fts(3) differ");
14757718be8SEnji Cooper 
14857718be8SEnji Cooper 			break;
14957718be8SEnji Cooper 
15057718be8SEnji Cooper 		default:
15157718be8SEnji Cooper 			break;
15257718be8SEnji Cooper 		}
15357718be8SEnji Cooper 	}
15457718be8SEnji Cooper 
15557718be8SEnji Cooper 	(void)fts_close(fts);
15657718be8SEnji Cooper }
15757718be8SEnji Cooper 
15857718be8SEnji Cooper ATF_TC(stat_err);
15957718be8SEnji Cooper ATF_TC_HEAD(stat_err, tc)
16057718be8SEnji Cooper {
16157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family");
16257718be8SEnji Cooper }
16357718be8SEnji Cooper 
16457718be8SEnji Cooper ATF_TC_BODY(stat_err, tc)
16557718be8SEnji Cooper {
16657718be8SEnji Cooper 	char buf[NAME_MAX + 1];
16757718be8SEnji Cooper 	struct stat st;
16857718be8SEnji Cooper 
16957718be8SEnji Cooper 	(void)memset(buf, 'x', sizeof(buf));
17057718be8SEnji Cooper 
17157718be8SEnji Cooper 	errno = 0;
17257718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1);
17357718be8SEnji Cooper 
17457718be8SEnji Cooper 	errno = 0;
17557718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1);
17657718be8SEnji Cooper 
17757718be8SEnji Cooper 	errno = 0;
17857718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1);
17957718be8SEnji Cooper 
18057718be8SEnji Cooper 	errno = 0;
18157718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1);
18257718be8SEnji Cooper 
18357718be8SEnji Cooper 	errno = 0;
18457718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1);
18557718be8SEnji Cooper 
18657718be8SEnji Cooper 	errno = 0;
18757718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1);
18857718be8SEnji Cooper 
18957718be8SEnji Cooper 	errno = 0;
19057718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1);
19157718be8SEnji Cooper 
19257718be8SEnji Cooper 	errno = 0;
19357718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
19457718be8SEnji Cooper 
19557718be8SEnji Cooper 	errno = 0;
19657718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
19757718be8SEnji Cooper }
19857718be8SEnji Cooper 
19957718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_mtime);
20057718be8SEnji Cooper ATF_TC_HEAD(stat_mtime, tc)
20157718be8SEnji Cooper {
20257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)");
20357718be8SEnji Cooper }
20457718be8SEnji Cooper 
20557718be8SEnji Cooper ATF_TC_BODY(stat_mtime, tc)
20657718be8SEnji Cooper {
20757718be8SEnji Cooper 	struct stat sa, sb;
20857718be8SEnji Cooper 	int fd[3];
20957718be8SEnji Cooper 	size_t i;
21057718be8SEnji Cooper 
21157718be8SEnji Cooper 	for (i = 0; i < __arraycount(fd); i++) {
21257718be8SEnji Cooper 
21357718be8SEnji Cooper 		(void)memset(&sa, 0, sizeof(struct stat));
21457718be8SEnji Cooper 		(void)memset(&sb, 0, sizeof(struct stat));
21557718be8SEnji Cooper 
21657718be8SEnji Cooper 		fd[i] = open(path, O_WRONLY | O_CREAT);
21757718be8SEnji Cooper 
21857718be8SEnji Cooper 		ATF_REQUIRE(fd[i] != -1);
21957718be8SEnji Cooper 		ATF_REQUIRE(write(fd[i], "X", 1) == 1);
22057718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sa) == 0);
22157718be8SEnji Cooper 
22257718be8SEnji Cooper 		(void)sleep(1);
22357718be8SEnji Cooper 
22457718be8SEnji Cooper 		ATF_REQUIRE(write(fd[i], "X", 1) == 1);
22557718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sb) == 0);
22657718be8SEnji Cooper 
22757718be8SEnji Cooper 		ATF_REQUIRE(close(fd[i]) == 0);
22857718be8SEnji Cooper 		ATF_REQUIRE(unlink(path) == 0);
22957718be8SEnji Cooper 
23057718be8SEnji Cooper 		if (sa.st_mtime == sb.st_mtime)
23157718be8SEnji Cooper 			atf_tc_fail("mtimes did not change");
23257718be8SEnji Cooper 	}
23357718be8SEnji Cooper }
23457718be8SEnji Cooper 
23557718be8SEnji Cooper ATF_TC_CLEANUP(stat_mtime, tc)
23657718be8SEnji Cooper {
23757718be8SEnji Cooper 	(void)unlink(path);
23857718be8SEnji Cooper }
23957718be8SEnji Cooper 
24057718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_perm);
24157718be8SEnji Cooper ATF_TC_HEAD(stat_perm, tc)
24257718be8SEnji Cooper {
24357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)");
24457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
24557718be8SEnji Cooper }
24657718be8SEnji Cooper 
24757718be8SEnji Cooper ATF_TC_BODY(stat_perm, tc)
24857718be8SEnji Cooper {
24957718be8SEnji Cooper 	struct stat sa, sb;
25057718be8SEnji Cooper 	gid_t gid;
25157718be8SEnji Cooper 	uid_t uid;
25257718be8SEnji Cooper 	int fd;
25357718be8SEnji Cooper 
25457718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
25557718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
25657718be8SEnji Cooper 
25757718be8SEnji Cooper 	uid = getuid();
25857718be8SEnji Cooper 	gid = getgid();
25957718be8SEnji Cooper 
26057718be8SEnji Cooper 	fd = open(path, O_RDONLY | O_CREAT);
26157718be8SEnji Cooper 
26257718be8SEnji Cooper 	ATF_REQUIRE(fd != -1);
26357718be8SEnji Cooper 	ATF_REQUIRE(fstat(fd, &sa) == 0);
26457718be8SEnji Cooper 	ATF_REQUIRE(stat(path, &sb) == 0);
26557718be8SEnji Cooper 
26657718be8SEnji Cooper 	if (gid != sa.st_gid || sa.st_gid != sb.st_gid)
26757718be8SEnji Cooper 		atf_tc_fail("invalid GID");
26857718be8SEnji Cooper 
26957718be8SEnji Cooper 	if (uid != sa.st_uid || sa.st_uid != sb.st_uid)
27057718be8SEnji Cooper 		atf_tc_fail("invalid UID");
27157718be8SEnji Cooper 
27257718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
27357718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
27457718be8SEnji Cooper }
27557718be8SEnji Cooper 
27657718be8SEnji Cooper ATF_TC_CLEANUP(stat_perm, tc)
27757718be8SEnji Cooper {
27857718be8SEnji Cooper 	(void)unlink(path);
27957718be8SEnji Cooper }
28057718be8SEnji Cooper 
28157718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_size);
28257718be8SEnji Cooper ATF_TC_HEAD(stat_size, tc)
28357718be8SEnji Cooper {
28457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)");
28557718be8SEnji Cooper }
28657718be8SEnji Cooper 
28757718be8SEnji Cooper ATF_TC_BODY(stat_size, tc)
28857718be8SEnji Cooper {
28957718be8SEnji Cooper 	struct stat sa, sb, sc;
29057718be8SEnji Cooper 	const size_t n = 10;
29157718be8SEnji Cooper 	size_t i;
29257718be8SEnji Cooper 	int fd;
29357718be8SEnji Cooper 
29457718be8SEnji Cooper 	fd = open(path, O_WRONLY | O_CREAT);
29557718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
29657718be8SEnji Cooper 
29757718be8SEnji Cooper 	for (i = 0; i < n; i++) {
29857718be8SEnji Cooper 
29957718be8SEnji Cooper 		(void)memset(&sa, 0, sizeof(struct stat));
30057718be8SEnji Cooper 		(void)memset(&sb, 0, sizeof(struct stat));
30157718be8SEnji Cooper 		(void)memset(&sc, 0, sizeof(struct stat));
30257718be8SEnji Cooper 
30357718be8SEnji Cooper 		ATF_REQUIRE(fstat(fd, &sa) == 0);
30457718be8SEnji Cooper 		ATF_REQUIRE(write(fd, "X", 1) == 1);
30557718be8SEnji Cooper 		ATF_REQUIRE(fstat(fd, &sb) == 0);
30657718be8SEnji Cooper 		ATF_REQUIRE(stat(path, &sc) == 0);
30757718be8SEnji Cooper 
30857718be8SEnji Cooper 		if (sa.st_size + 1 != sb.st_size)
30957718be8SEnji Cooper 			atf_tc_fail("invalid file size");
31057718be8SEnji Cooper 
31157718be8SEnji Cooper 		if (sb.st_size != sc.st_size)
31257718be8SEnji Cooper 			atf_tc_fail("stat(2) and fstat(2) mismatch");
31357718be8SEnji Cooper 	}
31457718be8SEnji Cooper 
31557718be8SEnji Cooper 	ATF_REQUIRE(close(fd) == 0);
31657718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
31757718be8SEnji Cooper }
31857718be8SEnji Cooper 
31957718be8SEnji Cooper ATF_TC_CLEANUP(stat_size, tc)
32057718be8SEnji Cooper {
32157718be8SEnji Cooper 	(void)unlink(path);
32257718be8SEnji Cooper }
32357718be8SEnji Cooper 
32457718be8SEnji Cooper ATF_TC(stat_socket);
32557718be8SEnji Cooper ATF_TC_HEAD(stat_socket, tc)
32657718be8SEnji Cooper {
32757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test fstat(2) with "
32857718be8SEnji Cooper 	    "a socket (PR kern/46077)");
32957718be8SEnji Cooper }
33057718be8SEnji Cooper 
33157718be8SEnji Cooper ATF_TC_BODY(stat_socket, tc)
33257718be8SEnji Cooper {
33357718be8SEnji Cooper 	struct sockaddr_in addr;
33457718be8SEnji Cooper 	struct stat st;
33557718be8SEnji Cooper 	uint32_t iaddr;
33657718be8SEnji Cooper 	int fd, flags;
33757718be8SEnji Cooper 
33857718be8SEnji Cooper 	(void)memset(&st, 0, sizeof(struct stat));
33957718be8SEnji Cooper 	(void)memset(&addr, 0, sizeof(struct sockaddr_in));
34057718be8SEnji Cooper 
34157718be8SEnji Cooper 	fd = socket(AF_INET, SOCK_STREAM, 0);
34257718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
34357718be8SEnji Cooper 
34457718be8SEnji Cooper 	flags = fcntl(fd, F_GETFL);
34557718be8SEnji Cooper 
34657718be8SEnji Cooper 	ATF_REQUIRE(flags != -1);
34757718be8SEnji Cooper 	ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
34857718be8SEnji Cooper 	ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1);
34957718be8SEnji Cooper 
35057718be8SEnji Cooper 	addr.sin_port = htons(42);
35157718be8SEnji Cooper 	addr.sin_family = AF_INET;
35257718be8SEnji Cooper 	addr.sin_addr.s_addr = iaddr;
35357718be8SEnji Cooper 
35457718be8SEnji Cooper 	errno = 0;
35557718be8SEnji Cooper 
35657718be8SEnji Cooper 	ATF_REQUIRE_ERRNO(EINPROGRESS,
35757718be8SEnji Cooper 	    connect(fd, (struct sockaddr *)&addr,
35857718be8SEnji Cooper 		sizeof(struct sockaddr_in)) == -1);
35957718be8SEnji Cooper 
36057718be8SEnji Cooper 	errno = 0;
36157718be8SEnji Cooper 
36257718be8SEnji Cooper 	if (fstat(fd, &st) != 0 || errno != 0)
36357718be8SEnji Cooper 		atf_tc_fail("fstat(2) failed for a EINPROGRESS socket");
36457718be8SEnji Cooper 
36557718be8SEnji Cooper 	(void)close(fd);
36657718be8SEnji Cooper }
36757718be8SEnji Cooper 
36857718be8SEnji Cooper ATF_TC_WITH_CLEANUP(stat_symlink);
36957718be8SEnji Cooper ATF_TC_HEAD(stat_symlink, tc)
37057718be8SEnji Cooper {
37157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)");
37257718be8SEnji Cooper }
37357718be8SEnji Cooper 
37457718be8SEnji Cooper ATF_TC_BODY(stat_symlink, tc)
37557718be8SEnji Cooper {
37657718be8SEnji Cooper 	const char *pathlink = "pathlink";
37757718be8SEnji Cooper 	struct stat sa, sb;
37857718be8SEnji Cooper 	int fd;
37957718be8SEnji Cooper 
38057718be8SEnji Cooper 	(void)memset(&sa, 0, sizeof(struct stat));
38157718be8SEnji Cooper 	(void)memset(&sb, 0, sizeof(struct stat));
38257718be8SEnji Cooper 
38357718be8SEnji Cooper 	fd = open(path, O_WRONLY | O_CREAT);
38457718be8SEnji Cooper 
38557718be8SEnji Cooper 	ATF_REQUIRE(fd >= 0);
38657718be8SEnji Cooper 	ATF_REQUIRE(symlink(path, pathlink) == 0);
38757718be8SEnji Cooper 	ATF_REQUIRE(stat(pathlink, &sa) == 0);
38857718be8SEnji Cooper 	ATF_REQUIRE(lstat(pathlink, &sb) == 0);
38957718be8SEnji Cooper 
39057718be8SEnji Cooper 	if (S_ISLNK(sa.st_mode) != 0)
39157718be8SEnji Cooper 		atf_tc_fail("stat(2) detected symbolic link");
39257718be8SEnji Cooper 
39357718be8SEnji Cooper 	if (S_ISLNK(sb.st_mode) == 0)
39457718be8SEnji Cooper 		atf_tc_fail("lstat(2) did not detect symbolic link");
39557718be8SEnji Cooper 
39657718be8SEnji Cooper 	if (sa.st_mode == sb.st_mode)
39757718be8SEnji Cooper 		atf_tc_fail("inconsistencies between stat(2) and lstat(2)");
39857718be8SEnji Cooper 
39957718be8SEnji Cooper 	ATF_REQUIRE(unlink(path) == 0);
40057718be8SEnji Cooper 	ATF_REQUIRE(unlink(pathlink) == 0);
40157718be8SEnji Cooper }
40257718be8SEnji Cooper 
40357718be8SEnji Cooper ATF_TC_CLEANUP(stat_symlink, tc)
40457718be8SEnji Cooper {
40557718be8SEnji Cooper 	(void)unlink(path);
40657718be8SEnji Cooper }
40757718be8SEnji Cooper 
40857718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
40957718be8SEnji Cooper {
41057718be8SEnji Cooper 
41157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_chflags);
41257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_dir);
41357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_err);
41457718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_mtime);
41557718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_perm);
41657718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_size);
41757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_socket);
41857718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, stat_symlink);
41957718be8SEnji Cooper 
42057718be8SEnji Cooper 	return atf_no_error();
42157718be8SEnji Cooper }
422