diff --git a/configure.ac b/configure.ac index b971b29e..71d051e2 100644 --- a/configure.ac +++ b/configure.ac @@ -241,6 +241,9 @@ AC_CHECK_FUNCS(m4_normalize([ fopen64 fork fputs_unlocked + fstatat + ftruncate + futimens if_indextoname inet_ntop inet_pton diff --git a/tests/.gitignore b/tests/.gitignore index 943c675d..5c5c5721 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -11,6 +11,7 @@ execveat fanotify_mark file_handle filter-unavailable +fstatat64 ftruncate ftruncate64 getdents @@ -37,6 +38,7 @@ nanosleep net-accept-connect netlink_inet_diag netlink_unix_diag +newfstatat oldselect pc pipe diff --git a/tests/Makefile.am b/tests/Makefile.am index fac6f5a0..9ccd395b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,6 +24,7 @@ check_PROGRAMS = \ fanotify_mark \ file_handle \ filter-unavailable \ + fstatat64 \ ftruncate \ ftruncate64 \ getdents \ @@ -50,6 +51,7 @@ check_PROGRAMS = \ net-accept-connect \ netlink_inet_diag \ netlink_unix_diag \ + newfstatat \ oldselect \ pc \ pipe \ @@ -104,9 +106,11 @@ check_PROGRAMS = \ clock_xettime_LDADD = -lrt filter_unavailable_LDADD = -lpthread +fstatat64_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 ftruncate64_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 mmap64_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 mq_LDADD = -lrt +newfstatat_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 pc_LDADD = $(dl_LIBS) stat_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 statfs_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64 @@ -134,6 +138,7 @@ TESTS = \ fanotify_mark.test \ file_handle.test \ filter-unavailable.test \ + fstatat64.test \ ftruncate.test \ ftruncate64.test \ getdents.test \ @@ -180,6 +185,7 @@ TESTS = \ net.test \ net-fd.test \ net-yy.test \ + newfstatat.test \ oldselect.test \ pipe.test \ pc.test \ @@ -231,6 +237,7 @@ EXTRA_DIST = init.sh run.sh match.awk \ execveat-v.expected \ fanotify_mark.expected \ filter-unavailable.expected \ + fstatat.c \ ip_mreq.expected \ ipc.sh \ ipc_msgbuf.expected \ diff --git a/tests/fstatat.c b/tests/fstatat.c new file mode 100644 index 00000000..7822f734 --- /dev/null +++ b/tests/fstatat.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined FSTATAT_NAME && defined HAVE_FSTATAT \ + && defined HAVE_FTRUNCATE && defined HAVE_FUTIMENS + +# include +# include +# include +# include +# include +# include + +#if defined MAJOR_IN_SYSMACROS +# include +#elif defined MAJOR_IN_MKDEV +# include +#else +# include +#endif + +static void +print_ftype(const 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(const unsigned int mode) +{ + printf("%#o", mode & ~S_IFMT); +} + +static void +print_time(const 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); +} + +static void +print_stat(const struct stat *st) +{ + printf("{st_dev=makedev(%u, %u)", + (unsigned int) major(st->st_dev), + (unsigned int) minor(st->st_dev)); + printf(", st_ino=%Lu", (unsigned long long) st->st_ino); + printf(", st_mode="); + print_ftype(st->st_mode); + printf("|"); + print_perms(st->st_mode); + printf(", st_nlink=%u", (unsigned int) st->st_nlink); + printf(", st_uid=%u", (unsigned int) st->st_uid); + printf(", st_gid=%u", (unsigned int) st->st_gid); + printf(", st_blksize=%u", (unsigned int) st->st_blksize); + printf(", st_blocks=%u", (unsigned int) st->st_blocks); + + switch (st->st_mode & S_IFMT) { + case S_IFCHR: case S_IFBLK: + printf(", st_rdev=makedev(%u, %u)", + (unsigned int) major(st->st_rdev), + (unsigned int) minor(st->st_rdev)); + break; + default: + printf(", st_size=%Lu", (unsigned long long) st->st_size); + } + + printf(", st_atime="); + print_time(st->st_atime); + if (st->st_atim.tv_nsec) + printf(".%09lu", (unsigned long) st->st_atim.tv_nsec); + printf(", st_mtime="); + print_time(st->st_mtime); + if (st->st_mtim.tv_nsec) + printf(".%09lu", (unsigned long) st->st_mtim.tv_nsec); + printf(", st_ctime="); + print_time(st->st_ctime); + if (st->st_ctim.tv_nsec) + printf(".%09lu", (unsigned long) st->st_ctim.tv_nsec); + printf("}"); +} + +int +main(void) +{ + static const char sample[] = FSTATAT_NAME ".sample"; + static const struct timespec ts[] = { + {-10843, 135}, {-10841, 246} + }; + const off_t size = 46118400291; + struct stat st; + + (void) close(0); + if (open(sample, O_RDWR | O_CREAT | O_TRUNC, 0640)) { + perror(sample); + return 77; + } + if (ftruncate(0, size)) { + perror("ftruncate"); + return 77; + } + if (futimens(0, ts)) { + perror("futimens"); + return 77; + } + if (fstatat(AT_FDCWD, sample, &st, AT_SYMLINK_NOFOLLOW)) { + perror("fstatat"); + return 77; + } + (void) unlink(sample); + + printf("%s(AT_FDCWD, \"%s\", ", FSTATAT_NAME, sample); + print_stat(&st); + puts(", AT_SYMLINK_NOFOLLOW) = 0"); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +int +main(void) +{ + return 77; +} + +#endif diff --git a/tests/fstatat64.c b/tests/fstatat64.c new file mode 100644 index 00000000..bc06d209 --- /dev/null +++ b/tests/fstatat64.c @@ -0,0 +1,12 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#undef FSTATAT_NAME +#ifdef __NR_fstatat64 +# define FSTATAT_NAME "fstatat64" +#endif + +#include "fstatat.c" diff --git a/tests/fstatat64.test b/tests/fstatat64.test new file mode 100755 index 00000000..b2b1ad62 --- /dev/null +++ b/tests/fstatat64.test @@ -0,0 +1,18 @@ +#!/bin/sh + +# Check fstatat64 syscall decoding. + +. "${srcdir=.}/init.sh" + +# strace -P is implemented using /proc/self/fd +[ -d /proc/self/fd/ ] || + framework_skip_ '/proc/self/fd/ is not available' + +syscall=${ME_%.test} +run_prog > /dev/null +OUT="$LOG.out" +run_strace -ve$syscall -P$syscall.sample $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT" + +exit 0 diff --git a/tests/newfstatat.c b/tests/newfstatat.c new file mode 100644 index 00000000..2f454021 --- /dev/null +++ b/tests/newfstatat.c @@ -0,0 +1,12 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#undef FSTATAT_NAME +#ifdef __NR_newfstatat +# define FSTATAT_NAME "newfstatat" +#endif + +#include "fstatat.c" diff --git a/tests/newfstatat.test b/tests/newfstatat.test new file mode 100755 index 00000000..03081548 --- /dev/null +++ b/tests/newfstatat.test @@ -0,0 +1,5 @@ +#!/bin/sh + +# Check newfstatat syscall decoding. + +. "${srcdir=.}/fstatat64.test"