aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatteo Croce <teknoraver@meta.com>2025-04-19 03:09:25 +0200
committerMatteo Croce <teknoraver@meta.com>2025-05-21 04:21:23 +0200
commit8fabaa8b76b03e6c4bd4cd6a266e30152f9e5ec9 (patch)
tree5d686a670e3ecd8072c1542cd1daa89980958632
parentea04d719352add738251446315cebdada90171a9 (diff)
downloadutil-linux-8fabaa8b76b03e6c4bd4cd6a266e30152f9e5ec9.tar.gz
fincore: add recursive directory scanning
Add a --recursive flag to fincore which allows to recursively scan directories. Co-authored-by: Karel Zak <kzak@redhat.com> Signed-off-by: Matteo Croce <teknoraver@meta.com>
-rw-r--r--bash-completion/fincore1
-rw-r--r--configure.ac4
-rw-r--r--meson.build1
-rw-r--r--misc-utils/fincore.1.adoc3
-rw-r--r--misc-utils/fincore.c88
-rw-r--r--tests/expected/fincore/count.1638453
-rw-r--r--tests/expected/fincore/count.16384.recursive12
-rw-r--r--tests/expected/fincore/count.409650
-rw-r--r--tests/expected/fincore/count.4096.recursive12
-rw-r--r--tests/expected/fincore/count.6553636
-rw-r--r--tests/expected/fincore/count.65536.recursive12
-rw-r--r--tests/expected/fincore/count.err (renamed from tests/expected/fincore/count.err.4096)0
-rw-r--r--tests/expected/fincore/count.err.655364
-rw-r--r--tests/expected/fincore/count.err.nosize4
-rw-r--r--tests/expected/fincore/count.nosize32
-rw-r--r--tests/expected/fincore/count.nosize.recursive12
-rw-r--r--tests/helpers/test_sysinfo.c90
-rwxr-xr-xtests/ts/fincore/count65
18 files changed, 372 insertions, 107 deletions
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 <stdio.h>
#include <string.h>
+#ifdef HAVE_FTS_OPEN
+#include <fts.h>
+#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 <list> 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
index e3fad01132..e3fad01132 100644
--- a/tests/expected/fincore/count.err.4096
+++ b/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 <fcntl.h>
+# include <sys/stat.h>
+# include <fts.h>
+#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