(root)/
strace-6.5/
tests-m32/
xstatx.c
       1  /*
       2   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       3   * Copyright (c) 2015-2022 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: GPL-2.0-or-later
       7   */
       8  
       9  #if defined HAVE_FTRUNCATE && defined HAVE_FUTIMENS
      10  
      11  # ifndef TEST_SYSCALL_STR
      12  #  error TEST_SYSCALL_STR must be defined
      13  # endif
      14  # ifndef TEST_SYSCALL_INVOKE
      15  #  error TEST_SYSCALL_INVOKE must be defined
      16  # endif
      17  # ifndef PRINT_SYSCALL_HEADER
      18  #  error PRINT_SYSCALL_HEADER must be defined
      19  # endif
      20  # ifndef PRINT_SYSCALL_FOOTER
      21  #  error PRINT_SYSCALL_FOOTER must be defined
      22  # endif
      23  
      24  # include <errno.h>
      25  # include <stdio.h>
      26  # include <stddef.h>
      27  # include <time.h>
      28  # include <unistd.h>
      29  # include <sys/sysmacros.h>
      30  
      31  # include "print_fields.h"
      32  
      33  # ifndef STRUCT_STAT
      34  #  define STRUCT_STAT struct stat
      35  #  define STRUCT_STAT_STR "struct stat"
      36  #  define STRUCT_STAT_IS_STAT64 0
      37  # endif
      38  # ifndef SAMPLE_SIZE
      39  #  define SAMPLE_SIZE ((libc_off_t) 43147718418ULL)
      40  # endif
      41  
      42  typedef off_t libc_off_t;
      43  
      44  # define stat libc_stat
      45  # define stat64 libc_stat64
      46  # define statx libc_statx
      47  # define statx_timestamp libc_statx_timestamp
      48  struct statx;
      49  # include <fcntl.h>
      50  # include <sys/stat.h>
      51  # undef statx_timestamp
      52  # undef statx
      53  # undef stat64
      54  # undef stat
      55  
      56  # undef st_atime
      57  # undef st_mtime
      58  # undef st_ctime
      59  # include "asm_stat.h"
      60  
      61  # if STRUCT_STAT_IS_STAT64
      62  #  undef HAVE_STRUCT_STAT_ST_MTIME_NSEC
      63  #  if defined MPERS_IS_m32
      64  #   ifdef HAVE_M32_STRUCT_STAT64_ST_MTIME_NSEC
      65  #    define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
      66  #   endif
      67  #  elif defined MPERS_IS_mx32
      68  #   ifdef HAVE_MX32_STRUCT_STAT64_ST_MTIME_NSEC
      69  #    define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
      70  #   endif
      71  #  elif defined HAVE_STRUCT_STAT64_ST_MTIME_NSEC
      72  #   define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
      73  #  endif /* MPERS_IS_m32 || MPERS_IS_mx32 || HAVE_STRUCT_STAT64_ST_MTIME_NSEC */
      74  # else /* !STRUCT_STAT_IS_STAT64 */
      75  #  if defined MPERS_IS_m32
      76  #   undef HAVE_STRUCT_STAT_ST_MTIME_NSEC
      77  #   ifdef HAVE_M32_STRUCT_STAT_ST_MTIME_NSEC
      78  #    define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
      79  #   endif
      80  #  elif defined MPERS_IS_mx32
      81  #   undef HAVE_STRUCT_STAT_ST_MTIME_NSEC
      82  #   ifdef HAVE_MX32_STRUCT_STAT_ST_MTIME_NSEC
      83  #    define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
      84  #   endif
      85  #  endif /*  MPERS_IS_m32 || MPERS_IS_mx32 */
      86  # endif /* STRUCT_STAT_IS_STAT64 */
      87  
      88  # ifndef TEST_BOGUS_STRUCT_STAT
      89  #  define TEST_BOGUS_STRUCT_STAT 1
      90  # endif
      91  
      92  # ifndef IS_FSTAT
      93  #  define IS_FSTAT 0
      94  # endif
      95  
      96  # ifndef OLD_STAT
      97  #  define OLD_STAT 0
      98  # endif
      99  
     100  # ifndef IS_STATX
     101  #  define IS_STATX 0
     102  # endif
     103  
     104  # if !XLAT_RAW /* Fixes -Wunused warning */
     105  static void
     106  print_ftype(const unsigned int mode)
     107  {
     108  	if (S_ISREG(mode))
     109  		printf("S_IFREG");
     110  	else if (S_ISDIR(mode))
     111  		printf("S_IFDIR");
     112  	else if (S_ISCHR(mode))
     113  		printf("S_IFCHR");
     114  	else if (S_ISBLK(mode))
     115  		printf("S_IFBLK");
     116  	else
     117  		printf("%#o", mode & S_IFMT);
     118  }
     119  
     120  static void
     121  print_perms(const unsigned int mode)
     122  {
     123  	printf("%#o", mode & ~S_IFMT);
     124  }
     125  # endif
     126  
     127  static void
     128  print_st_mode(const unsigned int mode)
     129  {
     130  # if XLAT_RAW
     131  	printf("%#o", mode);
     132  # elif XLAT_VERBOSE
     133  	printf("%#o /* ", mode);
     134  	print_ftype(mode);
     135  	printf("|");
     136  	print_perms(mode);
     137  	printf(" */");
     138  # else
     139  	print_ftype(mode);
     140  	printf("|");
     141  	print_perms(mode);
     142  # endif
     143  }
     144  
     145  # if !IS_STATX
     146  
     147  static const char *
     148  sprint_makedev(const unsigned long long val)
     149  {
     150  	static char devid[256];
     151  	int ret;
     152  
     153  #  if XLAT_RAW
     154  	ret = snprintf(devid, sizeof(devid),
     155  			"%#llx", val);
     156  #  elif XLAT_VERBOSE
     157  	ret = snprintf(devid, sizeof(devid),
     158  			"%#llx /* makedev(%#x, %#x) */",
     159  			val, major(val), minor(val));
     160  #  else /* XLAT_ABBREV */
     161  	ret = snprintf(devid, sizeof(devid),
     162  			"makedev(%#x, %#x)",
     163  			major(val), minor(val));
     164  #  endif
     165  	if (ret < 0)
     166  		perror_msg_and_fail("sprint_makedev(%llx)", val);
     167  	if ((unsigned) ret >= sizeof(devid))
     168  		error_msg_and_fail("sprint_makedev(%llx): buffer "
     169  					   "overflow", val);
     170  	return devid;
     171  }
     172  
     173  
     174  static void
     175  print_stat(const STRUCT_STAT *st)
     176  {
     177  	unsigned long long dev, rdev;
     178  
     179  	dev = zero_extend_signed_to_ull(st->st_dev);
     180  	rdev = zero_extend_signed_to_ull(st->st_rdev);
     181  	printf("{st_dev=%s", sprint_makedev(dev));
     182  	printf(", st_ino=%llu", zero_extend_signed_to_ull(st->st_ino));
     183  	printf(", st_mode=");
     184  	print_st_mode(st->st_mode);
     185  	printf(", st_nlink=%llu", zero_extend_signed_to_ull(st->st_nlink));
     186  	printf(", st_uid=%llu", zero_extend_signed_to_ull(st->st_uid));
     187  	printf(", st_gid=%llu", zero_extend_signed_to_ull(st->st_gid));
     188  #  if OLD_STAT
     189  	printf(", st_blksize=0, st_blocks=0");
     190  #  else /* !OLD_STAT */
     191  	printf(", st_blksize=%llu", zero_extend_signed_to_ull(st->st_blksize));
     192  	printf(", st_blocks=%llu", zero_extend_signed_to_ull(st->st_blocks));
     193  #  endif /* OLD_STAT */
     194  
     195  	switch (st->st_mode & S_IFMT) {
     196  	case S_IFCHR: case S_IFBLK:
     197  		printf(", st_rdev=%s", sprint_makedev(rdev));
     198  		break;
     199  	default:
     200  		printf(", st_size=%llu", zero_extend_signed_to_ull(st->st_size));
     201  	}
     202  
     203  #  if defined(HAVE_STRUCT_STAT_ST_MTIME_NSEC) && !OLD_STAT
     204  #   define TIME_NSEC(val)	zero_extend_signed_to_ull(val)
     205  #   define HAVE_NSEC		1
     206  #  else
     207  #   define TIME_NSEC(val)	0ULL
     208  #   define HAVE_NSEC		0
     209  #  endif
     210  
     211  #  define PRINT_ST_TIME(field)							\
     212  	do {									\
     213  		printf(", st_" #field "=%lld",					\
     214  		       sign_extend_unsigned_to_ll(st->st_ ## field));		\
     215  		print_time_t_nsec(sign_extend_unsigned_to_ll(st->st_ ## field),	\
     216  				  TIME_NSEC(st->st_ ## field ## _nsec), 1);	\
     217  		if (HAVE_NSEC)							\
     218  			printf(", st_" #field "_nsec=%llu",			\
     219  			       TIME_NSEC(st->st_ ## field ## _nsec));		\
     220  	} while (0)
     221  
     222  	PRINT_ST_TIME(atime);
     223  	PRINT_ST_TIME(mtime);
     224  	PRINT_ST_TIME(ctime);
     225  	printf("}");
     226  }
     227  
     228  # else /* !IS_STATX */
     229  
     230  static void
     231  print_stat(const STRUCT_STAT *st)
     232  {
     233  #  define PRINT_FIELD_U32_UID(field)					\
     234  	do {								\
     235  		if (st->field == (uint32_t) -1)				\
     236  			printf(", %s=-1", #field);			\
     237  		else							\
     238  			printf(", %s=%llu", #field,			\
     239  			       (unsigned long long) st->field);		\
     240  	} while (0)
     241  
     242  #  define PRINT_FIELD_TIME(field)						\
     243  	do {									\
     244  		printf(", %s={tv_sec=%lld, tv_nsec=%u}",			\
     245  		       #field, (long long) st->field.tv_sec,			\
     246  		       (unsigned) st->field.tv_nsec);				\
     247  		print_time_t_nsec(st->field.tv_sec,				\
     248  				  zero_extend_signed_to_ull(st->field.tv_nsec),	\
     249  				  1);						\
     250  	} while (0)
     251  
     252  	printf("{stx_mask=");
     253  	printflags(statx_masks, st->stx_mask, "STATX_???");
     254  
     255  	printf(", ");
     256  	PRINT_FIELD_U(*st, stx_blksize);
     257  
     258  	printf(", stx_attributes=");
     259  	printflags(statx_attrs, st->stx_attributes, "STATX_ATTR_???");
     260  
     261  	if (st->stx_mask & STATX_NLINK) {
     262  		printf(", ");
     263  		PRINT_FIELD_U(*st, stx_nlink);
     264  	}
     265  	if (st->stx_mask & STATX_UID)
     266  		PRINT_FIELD_U32_UID(stx_uid);
     267  	if (st->stx_mask & STATX_GID)
     268  		PRINT_FIELD_U32_UID(stx_gid);
     269  
     270  	if (st->stx_mask & (STATX_TYPE|STATX_MODE)) {
     271  		printf(", stx_mode=");
     272  		print_st_mode(st->stx_mode);
     273  	}
     274  
     275  	if (st->stx_mask & STATX_INO) {
     276  		printf(", ");
     277  		PRINT_FIELD_U(*st, stx_ino);
     278  	}
     279  	if (st->stx_mask & STATX_SIZE) {
     280  		printf(", ");
     281  		PRINT_FIELD_U(*st, stx_size);
     282  	}
     283  	if (st->stx_mask & STATX_BLOCKS) {
     284  		printf(", ");
     285  		PRINT_FIELD_U(*st, stx_blocks);
     286  	}
     287  
     288  	printf(", stx_attributes_mask=");
     289  	printflags(statx_attrs, st->stx_attributes_mask, "STATX_ATTR_???");
     290  
     291  	if (st->stx_mask & STATX_ATIME)
     292  		PRINT_FIELD_TIME(stx_atime);
     293  	if (st->stx_mask & STATX_BTIME)
     294  		PRINT_FIELD_TIME(stx_btime);
     295  	if (st->stx_mask & STATX_CTIME)
     296  		PRINT_FIELD_TIME(stx_ctime);
     297  	if (st->stx_mask & STATX_MTIME)
     298  		PRINT_FIELD_TIME(stx_mtime);
     299  	printf(", ");
     300  	PRINT_FIELD_U(*st, stx_rdev_major);
     301  	printf(", ");
     302  	PRINT_FIELD_U(*st, stx_rdev_minor);
     303  	printf(", ");
     304  	PRINT_FIELD_U(*st, stx_dev_major);
     305  	printf(", ");
     306  	PRINT_FIELD_U(*st, stx_dev_minor);
     307  	if (st->stx_mask & STATX_MNT_ID) {
     308  		printf(", ");
     309  		PRINT_FIELD_X(*st, stx_mnt_id);
     310  	}
     311  	if (st->stx_mask & STATX_DIOALIGN) {
     312  		printf(", ");
     313  		PRINT_FIELD_U(*st, stx_dio_mem_align);
     314  		printf(", ");
     315  		PRINT_FIELD_U(*st, stx_dio_offset_align);
     316  	}
     317  	printf("}");
     318  }
     319  
     320  # endif /* !IS_STATX */
     321  
     322  static int
     323  create_sample(const char *fname, const libc_off_t size)
     324  {
     325  	static const struct timespec ts[] = {
     326  		{-10843, 135}, {-10841, 246}
     327  	};
     328  
     329  	(void) close(0);
     330  	if (open(fname, O_RDWR | O_CREAT | O_TRUNC, 0640)) {
     331  		perror(fname);
     332  		return 77;
     333  	}
     334  	if (ftruncate(0, size)) {
     335  		perror("ftruncate");
     336  		return 77;
     337  	}
     338  	if (futimens(0, ts)) {
     339  		perror("futimens");
     340  		return 77;
     341  	}
     342  	return 0;
     343  }
     344  
     345  int
     346  main(void)
     347  {
     348  # if IS_FSTAT
     349  	skip_if_unavailable("/proc/self/fd/");
     350  # else
     351  	static const char full[] = "/dev/full";
     352  # endif
     353  	static const char sample[] = "stat.sample";
     354  	TAIL_ALLOC_OBJECT_CONST_PTR(STRUCT_STAT, st);
     355  
     356  	int rc;
     357  
     358  	rc = create_sample(sample, SAMPLE_SIZE);
     359  	if (rc)
     360  		return rc;
     361  
     362  # if TEST_BOGUS_STRUCT_STAT
     363  	STRUCT_STAT *st_cut = tail_alloc(sizeof(long) * 4);
     364  	rc = TEST_SYSCALL_INVOKE(sample, st_cut);
     365  	PRINT_SYSCALL_HEADER(sample);
     366  	printf("%p", st_cut);
     367  	PRINT_SYSCALL_FOOTER(rc);
     368  # endif
     369  
     370  # if !IS_FSTAT
     371  	rc = TEST_SYSCALL_INVOKE(full, st);
     372  	PRINT_SYSCALL_HEADER(full);
     373  	if (rc)
     374  		printf("%p", st);
     375  	else
     376  		print_stat(st);
     377  	PRINT_SYSCALL_FOOTER(rc);
     378  # endif
     379  
     380  	if ((rc = TEST_SYSCALL_INVOKE(sample, st))) {
     381  		if (errno != EOVERFLOW) {
     382  			rc = (errno == ENOSYS) ? 77 : 1;
     383  			perror(TEST_SYSCALL_STR);
     384  			return rc;
     385  		}
     386  	}
     387  
     388  # if IS_STATX
     389  #  define ST_SIZE_FIELD stx_size
     390  # else
     391  #  define ST_SIZE_FIELD st_size
     392  # endif
     393  	if (!rc && zero_extend_signed_to_ull(SAMPLE_SIZE) !=
     394  	    zero_extend_signed_to_ull(st->ST_SIZE_FIELD)) {
     395  		fprintf(stderr, "Size mismatch: "
     396  				"requested size(%llu) != st_size(%llu)\n",
     397  			zero_extend_signed_to_ull(SAMPLE_SIZE),
     398  			zero_extend_signed_to_ull(st->ST_SIZE_FIELD));
     399  		fprintf(stderr, "The most likely reason for this is incorrect"
     400  				" definition of %s.\n"
     401  				"Here is some diagnostics that might help:\n",
     402  			STRUCT_STAT_STR);
     403  
     404  # define LOG_STAT_OFFSETOF_SIZEOF(object, member)			\
     405  		fprintf(stderr, "offsetof(%s, %s) = %zu"		\
     406  				", sizeof(%s) = %zu\n",			\
     407  				STRUCT_STAT_STR, #member,		\
     408  				offsetof(STRUCT_STAT, member),		\
     409  				#member, sizeof((object).member))
     410  
     411  # if IS_STATX
     412  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mask);
     413  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_blksize);
     414  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_attributes);
     415  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_nlink);
     416  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_uid);
     417  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_gid);
     418  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mode);
     419  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_ino);
     420  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_size);
     421  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_blocks);
     422  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_attributes_mask);
     423  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_atime);
     424  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_btime);
     425  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_ctime);
     426  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_mtime);
     427  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_rdev_major);
     428  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_rdev_minor);
     429  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_dev_major);
     430  		LOG_STAT_OFFSETOF_SIZEOF(*st, stx_dev_minor);
     431  # else
     432  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_dev);
     433  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_ino);
     434  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_mode);
     435  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_nlink);
     436  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_uid);
     437  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_gid);
     438  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_rdev);
     439  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_size);
     440  #  if !OLD_STAT
     441  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_blksize);
     442  		LOG_STAT_OFFSETOF_SIZEOF(*st, st_blocks);
     443  #  endif /* !OLD_STAT */
     444  
     445  # endif /* IS_STATX */
     446  
     447  		return 1;
     448  	}
     449  
     450  	PRINT_SYSCALL_HEADER(sample);
     451  	if (rc)
     452  		printf("%p", st);
     453  	else
     454  		print_stat(st);
     455  	PRINT_SYSCALL_FOOTER(rc);
     456  
     457  # if IS_STATX
     458  
     459  #  define INVOKE()					\
     460  	do {						\
     461  		rc = TEST_SYSCALL_INVOKE(sample, st);	\
     462  		PRINT_SYSCALL_HEADER(sample);		\
     463  		if (rc)					\
     464  			printf("%p", st);		\
     465  		else					\
     466  			print_stat(st);			\
     467  		PRINT_SYSCALL_FOOTER(rc);		\
     468  	} while (0)
     469  
     470  #  define SET_FLAGS_INVOKE(flags, flags_str)			\
     471  	do {							\
     472  		TEST_SYSCALL_STATX_FLAGS = flags;		\
     473  		TEST_SYSCALL_STATX_FLAGS_STR = flags_str;	\
     474  		INVOKE();					\
     475  	} while (0)
     476  
     477  #  define SET_MASK_INVOKE(mask, mask_str)			\
     478  	do {							\
     479  		TEST_SYSCALL_STATX_MASK = mask;			\
     480  		TEST_SYSCALL_STATX_MASK_STR = mask_str;		\
     481  		INVOKE();					\
     482  	} while (0)
     483  
     484  	unsigned old_flags = TEST_SYSCALL_STATX_FLAGS;
     485  	const char *old_flags_str = TEST_SYSCALL_STATX_FLAGS_STR;
     486  	unsigned old_mask = TEST_SYSCALL_STATX_MASK;
     487  	const char *old_mask_str = TEST_SYSCALL_STATX_MASK_STR;
     488  
     489  	SET_FLAGS_INVOKE(AT_SYMLINK_FOLLOW | 0xffff0000U,
     490  		"AT_STATX_SYNC_AS_STAT|AT_SYMLINK_FOLLOW|0xffff0000");
     491  
     492  	SET_FLAGS_INVOKE(AT_STATX_SYNC_TYPE,
     493  		"AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC");
     494  
     495  	SET_FLAGS_INVOKE(0xffffff,
     496  		"AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC|AT_SYMLINK_NOFOLLOW|"
     497  		"AT_REMOVEDIR|AT_SYMLINK_FOLLOW|AT_NO_AUTOMOUNT|AT_EMPTY_PATH|"
     498  		"AT_RECURSIVE|0xff00ff");
     499  
     500  	/* We're done playing with flags. */
     501  	TEST_SYSCALL_STATX_FLAGS = old_flags;
     502  	TEST_SYSCALL_STATX_FLAGS_STR = old_flags_str;
     503  
     504  	SET_MASK_INVOKE(0, "0");
     505  	SET_MASK_INVOKE(0xffffc000U, "0xffffc000 /* STATX_??? */");
     506  
     507  	SET_MASK_INVOKE(0xfffffffbU,
     508  		"STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID|STATX_ATIME|"
     509  		"STATX_MTIME|STATX_CTIME|STATX_INO|STATX_SIZE|STATX_BLOCKS|"
     510  		"STATX_BTIME|STATX_MNT_ID|STATX_DIOALIGN|0xffffc000");
     511  
     512  	SET_MASK_INVOKE(STATX_UID, "STATX_UID");
     513  
     514  	/* ...and with mask. */
     515  	TEST_SYSCALL_STATX_MASK = old_mask;
     516  	TEST_SYSCALL_STATX_MASK_STR = old_mask_str;
     517  
     518  # endif /* IS_STATX */
     519  
     520  	puts("+++ exited with 0 +++");
     521  	return 0;
     522  }
     523  
     524  #else
     525  
     526  SKIP_MAIN_UNDEFINED("HAVE_FTRUNCATE && HAVE_FUTIMENS")
     527  
     528  #endif