1*653f037eSmartin /* $NetBSD: t_stat.c,v 1.6 2019/07/16 17:29:18 martin Exp $ */
2068fb4f1Sjruoho
3068fb4f1Sjruoho /*-
4068fb4f1Sjruoho * Copyright (c) 2011 The NetBSD Foundation, Inc.
5068fb4f1Sjruoho * All rights reserved.
6068fb4f1Sjruoho *
7068fb4f1Sjruoho * This code is derived from software contributed to The NetBSD Foundation
8068fb4f1Sjruoho * by Jukka Ruohonen.
9068fb4f1Sjruoho *
10068fb4f1Sjruoho * Redistribution and use in source and binary forms, with or without
11068fb4f1Sjruoho * modification, are permitted provided that the following conditions
12068fb4f1Sjruoho * are met:
13068fb4f1Sjruoho * 1. Redistributions of source code must retain the above copyright
14068fb4f1Sjruoho * notice, this list of conditions and the following disclaimer.
15068fb4f1Sjruoho * 2. Redistributions in binary form must reproduce the above copyright
16068fb4f1Sjruoho * notice, this list of conditions and the following disclaimer in the
17068fb4f1Sjruoho * documentation and/or other materials provided with the distribution.
18068fb4f1Sjruoho *
19068fb4f1Sjruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20068fb4f1Sjruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21068fb4f1Sjruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22068fb4f1Sjruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23068fb4f1Sjruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24068fb4f1Sjruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25068fb4f1Sjruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26068fb4f1Sjruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27068fb4f1Sjruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28068fb4f1Sjruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29068fb4f1Sjruoho * POSSIBILITY OF SUCH DAMAGE.
30068fb4f1Sjruoho */
31068fb4f1Sjruoho #include <sys/cdefs.h>
32*653f037eSmartin __RCSID("$NetBSD: t_stat.c,v 1.6 2019/07/16 17:29:18 martin Exp $");
33068fb4f1Sjruoho
34068fb4f1Sjruoho #include <sys/stat.h>
357ee67ae0Sjruoho #include <sys/socket.h>
36068fb4f1Sjruoho #include <sys/types.h>
37068fb4f1Sjruoho
387ee67ae0Sjruoho #include <arpa/inet.h>
394cc87d7eSchristos #include <netinet/in.h>
407ee67ae0Sjruoho
41068fb4f1Sjruoho #include <atf-c.h>
42068fb4f1Sjruoho #include <errno.h>
43068fb4f1Sjruoho #include <fcntl.h>
44068fb4f1Sjruoho #include <fts.h>
45068fb4f1Sjruoho #include <limits.h>
46068fb4f1Sjruoho #include <string.h>
47068fb4f1Sjruoho #include <unistd.h>
48068fb4f1Sjruoho
49068fb4f1Sjruoho #include <stdio.h>
50068fb4f1Sjruoho
51068fb4f1Sjruoho static const char *path = "stat";
52068fb4f1Sjruoho
53068fb4f1Sjruoho ATF_TC_WITH_CLEANUP(stat_chflags);
ATF_TC_HEAD(stat_chflags,tc)54068fb4f1Sjruoho ATF_TC_HEAD(stat_chflags, tc)
55068fb4f1Sjruoho {
56068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)");
57068fb4f1Sjruoho }
58068fb4f1Sjruoho
ATF_TC_BODY(stat_chflags,tc)59068fb4f1Sjruoho ATF_TC_BODY(stat_chflags, tc)
60068fb4f1Sjruoho {
61068fb4f1Sjruoho struct stat sa, sb;
62068fb4f1Sjruoho int fd;
63068fb4f1Sjruoho
64068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
65068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
66068fb4f1Sjruoho
67*653f037eSmartin fd = open(path, O_RDONLY | O_CREAT, 0600);
68068fb4f1Sjruoho
69068fb4f1Sjruoho ATF_REQUIRE(fd != -1);
70068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sa) == 0);
71068fb4f1Sjruoho ATF_REQUIRE(chflags(path, UF_NODUMP) == 0);
72068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sb) == 0);
73068fb4f1Sjruoho
74068fb4f1Sjruoho if (sa.st_flags == sb.st_flags)
75068fb4f1Sjruoho atf_tc_fail("stat(2) did not detect chflags(2)");
76068fb4f1Sjruoho
77068fb4f1Sjruoho ATF_REQUIRE(close(fd) == 0);
78068fb4f1Sjruoho ATF_REQUIRE(unlink(path) == 0);
79068fb4f1Sjruoho }
80068fb4f1Sjruoho
ATF_TC_CLEANUP(stat_chflags,tc)81068fb4f1Sjruoho ATF_TC_CLEANUP(stat_chflags, tc)
82068fb4f1Sjruoho {
83068fb4f1Sjruoho (void)unlink(path);
84068fb4f1Sjruoho }
85068fb4f1Sjruoho
86068fb4f1Sjruoho ATF_TC(stat_dir);
ATF_TC_HEAD(stat_dir,tc)87068fb4f1Sjruoho ATF_TC_HEAD(stat_dir, tc)
88068fb4f1Sjruoho {
89068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories");
90068fb4f1Sjruoho }
91068fb4f1Sjruoho
ATF_TC_BODY(stat_dir,tc)92068fb4f1Sjruoho ATF_TC_BODY(stat_dir, tc)
93068fb4f1Sjruoho {
94b338bf93Sjruoho const short depth = 2;
95068fb4f1Sjruoho struct stat sa, sb;
96068fb4f1Sjruoho char *argv[2];
97068fb4f1Sjruoho FTSENT *ftse;
98068fb4f1Sjruoho FTS *fts;
99068fb4f1Sjruoho int ops;
100068fb4f1Sjruoho
101068fb4f1Sjruoho argv[1] = NULL;
102068fb4f1Sjruoho argv[0] = __UNCONST("/");
103068fb4f1Sjruoho
104068fb4f1Sjruoho ops = FTS_NOCHDIR;
105068fb4f1Sjruoho ops |= FTS_PHYSICAL;
106068fb4f1Sjruoho
107068fb4f1Sjruoho fts = fts_open(argv, ops, NULL);
108068fb4f1Sjruoho ATF_REQUIRE(fts != NULL);
109068fb4f1Sjruoho
110068fb4f1Sjruoho while ((ftse = fts_read(fts)) != NULL) {
111068fb4f1Sjruoho
112068fb4f1Sjruoho if (ftse->fts_level < 1)
113068fb4f1Sjruoho continue;
114068fb4f1Sjruoho
115068fb4f1Sjruoho if (ftse->fts_level > depth) {
116068fb4f1Sjruoho (void)fts_set(fts, ftse, FTS_SKIP);
117068fb4f1Sjruoho continue;
118068fb4f1Sjruoho }
119068fb4f1Sjruoho
120068fb4f1Sjruoho switch(ftse->fts_info) {
121068fb4f1Sjruoho
122068fb4f1Sjruoho case FTS_DP:
123068fb4f1Sjruoho
124068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
125068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
126068fb4f1Sjruoho
127068fb4f1Sjruoho ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0);
128068fb4f1Sjruoho ATF_REQUIRE(chdir(ftse->fts_path) == 0);
129068fb4f1Sjruoho ATF_REQUIRE(stat(".", &sb) == 0);
130068fb4f1Sjruoho
131068fb4f1Sjruoho /*
132068fb4f1Sjruoho * The previous two stat(2) calls
133068fb4f1Sjruoho * should be for the same directory.
134068fb4f1Sjruoho */
135068fb4f1Sjruoho if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino)
136068fb4f1Sjruoho atf_tc_fail("inconsistent stat(2)");
137068fb4f1Sjruoho
138068fb4f1Sjruoho /*
139068fb4f1Sjruoho * Check that fts(3)'s stat(2)
140068fb4f1Sjruoho * call equals the manual one.
141068fb4f1Sjruoho */
142068fb4f1Sjruoho if (sb.st_ino != ftse->fts_statp->st_ino)
143068fb4f1Sjruoho atf_tc_fail("stat(2) and fts(3) differ");
144068fb4f1Sjruoho
145068fb4f1Sjruoho break;
146068fb4f1Sjruoho
147068fb4f1Sjruoho default:
148068fb4f1Sjruoho break;
149068fb4f1Sjruoho }
150068fb4f1Sjruoho }
151068fb4f1Sjruoho
152068fb4f1Sjruoho (void)fts_close(fts);
153068fb4f1Sjruoho }
154068fb4f1Sjruoho
155068fb4f1Sjruoho ATF_TC(stat_err);
ATF_TC_HEAD(stat_err,tc)156068fb4f1Sjruoho ATF_TC_HEAD(stat_err, tc)
157068fb4f1Sjruoho {
158068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family");
159068fb4f1Sjruoho }
160068fb4f1Sjruoho
ATF_TC_BODY(stat_err,tc)161068fb4f1Sjruoho ATF_TC_BODY(stat_err, tc)
162068fb4f1Sjruoho {
163068fb4f1Sjruoho char buf[NAME_MAX + 1];
164068fb4f1Sjruoho struct stat st;
165068fb4f1Sjruoho
166068fb4f1Sjruoho (void)memset(buf, 'x', sizeof(buf));
167068fb4f1Sjruoho
168068fb4f1Sjruoho errno = 0;
169068fb4f1Sjruoho ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1);
170068fb4f1Sjruoho
171068fb4f1Sjruoho errno = 0;
172068fb4f1Sjruoho ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1);
173068fb4f1Sjruoho
174068fb4f1Sjruoho errno = 0;
175068fb4f1Sjruoho ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1);
176068fb4f1Sjruoho
177068fb4f1Sjruoho errno = 0;
178068fb4f1Sjruoho ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1);
179068fb4f1Sjruoho
180068fb4f1Sjruoho errno = 0;
181068fb4f1Sjruoho ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1);
182068fb4f1Sjruoho
183068fb4f1Sjruoho errno = 0;
184068fb4f1Sjruoho ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1);
185068fb4f1Sjruoho
186068fb4f1Sjruoho errno = 0;
187068fb4f1Sjruoho ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1);
188068fb4f1Sjruoho
189068fb4f1Sjruoho errno = 0;
190068fb4f1Sjruoho ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
191068fb4f1Sjruoho
192068fb4f1Sjruoho errno = 0;
193068fb4f1Sjruoho ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1);
194068fb4f1Sjruoho }
195068fb4f1Sjruoho
196068fb4f1Sjruoho ATF_TC_WITH_CLEANUP(stat_mtime);
ATF_TC_HEAD(stat_mtime,tc)197068fb4f1Sjruoho ATF_TC_HEAD(stat_mtime, tc)
198068fb4f1Sjruoho {
199068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)");
200068fb4f1Sjruoho }
201068fb4f1Sjruoho
ATF_TC_BODY(stat_mtime,tc)202068fb4f1Sjruoho ATF_TC_BODY(stat_mtime, tc)
203068fb4f1Sjruoho {
204068fb4f1Sjruoho struct stat sa, sb;
205068fb4f1Sjruoho int fd[3];
206068fb4f1Sjruoho size_t i;
207068fb4f1Sjruoho
208068fb4f1Sjruoho for (i = 0; i < __arraycount(fd); i++) {
209068fb4f1Sjruoho
210068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
211068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
212068fb4f1Sjruoho
213*653f037eSmartin fd[i] = open(path, O_WRONLY | O_CREAT, 0600);
214068fb4f1Sjruoho
215068fb4f1Sjruoho ATF_REQUIRE(fd[i] != -1);
216068fb4f1Sjruoho ATF_REQUIRE(write(fd[i], "X", 1) == 1);
217068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sa) == 0);
218068fb4f1Sjruoho
219068fb4f1Sjruoho (void)sleep(1);
220068fb4f1Sjruoho
221068fb4f1Sjruoho ATF_REQUIRE(write(fd[i], "X", 1) == 1);
222068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sb) == 0);
223068fb4f1Sjruoho
224068fb4f1Sjruoho ATF_REQUIRE(close(fd[i]) == 0);
225068fb4f1Sjruoho ATF_REQUIRE(unlink(path) == 0);
226068fb4f1Sjruoho
227068fb4f1Sjruoho if (sa.st_mtime == sb.st_mtime)
228068fb4f1Sjruoho atf_tc_fail("mtimes did not change");
229068fb4f1Sjruoho }
230068fb4f1Sjruoho }
231068fb4f1Sjruoho
ATF_TC_CLEANUP(stat_mtime,tc)232068fb4f1Sjruoho ATF_TC_CLEANUP(stat_mtime, tc)
233068fb4f1Sjruoho {
234068fb4f1Sjruoho (void)unlink(path);
235068fb4f1Sjruoho }
236068fb4f1Sjruoho
237068fb4f1Sjruoho ATF_TC_WITH_CLEANUP(stat_perm);
ATF_TC_HEAD(stat_perm,tc)238068fb4f1Sjruoho ATF_TC_HEAD(stat_perm, tc)
239068fb4f1Sjruoho {
240068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)");
241068fb4f1Sjruoho atf_tc_set_md_var(tc, "require.user", "root");
242068fb4f1Sjruoho }
243068fb4f1Sjruoho
ATF_TC_BODY(stat_perm,tc)244068fb4f1Sjruoho ATF_TC_BODY(stat_perm, tc)
245068fb4f1Sjruoho {
246068fb4f1Sjruoho struct stat sa, sb;
247068fb4f1Sjruoho gid_t gid;
248068fb4f1Sjruoho uid_t uid;
249068fb4f1Sjruoho int fd;
250068fb4f1Sjruoho
251068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
252068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
253068fb4f1Sjruoho
254068fb4f1Sjruoho uid = getuid();
255068fb4f1Sjruoho gid = getgid();
256068fb4f1Sjruoho
257*653f037eSmartin fd = open(path, O_RDONLY | O_CREAT, 0600);
258068fb4f1Sjruoho
259068fb4f1Sjruoho ATF_REQUIRE(fd != -1);
260068fb4f1Sjruoho ATF_REQUIRE(fstat(fd, &sa) == 0);
261068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sb) == 0);
262068fb4f1Sjruoho
263068fb4f1Sjruoho if (gid != sa.st_gid || sa.st_gid != sb.st_gid)
264068fb4f1Sjruoho atf_tc_fail("invalid GID");
265068fb4f1Sjruoho
266068fb4f1Sjruoho if (uid != sa.st_uid || sa.st_uid != sb.st_uid)
267068fb4f1Sjruoho atf_tc_fail("invalid UID");
268068fb4f1Sjruoho
269068fb4f1Sjruoho ATF_REQUIRE(close(fd) == 0);
270068fb4f1Sjruoho ATF_REQUIRE(unlink(path) == 0);
271068fb4f1Sjruoho }
272068fb4f1Sjruoho
ATF_TC_CLEANUP(stat_perm,tc)273068fb4f1Sjruoho ATF_TC_CLEANUP(stat_perm, tc)
274068fb4f1Sjruoho {
275068fb4f1Sjruoho (void)unlink(path);
276068fb4f1Sjruoho }
277068fb4f1Sjruoho
278068fb4f1Sjruoho ATF_TC_WITH_CLEANUP(stat_size);
ATF_TC_HEAD(stat_size,tc)279068fb4f1Sjruoho ATF_TC_HEAD(stat_size, tc)
280068fb4f1Sjruoho {
281068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)");
282068fb4f1Sjruoho }
283068fb4f1Sjruoho
ATF_TC_BODY(stat_size,tc)284068fb4f1Sjruoho ATF_TC_BODY(stat_size, tc)
285068fb4f1Sjruoho {
286068fb4f1Sjruoho struct stat sa, sb, sc;
287068fb4f1Sjruoho const size_t n = 10;
288068fb4f1Sjruoho size_t i;
289068fb4f1Sjruoho int fd;
290068fb4f1Sjruoho
291*653f037eSmartin fd = open(path, O_WRONLY | O_CREAT, 0600);
292068fb4f1Sjruoho ATF_REQUIRE(fd >= 0);
293068fb4f1Sjruoho
294068fb4f1Sjruoho for (i = 0; i < n; i++) {
295068fb4f1Sjruoho
296068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
297068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
298068fb4f1Sjruoho (void)memset(&sc, 0, sizeof(struct stat));
299068fb4f1Sjruoho
300068fb4f1Sjruoho ATF_REQUIRE(fstat(fd, &sa) == 0);
301068fb4f1Sjruoho ATF_REQUIRE(write(fd, "X", 1) == 1);
302068fb4f1Sjruoho ATF_REQUIRE(fstat(fd, &sb) == 0);
303068fb4f1Sjruoho ATF_REQUIRE(stat(path, &sc) == 0);
304068fb4f1Sjruoho
305068fb4f1Sjruoho if (sa.st_size + 1 != sb.st_size)
306068fb4f1Sjruoho atf_tc_fail("invalid file size");
307068fb4f1Sjruoho
308068fb4f1Sjruoho if (sb.st_size != sc.st_size)
309068fb4f1Sjruoho atf_tc_fail("stat(2) and fstat(2) mismatch");
310068fb4f1Sjruoho }
311068fb4f1Sjruoho
312068fb4f1Sjruoho ATF_REQUIRE(close(fd) == 0);
313068fb4f1Sjruoho ATF_REQUIRE(unlink(path) == 0);
314068fb4f1Sjruoho }
315068fb4f1Sjruoho
ATF_TC_CLEANUP(stat_size,tc)316068fb4f1Sjruoho ATF_TC_CLEANUP(stat_size, tc)
317068fb4f1Sjruoho {
318068fb4f1Sjruoho (void)unlink(path);
319068fb4f1Sjruoho }
320068fb4f1Sjruoho
3217ee67ae0Sjruoho ATF_TC(stat_socket);
ATF_TC_HEAD(stat_socket,tc)3227ee67ae0Sjruoho ATF_TC_HEAD(stat_socket, tc)
3237ee67ae0Sjruoho {
3244608dbc0Sjruoho atf_tc_set_md_var(tc, "descr", "Test fstat(2) with "
3254608dbc0Sjruoho "a socket (PR kern/46077)");
3267ee67ae0Sjruoho }
3277ee67ae0Sjruoho
ATF_TC_BODY(stat_socket,tc)3287ee67ae0Sjruoho ATF_TC_BODY(stat_socket, tc)
3297ee67ae0Sjruoho {
3307ee67ae0Sjruoho struct sockaddr_in addr;
3317ee67ae0Sjruoho struct stat st;
3327ee67ae0Sjruoho uint32_t iaddr;
3337ee67ae0Sjruoho int fd, flags;
3347ee67ae0Sjruoho
3357ee67ae0Sjruoho (void)memset(&st, 0, sizeof(struct stat));
3367ee67ae0Sjruoho (void)memset(&addr, 0, sizeof(struct sockaddr_in));
3377ee67ae0Sjruoho
3387ee67ae0Sjruoho fd = socket(AF_INET, SOCK_STREAM, 0);
3397ee67ae0Sjruoho ATF_REQUIRE(fd >= 0);
3407ee67ae0Sjruoho
3417ee67ae0Sjruoho flags = fcntl(fd, F_GETFL);
3427ee67ae0Sjruoho
3437ee67ae0Sjruoho ATF_REQUIRE(flags != -1);
3447ee67ae0Sjruoho ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
3457ee67ae0Sjruoho ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1);
3467ee67ae0Sjruoho
3477ee67ae0Sjruoho addr.sin_port = htons(42);
3487ee67ae0Sjruoho addr.sin_family = AF_INET;
3497ee67ae0Sjruoho addr.sin_addr.s_addr = iaddr;
3507ee67ae0Sjruoho
3517ee67ae0Sjruoho errno = 0;
3527ee67ae0Sjruoho
3537ee67ae0Sjruoho ATF_REQUIRE_ERRNO(EINPROGRESS,
3547ee67ae0Sjruoho connect(fd, (struct sockaddr *)&addr,
3557ee67ae0Sjruoho sizeof(struct sockaddr_in)) == -1);
3567ee67ae0Sjruoho
3577ee67ae0Sjruoho errno = 0;
3587ee67ae0Sjruoho
3597ee67ae0Sjruoho if (fstat(fd, &st) != 0 || errno != 0)
3607ee67ae0Sjruoho atf_tc_fail("fstat(2) failed for a EINPROGRESS socket");
3617ee67ae0Sjruoho
3627ee67ae0Sjruoho (void)close(fd);
3637ee67ae0Sjruoho }
3647ee67ae0Sjruoho
365068fb4f1Sjruoho ATF_TC_WITH_CLEANUP(stat_symlink);
ATF_TC_HEAD(stat_symlink,tc)366068fb4f1Sjruoho ATF_TC_HEAD(stat_symlink, tc)
367068fb4f1Sjruoho {
368068fb4f1Sjruoho atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)");
369068fb4f1Sjruoho }
370068fb4f1Sjruoho
ATF_TC_BODY(stat_symlink,tc)371068fb4f1Sjruoho ATF_TC_BODY(stat_symlink, tc)
372068fb4f1Sjruoho {
373068fb4f1Sjruoho const char *pathlink = "pathlink";
374068fb4f1Sjruoho struct stat sa, sb;
375068fb4f1Sjruoho int fd;
376068fb4f1Sjruoho
377068fb4f1Sjruoho (void)memset(&sa, 0, sizeof(struct stat));
378068fb4f1Sjruoho (void)memset(&sb, 0, sizeof(struct stat));
379068fb4f1Sjruoho
380*653f037eSmartin fd = open(path, O_WRONLY | O_CREAT, 0600);
381068fb4f1Sjruoho
382068fb4f1Sjruoho ATF_REQUIRE(fd >= 0);
383068fb4f1Sjruoho ATF_REQUIRE(symlink(path, pathlink) == 0);
384068fb4f1Sjruoho ATF_REQUIRE(stat(pathlink, &sa) == 0);
385068fb4f1Sjruoho ATF_REQUIRE(lstat(pathlink, &sb) == 0);
386068fb4f1Sjruoho
387068fb4f1Sjruoho if (S_ISLNK(sa.st_mode) != 0)
388068fb4f1Sjruoho atf_tc_fail("stat(2) detected symbolic link");
389068fb4f1Sjruoho
390068fb4f1Sjruoho if (S_ISLNK(sb.st_mode) == 0)
391068fb4f1Sjruoho atf_tc_fail("lstat(2) did not detect symbolic link");
392068fb4f1Sjruoho
393068fb4f1Sjruoho if (sa.st_mode == sb.st_mode)
394068fb4f1Sjruoho atf_tc_fail("inconsistencies between stat(2) and lstat(2)");
395068fb4f1Sjruoho
3964cc87d7eSchristos (void)close(fd);
397068fb4f1Sjruoho ATF_REQUIRE(unlink(path) == 0);
398068fb4f1Sjruoho ATF_REQUIRE(unlink(pathlink) == 0);
399068fb4f1Sjruoho }
400068fb4f1Sjruoho
ATF_TC_CLEANUP(stat_symlink,tc)401068fb4f1Sjruoho ATF_TC_CLEANUP(stat_symlink, tc)
402068fb4f1Sjruoho {
403068fb4f1Sjruoho (void)unlink(path);
404068fb4f1Sjruoho }
405068fb4f1Sjruoho
ATF_TP_ADD_TCS(tp)406068fb4f1Sjruoho ATF_TP_ADD_TCS(tp)
407068fb4f1Sjruoho {
408068fb4f1Sjruoho
409068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_chflags);
410068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_dir);
411068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_err);
412068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_mtime);
413068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_perm);
414068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_size);
4157ee67ae0Sjruoho ATF_TP_ADD_TC(tp, stat_socket);
416068fb4f1Sjruoho ATF_TP_ADD_TC(tp, stat_symlink);
417068fb4f1Sjruoho
418068fb4f1Sjruoho return atf_no_error();
419068fb4f1Sjruoho }
420