1 /* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) 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 63 typedef 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 120 static void 121 print_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 135 static void 136 print_perms(const unsigned int mode) 137 { 138 printf("%#o", mode & ~S_IFMT); 139 } 140 141 # if !IS_STATX 142 143 static void 144 print_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 201 static void 202 print_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 260 static int 261 create_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 283 int 284 main(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 464 SKIP_MAIN_UNDEFINED("HAVE_FTRUNCATE && HAVE_FUTIMENS") 465 466 #endif 467