From 8fabaa8b76b03e6c4bd4cd6a266e30152f9e5ec9 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Sat, 19 Apr 2025 03:09:25 +0200 Subject: [PATCH] fincore: add recursive directory scanning Add a --recursive flag to fincore which allows to recursively scan directories. Co-authored-by: Karel Zak Signed-off-by: Matteo Croce --- bash-completion/fincore | 1 + configure.ac | 4 + meson.build | 1 + misc-utils/fincore.1.adoc | 3 + misc-utils/fincore.c | 88 ++++++++++++------ tests/expected/fincore/count.16384 | 53 +++++++++++ tests/expected/fincore/count.16384.recursive | 12 +++ tests/expected/fincore/count.4096 | 50 +++++------ tests/expected/fincore/count.4096.recursive | 12 +++ tests/expected/fincore/count.65536 | 36 ++++---- tests/expected/fincore/count.65536.recursive | 12 +++ .../fincore/{count.err.4096 => count.err} | 0 tests/expected/fincore/count.err.65536 | 4 - tests/expected/fincore/count.err.nosize | 4 - tests/expected/fincore/count.nosize | 32 +++---- tests/expected/fincore/count.nosize.recursive | 12 +++ tests/helpers/test_sysinfo.c | 90 +++++++++++++++++++ tests/ts/fincore/count | 65 +++++++++++--- 18 files changed, 372 insertions(+), 107 deletions(-) create mode 100644 tests/expected/fincore/count.16384 create mode 100644 tests/expected/fincore/count.16384.recursive create mode 100644 tests/expected/fincore/count.4096.recursive create mode 100644 tests/expected/fincore/count.65536.recursive rename tests/expected/fincore/{count.err.4096 => count.err} (100%) delete mode 100644 tests/expected/fincore/count.err.65536 delete mode 100644 tests/expected/fincore/count.err.nosize create mode 100644 tests/expected/fincore/count.nosize.recursive diff --git a/bash-completion/fincore b/bash-completion/fincore index f0f9c45f17..5f073b4ec0 100644 --- a/bash-completion/fincore +++ b/bash-completion/fincore @@ -32,6 +32,7 @@ _fincore_module() --output --output-all --raw + --recursive --help --version " diff --git a/configure.ac b/configure.ac index 68a8f54d92..b04ec74db1 100644 --- a/configure.ac +++ b/configure.ac @@ -822,6 +822,10 @@ AS_IF([test x"$have_dirfd" = xno], [ AM_CONDITIONAL([HAVE_DIRFD], [test "x$have_dirfd" = xyes || test "x$have_ddfd" = xyes]) +have_fts_open=no +AC_CHECK_FUNCS([fts_open], [have_fts_open=yes], [have_fts_open=no]) +AM_CONDITIONAL([HAVE_FTS_OPEN], [test "x$have_fts_open" = xyes]) + MQ_LIBS= AC_CHECK_LIB([rt], [mq_open], [MQ_LIBS="-lrt"]) AC_SUBST([MQ_LIBS]) diff --git a/meson.build b/meson.build index e225454d70..ec471f4b59 100644 --- a/meson.build +++ b/meson.build @@ -683,6 +683,7 @@ funcs = ''' open_memstream reboot getusershell + fts_open '''.split() foreach func: funcs diff --git a/misc-utils/fincore.1.adoc b/misc-utils/fincore.1.adoc index 2ee43435f8..7d0c8fca37 100644 --- a/misc-utils/fincore.1.adoc +++ b/misc-utils/fincore.1.adoc @@ -47,6 +47,9 @@ Produce output in raw format. All potentially unsafe characters are hex-escaped *-J*, *--json*:: Use JSON output format. +*-R*, *--recursive*:: +Recursively check all files in directories. + include::man-common/help-version.adoc[] == AUTHORS diff --git a/misc-utils/fincore.c b/misc-utils/fincore.c index a2f2400521..160dd8e0bf 100644 --- a/misc-utils/fincore.c +++ b/misc-utils/fincore.c @@ -26,6 +26,10 @@ #include #include +#ifdef HAVE_FTS_OPEN +#include +#endif + #include "c.h" #include "cctype.h" #include "nls.h" @@ -125,12 +129,13 @@ struct fincore_control { unsigned int bytes : 1, noheadings : 1, raw : 1, - json : 1; + json : 1, + recursive : 1; }; struct fincore_state { - const char * const name; + const char * name; long long unsigned int file_size; struct cachestat cstat; @@ -357,30 +362,34 @@ static int fincore_fd (struct fincore_control *ctl, * Returns: <0 on error, 0 success, 1 ignore. */ static int fincore_name(struct fincore_control *ctl, - struct fincore_state *st) + const char *filename, + const char *showname, + struct stat *statp) { int fd; int rc = 0; - struct stat sb; + struct stat _sb, *sb = statp ?: &_sb; + struct fincore_state _st = { .name = filename }, *st = &_st; - if ((fd = open (st->name, O_RDONLY)) < 0) { - warn(_("failed to open: %s"), st->name); + if ((fd = open(filename, O_RDONLY)) < 0) { + warn(_("failed to open: %s"), showname); return -errno; } - if (fstat (fd, &sb) < 0) { - warn(_("failed to do fstat: %s"), st->name); - close (fd); - return -errno; + if (!statp) { + if (fstat (fd, sb) < 0) { + warn(_("failed to do fstat: %s"), showname); + close (fd); + return -errno; + } } - st->file_size = sb.st_size; - if (S_ISBLK(sb.st_mode)) { + if (S_ISBLK(sb->st_mode)) { rc = blkdev_get_size(fd, &st->file_size); if (rc) - warn(_("failed ioctl to get size: %s"), st->name); - } else if (S_ISREG(sb.st_mode)) { - st->file_size = sb.st_size; + warn(_("failed ioctl to get size: %s"), showname); + } else if (S_ISREG(sb->st_mode)) { + st->file_size = sb->st_size; } else { rc = 1; /* ignore things like symlinks * and directories*/ @@ -390,6 +399,12 @@ static int fincore_name(struct fincore_control *ctl, rc = fincore_fd(ctl, fd, st); close (fd); + + if (!rc) { + st->name = showname; + rc = add_output_data(ctl, st); + } + return rc; } @@ -408,6 +423,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -o, --output output columns\n"), out); fputs(_(" --output-all output all columns\n"), out); fputs(_(" -r, --raw use raw output format\n"), out); + fputs(_(" -R, --recursive recursively check all files in directories\n"), out); fputs(USAGE_SEPARATOR, out); fprintf(out, USAGE_HELP_OPTIONS(23)); @@ -445,6 +461,7 @@ int main(int argc, char ** argv) { "help", no_argument, NULL, 'h' }, { "json", no_argument, NULL, 'J' }, { "raw", no_argument, NULL, 'r' }, + { "recursive", no_argument, NULL, 'R' }, { NULL, 0, NULL, 0 }, }; @@ -453,7 +470,7 @@ int main(int argc, char ** argv) textdomain(PACKAGE); close_stdout_atexit(); - while ((c = getopt_long (argc, argv, "bno:JrVh", longopts, NULL)) != -1) { + while ((c = getopt_long (argc, argv, "bno:JrRVh", longopts, NULL)) != -1) { switch (c) { case 'b': ctl.bytes = 1; @@ -474,6 +491,12 @@ int main(int argc, char ** argv) case 'r': ctl.raw = 1; break; + case 'R': +#ifndef HAVE_FTS_OPEN + errx(EXIT_FAILURE, _("recursive option is not supported")); +#endif + ctl.recursive = 1; + break; case 'V': print_version(EXIT_SUCCESS); case 'h': @@ -537,25 +560,32 @@ int main(int argc, char ** argv) } } - for(; optind < argc; optind++) { - struct fincore_state st = { - .name = argv[optind], - }; + if (ctl.recursive) { +#ifdef HAVE_FTS_OPEN + FTS *fts = fts_open(argv + optind, FTS_PHYSICAL, NULL); + FTSENT *ent; - switch (fincore_name(&ctl, &st)) { - case 0: - add_output_data(&ctl, &st); - break; - case 1: - break; /* ignore */ - default: + if (!fts) { + warn(_("failed to iterate tree")); rc = EXIT_FAILURE; - break; + } else { + while ((ent = fts_read(fts)) != NULL) { + if (ent->fts_info == FTS_F || ent->fts_info == FTS_DEFAULT) { + /* fts changes directory when iterating, + * so we need to use .fts_accpath to access + * the file named .fts_path */ + rc |= fincore_name(&ctl, ent->fts_accpath, ent->fts_path, ent->fts_statp); + } + } } +#endif + } else { + for(; optind < argc; optind++) + rc |= fincore_name(&ctl, argv[optind], argv[optind], NULL); } scols_print_table(ctl.tb); scols_unref_table(ctl.tb); - return rc; + return rc ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/tests/expected/fincore/count.16384 b/tests/expected/fincore/count.16384 new file mode 100644 index 0000000000..cf4dbf7b56 --- /dev/null +++ b/tests/expected/fincore/count.16384 @@ -0,0 +1,53 @@ +[ NO EXCITING FILE ] +return value: 1 +0 0 i_EMPTY_FILE +return value: 0 +1 16383 i_PAGESIZE_-1__incore_ +return value: 0 +1 16384 i_JUST_PAGESIZE_incore_ +return value: 0 +0 16384 i_JUST_PAGESIZE_directio_ +return value: 0 +2 32768 i_TWO_PAGES_incore_ +return value: 0 +0 32768 i_TWO_PAGES_directio_ +return value: 0 +1 32768 i_TWO_PAGES_mixed_directio_incore_ +return value: 0 +1 32768 i_TWO_PAGES_mixed_incore_directio_ +return value: 0 +2 536854528 i_WINDOW_SIZE_incore-sparse-incore_ +return value: 0 +0 536854528 i_WINDOW_SIZE_directio-sparse-directio_ +return value: 0 +1 536854528 i_WINDOW_SIZE_incore-sparse-directio_ +return value: 0 +1 536854528 i_WINDOW_SIZE_directio-sparse-incore_ +return value: 0 +2 536870912 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ +return value: 0 +0 536870912 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ +return value: 0 +1 536870912 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ +return value: 0 +1 536870912 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ +return value: 0 +[ MULTIPLE FILES ] +PAGES SIZE FILE +0 0 i_EMPTY_FILE +1 16383 i_PAGESIZE_-1__incore_ +1 16384 i_JUST_PAGESIZE_incore_ +0 16384 i_JUST_PAGESIZE_directio_ +2 32768 i_TWO_PAGES_incore_ +0 32768 i_TWO_PAGES_directio_ +1 32768 i_TWO_PAGES_mixed_directio_incore_ +1 32768 i_TWO_PAGES_mixed_incore_directio_ +2 536854528 i_WINDOW_SIZE_incore-sparse-incore_ +0 536854528 i_WINDOW_SIZE_directio-sparse-directio_ +1 536854528 i_WINDOW_SIZE_incore-sparse-directio_ +1 536854528 i_WINDOW_SIZE_directio-sparse-incore_ +2 536870912 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ +0 536870912 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ +1 536870912 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ +1 536870912 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ +return value: 1 diff --git a/tests/expected/fincore/count.16384.recursive b/tests/expected/fincore/count.16384.recursive new file mode 100644 index 0000000000..048a2d20f3 --- /dev/null +++ b/tests/expected/fincore/count.16384.recursive @@ -0,0 +1,12 @@ +0 0 i_dir/EMPTY_FILE +return value: 0 +1 16383 i_dir/PAGESIZE_-1__incore_ +return value: 0 +1 16384 i_dir/JUST_PAGESIZE_incore_ +return value: 0 +[ RECURSIVE SCAN ] +0 0 i_dir/EMPTY_FILE +1 16383 i_dir/PAGESIZE_-1__incore_ +1 16384 i_dir/JUST_PAGESIZE_incore_ +PAGES SIZE FILE +return value: 0 diff --git a/tests/expected/fincore/count.4096 b/tests/expected/fincore/count.4096 index a5d764f581..51f8078686 100644 --- a/tests/expected/fincore/count.4096 +++ b/tests/expected/fincore/count.4096 @@ -1,20 +1,20 @@ [ NO EXCITING FILE ] return value: 1 -0 0 i_EMPTY_FILE +0 0 i_EMPTY_FILE return value: 0 -1 4095 i_PAGESIZE_-1__incore_ +1 4095 i_PAGESIZE_-1__incore_ return value: 0 -1 4096 i_JUST_PAGESIZE_incore_ +1 4096 i_JUST_PAGESIZE_incore_ return value: 0 -0 4096 i_JUST_PAGESIZE_directio_ +0 4096 i_JUST_PAGESIZE_directio_ return value: 0 -2 8192 i_TWO_PAGES_incore_ +2 8192 i_TWO_PAGES_incore_ return value: 0 -0 8192 i_TWO_PAGES_directio_ +0 8192 i_TWO_PAGES_directio_ return value: 0 -1 8192 i_TWO_PAGES_mixed_directio_incore_ +1 8192 i_TWO_PAGES_mixed_directio_incore_ return value: 0 -1 8192 i_TWO_PAGES_mixed_incore_directio_ +1 8192 i_TWO_PAGES_mixed_incore_directio_ return value: 0 2 134213632 i_WINDOW_SIZE_incore-sparse-incore_ return value: 0 @@ -33,21 +33,21 @@ return value: 0 1 134217728 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ return value: 0 [ MULTIPLE FILES ] -PAGES SIZE FILE - 0 0 i_EMPTY_FILE - 1 4095 i_PAGESIZE_-1__incore_ - 1 4096 i_JUST_PAGESIZE_incore_ - 0 4096 i_JUST_PAGESIZE_directio_ - 2 8192 i_TWO_PAGES_incore_ - 0 8192 i_TWO_PAGES_directio_ - 1 8192 i_TWO_PAGES_mixed_directio_incore_ - 1 8192 i_TWO_PAGES_mixed_incore_directio_ - 2 134213632 i_WINDOW_SIZE_incore-sparse-incore_ - 0 134213632 i_WINDOW_SIZE_directio-sparse-directio_ - 1 134213632 i_WINDOW_SIZE_incore-sparse-directio_ - 1 134213632 i_WINDOW_SIZE_directio-sparse-incore_ - 2 134217728 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ - 0 134217728 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ - 1 134217728 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ - 1 134217728 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ +PAGES SIZE FILE +0 0 i_EMPTY_FILE +1 4095 i_PAGESIZE_-1__incore_ +1 4096 i_JUST_PAGESIZE_incore_ +0 4096 i_JUST_PAGESIZE_directio_ +2 8192 i_TWO_PAGES_incore_ +0 8192 i_TWO_PAGES_directio_ +1 8192 i_TWO_PAGES_mixed_directio_incore_ +1 8192 i_TWO_PAGES_mixed_incore_directio_ +2 134213632 i_WINDOW_SIZE_incore-sparse-incore_ +0 134213632 i_WINDOW_SIZE_directio-sparse-directio_ +1 134213632 i_WINDOW_SIZE_incore-sparse-directio_ +1 134213632 i_WINDOW_SIZE_directio-sparse-incore_ +2 134217728 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ +0 134217728 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ +1 134217728 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ +1 134217728 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ return value: 1 diff --git a/tests/expected/fincore/count.4096.recursive b/tests/expected/fincore/count.4096.recursive new file mode 100644 index 0000000000..d1b5846544 --- /dev/null +++ b/tests/expected/fincore/count.4096.recursive @@ -0,0 +1,12 @@ +0 0 i_dir/EMPTY_FILE +return value: 0 +1 4095 i_dir/PAGESIZE_-1__incore_ +return value: 0 +1 4096 i_dir/JUST_PAGESIZE_incore_ +return value: 0 +[ RECURSIVE SCAN ] +0 0 i_dir/EMPTY_FILE +1 4095 i_dir/PAGESIZE_-1__incore_ +1 4096 i_dir/JUST_PAGESIZE_incore_ +PAGES SIZE FILE +return value: 0 diff --git a/tests/expected/fincore/count.65536 b/tests/expected/fincore/count.65536 index 07a97d2e29..d66c78bd79 100644 --- a/tests/expected/fincore/count.65536 +++ b/tests/expected/fincore/count.65536 @@ -1,6 +1,6 @@ [ NO EXCITING FILE ] return value: 1 -0 0 i_EMPTY_FILE +0 0 i_EMPTY_FILE return value: 0 1 65535 i_PAGESIZE_-1__incore_ return value: 0 @@ -33,21 +33,21 @@ return value: 0 1 2147483648 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ return value: 0 [ MULTIPLE FILES ] -PAGES SIZE FILE - 0 0 i_EMPTY_FILE - 1 65535 i_PAGESIZE_-1__incore_ - 1 65536 i_JUST_PAGESIZE_incore_ - 0 65536 i_JUST_PAGESIZE_directio_ - 2 131072 i_TWO_PAGES_incore_ - 0 131072 i_TWO_PAGES_directio_ - 1 131072 i_TWO_PAGES_mixed_directio_incore_ - 1 131072 i_TWO_PAGES_mixed_incore_directio_ - 2 2147418112 i_WINDOW_SIZE_incore-sparse-incore_ - 0 2147418112 i_WINDOW_SIZE_directio-sparse-directio_ - 1 2147418112 i_WINDOW_SIZE_incore-sparse-directio_ - 1 2147418112 i_WINDOW_SIZE_directio-sparse-incore_ - 2 2147483648 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ - 0 2147483648 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ - 1 2147483648 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ - 1 2147483648 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ +PAGES SIZE FILE +0 0 i_EMPTY_FILE +1 65535 i_PAGESIZE_-1__incore_ +1 65536 i_JUST_PAGESIZE_incore_ +0 65536 i_JUST_PAGESIZE_directio_ +2 131072 i_TWO_PAGES_incore_ +0 131072 i_TWO_PAGES_directio_ +1 131072 i_TWO_PAGES_mixed_directio_incore_ +1 131072 i_TWO_PAGES_mixed_incore_directio_ +2 2147418112 i_WINDOW_SIZE_incore-sparse-incore_ +0 2147418112 i_WINDOW_SIZE_directio-sparse-directio_ +1 2147418112 i_WINDOW_SIZE_incore-sparse-directio_ +1 2147418112 i_WINDOW_SIZE_directio-sparse-incore_ +2 2147483648 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ +0 2147483648 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ +1 2147483648 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ +1 2147483648 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ return value: 1 diff --git a/tests/expected/fincore/count.65536.recursive b/tests/expected/fincore/count.65536.recursive new file mode 100644 index 0000000000..3a881e56dc --- /dev/null +++ b/tests/expected/fincore/count.65536.recursive @@ -0,0 +1,12 @@ +0 0 i_dir/EMPTY_FILE +return value: 0 +1 65535 i_dir/PAGESIZE_-1__incore_ +return value: 0 +1 65536 i_dir/JUST_PAGESIZE_incore_ +return value: 0 +[ RECURSIVE SCAN ] +0 0 i_dir/EMPTY_FILE +1 65535 i_dir/PAGESIZE_-1__incore_ +1 65536 i_dir/JUST_PAGESIZE_incore_ +PAGES SIZE FILE +return value: 0 diff --git a/tests/expected/fincore/count.err.4096 b/tests/expected/fincore/count.err similarity index 100% rename from tests/expected/fincore/count.err.4096 rename to tests/expected/fincore/count.err diff --git a/tests/expected/fincore/count.err.65536 b/tests/expected/fincore/count.err.65536 deleted file mode 100644 index e3fad01132..0000000000 --- a/tests/expected/fincore/count.err.65536 +++ /dev/null @@ -1,4 +0,0 @@ -[ NO EXCITING FILE ] -fincore: failed to open: no_such_file: No such file or directory -[ MULTIPLE FILES ] -fincore: failed to open: no_such_file: No such file or directory diff --git a/tests/expected/fincore/count.err.nosize b/tests/expected/fincore/count.err.nosize deleted file mode 100644 index e3fad01132..0000000000 --- a/tests/expected/fincore/count.err.nosize +++ /dev/null @@ -1,4 +0,0 @@ -[ NO EXCITING FILE ] -fincore: failed to open: no_such_file: No such file or directory -[ MULTIPLE FILES ] -fincore: failed to open: no_such_file: No such file or directory diff --git a/tests/expected/fincore/count.nosize b/tests/expected/fincore/count.nosize index ec26542957..0429fc309b 100644 --- a/tests/expected/fincore/count.nosize +++ b/tests/expected/fincore/count.nosize @@ -34,20 +34,20 @@ return value: 0 return value: 0 [ MULTIPLE FILES ] PAGES FILE - 0 i_EMPTY_FILE - 1 i_PAGESIZE_-1__incore_ - 1 i_JUST_PAGESIZE_incore_ - 0 i_JUST_PAGESIZE_directio_ - 2 i_TWO_PAGES_incore_ - 0 i_TWO_PAGES_directio_ - 1 i_TWO_PAGES_mixed_directio_incore_ - 1 i_TWO_PAGES_mixed_incore_directio_ - 2 i_WINDOW_SIZE_incore-sparse-incore_ - 0 i_WINDOW_SIZE_directio-sparse-directio_ - 1 i_WINDOW_SIZE_incore-sparse-directio_ - 1 i_WINDOW_SIZE_directio-sparse-incore_ - 2 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ - 0 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ - 1 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ - 1 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ +0 i_EMPTY_FILE +1 i_PAGESIZE_-1__incore_ +1 i_JUST_PAGESIZE_incore_ +0 i_JUST_PAGESIZE_directio_ +2 i_TWO_PAGES_incore_ +0 i_TWO_PAGES_directio_ +1 i_TWO_PAGES_mixed_directio_incore_ +1 i_TWO_PAGES_mixed_incore_directio_ +2 i_WINDOW_SIZE_incore-sparse-incore_ +0 i_WINDOW_SIZE_directio-sparse-directio_ +1 i_WINDOW_SIZE_incore-sparse-directio_ +1 i_WINDOW_SIZE_directio-sparse-incore_ +2 i_WINDOW_SIZE_+_1_page_incore-sparse-incore_ +0 i_WINDOW_SIZE_+_1_page_directio-sparse-directio_ +1 i_WINDOW_SIZE_+_1_page_incore-sparse-directio_ +1 i_WINDOW_SIZE_+_1_page_directio-sparse-incore_ return value: 1 diff --git a/tests/expected/fincore/count.nosize.recursive b/tests/expected/fincore/count.nosize.recursive new file mode 100644 index 0000000000..4c8c832841 --- /dev/null +++ b/tests/expected/fincore/count.nosize.recursive @@ -0,0 +1,12 @@ +0 i_dir/EMPTY_FILE +return value: 0 +1 i_dir/PAGESIZE_-1__incore_ +return value: 0 +1 i_dir/JUST_PAGESIZE_incore_ +return value: 0 +[ RECURSIVE SCAN ] +0 i_dir/EMPTY_FILE +1 i_dir/JUST_PAGESIZE_incore_ +1 i_dir/PAGESIZE_-1__incore_ +PAGES FILE +return value: 0 diff --git a/tests/helpers/test_sysinfo.c b/tests/helpers/test_sysinfo.c index b4a601e3bc..001f8599eb 100644 --- a/tests/helpers/test_sysinfo.c +++ b/tests/helpers/test_sysinfo.c @@ -45,6 +45,12 @@ # endif #endif +#ifdef HAVE_FTS_OPEN +# include +# include +# include +#endif + #include "xalloc.h" #include "namespace.h" @@ -218,6 +224,89 @@ static int hlp_hostname(void) return 0; } +static int hlp_fts(void) +{ +#ifdef HAVE_FTS_OPEN + char template[NAME_MAX]; + char *paths[] = { NULL, NULL }; + char path[PATH_MAX]; + FTSENT *node; + FTS *fts; + int r; + int files = 0, dirs = 0; + + snprintf(template, sizeof(template), "%s/fts_checkXXXXXX", getenv("TMPDIR") ?: "/tmp"); + + paths[0] = mkdtemp(template); + if (paths[0] == NULL) + return 0; + + r = mkdir(template, 0755); + if (r < 0 && errno != EEXIST) + return 0; + dirs++; + + snprintf(path, sizeof(path), "%s/subdir", template); + r = mkdir(path, 0755); + if (r < 0 && errno != EEXIST) + return 0; + dirs++; + + snprintf(path, sizeof(path), "%s/file1.txt", template); + r = creat(path, 0644); + if (r < 0) + return 0; + close(r); + files++; + + snprintf(path, sizeof(path), "%s/file2.txt", template); + r = creat(path, 0644); + if (r < 0) + return 0; + close(r); + files++; + + snprintf(path, sizeof(path), "%s/subdir/file3.txt", template); + r = creat(path, 0644); + if (r < 0) + return 0; + close(r); + files++; + + snprintf(path, sizeof(path), "%s/subdir/file4.txt", template); + r = creat(path, 0644); + if (r < 0) + return 0; + close(r); + files++; + + fts = fts_open(paths, FTS_NOCHDIR | FTS_PHYSICAL, NULL); + if (fts == NULL) + return 0; + + while ((node = fts_read(fts)) != NULL) { + switch (node->fts_info) { + case FTS_F: + files--; + break; + case FTS_D: + dirs--; + break; + case FTS_ERR: + return 0; + default: + break; + } + } + + if (fts_close(fts) < 0 || files != 0 || dirs != 0) + return 0; + + puts("FTS"); +#endif + return 0; +} + static const mntHlpfnc hlps[] = { { "WORDSIZE", hlp_wordsize }, @@ -238,6 +327,7 @@ static const mntHlpfnc hlps[] = { "ns-gettype-ok", hlp_get_nstype_ok }, { "ns-getuserns-ok", hlp_get_userns_ok }, { "hostname", hlp_hostname, }, + { "fts", hlp_fts, }, { NULL, NULL } }; diff --git a/tests/ts/fincore/count b/tests/ts/fincore/count index 8a5fffe364..e132b99026 100755 --- a/tests/ts/fincore/count +++ b/tests/ts/fincore/count @@ -14,6 +14,11 @@ if [[ "$FS" = "tmpfs" || "$FS" = "overlay" || "$FS" = "" ]]; then ts_skip "fincore does not work on tmpfs or unknown fs" fi +# https://github.com/util-linux/util-linux/pull/3529 +if [ "$($TS_HELPER_SYSINFO fts)" != FTS ]; then + ts_skip "fts_open() is unreliable on this setup" +fi + function footer { echo "return value: $1" @@ -23,7 +28,7 @@ function make_input_name { header=$1 prefix=i_ - echo ${prefix}$(sed -e "s/[^-+a-zA-Z0-9_]/_/g"<<<"$header") + echo ${prefix}$(sed -e "s/[^-+a-zA-Z0-9_/]/_/g"<<<"$header") } function _dd @@ -71,7 +76,7 @@ function run_dd_test _dd if=/dev/zero of=$input count=1 bs=$bs $flags || return fi - $TS_CMD_FINCORE --output $OUT_COLUMNS --bytes --noheadings $input + $TS_CMD_FINCORE --raw --output $OUT_COLUMNS --bytes --noheadings $input footer "$?" } @@ -91,7 +96,7 @@ function run_dd_dd_test _dd if=/dev/zero of=$input count=1 bs=$bs $flags0 || return _dd if=/dev/zero of=$input count=1 bs=$bs $flags1 || return - $TS_CMD_FINCORE --output $OUT_COLUMNS --bytes --noheadings $input + $TS_CMD_FINCORE --raw --output $OUT_COLUMNS --bytes --noheadings $input footer "$?" } @@ -100,17 +105,32 @@ function run_dd_dd_test PAGE_SIZE=$($TS_HELPER_SYSINFO pagesize) WINDOW_SIZE=$(( 32 * 1024 * PAGE_SIZE )) +AGG_OUT="$TS_OUTDIR/count.aggregate" +AGG_ERR="$TS_OUTDIR/count.err.aggregate" + # we use PAGE_SIZE dependent output for a few systems if test -f "$TS_EXPECTED.$PAGE_SIZE"; then - TS_EXPECTED+=".$PAGE_SIZE" - TS_EXPECTED_ERR+=".$PAGE_SIZE" + cat "$TS_EXPECTED.$PAGE_SIZE" >"$AGG_OUT" OUT_COLUMNS="PAGES,SIZE,FILE" else - TS_EXPECTED+=".nosize" - TS_EXPECTED_ERR+=".nosize" + cat "$TS_EXPECTED.nosize" >"$AGG_OUT" OUT_COLUMNS="PAGES,FILE" fi +cat "$TS_EXPECTED_ERR" >"$AGG_ERR" + +if ! $TS_CMD_FINCORE --recursive |& grep -q 'recursive option is not supported' ; then + RECURSIVE=1 + if test -f "$TS_EXPECTED.$PAGE_SIZE"; then + cat "$TS_EXPECTED.$PAGE_SIZE.recursive" >> "$AGG_OUT" + else + cat "$TS_EXPECTED.nosize.recursive" >> "$AGG_OUT" + fi + echo '[ RECURSIVE SCAN ]' >> "$AGG_ERR" +fi + +TS_EXPECTED="$AGG_OUT" +TS_EXPECTED_ERR="$AGG_ERR" ts_check_test_command "$TS_CMD_FINCORE" ts_cd "$TS_OUTDIR" @@ -125,7 +145,7 @@ ts_log_both "[ NO EXCITING FILE ]" input=no_such_file INPUT="${INPUT} ${input}" - $TS_CMD_FINCORE --output $OUT_COLUMNS --bytes --noheadings $input + $TS_CMD_FINCORE --raw --output $OUT_COLUMNS --bytes --noheadings $input footer "$?" } >> $TS_OUTPUT 2>> $TS_ERRLOG @@ -154,13 +174,13 @@ ts_log_both "[ NO EXCITING FILE ]" } >> $TS_OUTPUT 2>> $TS_ERRLOG { - run_dd_dd_test "TWO PAGES(mixed directio/incore)" \ + run_dd_dd_test "TWO PAGES(mixed directio,incore)" \ oflag=direct \ "oflag=append seek=1" } >> $TS_OUTPUT 2>> $TS_ERRLOG { - run_dd_dd_test "TWO PAGES(mixed incore/directio)" \ + run_dd_dd_test "TWO PAGES(mixed incore,directio)" \ "" \ "oflag=direct,append seek=1" } >> $TS_OUTPUT 2>> $TS_ERRLOG @@ -223,9 +243,32 @@ ts_log_both "[ NO EXCITING FILE ]" ts_log_both "[ MULTIPLE FILES ]" { - $TS_CMD_FINCORE --output $OUT_COLUMNS --bytes $INPUT + $TS_CMD_FINCORE --raw --output $OUT_COLUMNS --bytes $INPUT footer "$?" } >> $TS_OUTPUT 2>> $TS_ERRLOG +if [ -n "$RECURSIVE" ]; then + dir=$(make_input_name dir) + mkdir -p "$dir" + + { + run_dd_test "dir/EMPTY FILE" 0 + } >> $TS_OUTPUT 2>> $TS_ERRLOG + + { + run_dd_test "dir/PAGESIZE -1 (incore)" $(( PAGE_SIZE - 1 )) + } >> $TS_OUTPUT 2>> $TS_ERRLOG + + { + run_dd_test "dir/JUST PAGESIZE(incore)" $(( PAGE_SIZE )) + } >> $TS_OUTPUT 2>> $TS_ERRLOG + + ts_log_both "[ RECURSIVE SCAN ]" + { + $TS_CMD_FINCORE --raw --output $OUT_COLUMNS --bytes --recursive --raw "$dir" |sort + footer "$?" + } >> $TS_OUTPUT 2>> $TS_ERRLOG +fi + rm -f $INPUT ts_finalize -- 2.47.2