1/* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#if defined HAVE_FTRUNCATE && defined HAVE_FUTIMENS 29 30# ifndef TEST_SYSCALL_STR 31# error TEST_SYSCALL_STR must be defined 32# endif 33# ifndef TEST_SYSCALL_INVOKE 34# error TEST_SYSCALL_INVOKE must be defined 35# endif 36# ifndef PRINT_SYSCALL_HEADER 37# error PRINT_SYSCALL_HEADER must be defined 38# endif 39# ifndef PRINT_SYSCALL_FOOTER 40# error PRINT_SYSCALL_FOOTER must be defined 41# endif 42 43# include <errno.h> 44# include <stdio.h> 45# include <stddef.h> 46# include <time.h> 47# include <unistd.h> 48# include <sys/sysmacros.h> 49 50static void 51print_time(const time_t t) 52{ 53 if (!t) { 54 printf("0"); 55 return; 56 } 57 58 struct tm *p = localtime(&t); 59 60 if (p) { 61 char buf[256]; 62 63 strftime(buf, sizeof(buf), "%FT%T%z", p); 64 65 printf("%s", buf); 66 } else { 67 printf("%llu", zero_extend_signed_to_ull(t)); 68 } 69} 70 71# ifndef STRUCT_STAT 72# define STRUCT_STAT struct stat 73# define STRUCT_STAT_STR "struct stat" 74# define STRUCT_STAT_IS_STAT64 0 75# endif 76# ifndef SAMPLE_SIZE 77# define SAMPLE_SIZE ((libc_off_t) 43147718418ULL) 78# endif 79 80typedef off_t libc_off_t; 81 82# define stat libc_stat 83# define stat64 libc_stat64 84# include <fcntl.h> 85# include <sys/stat.h> 86# undef stat 87# undef stat64 88 89# undef st_atime 90# undef st_mtime 91# undef st_ctime 92# include "asm_stat.h" 93 94# if STRUCT_STAT_IS_STAT64 95# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 96# if defined MPERS_IS_m32 97# ifdef HAVE_M32_STRUCT_STAT64_ST_MTIME_NSEC 98# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 99# endif 100# elif defined MPERS_IS_mx32 101# ifdef HAVE_MX32_STRUCT_STAT64_ST_MTIME_NSEC 102# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 103# endif 104# elif defined HAVE_STRUCT_STAT64_ST_MTIME_NSEC 105# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 106# endif /* MPERS_IS_m32 || MPERS_IS_mx32 || HAVE_STRUCT_STAT64_ST_MTIME_NSEC */ 107# else /* !STRUCT_STAT_IS_STAT64 */ 108# if defined MPERS_IS_m32 109# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 110# ifdef HAVE_M32_STRUCT_STAT_ST_MTIME_NSEC 111# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 112# endif 113# elif defined MPERS_IS_mx32 114# undef HAVE_STRUCT_STAT_ST_MTIME_NSEC 115# ifdef HAVE_MX32_STRUCT_STAT_ST_MTIME_NSEC 116# define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1 117# endif 118# endif /* MPERS_IS_m32 || MPERS_IS_mx32 */ 119# endif /* STRUCT_STAT_IS_STAT64 */ 120 121# ifndef TEST_BOGUS_STRUCT_STAT 122# define TEST_BOGUS_STRUCT_STAT 1 123# endif 124 125# ifndef IS_FSTAT 126# define IS_FSTAT 0 127# endif 128 129# ifndef OLD_STAT 130# define OLD_STAT 0 131# endif 132 133static void 134print_ftype(const unsigned int mode) 135{ 136 if (S_ISREG(mode)) 137 printf("S_IFREG"); 138 else if (S_ISDIR(mode)) 139 printf("S_IFDIR"); 140 else if (S_ISCHR(mode)) 141 printf("S_IFCHR"); 142 else if (S_ISBLK(mode)) 143 printf("S_IFBLK"); 144 else 145 printf("%#o", mode & S_IFMT); 146} 147 148static void 149print_perms(const unsigned int mode) 150{ 151 printf("%#o", mode & ~S_IFMT); 152} 153 154static void 155print_stat(const STRUCT_STAT *st) 156{ 157 printf("{st_dev=makedev(%u, %u)", 158 (unsigned int) major(zero_extend_signed_to_ull(st->st_dev)), 159 (unsigned int) minor(zero_extend_signed_to_ull(st->st_dev))); 160 printf(", st_ino=%llu", zero_extend_signed_to_ull(st->st_ino)); 161 printf(", st_mode="); 162 print_ftype(st->st_mode); 163 printf("|"); 164 print_perms(st->st_mode); 165 printf(", st_nlink=%llu", zero_extend_signed_to_ull(st->st_nlink)); 166 printf(", st_uid=%llu", zero_extend_signed_to_ull(st->st_uid)); 167 printf(", st_gid=%llu", zero_extend_signed_to_ull(st->st_gid)); 168# if OLD_STAT 169 printf(", st_blksize=0, st_blocks=0"); 170# else /* !OLD_STAT */ 171 printf(", st_blksize=%llu", zero_extend_signed_to_ull(st->st_blksize)); 172 printf(", st_blocks=%llu", zero_extend_signed_to_ull(st->st_blocks)); 173# endif /* OLD_STAT */ 174 175 switch (st->st_mode & S_IFMT) { 176 case S_IFCHR: case S_IFBLK: 177 printf(", st_rdev=makedev(%u, %u)", 178 (unsigned int) major(zero_extend_signed_to_ull(st->st_rdev)), 179 (unsigned int) minor(zero_extend_signed_to_ull(st->st_rdev))); 180 break; 181 default: 182 printf(", st_size=%llu", zero_extend_signed_to_ull(st->st_size)); 183 } 184 185 printf(", st_atime="); 186 print_time(sign_extend_unsigned_to_ll(st->st_atime)); 187# if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT 188 if (st->st_atime_nsec) 189 printf(".%09llu", zero_extend_signed_to_ull(st->st_atime_nsec)); 190# endif 191 printf(", st_mtime="); 192 print_time(sign_extend_unsigned_to_ll(st->st_mtime)); 193# if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT 194 if (st->st_mtime_nsec) 195 printf(".%09llu", zero_extend_signed_to_ull(st->st_mtime_nsec)); 196# endif 197 printf(", st_ctime="); 198 print_time(sign_extend_unsigned_to_ll(st->st_ctime)); 199# if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT 200 if (st->st_ctime_nsec) 201 printf(".%09llu", zero_extend_signed_to_ull(st->st_ctime_nsec)); 202# endif 203 printf("}"); 204} 205 206static int 207create_sample(const char *fname, const libc_off_t size) 208{ 209 static const struct timespec ts[] = { 210 {-10843, 135}, {-10841, 246} 211 }; 212 213 (void) close(0); 214 if (open(fname, O_RDWR | O_CREAT | O_TRUNC, 0640)) { 215 perror(fname); 216 return 77; 217 } 218 if (ftruncate(0, size)) { 219 perror("ftruncate"); 220 return 77; 221 } 222 if (futimens(0, ts)) { 223 perror("futimens"); 224 return 77; 225 } 226 return 0; 227} 228 229int 230main(void) 231{ 232# if !IS_FSTAT 233 static const char full[] = "/dev/full"; 234# endif 235 static const char sample[] = TEST_SYSCALL_STR ".sample"; 236 STRUCT_STAT st[2]; 237 238 int rc; 239 240 rc = create_sample(sample, SAMPLE_SIZE); 241 if (rc) { 242 (void) unlink(sample); 243 return rc; 244 } 245 246# if TEST_BOGUS_STRUCT_STAT 247 STRUCT_STAT *st_cut = tail_alloc(sizeof(long) * 4); 248 rc = TEST_SYSCALL_INVOKE(sample, st_cut); 249 PRINT_SYSCALL_HEADER(sample); 250 printf("%p", st_cut); 251 PRINT_SYSCALL_FOOTER(rc); 252# endif 253 254# if !IS_FSTAT 255 rc = TEST_SYSCALL_INVOKE(full, st); 256 PRINT_SYSCALL_HEADER(full); 257 if (rc) 258 printf("%p", st); 259 else 260 print_stat(st); 261 PRINT_SYSCALL_FOOTER(rc); 262# endif 263 264 if ((rc = TEST_SYSCALL_INVOKE(sample, st))) { 265# if OLD_STAT 266 if (errno != EOVERFLOW) 267# endif 268 { 269 perror(TEST_SYSCALL_STR); 270 (void) unlink(sample); 271 return 77; 272 } 273 } 274 (void) unlink(sample); 275 if (!rc && zero_extend_signed_to_ull(SAMPLE_SIZE) != 276 zero_extend_signed_to_ull(st[0].st_size)) { 277 fprintf(stderr, "Size mismatch: " 278 "requested size(%llu) != st_size(%llu)\n", 279 zero_extend_signed_to_ull(SAMPLE_SIZE), 280 zero_extend_signed_to_ull(st[0].st_size)); 281 fprintf(stderr, "The most likely reason for this is incorrect" 282 " definition of %s.\n" 283 "Here is some diagnostics that might help:\n", 284 STRUCT_STAT_STR); 285 286#define LOG_STAT_OFFSETOF_SIZEOF(object, member) \ 287 fprintf(stderr, "offsetof(%s, %s) = %zu" \ 288 ", sizeof(%s) = %zu\n", \ 289 STRUCT_STAT_STR, #member, \ 290 offsetof(STRUCT_STAT, member), \ 291 #member, sizeof((object).member)) 292 293 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_dev); 294 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_ino); 295 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_mode); 296 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_nlink); 297 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_uid); 298 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_gid); 299 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_rdev); 300 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_size); 301# if !OLD_STAT 302 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_blksize); 303 LOG_STAT_OFFSETOF_SIZEOF(st[0], st_blocks); 304# endif /* !OLD_STAT */ 305 306 return 1; 307 } 308 309 PRINT_SYSCALL_HEADER(sample); 310 if (rc) 311 printf("%p", st); 312 else 313 print_stat(st); 314 PRINT_SYSCALL_FOOTER(rc); 315 316 puts("+++ exited with 0 +++"); 317 return 0; 318} 319 320#else 321 322SKIP_MAIN_UNDEFINED("HAVE_FTRUNCATE && HAVE_FUTIMENS") 323 324#endif 325