tests: check verbose decoding of 32-bit and 64-bit struct stat
* tests/stat.c: New file.
* tests/stat32.c: Likewise.
* tests/stat32-v.test: New file.
* tests/stat64-v.test: Likewise.
* tests/Makefile.am (check_PROGRAMS): Add stat and stat32.
(stat_CFLAGS): Define.
(TESTS): Add stat32-v.test and stat64-v.test.
* tests/.gitignore: Add stat and stat32.
diff --git a/tests/.gitignore b/tests/.gitignore
index b53ef6a..af463d0 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -8,6 +8,8 @@
set_ptracer_any
sigaction
stack-fcall
+stat
+stat32
statfs
uid
uid16
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e307c57..b88ed55 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,12 +13,15 @@
set_ptracer_any \
sigaction \
stack-fcall \
+ stat \
+ stat32 \
statfs \
uid \
uid16 \
uid32 \
uio
+stat_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
statfs_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
uio_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
stack_fcall_SOURCES = stack-fcall.c \
@@ -33,6 +36,8 @@
scm_rights-fd.test \
sigaction.test \
stat.test \
+ stat32-v.test \
+ stat64-v.test \
statfs.test \
mmsg.test \
net.test \
diff --git a/tests/stat.c b/tests/stat.c
new file mode 100644
index 0000000..21e37fb
--- /dev/null
+++ b/tests/stat.c
@@ -0,0 +1,171 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+#if defined MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+#elif defined MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+#else
+# include <sys/types.h>
+#endif
+
+#undef STAT_FNAME
+#undef NR_stat
+
+#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
+# include <sys/stat.h>
+# define STAT_FNAME "stat(64)?"
+#else
+# include <sys/syscall.h>
+# if defined __NR_stat
+# define NR_stat __NR_stat
+# define STAT_FNAME "stat"
+# elif defined __NR_newstat
+# define NR_stat __NR_newstat
+# define STAT_FNAME "newstat"
+# endif
+# ifdef STAT_FNAME
+/* for S_IFMT */
+# define stat libc_stat
+# define stat64 libc_stat64
+# include <sys/stat.h>
+# undef stat
+# undef stat64
+# undef st_atime
+# undef st_mtime
+# undef st_ctime
+
+# undef dev_t
+# undef ino_t
+# undef mode_t
+# undef nlink_t
+# undef uid_t
+# undef gid_t
+# undef off_t
+# undef loff_t
+# define dev_t __kernel_dev_t
+# define ino_t __kernel_ino_t
+# define mode_t __kernel_mode_t
+# define nlink_t __kernel_nlink_t
+# define uid_t __kernel_uid_t
+# define gid_t __kernel_gid_t
+# define off_t __kernel_off_t
+# define loff_t __kernel_loff_t
+# include <asm/stat.h>
+# endif /* STAT_FNAME */
+#endif /* _FILE_OFFSET_BITS */
+
+#ifdef STAT_FNAME
+
+static void
+print_ftype(unsigned int mode)
+{
+ if (S_ISREG(mode))
+ printf("S_IFREG");
+ else if (S_ISDIR(mode))
+ printf("S_IFDIR");
+ else if (S_ISCHR(mode))
+ printf("S_IFCHR");
+ else if (S_ISBLK(mode))
+ printf("S_IFBLK");
+ else
+ printf("%#o", mode & S_IFMT);
+}
+
+static void
+print_perms(unsigned int mode)
+{
+ printf("%#o", mode & ~S_IFMT);
+}
+
+static void
+print_time(time_t t)
+{
+ if (!t) {
+ printf("0");
+ return;
+ }
+
+ struct tm *p = localtime(&t);
+
+ if (p)
+ printf("%02d/%02d/%02d-%02d:%02d:%02d",
+ p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,
+ p->tm_hour, p->tm_min, p->tm_sec);
+ else
+ printf("%llu", (unsigned long long) t);
+}
+
+int
+main(int ac, const char **av)
+{
+ assert(ac == 2);
+ struct stat stb;
+
+#ifdef NR_stat
+ if (sizeof(stb.st_size) > 4)
+ return 77;
+ assert(syscall(NR_stat, av[1], &stb) == 0);
+#else
+ assert(stat(av[1], &stb) == 0);
+#endif
+
+ printf(STAT_FNAME "\\(\"%s\", \\{", av[1]);
+ printf("st_dev=makedev\\(%u, %u\\)",
+ (unsigned int) major(stb.st_dev),
+ (unsigned int) minor(stb.st_dev));
+ printf(", st_ino=%llu", (unsigned long long) stb.st_ino);
+ printf(", st_mode=");
+ print_ftype(stb.st_mode);
+ printf("\\|");
+ print_perms(stb.st_mode);
+ printf(", st_nlink=%u", (unsigned int) stb.st_nlink);
+ printf(", st_uid=%u", (unsigned int) stb.st_uid);
+ printf(", st_gid=%u", (unsigned int) stb.st_gid);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ printf(", st_blksize=%u", (unsigned int) stb.st_blksize);
+#endif
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+ printf(", st_blocks=%u", (unsigned int) stb.st_blocks);
+#endif
+
+ switch (stb.st_mode & S_IFMT) {
+ case S_IFCHR: case S_IFBLK:
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+ printf(", st_rdev=makedev\\(%u, %u\\)",
+ (unsigned int) major(stb.st_rdev),
+ (unsigned int) minor(stb.st_rdev));
+#else
+ printf(", st_size=makedev\\(%u, %u\\)",
+ (unsigned int) major(stb.st_size),
+ (unsigned int) minor(stb.st_size));
+#endif
+ break;
+ default:
+ printf(", st_size=%llu", (unsigned long long) stb.st_size);
+ }
+
+ printf(", st_atime=");
+ print_time(stb.st_atime);
+ printf(", st_mtime=");
+ print_time(stb.st_mtime);
+ printf(", st_ctime=");
+ print_time(stb.st_ctime);
+ printf("(, st_flags=[0-9]+)?");
+ printf("(, st_fstype=[^,]*)?");
+ printf("(, st_gen=[0-9]+)?");
+ printf("\\}\\) += 0\n");
+ return 0;
+}
+
+#else /* !STAT_FNAME */
+int main(void)
+{
+ return 77;
+}
+#endif
diff --git a/tests/stat32-v.test b/tests/stat32-v.test
new file mode 100755
index 0000000..74373c3
--- /dev/null
+++ b/tests/stat32-v.test
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Check verbose decoding of 32-bit stat syscall.
+
+. "${srcdir=.}/init.sh"
+
+check_prog dd
+check_prog grep
+check_prog touch
+
+OUT="$LOG.out"
+size=233811181
+sample=stat32_sample
+
+umask 022
+truncate_cmd="dd seek=$size obs=1 count=0 if=/dev/null of=$sample"
+$truncate_cmd > "$OUT" 2>&1 || {
+ cat "$OUT"
+ framework_skip_ 'failed to create a large sparse file'
+}
+
+./stat32 $sample > /dev/null || {
+ if [ $? -eq 77 ]; then
+ framework_skip_ '32-bit stat syscall is not available'
+ else
+ fail_ 'stat32 failed'
+ fi
+}
+
+touch -t 0102030405 $sample
+
+for f in $sample . /dev/null; do
+ args="-v -efile ./stat32 $f"
+ $STRACE -o "$LOG" $args > "$OUT" &&
+ LC_ALL=C grep -E -x -f "$OUT" "$LOG" > /dev/null || {
+ cat "$OUT" "$LOG"
+ fail_ "$STRACE $args output mismatch"
+ }
+done
+
+rm -f $sample "$OUT"
+
+exit 0
diff --git a/tests/stat32.c b/tests/stat32.c
new file mode 100644
index 0000000..a074251
--- /dev/null
+++ b/tests/stat32.c
@@ -0,0 +1 @@
+#include "stat.c"
diff --git a/tests/stat64-v.test b/tests/stat64-v.test
new file mode 100755
index 0000000..7e08e25
--- /dev/null
+++ b/tests/stat64-v.test
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# Check verbose decoding of 64-bit stat syscall.
+
+. "${srcdir=.}/init.sh"
+
+check_prog dd
+check_prog grep
+check_prog touch
+
+OUT="$LOG.out"
+size=46118400000
+sample=stat64_sample
+
+umask 022
+truncate_cmd="dd seek=$size obs=1 count=0 if=/dev/null of=$sample"
+$truncate_cmd > "$OUT" 2>&1 || {
+ cat "$OUT"
+ framework_skip_ 'failed to create a large sparse file'
+}
+
+./stat $sample > /dev/null ||
+ fail_ 'stat failed'
+
+touch -t 0102030405 $sample
+
+for f in $sample . /dev/null; do
+ args="-v -efile ./stat $f"
+ $STRACE -o "$LOG" $args > "$OUT" &&
+ LC_ALL=C grep -E -x -f "$OUT" "$LOG" > /dev/null || {
+ cat "$OUT" "$LOG"
+ fail_ "$STRACE $args output mismatch"
+ }
+done
+
+rm -f $sample "$OUT"
+
+exit 0