On 3/29/17 11:49 AM, David Howells wrote: > Here's my third attempt at changing Eric's statx patch. I've got rid of the > compare option to statx and added a raw output option to stat. They're still > not directly comparable since the stat output lacks some fields, but it will > hopefully be possible to load them into associative arrays in bash and compare > them that way. Thanks for working on this; comments below. But - do you plan to send this as (a) formal patch(es) with signed-off-by etc? Or do you want me to just fold this into my patch with some sort of Changes-inspired-by: David Howells <dhowells@xxxxxxxxxx> tag? ;) The changes to stat_f should be their own standalone patch, I think. (meh, it's kind of unfortunate that the current stat_f does more than just stat, isn't it?) I may make further changes so that a bare "statx" prints exactly the same info as a bare "stat", and a new "-r" to each one dumps the raw stat[x] structure. Just for some symmetry... > --- > diff --git a/io/stat.c b/io/stat.c > index a7aebcd..d2ea854 100644 > --- a/io/stat.c > +++ b/io/stat.c > @@ -44,6 +44,35 @@ filesize(void) > return st.st_size; > } > > +static int > +dump_raw_stat(struct stat *st) > +{ > + if (fstat(file->fd, st) < 0) { > + perror("fstat"); > + return -1; > + } > + > + printf("stat.blksize: %lu\n", st->st_blksize); > + printf("stat.nlink: %lu\n", st->st_nlink); > + printf("stat.uid: %u\n", st->st_uid); > + printf("stat.gid: %u\n", st->st_gid); > + printf("stat.mode: 0%o\n", st->st_mode); > + printf("stat.ino: %lu\n", st->st_ino); > + printf("stat.size: %lu\n", st->st_size); > + printf("stat.blocks: %lu\n", st->st_blocks); > + printf("stat.atime.tv_sec: %ld\n", st->st_atim.tv_sec); > + printf("stat.atime.tv_nsec: %ld\n", st->st_atim.tv_nsec); > + printf("stat.ctime.tv_sec: %ld\n", st->st_ctim.tv_sec); > + printf("stat.ctime.tv_nsec: %ld\n", st->st_ctim.tv_nsec); > + printf("stat.mtime.tv_sec: %ld\n", st->st_mtim.tv_sec); > + printf("stat.mtime.tv_nsec: %ld\n", st->st_mtim.tv_nsec); > + printf("stat.rdev_major: %u\n", major(st->st_rdev)); > + printf("stat.rdev_minor: %u\n", minor(st->st_rdev)); > + printf("stat.dev_major: %u\n", major(st->st_dev)); > + printf("stat.dev_minor: %u\n", minor(st->st_dev)); > + return 0; > +} > + > static char * > filetype(mode_t mode) > { > @@ -74,7 +103,23 @@ stat_f( > struct dioattr dio; > struct fsxattr fsx, fsxa; > struct stat st; > - int verbose = (argc == 2 && !strcmp(argv[1], "-v")); > + int c, verbose = 0, raw = 0; > + > + while ((c = getopt(argc, argv, "rv")) != EOF) { > + switch (c) { > + case 'r': > + raw = 1; > + break; > + case 'v': > + verbose = 1; > + break; > + default: > + return command_usage(&stat_cmd); > + } > + } > + > + if (raw) > + return dump_raw_stat(&st); > > printf(_("fd.path = \"%s\"\n"), file->name); > printf(_("fd.flags = %s,%s,%s%s%s%s%s\n"), > @@ -189,12 +234,9 @@ 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" > -" -A -- Suppress terminal automount traversal\n" > +" -m mask -- Specify the field mask for the statx call (can also be 'basic' or 'all'; default STATX_ALL)\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" ok, I like the basic/all/mask better, yes. > "\n")); > } > > @@ -202,28 +244,28 @@ statx_help(void) > static void > dump_statx(struct statx *stx) > { > - printf("stx_mask: 0x%x\n", stx->stx_mask); > - printf("stx_blksize: %u\n", stx->stx_blksize); > - printf("stx_attributes: 0x%llx\n", stx->stx_attributes); > - printf("stx_nlink: %u\n", stx->stx_nlink); > - printf("stx_uid: %u\n", stx->stx_uid); > - printf("stx_gid: %u\n", stx->stx_gid); > - printf("stx_mode: 0%o\n", stx->stx_mode); > - printf("stx_ino: %llu\n", stx->stx_ino); > - printf("stx_size: %llu\n", stx->stx_size); > - printf("stx_blocks: %llu\n", stx->stx_blocks); > - printf("stx_atime.tv_sec: %lld\n", stx->stx_atime.tv_sec); > - printf("stx_atime.tv_nsec: %d\n", stx->stx_atime.tv_nsec); > - printf("stx_btime.tv_sec: %lld\n", stx->stx_btime.tv_sec); > - printf("stx_btime.tv_nsec: %d\n", stx->stx_btime.tv_nsec); > - printf("stx_ctime.tv_sec: %lld\n", stx->stx_ctime.tv_sec); > - printf("stx_ctime.tv_nsec: %d\n", stx->stx_ctime.tv_nsec); > - printf("stx_mtime.tv_sec: %lld\n", stx->stx_mtime.tv_sec); > - printf("stx_mtime.tv_nsec: %d\n", stx->stx_mtime.tv_nsec); > - printf("stx_rdev_major: %u\n", stx->stx_rdev_major); > - printf("stx_rdev_minor: %u\n", stx->stx_rdev_minor); > - printf("stx_dev_major: %u\n", stx->stx_dev_major); > - printf("stx_dev_minor: %u\n", stx->stx_dev_minor); > + printf("stat.mask: 0x%x\n", stx->stx_mask); Seems a little weird to be printing something that looks like structure.member, when it's not actually the structure or member name, but I suppose it facilitates parsing the output for testing? > + printf("stat.blksize: %u\n", stx->stx_blksize); > + printf("stat.attributes: 0x%llx\n", stx->stx_attributes); > + printf("stat.nlink: %u\n", stx->stx_nlink); > + printf("stat.uid: %u\n", stx->stx_uid); > + printf("stat.gid: %u\n", stx->stx_gid); > + printf("stat.mode: 0%o\n", stx->stx_mode); > + printf("stat.ino: %llu\n", stx->stx_ino); > + printf("stat.size: %llu\n", stx->stx_size); > + printf("stat.blocks: %llu\n", stx->stx_blocks); > + printf("stat.atime.tv_sec: %lld\n", stx->stx_atime.tv_sec); > + printf("stat.atime.tv_nsec: %d\n", stx->stx_atime.tv_nsec); > + printf("stat.btime.tv_sec: %lld\n", stx->stx_btime.tv_sec); > + printf("stat.btime.tv_nsec: %d\n", stx->stx_btime.tv_nsec); > + printf("stat.ctime.tv_sec: %lld\n", stx->stx_ctime.tv_sec); > + printf("stat.ctime.tv_nsec: %d\n", stx->stx_ctime.tv_nsec); > + printf("stat.mtime.tv_sec: %lld\n", stx->stx_mtime.tv_sec); > + printf("stat.mtime.tv_nsec: %d\n", stx->stx_mtime.tv_nsec); > + printf("stat.rdev_major: %u\n", stx->stx_rdev_major); > + printf("stat.rdev_minor: %u\n", stx->stx_rdev_minor); > + printf("stat.dev_major: %u\n", stx->stx_dev_major); > + printf("stat.dev_minor: %u\n", stx->stx_dev_minor); > } > > /* > @@ -239,16 +281,18 @@ statx_f( > { > int c; > struct statx stx; > - int atflag = AT_SYMLINK_NOFOLLOW; > - unsigned int m_mask = 0; /* mask requested with -m */ > - int Oflag = 0, mflag = 0; /* -O or -m was used */ > + int atflag = 0; > unsigned int mask = STATX_ALL; > > - while ((c = getopt(argc, argv, "m:FDLOA")) != EOF) { > + while ((c = getopt(argc, argv, "m:FD")) != EOF) { > switch (c) { > 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); best to check for failure here I suppose, but I've already got that in my current patch. > break; > case 'F': > atflag &= ~AT_STATX_SYNC_TYPE; > @@ -258,38 +302,19 @@ statx_f( > atflag &= ~AT_STATX_SYNC_TYPE; > atflag |= AT_STATX_DONT_SYNC; > break; > - case 'L': > - atflag &= ~AT_SYMLINK_NOFOLLOW; > - break; > - case 'O': > - mask = STATX_BASIC_STATS; > - Oflag = 1; > - break; > - case 'A': > - atflag |= AT_NO_AUTOMOUNT; > - break; > default: > return command_usage(&statx_cmd); > } > } > > - if (Oflag && mflag) { > - printf("Cannot specify both -m mask and -O\n"); > - return 0; > - } > - > - /* -m overrides any other mask options */ > - if (mflag) > - mask = m_mask; > - > memset(&stx, 0xbf, sizeof(stx)); > - if (statx(AT_FDCWD, file->name, atflag, mask, &stx) < 0) { > + > + if (statx(file->fd, NULL, atflag, mask, &stx) < 0) { > perror("statx"); > return 0; > } > - > + whitespace ;) > dump_statx(&stx); > - > return 0; > } > > @@ -301,7 +326,7 @@ stat_init(void) > stat_cmd.argmin = 0; > stat_cmd.argmax = 1; > stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; > - stat_cmd.args = _("[-v]"); > + stat_cmd.args = _("[-rv]"); > stat_cmd.oneline = _("information about the currently open file"); > > statfs_cmd.name = "statfs"; > @@ -315,7 +340,7 @@ stat_init(void) > statx_cmd.argmin = 0; > statx_cmd.argmax = -1; > statx_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK; > - statx_cmd.args = _("[-O | -m mask][-FDLAP]"); > + statx_cmd.args = _("[-m basic | -m all | -m <mask>][-FD]"); > statx_cmd.oneline = > _("extended information about the currently open file"); > statx_cmd.help = statx_help; > diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 > index 77ba760..486ad11 100644 > --- a/man/man8/xfs_io.8 > +++ b/man/man8/xfs_io.8 > @@ -876,24 +876,29 @@ Only available in expert mode and requires privileges. > Force the filesystem to shutdown (with or without flushing the log). > Only available in expert mode and requires privileges. > .TP > -.BR stat " [ " \-v " ]" > +.BR stat " [ \-" rv " ]" > Selected statistics from > .BR stat (2) > and the XFS_IOC_GETXATTR system call on the current file. If the > .B \-v > option is specified, the atime (last access), mtime > -(last modify), and ctime (last change) timestamps are also displayed. > +(last modify), and ctime (last change) timestamps are also displayed. If the > +.B \-r > +option is specified, the raw output will be dumped in the same form as the > +output for the statx command, but with some fields missing. > .TP > -.BR statx " [ " \-O " | " "\-m mask" " ][ \-" FDLA " ]" > +.BR statx " [ " "\-m mask" " ][ \-" FD " ]" > Extended information from the statx syscall. > .RS 1.0i > .PD 0 > .TP 0.4i > .B \-m mask > -Specify the field mask for the statx call (default STATX_ALL) > -.TP > -.B \-O > -Add only basic stats (STATX_BASIC_STATS) to default mask > +Specify the field mask for the statx call as an decimal, hex or octal integer > +or > +.RI \" basic "\" or \"" all \" > +to specify the basic stats that > +.IR stat () > +returns or all the stats known by the header file. All is the default. > .TP > .B \-F > Force the attributes to be sync'd with the server > @@ -901,12 +906,6 @@ Force the attributes to be sync'd with the server > .B \-D > Don't sync attributes with the server > .TP > -.B \-L > -Follow symlinks (statx link target) > -.TP > -.B \-A > -Suppress terminal automount traversal > -.TP > .RE > .IP > .TP > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html >