aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2025-07-02 10:22:16 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2025-07-02 10:22:29 +0000
commit8d02b7190d3b926118fafc6a70a80676c349e186 (patch)
tree33f709577a71bab6d9f9018c466a4dacebefdc16 /lib
parentbc624c9735364ba68ee6975864110a5fee5e3b16 (diff)
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/tests/gen/Makefile9
-rw-r--r--lib/libc/tests/gen/fts_misc_test.c78
-rw-r--r--lib/libc/tests/gen/fts_options_test.c84
-rw-r--r--lib/libc/tests/gen/fts_test.h81
4 files changed, 180 insertions, 72 deletions
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
index b7df4b1d037b..a967ad5ddf91 100644
--- a/lib/libc/tests/gen/Makefile
+++ b/lib/libc/tests/gen/Makefile
@@ -10,6 +10,7 @@ ATF_TESTS_C+= fpclassify2_test
.if ${COMPILER_FEATURES:Mblocks}
ATF_TESTS_C+= fts_blocks_test
.endif
+ATF_TESTS_C+= fts_misc_test
ATF_TESTS_C+= fts_options_test
ATF_TESTS_C+= ftw_test
ATF_TESTS_C+= getentropy_test
@@ -104,6 +105,14 @@ TEST_METADATA.setdomainname_test+= is_exclusive=true
TESTS_SUBDIRS= execve
TESTS_SUBDIRS+= posix_spawn
+# Tests that require address sanitizer
+.if ${COMPILER_FEATURES:Masan}
+.for t in scandir_test realpath2_test
+CFLAGS.${t}.c+= -fsanitize=address
+LDFLAGS.${t}+= -fsanitize=address
+.endfor
+.endif
+
# Tests that require blocks support
.for t in fts_blocks_test glob_blocks_test scandir_blocks_test
CFLAGS.${t}.c+= -fblocks
diff --git a/lib/libc/tests/gen/fts_misc_test.c b/lib/libc/tests/gen/fts_misc_test.c
new file mode 100644
index 000000000000..91640078f63c
--- /dev/null
+++ b/lib/libc/tests/gen/fts_misc_test.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "fts_test.h"
+
+ATF_TC(fts_unrdir);
+ATF_TC_HEAD(fts_unrdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "unreadable directories");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(fts_unrdir, tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400));
+ fts_test(tc, &(struct fts_testcase){
+ (char *[]){ "dir", NULL },
+ FTS_PHYSICAL,
+ (struct fts_expect[]){
+ { FTS_D, "dir", "dir" },
+ { FTS_D, "unr", "unr" },
+ { FTS_DNR, "unr", "unr" },
+ { FTS_D, "unx", "unx" },
+ { FTS_DP, "unx", "unx" },
+ { FTS_DP, "dir", "dir" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_unrdir_nochdir);
+ATF_TC_HEAD(fts_unrdir_nochdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "unreadable directories (nochdir)");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(fts_unrdir_nochdir, tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400));
+ fts_test(tc, &(struct fts_testcase){
+ (char *[]){ "dir", NULL },
+ FTS_PHYSICAL | FTS_NOCHDIR,
+ (struct fts_expect[]){
+ { FTS_D, "dir", "dir" },
+ { FTS_D, "unr", "dir/unr" },
+ { FTS_DNR, "unr", "dir/unr" },
+ { FTS_D, "unx", "dir/unx" },
+ { FTS_DP, "unx", "dir/unx" },
+ { FTS_DP, "dir", "dir" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ fts_check_debug();
+ ATF_TP_ADD_TC(tp, fts_unrdir);
+ ATF_TP_ADD_TC(tp, fts_unrdir_nochdir);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fts_options_test.c b/lib/libc/tests/gen/fts_options_test.c
index c80474b70ac7..fc3015138a49 100644
--- a/lib/libc/tests/gen/fts_options_test.c
+++ b/lib/libc/tests/gen/fts_options_test.c
@@ -15,17 +15,7 @@
#include <atf-c.h>
-struct fts_expect {
- int fts_info;
- const char *fts_name;
- const char *fts_accpath;
-};
-
-struct fts_testcase {
- char **paths;
- int fts_options;
- struct fts_expect *fts_expect;
-};
+#include "fts_test.h"
static char *all_paths[] = {
"dir",
@@ -37,20 +27,12 @@ static char *all_paths[] = {
NULL
};
-/* shorter name for dead links */
-#define FTS_DL FTS_SLNONE
-
-/* are we being debugged? */
-static bool debug;
-
/*
* Prepare the files and directories we will be inspecting.
*/
static void
fts_options_prepare(const struct atf_tc *tc)
{
- debug = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
- isatty(STDERR_FILENO);
ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
ATF_REQUIRE_EQ(0, close(creat("file", 0644)));
ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
@@ -60,49 +42,6 @@ fts_options_prepare(const struct atf_tc *tc)
ATF_REQUIRE_EQ(0, symlink("noent", "dead"));
}
-/*
- * Lexical order for reproducability.
- */
-static int
-fts_options_compar(const FTSENT * const *a, const FTSENT * const *b)
-{
- return (strcmp((*a)->fts_name, (*b)->fts_name));
-}
-
-/*
- * Run FTS with the specified paths and options and verify that it
- * produces the expected result in the correct order.
- */
-static void
-fts_options_test(const struct atf_tc *tc, const struct fts_testcase *fts_tc)
-{
- FTS *fts;
- FTSENT *ftse;
- const struct fts_expect *expect = fts_tc->fts_expect;
- long level = 0;
-
- fts = fts_open(fts_tc->paths, fts_tc->fts_options, fts_options_compar);
- ATF_REQUIRE_MSG(fts != NULL, "fts_open(): %m");
- while ((ftse = fts_read(fts)) != NULL && expect->fts_name != NULL) {
- if (expect->fts_info == FTS_DP)
- level--;
- if (debug) {
- fprintf(stderr, "%2ld %2d %s\n", level,
- ftse->fts_info, ftse->fts_name);
- }
- ATF_CHECK_STREQ(expect->fts_name, ftse->fts_name);
- ATF_CHECK_STREQ(expect->fts_accpath, ftse->fts_accpath);
- ATF_CHECK_INTEQ(expect->fts_info, ftse->fts_info);
- ATF_CHECK_INTEQ(level, ftse->fts_level);
- if (expect->fts_info == FTS_D)
- level++;
- expect++;
- }
- ATF_CHECK_EQ(NULL, ftse);
- ATF_CHECK_EQ(NULL, expect->fts_name);
- ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m");
-}
-
ATF_TC(fts_options_logical);
ATF_TC_HEAD(fts_options_logical, tc)
{
@@ -111,7 +50,7 @@ ATF_TC_HEAD(fts_options_logical, tc)
ATF_TC_BODY(fts_options_logical, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_LOGICAL,
(struct fts_expect[]){
@@ -162,7 +101,7 @@ ATF_TC_BODY(fts_options_logical_nostat, tc)
*/
atf_tc_expect_fail("FTS_LOGICAL nullifies FTS_NOSTAT");
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_LOGICAL | FTS_NOSTAT,
(struct fts_expect[]){
@@ -203,7 +142,7 @@ ATF_TC_HEAD(fts_options_logical_seedot, tc)
ATF_TC_BODY(fts_options_logical_seedot, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_LOGICAL | FTS_SEEDOT,
(struct fts_expect[]){
@@ -252,7 +191,7 @@ ATF_TC_HEAD(fts_options_physical, tc)
ATF_TC_BODY(fts_options_physical, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL,
(struct fts_expect[]){
@@ -278,7 +217,7 @@ ATF_TC_HEAD(fts_options_physical_nochdir, tc)
ATF_TC_BODY(fts_options_physical_nochdir, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_NOCHDIR,
(struct fts_expect[]){
@@ -304,7 +243,7 @@ ATF_TC_HEAD(fts_options_physical_comfollow, tc)
ATF_TC_BODY(fts_options_physical_comfollow, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_COMFOLLOW,
(struct fts_expect[]){
@@ -333,7 +272,7 @@ ATF_TC_HEAD(fts_options_physical_comfollowdir, tc)
ATF_TC_BODY(fts_options_physical_comfollowdir, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_COMFOLLOWDIR,
(struct fts_expect[]){
@@ -362,7 +301,7 @@ ATF_TC_HEAD(fts_options_physical_nostat, tc)
ATF_TC_BODY(fts_options_physical_nostat, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_NOSTAT,
(struct fts_expect[]){
@@ -388,7 +327,7 @@ ATF_TC_HEAD(fts_options_physical_nostat_type, tc)
ATF_TC_BODY(fts_options_physical_nostat_type, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_NOSTAT_TYPE,
(struct fts_expect[]){
@@ -414,7 +353,7 @@ ATF_TC_HEAD(fts_options_physical_seedot, tc)
ATF_TC_BODY(fts_options_physical_seedot, tc)
{
fts_options_prepare(tc);
- fts_options_test(tc, &(struct fts_testcase){
+ fts_test(tc, &(struct fts_testcase){
all_paths,
FTS_PHYSICAL | FTS_SEEDOT,
(struct fts_expect[]){
@@ -440,6 +379,7 @@ ATF_TC_BODY(fts_options_physical_seedot, tc)
ATF_TP_ADD_TCS(tp)
{
+ fts_check_debug();
ATF_TP_ADD_TC(tp, fts_options_logical);
ATF_TP_ADD_TC(tp, fts_options_logical_nostat);
ATF_TP_ADD_TC(tp, fts_options_logical_seedot);
diff --git a/lib/libc/tests/gen/fts_test.h b/lib/libc/tests/gen/fts_test.h
new file mode 100644
index 000000000000..b3f15050f265
--- /dev/null
+++ b/lib/libc/tests/gen/fts_test.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef FTS_TEST_H_INCLUDED
+#define FTS_TEST_H_INCLUDED
+
+struct fts_expect {
+ int fts_info;
+ const char *fts_name;
+ const char *fts_accpath;
+};
+
+struct fts_testcase {
+ char **paths;
+ int fts_options;
+ struct fts_expect *fts_expect;
+};
+
+/* shorter name for dead links */
+#define FTS_DL FTS_SLNONE
+
+/* are we being debugged? */
+static bool fts_test_debug;
+
+/*
+ * Set debug flag if appropriate.
+ */
+static void
+fts_check_debug(void)
+{
+ fts_test_debug = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
+ isatty(STDERR_FILENO);
+}
+
+/*
+ * Lexical order for reproducability.
+ */
+static int
+fts_lexical_compar(const FTSENT * const *a, const FTSENT * const *b)
+{
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+/*
+ * Run FTS with the specified paths and options and verify that it
+ * produces the expected result in the correct order.
+ */
+static void
+fts_test(const struct atf_tc *tc, const struct fts_testcase *fts_tc)
+{
+ FTS *fts;
+ FTSENT *ftse;
+ const struct fts_expect *expect = fts_tc->fts_expect;
+ long level = 0;
+
+ fts = fts_open(fts_tc->paths, fts_tc->fts_options, fts_lexical_compar);
+ ATF_REQUIRE_MSG(fts != NULL, "fts_open(): %m");
+ while ((ftse = fts_read(fts)) != NULL && expect->fts_name != NULL) {
+ if (expect->fts_info == FTS_DP || expect->fts_info == FTS_DNR)
+ level--;
+ if (fts_test_debug) {
+ fprintf(stderr, "%2ld %2d %s\n", level,
+ ftse->fts_info, ftse->fts_name);
+ }
+ ATF_CHECK_STREQ(expect->fts_name, ftse->fts_name);
+ ATF_CHECK_STREQ(expect->fts_accpath, ftse->fts_accpath);
+ ATF_CHECK_INTEQ(expect->fts_info, ftse->fts_info);
+ ATF_CHECK_INTEQ(level, ftse->fts_level);
+ if (expect->fts_info == FTS_D)
+ level++;
+ expect++;
+ }
+ ATF_CHECK_EQ(NULL, ftse);
+ ATF_CHECK_EQ(NULL, expect->fts_name);
+ ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m");
+}
+
+#endif /* FTS_TEST_H_INCLUDED */