1/* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org> 3 * Copyright (c) 2015-2017 The strace developers. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#if defined HAVE_FTRUNCATE && defined HAVE_FUTIMENS 30 31# ifndef TEST_SYSCALL_STR 32# error TEST_SYSCALL_STR must be defined 33# endif 34# ifndef TEST_SYSCALL_INVOKE 35# error TEST_SYSCALL_INVOKE must be defined 36# endif 37# ifndef PRINT_SYSCALL_HEADER 38# error PRINT_SYSCALL_HEADER must be defined 39# endif 40# ifndef PRINT_SYSCALL_FOOTER 41# error PRINT_SYSCALL_FOOTER must be defined 42# endif 43 44# include <errno.h> 45# include <stdio.h> 46# include <stddef.h> 47# include <time.h> 48# include <unistd.h> 49# include <sys/sysmacros.h> 50 51# include "print_fields.h" 52# include "statx.h" 53 54# ifndef STRUCT_STAT 55# define STRUCT_STAT struct stat 56# define STRUCT_STAT_STR "struct stat" 57# define STRUCT_STAT_IS_STAT64 0 58# endif 59# ifndef SAMPLE_SIZE 60# define SAMPLE_SIZE ((libc_off_t) 43147718418ULL) 61# endif 62 63typedef off_t libc_off_t; 64 65# define stat libc_stat 66# define stat64 libc_stat64 67# include <fcntl.h> 68# include <sys/stat.h> 69# undef stat 70# undef stat64 71 72# undef st_atime 73# undef st_mtime 74# undef st_ctime 75# include "asm_stat.h" 76 77# if STRUCT_STAT_IS_STAT64 78# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 79# if defined MPERS_IS_m32 80# ifdef HAVE_M32_STRUCT_STAT64_ST_MTIME_NSEC 81# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 82# endif 83# elif defined MPERS_IS_mx32 84# ifdef HAVE_MX32_STRUCT_STAT64_ST_MTIME_NSEC 85# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 86# endif 87# elif defined HAVE_STRUCT_STAT64_ST_MTIME_NSEC 88# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 89# endif /* MPERS_IS_m32 || MPERS_IS_mx32 || HAVE_STRUCT_STAT64_ST_MTIME_NSEC */ 90# else /* !STRUCT_STAT_IS_STAT64 */ 91# if defined MPERS_IS_m32 92# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 93# ifdef HAVE_M32_STRUCT_STAT_ST_MTIME_NSEC 94# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 95# endif 96# elif defined MPERS_IS_mx32 97# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 98# ifdef HAVE_MX32_STRUCT_STAT_ST_MTIME_NSEC 99# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 100# endif 101# endif /* MPERS_IS_m32 || MPERS_IS_mx32 */ 102# endif /* STRUCT_STAT_IS_STAT64 */ 103 104# ifndef TEST_BOGUS_STRUCT_STAT 105# define TEST_BOGUS_STRUCT_STAT 1 106# endif 107 108# ifndef IS_FSTAT 109# define IS_FSTAT 0 110# endif 111 112# ifndef OLD_STAT 113# define OLD_STAT 0 114# endif 115 116# ifndef IS_STATX 117# define IS_STATX 0 118# endif 119 120static void 121print_ftype(const unsigned int mode) 122{ 123 if (S_ISREG(mode)) 124 printf("S_IFREG"); 125 else if (S_ISDIR(mode)) 126 printf("S_IFDIR"); 127 else if (S_ISCHR(mode)) 128 printf("S_IFCHR"); 129 else if (S_ISBLK(mode)) 130 printf("S_IFBLK"); 131 else 132 printf("%#o", mode & S_IFMT); 133} 134 135static void 136print_perms(const unsigned int mode) 137{ 138 printf("%#o", mode & ~S_IFMT); 139} 140 141# if !IS_STATX 142 143static void 144print_stat(const STRUCT_STAT *st) 145{ 146 printf("{st_dev=makedev(%u, %u)", 147 (unsigned int) major(zero_extend_signed_to_ull(st->st_dev)), 148 (unsigned int) minor(zero_extend_signed_to_ull(st->st_dev))); 149 printf(", st_ino=%llu", zero_extend_signed_to_ull(st->st_ino)); 150 printf(", st_mode="); 151 print_ftype(st->st_mode); 152 printf("|"); 153 print_perms(st->st_mode); 154 printf(", st_nlink=%llu", zero_extend_signed_to_ull(st->st_nlink)); 155 printf(", st_uid=%llu", zero_extend_signed_to_ull(st->st_uid)); 156 printf(", st_gid=%llu", zero_extend_signed_to_ull(st->st_gid)); 157# if OLD_STAT 158 printf(", st_blksize=0, st_blocks=0"); 159# else /* !OLD_STAT */ 160 printf(", st_blksize=%llu", zero_extend_signed_to_ull(st->st_blksize)); 161 printf(", st_blocks=%llu", zero_extend_signed_to_ull(st->st_blocks)); 162# endif /* OLD_STAT */ 163 164 switch (st->st_mode & S_IFMT) { 165 case S_IFCHR: case S_IFBLK: 166 printf(", st_rdev=makedev(%u, %u)", 167 (unsigned int) major(zero_extend_signed_to_ull(st->st_rdev)), 168 (unsigned int) minor(zero_extend_signed_to_ull(st->st_rdev))); 169 break; 170 default: 171 printf(", st_size=%llu", zero_extend_signed_to_ull(st->st_size)); 172 } 173 174# if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT 175# define TIME_NSEC(val) zero_extend_signed_to_ull(val) 176# define HAVE_NSEC 1 177# else 178# define TIME_NSEC(val) 0ULL 179# define HAVE_NSEC 0 180# endif 181 182#define PRINT_ST_TIME(field) \ 183 do { \ 184 printf(", st_" #field "=%lld", \ 185 sign_extend_unsigned_to_ll(st->st_ ## field)); \ 186 print_time_t_nsec(sign_extend_unsigned_to_ll(st->st_ ## field), \ 187 TIME_NSEC(st->st_ ## field ## _nsec), 1); \ 188 if (HAVE_NSEC) \ 189 printf(", st_" #field "_nsec=%llu", \ 190 TIME_NSEC(st->st_ ## field ## _nsec)); \ 191 } while (0) 192 193 PRINT_ST_TIME(atime); 194 PRINT_ST_TIME(mtime); 195 PRINT_ST_TIME(ctime); 196 printf("}"); 197} 198 199# else /* !IS_STATX */ 200 201static void 202print_stat(const STRUCT_STAT *st) 203{ 204# define PRINT_FIELD_U32_UID(field) \ 205 do { \ 206 if (st->field == (uint32_t) -1) \ 207 printf(", %s=-1", #field); \ 208 else \ 209 printf(", %s=%llu", #field, \ 210 (unsigned long long) st->field); \ 211 } while (0) 212 213# define PRINT_FIELD_TIME(field) \ 214 do { \ 215 printf(", %s={tv_sec=%lld, tv_nsec=%u}", \ 216 #field, (long long) st->field.tv_sec, \ 217 (unsigned) st->field.tv_nsec); \ 218 print_time_t_nsec(st->field.tv_sec, \ 219 zero_extend_signed_to_ull(st->field.tv_nsec), \ 220 1); \ 221 } while (0) 222 223 printf("{stx_mask="); 224 printflags(statx_masks, st->stx_mask, "STATX_???"); 225 226 PRINT_FIELD_U(", ", *st, stx_blksize); 227 228 printf(", stx_attributes="); 229 printflags(statx_attrs, st->stx_attributes, "STATX_ATTR_???"); 230 231 PRINT_FIELD_U(", ", *st, stx_nlink); 232 PRINT_FIELD_U32_UID(stx_uid); 233 PRINT_FIELD_U32_UID(stx_gid); 234 235 printf(", stx_mode="); 236 print_ftype(st->stx_mode); 237 printf("|"); 238 print_perms(st->stx_mode); 239 240 PRINT_FIELD_U(", ", *st, stx_ino); 241 PRINT_FIELD_U(", ", *st, stx_size); 242 PRINT_FIELD_U(", ", *st, stx_blocks); 243 244 printf(", stx_attributes_mask="); 245 printflags(statx_attrs, st->stx_attributes_mask, "STATX_ATTR_???"); 246 247 PRINT_FIELD_TIME(stx_atime); 248 PRINT_FIELD_TIME(stx_btime); 249 PRINT_FIELD_TIME(stx_ctime); 250 PRINT_FIELD_TIME(stx_mtime); 251 PRINT_FIELD_U(", ", *st, stx_rdev_major); 252 PRINT_FIELD_U(", ", *st, stx_rdev_minor); 253 PRINT_FIELD_U(", ", *st, stx_dev_major); 254 PRINT_FIELD_U(", ", *st, stx_dev_minor); 255 printf("}"); 256} 257 258# endif /* !IS_STATX */ 259 260static int 261create_sample(const char *fname, const libc_off_t size) 262{ 263 static const struct timespec ts[] = { 264 {-10843, 135}, {-10841, 246} 265 }; 266 267 (void) close(0); 268 if (open(fname, O_RDWR | O_CREAT | O_TRUNC, 0640)) { 269 perror(fname); 270 return 77; 271 } 272 if (ftruncate(0, size)) { 273 perror("ftruncate"); 274 return 77; 275 } 276 if (futimens(0, ts)) { 277 perror("futimens"); 278 return 77; 279 } 280 return 0; 281} 282 283int 284main(void) 285{ 286# if IS_FSTAT 287 skip_if_unavailable("/proc/self/fd/"); 288# else 289 static const char full[] = "/dev/full"; 290# endif 291 static const char sample[] = "stat.sample"; 292 TAIL_ALLOC_OBJECT_CONST_PTR(STRUCT_STAT, st); 293 294 int rc; 295 296 rc = create_sample(sample, SAMPLE_SIZE); 297 if (rc) 298 return rc; 299 300# if TEST_BOGUS_STRUCT_STAT 301 STRUCT_STAT *st_cut = tail_alloc(sizeof(long) * 4); 302 rc = TEST_SYSCALL_INVOKE(sample, st_cut); 303 PRINT_SYSCALL_HEADER(sample); 304 printf("%p", st_cut); 305 PRINT_SYSCALL_FOOTER(rc); 306# endif 307 308# if !IS_FSTAT 309 rc = TEST_SYSCALL_INVOKE(full, st); 310 PRINT_SYSCALL_HEADER(full); 311 if (rc) 312 printf("%p", st); 313 else 314 print_stat(st); 315 PRINT_SYSCALL_FOOTER(rc); 316# endif 317 318 if ((rc = TEST_SYSCALL_INVOKE(sample, st))) { 319 if (errno != EOVERFLOW) { 320 rc = (errno == ENOSYS) ? 77 : 1; 321 perror(TEST_SYSCALL_STR); 322 return rc; 323 } 324 } 325 326# if IS_STATX 327# define ST_SIZE_FIELD stx_size 328# else 329# define ST_SIZE_FIELD st_size 330# endif 331 if (!rc && zero_extend_signed_to_ull(SAMPLE_SIZE) != 332 zero_extend_signed_to_ull(st->ST_SIZE_FIELD)) { 333 fprintf(stderr, "Size mismatch: " 334 "requested size(%llu) != st_size(%llu)\n", 335 zero_extend_signed_to_ull(SAMPLE_SIZE), 336 zero_extend_signed_to_ull(st->ST_SIZE_FIELD)); 337 fprintf(stderr, "The most likely reason for this is incorrect" 338 " definition of %s.\n" 339 "Here is some diagnostics that might help:\n", 340 STRUCT_STAT_STR); 341 342# define LOG_STAT_OFFSETOF_SIZEOF(object, member) \ 343 fprintf(stderr, "offsetof(%s, %s) = %zu" \ 344 ", sizeof(%s) = %zu\n", \ 345 STRUCT_STAT_STR, #member, \ 346 offsetof(STRUCT_STAT, member), \ 347 #member, sizeof((object).member)) 348 349# if IS_STATX 350 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mask); 351 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_blksize); 352 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_attributes); 353 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_nlink); 354 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_uid); 355 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_gid); 356 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mode); 357 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_ino); 358 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_size); 359 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_blocks); 360 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_attributes_mask); 361 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_atime); 362 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_btime); 363 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_ctime); 364 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mtime); 365 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_rdev_major); 366 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_rdev_minor); 367 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_dev_major); 368 LOG_STAT_OFFSETOF_SIZEOF(*st, stx_dev_minor); 369# else 370 LOG_STAT_OFFSETOF_SIZEOF(*st, st_dev); 371 LOG_STAT_OFFSETOF_SIZEOF(*st, st_ino); 372 LOG_STAT_OFFSETOF_SIZEOF(*st, st_mode); 373 LOG_STAT_OFFSETOF_SIZEOF(*st, st_nlink); 374 LOG_STAT_OFFSETOF_SIZEOF(*st, st_uid); 375 LOG_STAT_OFFSETOF_SIZEOF(*st, st_gid); 376 LOG_STAT_OFFSETOF_SIZEOF(*st, st_rdev); 377 LOG_STAT_OFFSETOF_SIZEOF(*st, st_size); 378# if !OLD_STAT 379 LOG_STAT_OFFSETOF_SIZEOF(*st, st_blksize); 380 LOG_STAT_OFFSETOF_SIZEOF(*st, st_blocks); 381# endif /* !OLD_STAT */ 382 383# endif /* IS_STATX */ 384 385 return 1; 386 } 387 388 PRINT_SYSCALL_HEADER(sample); 389 if (rc) 390 printf("%p", st); 391 else 392 print_stat(st); 393 PRINT_SYSCALL_FOOTER(rc); 394 395# if IS_STATX 396 397# define INVOKE() \ 398 do { \ 399 rc = TEST_SYSCALL_INVOKE(sample, st); \ 400 PRINT_SYSCALL_HEADER(sample); \ 401 if (rc) \ 402 printf("%p", st); \ 403 else \ 404 print_stat(st); \ 405 PRINT_SYSCALL_FOOTER(rc); \ 406 } while (0) 407 408# define SET_FLAGS_INVOKE(flags, flags_str) \ 409 do { \ 410 TEST_SYSCALL_STATX_FLAGS = flags; \ 411 TEST_SYSCALL_STATX_FLAGS_STR = flags_str; \ 412 INVOKE(); \ 413 } while (0) 414 415# define SET_MASK_INVOKE(mask, mask_str) \ 416 do { \ 417 TEST_SYSCALL_STATX_MASK = mask; \ 418 TEST_SYSCALL_STATX_MASK_STR = mask_str; \ 419 INVOKE(); \ 420 } while (0) 421 422 unsigned old_flags = TEST_SYSCALL_STATX_FLAGS; 423 const char *old_flags_str = TEST_SYSCALL_STATX_FLAGS_STR; 424 unsigned old_mask = TEST_SYSCALL_STATX_MASK; 425 const char *old_mask_str = TEST_SYSCALL_STATX_MASK_STR; 426 427 SET_FLAGS_INVOKE(AT_SYMLINK_FOLLOW | 0xffff0000U, 428 "AT_STATX_SYNC_AS_STAT|AT_SYMLINK_FOLLOW|0xffff0000"); 429 430 SET_FLAGS_INVOKE(AT_STATX_SYNC_TYPE, 431 "AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC"); 432 433 SET_FLAGS_INVOKE(0xffffff, 434 "AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC|AT_SYMLINK_NOFOLLOW|" 435 "AT_REMOVEDIR|AT_SYMLINK_FOLLOW|AT_NO_AUTOMOUNT|AT_EMPTY_PATH|" 436 "0xff80ff"); 437 438 /* We're done playing with flags. */ 439 TEST_SYSCALL_STATX_FLAGS = old_flags; 440 TEST_SYSCALL_STATX_FLAGS_STR = old_flags_str; 441 442 SET_MASK_INVOKE(0, "0"); 443 SET_MASK_INVOKE(0xfffff000U, "0xfffff000 /* STATX_??? */"); 444 445 SET_MASK_INVOKE(0xfffffffbU, 446 "STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID|STATX_ATIME|" 447 "STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|" 448 "STATX_BTIME|0xfffff000"); 449 450 SET_MASK_INVOKE(STATX_UID, "STATX_UID"); 451 452 /* ...and with mask. */ 453 TEST_SYSCALL_STATX_MASK = old_mask; 454 TEST_SYSCALL_STATX_MASK_STR = old_mask_str; 455 456# endif /* IS_STATX */ 457 458 puts("+++ exited with 0 +++"); 459 return 0; 460} 461 462#else 463 464SKIP_MAIN_UNDEFINED("HAVE_FTRUNCATE && HAVE_FUTIMENS") 465 466#endif 467