Home | History | Annotate | Download | only in tests-m32
      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