1 /* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) 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 50 static void 51 print_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 80 typedef 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 133 static void 134 print_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 148 static void 149 print_perms(const unsigned int mode) 150 { 151 printf("%#o", mode & ~S_IFMT); 152 } 153 154 static void 155 print_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 206 static int 207 create_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 229 int 230 main(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 322 SKIP_MAIN_UNDEFINED("HAVE_FTRUNCATE && HAVE_FUTIMENS") 323 324 #endif 325