1 /* $NetBSD: t_stat.c,v 1.2 2011/10/16 08:28:10 jruoho Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jukka Ruohonen. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: t_stat.c,v 1.2 2011/10/16 08:28:10 jruoho Exp $"); 33 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 37 #include <atf-c.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <fts.h> 41 #include <limits.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <stdio.h> 46 47 static const char *path = "stat"; 48 49 ATF_TC_WITH_CLEANUP(stat_chflags); 50 ATF_TC_HEAD(stat_chflags, tc) 51 { 52 atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)"); 53 } 54 55 ATF_TC_BODY(stat_chflags, tc) 56 { 57 struct stat sa, sb; 58 int fd; 59 60 (void)memset(&sa, 0, sizeof(struct stat)); 61 (void)memset(&sb, 0, sizeof(struct stat)); 62 63 fd = open(path, O_RDONLY | O_CREAT); 64 65 ATF_REQUIRE(fd != -1); 66 ATF_REQUIRE(stat(path, &sa) == 0); 67 ATF_REQUIRE(chflags(path, UF_NODUMP) == 0); 68 ATF_REQUIRE(stat(path, &sb) == 0); 69 70 if (sa.st_flags == sb.st_flags) 71 atf_tc_fail("stat(2) did not detect chflags(2)"); 72 73 ATF_REQUIRE(close(fd) == 0); 74 ATF_REQUIRE(unlink(path) == 0); 75 } 76 77 ATF_TC_CLEANUP(stat_chflags, tc) 78 { 79 (void)unlink(path); 80 } 81 82 ATF_TC(stat_dir); 83 ATF_TC_HEAD(stat_dir, tc) 84 { 85 atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories"); 86 } 87 88 ATF_TC_BODY(stat_dir, tc) 89 { 90 const short depth = 2; 91 struct stat sa, sb; 92 char *argv[2]; 93 FTSENT *ftse; 94 FTS *fts; 95 int ops; 96 97 argv[1] = NULL; 98 argv[0] = __UNCONST("/"); 99 100 ops = FTS_NOCHDIR; 101 ops |= FTS_PHYSICAL; 102 103 fts = fts_open(argv, ops, NULL); 104 ATF_REQUIRE(fts != NULL); 105 106 while ((ftse = fts_read(fts)) != NULL) { 107 108 if (ftse->fts_level < 1) 109 continue; 110 111 if (ftse->fts_level > depth) { 112 (void)fts_set(fts, ftse, FTS_SKIP); 113 continue; 114 } 115 116 switch(ftse->fts_info) { 117 118 case FTS_DP: 119 120 (void)memset(&sa, 0, sizeof(struct stat)); 121 (void)memset(&sb, 0, sizeof(struct stat)); 122 123 ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0); 124 ATF_REQUIRE(chdir(ftse->fts_path) == 0); 125 ATF_REQUIRE(stat(".", &sb) == 0); 126 127 /* 128 * The previous two stat(2) calls 129 * should be for the same directory. 130 */ 131 if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino) 132 atf_tc_fail("inconsistent stat(2)"); 133 134 /* 135 * Check that fts(3)'s stat(2) 136 * call equals the manual one. 137 */ 138 if (sb.st_ino != ftse->fts_statp->st_ino) 139 atf_tc_fail("stat(2) and fts(3) differ"); 140 141 break; 142 143 default: 144 break; 145 } 146 } 147 148 (void)fts_close(fts); 149 } 150 151 ATF_TC(stat_err); 152 ATF_TC_HEAD(stat_err, tc) 153 { 154 atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family"); 155 } 156 157 ATF_TC_BODY(stat_err, tc) 158 { 159 char buf[NAME_MAX + 1]; 160 struct stat st; 161 162 (void)memset(buf, 'x', sizeof(buf)); 163 164 errno = 0; 165 ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1); 166 167 errno = 0; 168 ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1); 169 170 errno = 0; 171 ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1); 172 173 errno = 0; 174 ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1); 175 176 errno = 0; 177 ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1); 178 179 errno = 0; 180 ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1); 181 182 errno = 0; 183 ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1); 184 185 errno = 0; 186 ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); 187 188 errno = 0; 189 ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); 190 } 191 192 ATF_TC_WITH_CLEANUP(stat_mtime); 193 ATF_TC_HEAD(stat_mtime, tc) 194 { 195 atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)"); 196 } 197 198 ATF_TC_BODY(stat_mtime, tc) 199 { 200 struct stat sa, sb; 201 int fd[3]; 202 size_t i; 203 204 for (i = 0; i < __arraycount(fd); i++) { 205 206 (void)memset(&sa, 0, sizeof(struct stat)); 207 (void)memset(&sb, 0, sizeof(struct stat)); 208 209 fd[i] = open(path, O_WRONLY | O_CREAT); 210 211 ATF_REQUIRE(fd[i] != -1); 212 ATF_REQUIRE(write(fd[i], "X", 1) == 1); 213 ATF_REQUIRE(stat(path, &sa) == 0); 214 215 (void)sleep(1); 216 217 ATF_REQUIRE(write(fd[i], "X", 1) == 1); 218 ATF_REQUIRE(stat(path, &sb) == 0); 219 220 ATF_REQUIRE(close(fd[i]) == 0); 221 ATF_REQUIRE(unlink(path) == 0); 222 223 if (sa.st_mtime == sb.st_mtime) 224 atf_tc_fail("mtimes did not change"); 225 } 226 } 227 228 ATF_TC_CLEANUP(stat_mtime, tc) 229 { 230 (void)unlink(path); 231 } 232 233 ATF_TC_WITH_CLEANUP(stat_perm); 234 ATF_TC_HEAD(stat_perm, tc) 235 { 236 atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)"); 237 atf_tc_set_md_var(tc, "require.user", "root"); 238 } 239 240 ATF_TC_BODY(stat_perm, tc) 241 { 242 struct stat sa, sb; 243 gid_t gid; 244 uid_t uid; 245 int fd; 246 247 (void)memset(&sa, 0, sizeof(struct stat)); 248 (void)memset(&sb, 0, sizeof(struct stat)); 249 250 uid = getuid(); 251 gid = getgid(); 252 253 fd = open(path, O_RDONLY | O_CREAT); 254 255 ATF_REQUIRE(fd != -1); 256 ATF_REQUIRE(fstat(fd, &sa) == 0); 257 ATF_REQUIRE(stat(path, &sb) == 0); 258 259 if (gid != sa.st_gid || sa.st_gid != sb.st_gid) 260 atf_tc_fail("invalid GID"); 261 262 if (uid != sa.st_uid || sa.st_uid != sb.st_uid) 263 atf_tc_fail("invalid UID"); 264 265 ATF_REQUIRE(close(fd) == 0); 266 ATF_REQUIRE(unlink(path) == 0); 267 } 268 269 ATF_TC_CLEANUP(stat_perm, tc) 270 { 271 (void)unlink(path); 272 } 273 274 ATF_TC_WITH_CLEANUP(stat_size); 275 ATF_TC_HEAD(stat_size, tc) 276 { 277 atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)"); 278 } 279 280 ATF_TC_BODY(stat_size, tc) 281 { 282 struct stat sa, sb, sc; 283 const size_t n = 10; 284 size_t i; 285 int fd; 286 287 fd = open(path, O_WRONLY | O_CREAT); 288 ATF_REQUIRE(fd >= 0); 289 290 for (i = 0; i < n; i++) { 291 292 (void)memset(&sa, 0, sizeof(struct stat)); 293 (void)memset(&sb, 0, sizeof(struct stat)); 294 (void)memset(&sc, 0, sizeof(struct stat)); 295 296 ATF_REQUIRE(fstat(fd, &sa) == 0); 297 ATF_REQUIRE(write(fd, "X", 1) == 1); 298 ATF_REQUIRE(fstat(fd, &sb) == 0); 299 ATF_REQUIRE(stat(path, &sc) == 0); 300 301 if (sa.st_size + 1 != sb.st_size) 302 atf_tc_fail("invalid file size"); 303 304 if (sb.st_size != sc.st_size) 305 atf_tc_fail("stat(2) and fstat(2) mismatch"); 306 } 307 308 ATF_REQUIRE(close(fd) == 0); 309 ATF_REQUIRE(unlink(path) == 0); 310 } 311 312 ATF_TC_CLEANUP(stat_size, tc) 313 { 314 (void)unlink(path); 315 } 316 317 ATF_TC_WITH_CLEANUP(stat_symlink); 318 ATF_TC_HEAD(stat_symlink, tc) 319 { 320 atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)"); 321 } 322 323 ATF_TC_BODY(stat_symlink, tc) 324 { 325 const char *pathlink = "pathlink"; 326 struct stat sa, sb; 327 int fd; 328 329 (void)memset(&sa, 0, sizeof(struct stat)); 330 (void)memset(&sb, 0, sizeof(struct stat)); 331 332 fd = open(path, O_WRONLY | O_CREAT); 333 334 ATF_REQUIRE(fd >= 0); 335 ATF_REQUIRE(symlink(path, pathlink) == 0); 336 ATF_REQUIRE(stat(pathlink, &sa) == 0); 337 ATF_REQUIRE(lstat(pathlink, &sb) == 0); 338 339 if (S_ISLNK(sa.st_mode) != 0) 340 atf_tc_fail("stat(2) detected symbolic link"); 341 342 if (S_ISLNK(sb.st_mode) == 0) 343 atf_tc_fail("lstat(2) did not detect symbolic link"); 344 345 if (sa.st_mode == sb.st_mode) 346 atf_tc_fail("inconsistencies between stat(2) and lstat(2)"); 347 348 ATF_REQUIRE(unlink(path) == 0); 349 ATF_REQUIRE(unlink(pathlink) == 0); 350 } 351 352 ATF_TC_CLEANUP(stat_symlink, tc) 353 { 354 (void)unlink(path); 355 } 356 357 ATF_TP_ADD_TCS(tp) 358 { 359 360 ATF_TP_ADD_TC(tp, stat_chflags); 361 ATF_TP_ADD_TC(tp, stat_dir); 362 ATF_TP_ADD_TC(tp, stat_err); 363 ATF_TP_ADD_TC(tp, stat_mtime); 364 ATF_TP_ADD_TC(tp, stat_perm); 365 ATF_TP_ADD_TC(tp, stat_size); 366 ATF_TP_ADD_TC(tp, stat_symlink); 367 368 return atf_no_error(); 369 } 370