1314817Sngie/* $NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 christos Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * This code is derived from software contributed to The NetBSD Foundation 8272343Sngie * by Jukka Ruohonen. 9272343Sngie * 10272343Sngie * Redistribution and use in source and binary forms, with or without 11272343Sngie * modification, are permitted provided that the following conditions 12272343Sngie * are met: 13272343Sngie * 1. Redistributions of source code must retain the above copyright 14272343Sngie * notice, this list of conditions and the following disclaimer. 15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 16272343Sngie * notice, this list of conditions and the following disclaimer in the 17272343Sngie * documentation and/or other materials provided with the distribution. 18272343Sngie * 19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29272343Sngie * POSSIBILITY OF SUCH DAMAGE. 30272343Sngie */ 31272343Sngie#include <sys/cdefs.h> 32314817Sngie__RCSID("$NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 christos Exp $"); 33272343Sngie 34272343Sngie#include <sys/stat.h> 35272343Sngie#include <sys/socket.h> 36272343Sngie#include <sys/types.h> 37272343Sngie 38272343Sngie#include <arpa/inet.h> 39314817Sngie#include <netinet/in.h> 40272343Sngie 41272343Sngie#include <atf-c.h> 42272343Sngie#include <errno.h> 43272343Sngie#include <fcntl.h> 44272343Sngie#include <fts.h> 45272343Sngie#include <limits.h> 46272343Sngie#include <string.h> 47272343Sngie#include <unistd.h> 48272343Sngie 49272343Sngie#include <stdio.h> 50272343Sngie 51272343Sngiestatic const char *path = "stat"; 52272343Sngie 53272343SngieATF_TC_WITH_CLEANUP(stat_chflags); 54272343SngieATF_TC_HEAD(stat_chflags, tc) 55272343Sngie{ 56272343Sngie atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)"); 57272343Sngie} 58272343Sngie 59272343SngieATF_TC_BODY(stat_chflags, tc) 60272343Sngie{ 61272343Sngie struct stat sa, sb; 62272343Sngie int fd; 63272343Sngie 64272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 65272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 66272343Sngie 67272343Sngie fd = open(path, O_RDONLY | O_CREAT); 68272343Sngie 69272343Sngie ATF_REQUIRE(fd != -1); 70272343Sngie ATF_REQUIRE(stat(path, &sa) == 0); 71272343Sngie ATF_REQUIRE(chflags(path, UF_NODUMP) == 0); 72272343Sngie ATF_REQUIRE(stat(path, &sb) == 0); 73272343Sngie 74272343Sngie if (sa.st_flags == sb.st_flags) 75272343Sngie atf_tc_fail("stat(2) did not detect chflags(2)"); 76272343Sngie 77272343Sngie ATF_REQUIRE(close(fd) == 0); 78272343Sngie ATF_REQUIRE(unlink(path) == 0); 79272343Sngie} 80272343Sngie 81272343SngieATF_TC_CLEANUP(stat_chflags, tc) 82272343Sngie{ 83272343Sngie (void)unlink(path); 84272343Sngie} 85272343Sngie 86272343SngieATF_TC(stat_dir); 87272343SngieATF_TC_HEAD(stat_dir, tc) 88272343Sngie{ 89272343Sngie atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories"); 90272343Sngie} 91272343Sngie 92272343SngieATF_TC_BODY(stat_dir, tc) 93272343Sngie{ 94272343Sngie const short depth = 2; 95272343Sngie struct stat sa, sb; 96272343Sngie char *argv[2]; 97272343Sngie FTSENT *ftse; 98272343Sngie FTS *fts; 99272343Sngie int ops; 100272343Sngie 101272343Sngie argv[1] = NULL; 102272343Sngie argv[0] = __UNCONST("/"); 103272343Sngie 104272343Sngie ops = FTS_NOCHDIR; 105272343Sngie ops |= FTS_PHYSICAL; 106272343Sngie 107272343Sngie fts = fts_open(argv, ops, NULL); 108272343Sngie ATF_REQUIRE(fts != NULL); 109272343Sngie 110272343Sngie while ((ftse = fts_read(fts)) != NULL) { 111272343Sngie 112272343Sngie if (ftse->fts_level < 1) 113272343Sngie continue; 114272343Sngie 115272343Sngie if (ftse->fts_level > depth) { 116272343Sngie (void)fts_set(fts, ftse, FTS_SKIP); 117272343Sngie continue; 118272343Sngie } 119272343Sngie 120272343Sngie switch(ftse->fts_info) { 121272343Sngie 122272343Sngie case FTS_DP: 123272343Sngie 124272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 125272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 126272343Sngie 127272343Sngie ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0); 128272343Sngie ATF_REQUIRE(chdir(ftse->fts_path) == 0); 129272343Sngie ATF_REQUIRE(stat(".", &sb) == 0); 130272343Sngie 131272343Sngie /* 132272343Sngie * The previous two stat(2) calls 133272343Sngie * should be for the same directory. 134272343Sngie */ 135272343Sngie if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino) 136272343Sngie atf_tc_fail("inconsistent stat(2)"); 137272343Sngie 138272343Sngie /* 139272343Sngie * Check that fts(3)'s stat(2) 140272343Sngie * call equals the manual one. 141272343Sngie */ 142272343Sngie if (sb.st_ino != ftse->fts_statp->st_ino) 143272343Sngie atf_tc_fail("stat(2) and fts(3) differ"); 144272343Sngie 145272343Sngie break; 146272343Sngie 147272343Sngie default: 148272343Sngie break; 149272343Sngie } 150272343Sngie } 151272343Sngie 152272343Sngie (void)fts_close(fts); 153272343Sngie} 154272343Sngie 155272343SngieATF_TC(stat_err); 156272343SngieATF_TC_HEAD(stat_err, tc) 157272343Sngie{ 158272343Sngie atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family"); 159272343Sngie} 160272343Sngie 161272343SngieATF_TC_BODY(stat_err, tc) 162272343Sngie{ 163272343Sngie char buf[NAME_MAX + 1]; 164272343Sngie struct stat st; 165272343Sngie 166272343Sngie (void)memset(buf, 'x', sizeof(buf)); 167272343Sngie 168272343Sngie errno = 0; 169272343Sngie ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1); 170272343Sngie 171272343Sngie errno = 0; 172272343Sngie ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1); 173272343Sngie 174272343Sngie errno = 0; 175272343Sngie ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1); 176272343Sngie 177272343Sngie errno = 0; 178272343Sngie ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1); 179272343Sngie 180272343Sngie errno = 0; 181272343Sngie ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1); 182272343Sngie 183272343Sngie errno = 0; 184272343Sngie ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1); 185272343Sngie 186272343Sngie errno = 0; 187272343Sngie ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1); 188272343Sngie 189272343Sngie errno = 0; 190272343Sngie ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); 191272343Sngie 192272343Sngie errno = 0; 193272343Sngie ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); 194272343Sngie} 195272343Sngie 196272343SngieATF_TC_WITH_CLEANUP(stat_mtime); 197272343SngieATF_TC_HEAD(stat_mtime, tc) 198272343Sngie{ 199272343Sngie atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)"); 200272343Sngie} 201272343Sngie 202272343SngieATF_TC_BODY(stat_mtime, tc) 203272343Sngie{ 204272343Sngie struct stat sa, sb; 205272343Sngie int fd[3]; 206272343Sngie size_t i; 207272343Sngie 208272343Sngie for (i = 0; i < __arraycount(fd); i++) { 209272343Sngie 210272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 211272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 212272343Sngie 213272343Sngie fd[i] = open(path, O_WRONLY | O_CREAT); 214272343Sngie 215272343Sngie ATF_REQUIRE(fd[i] != -1); 216272343Sngie ATF_REQUIRE(write(fd[i], "X", 1) == 1); 217272343Sngie ATF_REQUIRE(stat(path, &sa) == 0); 218272343Sngie 219272343Sngie (void)sleep(1); 220272343Sngie 221272343Sngie ATF_REQUIRE(write(fd[i], "X", 1) == 1); 222272343Sngie ATF_REQUIRE(stat(path, &sb) == 0); 223272343Sngie 224272343Sngie ATF_REQUIRE(close(fd[i]) == 0); 225272343Sngie ATF_REQUIRE(unlink(path) == 0); 226272343Sngie 227272343Sngie if (sa.st_mtime == sb.st_mtime) 228272343Sngie atf_tc_fail("mtimes did not change"); 229272343Sngie } 230272343Sngie} 231272343Sngie 232272343SngieATF_TC_CLEANUP(stat_mtime, tc) 233272343Sngie{ 234272343Sngie (void)unlink(path); 235272343Sngie} 236272343Sngie 237272343SngieATF_TC_WITH_CLEANUP(stat_perm); 238272343SngieATF_TC_HEAD(stat_perm, tc) 239272343Sngie{ 240272343Sngie atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)"); 241272343Sngie atf_tc_set_md_var(tc, "require.user", "root"); 242272343Sngie} 243272343Sngie 244272343SngieATF_TC_BODY(stat_perm, tc) 245272343Sngie{ 246272343Sngie struct stat sa, sb; 247272343Sngie gid_t gid; 248272343Sngie uid_t uid; 249272343Sngie int fd; 250272343Sngie 251272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 252272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 253272343Sngie 254272343Sngie uid = getuid(); 255272343Sngie gid = getgid(); 256272343Sngie 257272343Sngie fd = open(path, O_RDONLY | O_CREAT); 258272343Sngie 259272343Sngie ATF_REQUIRE(fd != -1); 260272343Sngie ATF_REQUIRE(fstat(fd, &sa) == 0); 261272343Sngie ATF_REQUIRE(stat(path, &sb) == 0); 262272343Sngie 263272343Sngie if (gid != sa.st_gid || sa.st_gid != sb.st_gid) 264272343Sngie atf_tc_fail("invalid GID"); 265272343Sngie 266272343Sngie if (uid != sa.st_uid || sa.st_uid != sb.st_uid) 267272343Sngie atf_tc_fail("invalid UID"); 268272343Sngie 269272343Sngie ATF_REQUIRE(close(fd) == 0); 270272343Sngie ATF_REQUIRE(unlink(path) == 0); 271272343Sngie} 272272343Sngie 273272343SngieATF_TC_CLEANUP(stat_perm, tc) 274272343Sngie{ 275272343Sngie (void)unlink(path); 276272343Sngie} 277272343Sngie 278272343SngieATF_TC_WITH_CLEANUP(stat_size); 279272343SngieATF_TC_HEAD(stat_size, tc) 280272343Sngie{ 281272343Sngie atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)"); 282272343Sngie} 283272343Sngie 284272343SngieATF_TC_BODY(stat_size, tc) 285272343Sngie{ 286272343Sngie struct stat sa, sb, sc; 287272343Sngie const size_t n = 10; 288272343Sngie size_t i; 289272343Sngie int fd; 290272343Sngie 291272343Sngie fd = open(path, O_WRONLY | O_CREAT); 292272343Sngie ATF_REQUIRE(fd >= 0); 293272343Sngie 294272343Sngie for (i = 0; i < n; i++) { 295272343Sngie 296272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 297272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 298272343Sngie (void)memset(&sc, 0, sizeof(struct stat)); 299272343Sngie 300272343Sngie ATF_REQUIRE(fstat(fd, &sa) == 0); 301272343Sngie ATF_REQUIRE(write(fd, "X", 1) == 1); 302272343Sngie ATF_REQUIRE(fstat(fd, &sb) == 0); 303272343Sngie ATF_REQUIRE(stat(path, &sc) == 0); 304272343Sngie 305272343Sngie if (sa.st_size + 1 != sb.st_size) 306272343Sngie atf_tc_fail("invalid file size"); 307272343Sngie 308272343Sngie if (sb.st_size != sc.st_size) 309272343Sngie atf_tc_fail("stat(2) and fstat(2) mismatch"); 310272343Sngie } 311272343Sngie 312272343Sngie ATF_REQUIRE(close(fd) == 0); 313272343Sngie ATF_REQUIRE(unlink(path) == 0); 314272343Sngie} 315272343Sngie 316272343SngieATF_TC_CLEANUP(stat_size, tc) 317272343Sngie{ 318272343Sngie (void)unlink(path); 319272343Sngie} 320272343Sngie 321272343SngieATF_TC(stat_socket); 322272343SngieATF_TC_HEAD(stat_socket, tc) 323272343Sngie{ 324272343Sngie atf_tc_set_md_var(tc, "descr", "Test fstat(2) with " 325272343Sngie "a socket (PR kern/46077)"); 326272343Sngie} 327272343Sngie 328272343SngieATF_TC_BODY(stat_socket, tc) 329272343Sngie{ 330272343Sngie struct sockaddr_in addr; 331272343Sngie struct stat st; 332272343Sngie uint32_t iaddr; 333272343Sngie int fd, flags; 334272343Sngie 335272343Sngie (void)memset(&st, 0, sizeof(struct stat)); 336272343Sngie (void)memset(&addr, 0, sizeof(struct sockaddr_in)); 337272343Sngie 338272343Sngie fd = socket(AF_INET, SOCK_STREAM, 0); 339272343Sngie ATF_REQUIRE(fd >= 0); 340272343Sngie 341272343Sngie flags = fcntl(fd, F_GETFL); 342272343Sngie 343272343Sngie ATF_REQUIRE(flags != -1); 344272343Sngie ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1); 345272343Sngie ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1); 346272343Sngie 347272343Sngie addr.sin_port = htons(42); 348272343Sngie addr.sin_family = AF_INET; 349272343Sngie addr.sin_addr.s_addr = iaddr; 350272343Sngie 351272343Sngie errno = 0; 352272343Sngie 353272343Sngie ATF_REQUIRE_ERRNO(EINPROGRESS, 354272343Sngie connect(fd, (struct sockaddr *)&addr, 355272343Sngie sizeof(struct sockaddr_in)) == -1); 356272343Sngie 357272343Sngie errno = 0; 358272343Sngie 359272343Sngie if (fstat(fd, &st) != 0 || errno != 0) 360272343Sngie atf_tc_fail("fstat(2) failed for a EINPROGRESS socket"); 361272343Sngie 362272343Sngie (void)close(fd); 363272343Sngie} 364272343Sngie 365272343SngieATF_TC_WITH_CLEANUP(stat_symlink); 366272343SngieATF_TC_HEAD(stat_symlink, tc) 367272343Sngie{ 368272343Sngie atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)"); 369272343Sngie} 370272343Sngie 371272343SngieATF_TC_BODY(stat_symlink, tc) 372272343Sngie{ 373272343Sngie const char *pathlink = "pathlink"; 374272343Sngie struct stat sa, sb; 375272343Sngie int fd; 376272343Sngie 377272343Sngie (void)memset(&sa, 0, sizeof(struct stat)); 378272343Sngie (void)memset(&sb, 0, sizeof(struct stat)); 379272343Sngie 380272343Sngie fd = open(path, O_WRONLY | O_CREAT); 381272343Sngie 382272343Sngie ATF_REQUIRE(fd >= 0); 383272343Sngie ATF_REQUIRE(symlink(path, pathlink) == 0); 384272343Sngie ATF_REQUIRE(stat(pathlink, &sa) == 0); 385272343Sngie ATF_REQUIRE(lstat(pathlink, &sb) == 0); 386272343Sngie 387272343Sngie if (S_ISLNK(sa.st_mode) != 0) 388272343Sngie atf_tc_fail("stat(2) detected symbolic link"); 389272343Sngie 390272343Sngie if (S_ISLNK(sb.st_mode) == 0) 391272343Sngie atf_tc_fail("lstat(2) did not detect symbolic link"); 392272343Sngie 393272343Sngie if (sa.st_mode == sb.st_mode) 394272343Sngie atf_tc_fail("inconsistencies between stat(2) and lstat(2)"); 395272343Sngie 396314817Sngie (void)close(fd); 397272343Sngie ATF_REQUIRE(unlink(path) == 0); 398272343Sngie ATF_REQUIRE(unlink(pathlink) == 0); 399272343Sngie} 400272343Sngie 401272343SngieATF_TC_CLEANUP(stat_symlink, tc) 402272343Sngie{ 403272343Sngie (void)unlink(path); 404272343Sngie} 405272343Sngie 406272343SngieATF_TP_ADD_TCS(tp) 407272343Sngie{ 408272343Sngie 409272343Sngie ATF_TP_ADD_TC(tp, stat_chflags); 410272343Sngie ATF_TP_ADD_TC(tp, stat_dir); 411272343Sngie ATF_TP_ADD_TC(tp, stat_err); 412272343Sngie ATF_TP_ADD_TC(tp, stat_mtime); 413272343Sngie ATF_TP_ADD_TC(tp, stat_perm); 414272343Sngie ATF_TP_ADD_TC(tp, stat_size); 415272343Sngie ATF_TP_ADD_TC(tp, stat_socket); 416272343Sngie ATF_TP_ADD_TC(tp, stat_symlink); 417272343Sngie 418272343Sngie return atf_no_error(); 419272343Sngie} 420