On Fri, 21 Sep 2018 at 18:34, David Howells <dhowells@xxxxxxxxxx> wrote: > > Add a sample program to demonstrate fsopen/fsmount/move_mount to mount > something. > > Signed-off-by: David Howells <dhowells@xxxxxxxxxx> I was trying to build today linux-next tag next-20181217, I ran into the build error below when I was trying to build a allmodconfig kernel. I think this patch triggers the build error. In file included from /usr/include/x86_64-linux-gnu/sys/stat.h:446, from ../samples/vfs/test-statx.c:28: /usr/include/x86_64-linux-gnu/bits/statx.h:25:8: error: redefinition of ‘struct statx_timestamp’ struct statx_timestamp ^~~~~~~~~~~~~~~ In file included from ../samples/vfs/test-statx.c:26: ./usr/include/linux/stat.h:56:8: note: originally defined here struct statx_timestamp { ^~~~~~~~~~~~~~~ In file included from /usr/include/x86_64-linux-gnu/sys/stat.h:446, from ../samples/vfs/test-statx.c:28: /usr/include/x86_64-linux-gnu/bits/statx.h:36:8: error: redefinition of ‘struct statx’ struct statx ^~~~~ In file included from ../samples/vfs/test-statx.c:26: ./usr/include/linux/stat.h:99:8: note: originally defined here struct statx { ^~~~~ ../samples/vfs/test-statx.c:40:9: error: conflicting types for ‘statx’ ssize_t statx(int dfd, const char *filename, unsigned flags, ^~~~~ In file included from /usr/include/x86_64-linux-gnu/sys/stat.h:446, from ../samples/vfs/test-statx.c:28: /usr/include/x86_64-linux-gnu/bits/statx.h:87:5: note: previous declaration of ‘statx’ was here int statx (int __dirfd, const char *__restrict __path, int __flags, ^~~~~ make[3]: *** [scripts/Makefile.host:90: samples/vfs/test-statx] Error 1 make[3]: Target '__build' not remade because of errors. make[2]: *** [../scripts/Makefile.build:492: samples/vfs] Error 2 make[2]: Target '__build' not remade because of errors. make[1]: *** [/srv/src/kernel/next/Makefile:1065: samples] Error 2 make[1]: Target 'bzImage' not remade because of errors. make: *** [Makefile:152: sub-make] Error 2 make: Target 'bzImage' not remade because of errors. My libc version: $ dpkg -l libc6 ii libc6:amd64 2.28-2 amd64 GNU C Library: Shared libraries Any idea what I do wrong? Cheers, Anders > --- > > samples/Kconfig | 10 +- > samples/Makefile | 2 > samples/statx/Makefile | 7 - > samples/statx/test-statx.c | 258 -------------------------------------------- > samples/vfs/Makefile | 10 ++ > samples/vfs/test-fsmount.c | 118 ++++++++++++++++++++ > samples/vfs/test-statx.c | 258 ++++++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 393 insertions(+), 270 deletions(-) > delete mode 100644 samples/statx/Makefile > delete mode 100644 samples/statx/test-statx.c > create mode 100644 samples/vfs/Makefile > create mode 100644 samples/vfs/test-fsmount.c > create mode 100644 samples/vfs/test-statx.c > > diff --git a/samples/Kconfig b/samples/Kconfig > index bd133efc1a56..8df1c012820f 100644 > --- a/samples/Kconfig > +++ b/samples/Kconfig > @@ -146,10 +146,12 @@ config SAMPLE_VFIO_MDEV_MBOCHS > Specifically it does *not* include any legacy vga stuff. > Device looks a lot like "qemu -device secondary-vga". > > -config SAMPLE_STATX > - bool "Build example extended-stat using code" > - depends on BROKEN > +config SAMPLE_VFS > + bool "Build example programs that use new VFS system calls" > + depends on X86 > help > - Build example userspace program to use the new extended-stat syscall. > + Build example userspace programs that use new VFS system calls such > + as mount API and statx(). Note that this is restricted to the x86 > + arch whilst it accesses system calls that aren't yet in all arches. > > endif # SAMPLES > diff --git a/samples/Makefile b/samples/Makefile > index bd601c038b86..c5a6175c2d3f 100644 > --- a/samples/Makefile > +++ b/samples/Makefile > @@ -3,4 +3,4 @@ > obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ > hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ > configfs/ connector/ v4l/ trace_printk/ \ > - vfio-mdev/ statx/ qmi/ > + vfio-mdev/ vfs/ qmi/ > diff --git a/samples/statx/Makefile b/samples/statx/Makefile > deleted file mode 100644 > index 59df7c25a9d1..000000000000 > --- a/samples/statx/Makefile > +++ /dev/null > @@ -1,7 +0,0 @@ > -# List of programs to build > -hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx > - > -# Tell kbuild to always build the programs > -always := $(hostprogs-y) > - > -HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include > diff --git a/samples/statx/test-statx.c b/samples/statx/test-statx.c > deleted file mode 100644 > index d4d77b09412c..000000000000 > --- a/samples/statx/test-statx.c > +++ /dev/null > @@ -1,258 +0,0 @@ > -/* Test the statx() system call. > - * > - * Note that the output of this program is intended to look like the output of > - * /bin/stat where possible. > - * > - * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved. > - * Written by David Howells (dhowells@xxxxxxxxxx) > - * > - * This program is free software; you can redistribute it and/or > - * modify it under the terms of the GNU General Public Licence > - * as published by the Free Software Foundation; either version > - * 2 of the Licence, or (at your option) any later version. > - */ > - > -#define _GNU_SOURCE > -#define _ATFILE_SOURCE > -#include <stdio.h> > -#include <stdlib.h> > -#include <string.h> > -#include <unistd.h> > -#include <ctype.h> > -#include <errno.h> > -#include <time.h> > -#include <sys/syscall.h> > -#include <sys/types.h> > -#include <linux/stat.h> > -#include <linux/fcntl.h> > -#include <sys/stat.h> > - > -#define AT_STATX_SYNC_TYPE 0x6000 > -#define AT_STATX_SYNC_AS_STAT 0x0000 > -#define AT_STATX_FORCE_SYNC 0x2000 > -#define AT_STATX_DONT_SYNC 0x4000 > - > -static __attribute__((unused)) > -ssize_t statx(int dfd, const char *filename, unsigned flags, > - unsigned int mask, struct statx *buffer) > -{ > - return syscall(__NR_statx, dfd, filename, flags, mask, buffer); > -} > - > -static void print_time(const char *field, struct statx_timestamp *ts) > -{ > - struct tm tm; > - time_t tim; > - char buffer[100]; > - int len; > - > - tim = ts->tv_sec; > - if (!localtime_r(&tim, &tm)) { > - perror("localtime_r"); > - exit(1); > - } > - len = strftime(buffer, 100, "%F %T", &tm); > - if (len == 0) { > - perror("strftime"); > - exit(1); > - } > - printf("%s", field); > - fwrite(buffer, 1, len, stdout); > - printf(".%09u", ts->tv_nsec); > - len = strftime(buffer, 100, "%z", &tm); > - if (len == 0) { > - perror("strftime2"); > - exit(1); > - } > - fwrite(buffer, 1, len, stdout); > - printf("\n"); > -} > - > -static void dump_statx(struct statx *stx) > -{ > - char buffer[256], ft = '?'; > - > - printf("results=%x\n", stx->stx_mask); > - > - printf(" "); > - if (stx->stx_mask & STATX_SIZE) > - printf(" Size: %-15llu", (unsigned long long)stx->stx_size); > - if (stx->stx_mask & STATX_BLOCKS) > - printf(" Blocks: %-10llu", (unsigned long long)stx->stx_blocks); > - printf(" IO Block: %-6llu", (unsigned long long)stx->stx_blksize); > - if (stx->stx_mask & STATX_TYPE) { > - switch (stx->stx_mode & S_IFMT) { > - case S_IFIFO: printf(" FIFO\n"); ft = 'p'; break; > - case S_IFCHR: printf(" character special file\n"); ft = 'c'; break; > - case S_IFDIR: printf(" directory\n"); ft = 'd'; break; > - case S_IFBLK: printf(" block special file\n"); ft = 'b'; break; > - case S_IFREG: printf(" regular file\n"); ft = '-'; break; > - case S_IFLNK: printf(" symbolic link\n"); ft = 'l'; break; > - case S_IFSOCK: printf(" socket\n"); ft = 's'; break; > - default: > - printf(" unknown type (%o)\n", stx->stx_mode & S_IFMT); > - break; > - } > - } else { > - printf(" no type\n"); > - } > - > - sprintf(buffer, "%02x:%02x", stx->stx_dev_major, stx->stx_dev_minor); > - printf("Device: %-15s", buffer); > - if (stx->stx_mask & STATX_INO) > - printf(" Inode: %-11llu", (unsigned long long) stx->stx_ino); > - if (stx->stx_mask & STATX_NLINK) > - printf(" Links: %-5u", stx->stx_nlink); > - if (stx->stx_mask & STATX_TYPE) { > - switch (stx->stx_mode & S_IFMT) { > - case S_IFBLK: > - case S_IFCHR: > - printf(" Device type: %u,%u", > - stx->stx_rdev_major, stx->stx_rdev_minor); > - break; > - } > - } > - printf("\n"); > - > - if (stx->stx_mask & STATX_MODE) > - printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ", > - stx->stx_mode & 07777, > - ft, > - stx->stx_mode & S_IRUSR ? 'r' : '-', > - stx->stx_mode & S_IWUSR ? 'w' : '-', > - stx->stx_mode & S_IXUSR ? 'x' : '-', > - stx->stx_mode & S_IRGRP ? 'r' : '-', > - stx->stx_mode & S_IWGRP ? 'w' : '-', > - stx->stx_mode & S_IXGRP ? 'x' : '-', > - stx->stx_mode & S_IROTH ? 'r' : '-', > - stx->stx_mode & S_IWOTH ? 'w' : '-', > - stx->stx_mode & S_IXOTH ? 'x' : '-'); > - if (stx->stx_mask & STATX_UID) > - printf("Uid: %5d ", stx->stx_uid); > - if (stx->stx_mask & STATX_GID) > - printf("Gid: %5d\n", stx->stx_gid); > - > - if (stx->stx_mask & STATX_ATIME) > - print_time("Access: ", &stx->stx_atime); > - if (stx->stx_mask & STATX_MTIME) > - print_time("Modify: ", &stx->stx_mtime); > - if (stx->stx_mask & STATX_CTIME) > - print_time("Change: ", &stx->stx_ctime); > - if (stx->stx_mask & STATX_BTIME) > - print_time(" Birth: ", &stx->stx_btime); > - > - if (stx->stx_attributes_mask) { > - unsigned char bits, mbits; > - int loop, byte; > - > - static char attr_representation[64 + 1] = > - /* STATX_ATTR_ flags: */ > - "????????" /* 63-56 */ > - "????????" /* 55-48 */ > - "????????" /* 47-40 */ > - "????????" /* 39-32 */ > - "????????" /* 31-24 0x00000000-ff000000 */ > - "????????" /* 23-16 0x00000000-00ff0000 */ > - "???me???" /* 15- 8 0x00000000-0000ff00 */ > - "?dai?c??" /* 7- 0 0x00000000-000000ff */ > - ; > - > - printf("Attributes: %016llx (", stx->stx_attributes); > - for (byte = 64 - 8; byte >= 0; byte -= 8) { > - bits = stx->stx_attributes >> byte; > - mbits = stx->stx_attributes_mask >> byte; > - for (loop = 7; loop >= 0; loop--) { > - int bit = byte + loop; > - > - if (!(mbits & 0x80)) > - putchar('.'); /* Not supported */ > - else if (bits & 0x80) > - putchar(attr_representation[63 - bit]); > - else > - putchar('-'); /* Not set */ > - bits <<= 1; > - mbits <<= 1; > - } > - if (byte) > - putchar(' '); > - } > - printf(")\n"); > - } > -} > - > -static void dump_hex(unsigned long long *data, int from, int to) > -{ > - unsigned offset, print_offset = 1, col = 0; > - > - from /= 8; > - to = (to + 7) / 8; > - > - for (offset = from; offset < to; offset++) { > - if (print_offset) { > - printf("%04x: ", offset * 8); > - print_offset = 0; > - } > - printf("%016llx", data[offset]); > - col++; > - if ((col & 3) == 0) { > - printf("\n"); > - print_offset = 1; > - } else { > - printf(" "); > - } > - } > - > - if (!print_offset) > - printf("\n"); > -} > - > -int main(int argc, char **argv) > -{ > - struct statx stx; > - int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW; > - > - unsigned int mask = STATX_ALL; > - > - for (argv++; *argv; argv++) { > - if (strcmp(*argv, "-F") == 0) { > - atflag &= ~AT_STATX_SYNC_TYPE; > - atflag |= AT_STATX_FORCE_SYNC; > - continue; > - } > - if (strcmp(*argv, "-D") == 0) { > - atflag &= ~AT_STATX_SYNC_TYPE; > - atflag |= AT_STATX_DONT_SYNC; > - continue; > - } > - if (strcmp(*argv, "-L") == 0) { > - atflag &= ~AT_SYMLINK_NOFOLLOW; > - continue; > - } > - if (strcmp(*argv, "-O") == 0) { > - mask &= ~STATX_BASIC_STATS; > - continue; > - } > - if (strcmp(*argv, "-A") == 0) { > - atflag |= AT_NO_AUTOMOUNT; > - continue; > - } > - if (strcmp(*argv, "-R") == 0) { > - raw = 1; > - continue; > - } > - > - memset(&stx, 0xbf, sizeof(stx)); > - ret = statx(AT_FDCWD, *argv, atflag, mask, &stx); > - printf("statx(%s) = %d\n", *argv, ret); > - if (ret < 0) { > - perror(*argv); > - exit(1); > - } > - > - if (raw) > - dump_hex((unsigned long long *)&stx, 0, sizeof(stx)); > - > - dump_statx(&stx); > - } > - return 0; > -} > diff --git a/samples/vfs/Makefile b/samples/vfs/Makefile > new file mode 100644 > index 000000000000..4ac9690fb3c4 > --- /dev/null > +++ b/samples/vfs/Makefile > @@ -0,0 +1,10 @@ > +# List of programs to build > +hostprogs-$(CONFIG_SAMPLE_VFS) := \ > + test-fsmount \ > + test-statx > + > +# Tell kbuild to always build the programs > +always := $(hostprogs-y) > + > +HOSTCFLAGS_test-fsmount.o += -I$(objtree)/usr/include > +HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include > diff --git a/samples/vfs/test-fsmount.c b/samples/vfs/test-fsmount.c > new file mode 100644 > index 000000000000..74124025ade0 > --- /dev/null > +++ b/samples/vfs/test-fsmount.c > @@ -0,0 +1,118 @@ > +/* fd-based mount test. > + * > + * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. > + * Written by David Howells (dhowells@xxxxxxxxxx) > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public Licence > + * as published by the Free Software Foundation; either version > + * 2 of the Licence, or (at your option) any later version. > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <sys/prctl.h> > +#include <sys/wait.h> > +#include <linux/fs.h> > +#include <linux/unistd.h> > + > +#define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0) > + > +static void check_messages(int fd) > +{ > + char buf[4096]; > + int err, n; > + > + err = errno; > + > + for (;;) { > + n = read(fd, buf, sizeof(buf)); > + if (n < 0) > + break; > + n -= 2; > + > + switch (buf[0]) { > + case 'e': > + fprintf(stderr, "Error: %*.*s\n", n, n, buf + 2); > + break; > + case 'w': > + fprintf(stderr, "Warning: %*.*s\n", n, n, buf + 2); > + break; > + case 'i': > + fprintf(stderr, "Info: %*.*s\n", n, n, buf + 2); > + break; > + } > + } > + > + errno = err; > +} > + > +static __attribute__((noreturn)) > +void mount_error(int fd, const char *s) > +{ > + check_messages(fd); > + fprintf(stderr, "%s: %m\n", s); > + exit(1); > +} > + > +static inline int fsopen(const char *fs_name, unsigned int flags) > +{ > + return syscall(__NR_fsopen, fs_name, flags); > +} > + > +static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags) > +{ > + return syscall(__NR_fsmount, fsfd, flags, ms_flags); > +} > + > +static inline int fsconfig(int fsfd, unsigned int cmd, > + const char *key, const void *val, int aux) > +{ > + return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux); > +} > + > +static inline int move_mount(int from_dfd, const char *from_pathname, > + int to_dfd, const char *to_pathname, > + unsigned int flags) > +{ > + return syscall(__NR_move_mount, > + from_dfd, from_pathname, > + to_dfd, to_pathname, flags); > +} > + > +#define E_fsconfig(fd, cmd, key, val, aux) \ > + do { \ > + if (fsconfig(fd, cmd, key, val, aux) == -1) \ > + mount_error(fd, key ?: "create"); \ > + } while (0) > + > +int main(int argc, char *argv[]) > +{ > + int fsfd, mfd; > + > + /* Mount a publically available AFS filesystem */ > + fsfd = fsopen("afs", 0); > + if (fsfd == -1) { > + perror("fsopen"); > + exit(1); > + } > + > + E_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "#grand.central.org:root.cell.", 0); > + E_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); > + > + mfd = fsmount(fsfd, 0, MS_RDONLY); > + if (mfd < 0) > + mount_error(fsfd, "fsmount"); > + E(close(fsfd)); > + > + if (move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH) < 0) { > + perror("move_mount"); > + exit(1); > + } > + > + E(close(mfd)); > + exit(0); > +} > diff --git a/samples/vfs/test-statx.c b/samples/vfs/test-statx.c > new file mode 100644 > index 000000000000..d4d77b09412c > --- /dev/null > +++ b/samples/vfs/test-statx.c > @@ -0,0 +1,258 @@ > +/* Test the statx() system call. > + * > + * Note that the output of this program is intended to look like the output of > + * /bin/stat where possible. > + * > + * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved. > + * Written by David Howells (dhowells@xxxxxxxxxx) > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public Licence > + * as published by the Free Software Foundation; either version > + * 2 of the Licence, or (at your option) any later version. > + */ > + > +#define _GNU_SOURCE > +#define _ATFILE_SOURCE > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <ctype.h> > +#include <errno.h> > +#include <time.h> > +#include <sys/syscall.h> > +#include <sys/types.h> > +#include <linux/stat.h> > +#include <linux/fcntl.h> > +#include <sys/stat.h> > + > +#define AT_STATX_SYNC_TYPE 0x6000 > +#define AT_STATX_SYNC_AS_STAT 0x0000 > +#define AT_STATX_FORCE_SYNC 0x2000 > +#define AT_STATX_DONT_SYNC 0x4000 > + > +static __attribute__((unused)) > +ssize_t statx(int dfd, const char *filename, unsigned flags, > + unsigned int mask, struct statx *buffer) > +{ > + return syscall(__NR_statx, dfd, filename, flags, mask, buffer); > +} > + > +static void print_time(const char *field, struct statx_timestamp *ts) > +{ > + struct tm tm; > + time_t tim; > + char buffer[100]; > + int len; > + > + tim = ts->tv_sec; > + if (!localtime_r(&tim, &tm)) { > + perror("localtime_r"); > + exit(1); > + } > + len = strftime(buffer, 100, "%F %T", &tm); > + if (len == 0) { > + perror("strftime"); > + exit(1); > + } > + printf("%s", field); > + fwrite(buffer, 1, len, stdout); > + printf(".%09u", ts->tv_nsec); > + len = strftime(buffer, 100, "%z", &tm); > + if (len == 0) { > + perror("strftime2"); > + exit(1); > + } > + fwrite(buffer, 1, len, stdout); > + printf("\n"); > +} > + > +static void dump_statx(struct statx *stx) > +{ > + char buffer[256], ft = '?'; > + > + printf("results=%x\n", stx->stx_mask); > + > + printf(" "); > + if (stx->stx_mask & STATX_SIZE) > + printf(" Size: %-15llu", (unsigned long long)stx->stx_size); > + if (stx->stx_mask & STATX_BLOCKS) > + printf(" Blocks: %-10llu", (unsigned long long)stx->stx_blocks); > + printf(" IO Block: %-6llu", (unsigned long long)stx->stx_blksize); > + if (stx->stx_mask & STATX_TYPE) { > + switch (stx->stx_mode & S_IFMT) { > + case S_IFIFO: printf(" FIFO\n"); ft = 'p'; break; > + case S_IFCHR: printf(" character special file\n"); ft = 'c'; break; > + case S_IFDIR: printf(" directory\n"); ft = 'd'; break; > + case S_IFBLK: printf(" block special file\n"); ft = 'b'; break; > + case S_IFREG: printf(" regular file\n"); ft = '-'; break; > + case S_IFLNK: printf(" symbolic link\n"); ft = 'l'; break; > + case S_IFSOCK: printf(" socket\n"); ft = 's'; break; > + default: > + printf(" unknown type (%o)\n", stx->stx_mode & S_IFMT); > + break; > + } > + } else { > + printf(" no type\n"); > + } > + > + sprintf(buffer, "%02x:%02x", stx->stx_dev_major, stx->stx_dev_minor); > + printf("Device: %-15s", buffer); > + if (stx->stx_mask & STATX_INO) > + printf(" Inode: %-11llu", (unsigned long long) stx->stx_ino); > + if (stx->stx_mask & STATX_NLINK) > + printf(" Links: %-5u", stx->stx_nlink); > + if (stx->stx_mask & STATX_TYPE) { > + switch (stx->stx_mode & S_IFMT) { > + case S_IFBLK: > + case S_IFCHR: > + printf(" Device type: %u,%u", > + stx->stx_rdev_major, stx->stx_rdev_minor); > + break; > + } > + } > + printf("\n"); > + > + if (stx->stx_mask & STATX_MODE) > + printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ", > + stx->stx_mode & 07777, > + ft, > + stx->stx_mode & S_IRUSR ? 'r' : '-', > + stx->stx_mode & S_IWUSR ? 'w' : '-', > + stx->stx_mode & S_IXUSR ? 'x' : '-', > + stx->stx_mode & S_IRGRP ? 'r' : '-', > + stx->stx_mode & S_IWGRP ? 'w' : '-', > + stx->stx_mode & S_IXGRP ? 'x' : '-', > + stx->stx_mode & S_IROTH ? 'r' : '-', > + stx->stx_mode & S_IWOTH ? 'w' : '-', > + stx->stx_mode & S_IXOTH ? 'x' : '-'); > + if (stx->stx_mask & STATX_UID) > + printf("Uid: %5d ", stx->stx_uid); > + if (stx->stx_mask & STATX_GID) > + printf("Gid: %5d\n", stx->stx_gid); > + > + if (stx->stx_mask & STATX_ATIME) > + print_time("Access: ", &stx->stx_atime); > + if (stx->stx_mask & STATX_MTIME) > + print_time("Modify: ", &stx->stx_mtime); > + if (stx->stx_mask & STATX_CTIME) > + print_time("Change: ", &stx->stx_ctime); > + if (stx->stx_mask & STATX_BTIME) > + print_time(" Birth: ", &stx->stx_btime); > + > + if (stx->stx_attributes_mask) { > + unsigned char bits, mbits; > + int loop, byte; > + > + static char attr_representation[64 + 1] = > + /* STATX_ATTR_ flags: */ > + "????????" /* 63-56 */ > + "????????" /* 55-48 */ > + "????????" /* 47-40 */ > + "????????" /* 39-32 */ > + "????????" /* 31-24 0x00000000-ff000000 */ > + "????????" /* 23-16 0x00000000-00ff0000 */ > + "???me???" /* 15- 8 0x00000000-0000ff00 */ > + "?dai?c??" /* 7- 0 0x00000000-000000ff */ > + ; > + > + printf("Attributes: %016llx (", stx->stx_attributes); > + for (byte = 64 - 8; byte >= 0; byte -= 8) { > + bits = stx->stx_attributes >> byte; > + mbits = stx->stx_attributes_mask >> byte; > + for (loop = 7; loop >= 0; loop--) { > + int bit = byte + loop; > + > + if (!(mbits & 0x80)) > + putchar('.'); /* Not supported */ > + else if (bits & 0x80) > + putchar(attr_representation[63 - bit]); > + else > + putchar('-'); /* Not set */ > + bits <<= 1; > + mbits <<= 1; > + } > + if (byte) > + putchar(' '); > + } > + printf(")\n"); > + } > +} > + > +static void dump_hex(unsigned long long *data, int from, int to) > +{ > + unsigned offset, print_offset = 1, col = 0; > + > + from /= 8; > + to = (to + 7) / 8; > + > + for (offset = from; offset < to; offset++) { > + if (print_offset) { > + printf("%04x: ", offset * 8); > + print_offset = 0; > + } > + printf("%016llx", data[offset]); > + col++; > + if ((col & 3) == 0) { > + printf("\n"); > + print_offset = 1; > + } else { > + printf(" "); > + } > + } > + > + if (!print_offset) > + printf("\n"); > +} > + > +int main(int argc, char **argv) > +{ > + struct statx stx; > + int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW; > + > + unsigned int mask = STATX_ALL; > + > + for (argv++; *argv; argv++) { > + if (strcmp(*argv, "-F") == 0) { > + atflag &= ~AT_STATX_SYNC_TYPE; > + atflag |= AT_STATX_FORCE_SYNC; > + continue; > + } > + if (strcmp(*argv, "-D") == 0) { > + atflag &= ~AT_STATX_SYNC_TYPE; > + atflag |= AT_STATX_DONT_SYNC; > + continue; > + } > + if (strcmp(*argv, "-L") == 0) { > + atflag &= ~AT_SYMLINK_NOFOLLOW; > + continue; > + } > + if (strcmp(*argv, "-O") == 0) { > + mask &= ~STATX_BASIC_STATS; > + continue; > + } > + if (strcmp(*argv, "-A") == 0) { > + atflag |= AT_NO_AUTOMOUNT; > + continue; > + } > + if (strcmp(*argv, "-R") == 0) { > + raw = 1; > + continue; > + } > + > + memset(&stx, 0xbf, sizeof(stx)); > + ret = statx(AT_FDCWD, *argv, atflag, mask, &stx); > + printf("statx(%s) = %d\n", *argv, ret); > + if (ret < 0) { > + perror(*argv); > + exit(1); > + } > + > + if (raw) > + dump_hex((unsigned long long *)&stx, 0, sizeof(stx)); > + > + dump_statx(&stx); > + } > + return 0; > +} >