Eric Sandeen <sandeen@xxxxxxxxxxx> wrote: > Wire up the statx syscall to xfs_io. > > xfs_io> help statx > statx [-O | -m mask][-FDLA] -- extended information about the currently open file > ... I would like to make the attached changes, to make it more capable, except that xfs_io seems to precheck the "-m mask" argument somewhere: [root@andromeda ~]# xfs_io -c statx -m all /dev/null non-numeric mode -- all and interprets "-c" for itself on the command line: [root@andromeda ~]# xfs_io -c statx -c /dev/null command "/dev/null" not found though both these seem to work when used from xfs_io's command prompt. I guess I should switch -c to -C and also -m to -M since it's not a file mode as I think the core is expecting. Also, how do you get xfs_io to tell you what fd it has opened from its own command prompt? I would need to pass that to the -d flag as a dir fd. David --- commit 03e4ca1cdc59aaa362fdd51f079493a1f0da254c Author: David Howells <dhowells@xxxxxxxxxx> Date: Tue Mar 28 10:42:23 2017 +0100 changes diff --git a/io/stat.c b/io/stat.c index a7aebcd..0b05ec9 100644 --- a/io/stat.c +++ b/io/stat.c @@ -189,12 +189,14 @@ statx_help(void) " Display extended file status.\n" "\n" " Options:\n" -" -m mask -- Specify the field mask for the statx call (default STATX_ALL)\n" +" -c -- Compare against fstat/fstatat on the same file/fd\n" +" -d dirfd -- Use a specific directory fd\n" +" -f -- Do fstat equivalent and operate on fd\n" +" -m mask -- Specify the field mask for the statx call (can also be 'basic' or 'all'; default STATX_ALL)\n" " -A -- Suppress terminal automount traversal\n" " -D -- Don't sync attributes with the server\n" " -F -- Force the attributes to be sync'd with the server\n" " -L -- Follow symlinks (statx link target)\n" -" -O -- Add only basic stats (STATX_BASIC_STATS) to default mask\n" "\n")); } @@ -227,6 +229,65 @@ dump_statx(struct statx *stx) } /* + * Compare the contents of a statx struct with that of a stat struct and check + * that they're the same. + */ +static int +cmp_statx(const struct statx *stx, const struct stat *st) +{ + const char *what = NULL; + +#define cmp(x) \ + do { \ + what = #x; \ + if (stx->stx_##x != st->st_##x) \ + goto mismatch; \ + } while (0) + + cmp(blksize); + cmp(nlink); + cmp(uid); + cmp(gid); + cmp(mode); + cmp(ino); + cmp(size); + cmp(blocks); + +#define devcmp(x) \ + do { \ + what = #x".major"; \ + if (stx->stx_##x##_major != major(st->st_##x)) \ + goto mismatch; \ + what = #x".minor"; \ + if (stx->stx_##x##_minor != minor(st->st_##x)) \ + goto mismatch; \ + } while (0) + + devcmp(dev); + devcmp(rdev); + +#define timecmp(x) \ + do { \ + what = #x".tv_sec"; \ + if (stx->stx_##x##time.tv_sec != st->st_##x##tim.tv_sec) \ + goto mismatch; \ + what = #x".tv_nsec"; \ + if (stx->stx_##x##time.tv_nsec != st->st_##x##tim.tv_nsec) \ + goto mismatch; \ + } while (0) + + timecmp(a); + timecmp(c); + timecmp(m); + + return 0; + +mismatch: + fprintf(stderr, "Mismatch between stat and statx output (%s)\n", what); + return -1; +} + +/* * options: * - input flags - query type * - output style for flags (and all else?) (chars vs. hex?) @@ -239,16 +300,31 @@ statx_f( { int c; struct statx stx; + struct stat st; int atflag = AT_SYMLINK_NOFOLLOW; - unsigned int m_mask = 0; /* mask requested with -m */ - int Oflag = 0, mflag = 0; /* -O or -m was used */ unsigned int mask = STATX_ALL; + int use_fd = 0; + int dirfd = AT_FDCWD; + int compare = 0; - while ((c = getopt(argc, argv, "m:FDLOA")) != EOF) { + while ((c = getopt(argc, argv, "d:cfm:FDLA")) != EOF) { switch (c) { + case 'c': + compare = 1; + break; + case 'd': + dirfd = strtoul(optarg, NULL, 0); + break; + case 'f': + use_fd = 1; + break; case 'm': - m_mask = atoi(optarg); - mflag = 1; + if (strcmp(optarg, "basic") == 0) + mask = STATX_BASIC_STATS; + else if (strcmp(optarg, "all") == 0) + mask = STATX_ALL; + else + mask = strtoul(optarg, NULL, 0); break; case 'F': atflag &= ~AT_STATX_SYNC_TYPE; @@ -261,10 +337,6 @@ statx_f( case 'L': atflag &= ~AT_SYMLINK_NOFOLLOW; break; - case 'O': - mask = STATX_BASIC_STATS; - Oflag = 1; - break; case 'A': atflag |= AT_NO_AUTOMOUNT; break; @@ -273,23 +345,38 @@ statx_f( } } - if (Oflag && mflag) { - printf("Cannot specify both -m mask and -O\n"); - return 0; + memset(&stx, 0xbf, sizeof(stx)); + + if (use_fd) { + if (statx(file->fd, NULL, atflag, mask, &stx) < 0) { + perror("statx"); + return 0; + } + } else { + if (statx(dirfd, file->name, atflag, mask, &stx) < 0) { + perror("statx"); + return 0; + } } - /* -m overrides any other mask options */ - if (mflag) - mask = m_mask; + if (compare) { + if (use_fd) { + if (fstat(file->fd, &st) < 0) { + perror("fstat"); + return 0; + } + } else { + if (fstatat(dirfd, file->name, &st, + atflag & ~AT_STATX_SYNC_TYPE) < 0) { + perror("fstatat"); + return 0; + } + } - memset(&stx, 0xbf, sizeof(stx)); - if (statx(AT_FDCWD, file->name, atflag, mask, &stx) < 0) { - perror("statx"); - return 0; + cmp_statx(&stx, &st); } - + dump_statx(&stx); - return 0; }