diff options
Diffstat (limited to 'lib/libc/tests/gen')
35 files changed, 1648 insertions, 75 deletions
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile index a808f6617ec7..8c2151105209 100644 --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> ATF_TESTS_C+= arc4random_test @@ -9,14 +7,28 @@ ATF_TESTS_C+= fmtcheck2_test ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test 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 ATF_TESTS_C+= getmntinfo_test ATF_TESTS_C+= glob2_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= glob_blocks_test +.endif ATF_TESTS_C+= makecontext_test +ATF_TESTS_C+= opendir_test ATF_TESTS_C+= popen_test ATF_TESTS_C+= posix_spawn_test ATF_TESTS_C+= realpath2_test +ATF_TESTS_C+= scandir_test +.if ${COMPILER_FEATURES:Mblocks} +ATF_TESTS_C+= scandir_blocks_test +.endif +ATF_TESTS_C+= sig2str_test ATF_TESTS_C+= sigsetops_test ATF_TESTS_C+= wordexp_test @@ -94,6 +106,20 @@ 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 +LIBADD.${t}+= BlocksRuntime +.endfor + # The old testcase name TEST_FNMATCH= test-fnmatch CLEANFILES+= ${GEN_SH_CASE_TESTCASES} diff --git a/lib/libc/tests/gen/Makefile.depend b/lib/libc/tests/gen/Makefile.depend index a359c100b4e2..33d10e940cd0 100644 --- a/lib/libc/tests/gen/Makefile.depend +++ b/lib/libc/tests/gen/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/arc4random_test.c b/lib/libc/tests/gen/arc4random_test.c index a28db303e88c..79139f29f8fa 100644 --- a/lib/libc/tests/gen/arc4random_test.c +++ b/lib/libc/tests/gen/arc4random_test.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2011 David Schultz + * Copyright (c) 2024 Robert Clausecker <fuz@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,14 +25,12 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/types.h> #include <sys/mman.h> #include <sys/wait.h> #include <errno.h> #include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -80,10 +79,34 @@ ATF_TC_BODY(test_arc4random, tc) "sequences are the same"); } +/* + * Test whether arc4random_uniform() returns a number below the given threshold. + * Test with various thresholds. + */ +ATF_TC_WITHOUT_HEAD(test_arc4random_uniform); +ATF_TC_BODY(test_arc4random_uniform, tc) +{ + size_t i, j; + static const uint32_t thresholds[] = { + 1, 2, 3, 4, 5, 10, 100, 1000, + INT32_MAX, (uint32_t)INT32_MAX + 1, + UINT32_MAX - 1000000000, UINT32_MAX - 1000000, UINT32_MAX - 1, 0 + }; + + for (i = 0; thresholds[i] != 0; i++) + for (j = 0; j < 10000; j++) + ATF_CHECK(arc4random_uniform(thresholds[i]) < thresholds[i]); + + /* for a threshold of zero, just check that we get zero every time */ + for (j = 0; j < 1000; j++) + ATF_CHECK_EQ(0, arc4random_uniform(0)); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, test_arc4random); + ATF_TP_ADD_TC(tp, test_arc4random_uniform); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/dir2_test.c b/lib/libc/tests/gen/dir2_test.c index 3322a5e5086c..4ec5a1759d06 100644 --- a/lib/libc/tests/gen/dir2_test.c +++ b/lib/libc/tests/gen/dir2_test.c @@ -31,9 +31,6 @@ * opendir, readdir, seekdir, telldir, closedir, etc */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <dirent.h> #include <fcntl.h> #include <stdio.h> diff --git a/lib/libc/tests/gen/dlopen_empty_test.c b/lib/libc/tests/gen/dlopen_empty_test.c index 42f9269a10b2..6fb3bf8d8343 100644 --- a/lib/libc/tests/gen/dlopen_empty_test.c +++ b/lib/libc/tests/gen/dlopen_empty_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/stat.h> #include <dlfcn.h> #include <errno.h> diff --git a/lib/libc/tests/gen/execve/Makefile b/lib/libc/tests/gen/execve/Makefile index 5e8bc6fb7640..7bf911d1cb47 100644 --- a/lib/libc/tests/gen/execve/Makefile +++ b/lib/libc/tests/gen/execve/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> NETBSD_ATF_TESTS_C= execve_test diff --git a/lib/libc/tests/gen/execve/Makefile.depend b/lib/libc/tests/gen/execve/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/gen/execve/Makefile.depend +++ b/lib/libc/tests/gen/execve/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/fmtcheck_test.c b/lib/libc/tests/gen/fmtcheck_test.c index 3e180c9ca2e6..27a12217e81e 100644 --- a/lib/libc/tests/gen/fmtcheck_test.c +++ b/lib/libc/tests/gen/fmtcheck_test.c @@ -28,9 +28,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <err.h> #include <stdio.h> diff --git a/lib/libc/tests/gen/fmtmsg_test.c b/lib/libc/tests/gen/fmtmsg_test.c index aa3ca19425fe..30a5156cdcc8 100644 --- a/lib/libc/tests/gen/fmtmsg_test.c +++ b/lib/libc/tests/gen/fmtmsg_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/wait.h> #include <err.h> diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c index 8d9ead2eff91..0ff7400a4a4f 100644 --- a/lib/libc/tests/gen/fnmatch_test.c +++ b/lib/libc/tests/gen/fnmatch_test.c @@ -24,11 +24,9 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> +#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -179,10 +177,90 @@ ATF_TC_BODY(fnmatch_test, tc) } +ATF_TC(fnmatch_characterclass); +ATF_TC_HEAD(fnmatch_characterclass, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with character classes"); +} + +ATF_TC_BODY(fnmatch_characterclass, tc) +{ + ATF_CHECK(fnmatch("[[:alnum:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:cntrl:]]", "\a", 0) == 0); + ATF_CHECK(fnmatch("[[:lower:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:space:]]", " ", 0) == 0); + ATF_CHECK(fnmatch("[[:alpha:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:digit:]]", "0", 0) == 0); + ATF_CHECK(fnmatch("[[:print:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:upper:]]", "A", 0) == 0); + ATF_CHECK(fnmatch("[[:blank:]]", " ", 0) == 0); + ATF_CHECK(fnmatch("[[:graph:]]", "a", 0) == 0); + ATF_CHECK(fnmatch("[[:punct:]]", ".", 0) == 0); + ATF_CHECK(fnmatch("[[:xdigit:]]", "f", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[:' and ':]' + * should be interpreted as character classes symbol only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[:alnum:]", "a", 0) == 0); + ATF_CHECK(fnmatch("[:alnum:]", ":", 0) == 0); + ATF_CHECK(fnmatch("[:alnum:]", "1", 0) != 0); +} + +ATF_TC(fnmatch_collsym); +ATF_TC_HEAD(fnmatch_collsym, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with collating symbols"); +} + +ATF_TC_BODY(fnmatch_collsym, tc) +{ + setlocale(LC_ALL, "cs_CZ.UTF-8"); + ATF_CHECK(fnmatch("[ch]", "ch", 0) != 0); + ATF_CHECK(fnmatch("[[.ch.]]", "ch", 0) == 0); + ATF_CHECK(fnmatch("[[.ch.]]h", "chh", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[.' and '.]' + * should be interpreted as a collating symbol only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[.ch.]", "c", 0) == 0); + ATF_CHECK(fnmatch("[.ch.]", "h", 0) == 0); + ATF_CHECK(fnmatch("[.ch.]", ".", 0) == 0); +} + +ATF_TC(fnmatch_equivclass); +ATF_TC_HEAD(fnmatch_equivclass, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fnmatch with equivalence classes"); +} + +ATF_TC_BODY(fnmatch_equivclass, tc) +{ + setlocale(LC_ALL, "en_US.UTF-8"); + ATF_CHECK(fnmatch("[[=a=]]b", "ab", 0) == 0); + ATF_CHECK(fnmatch("[[=a=]]b", "Ab", 0) == 0); + ATF_CHECK(fnmatch("[[=à=]]b", "ab", 0) == 0); + ATF_CHECK(fnmatch("[[=a=]]b", "àb", 0) == 0); + + /* + * POSIX.1, section 9.3.5. states that '[=' and '=]' + * should be interpreted as an equivalence class only + * when part of a bracket expression. + */ + ATF_CHECK(fnmatch("[=a=]b", "=b", 0) == 0); + ATF_CHECK(fnmatch("[=a=]b", "ab", 0) == 0); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, fnmatch_test); + ATF_TP_ADD_TC(tp, fnmatch_collsym); + ATF_TP_ADD_TC(tp, fnmatch_characterclass); + ATF_TP_ADD_TC(tp, fnmatch_equivclass); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/fnmatch_testcases.h b/lib/libc/tests/gen/fnmatch_testcases.h index 996e13c7756b..196160a4801b 100644 --- a/lib/libc/tests/gen/fnmatch_testcases.h +++ b/lib/libc/tests/gen/fnmatch_testcases.h @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <fnmatch.h> struct testcase { diff --git a/lib/libc/tests/gen/fpclassify2_test.c b/lib/libc/tests/gen/fpclassify2_test.c index a6bb1df3c9f2..45180ac5be42 100644 --- a/lib/libc/tests/gen/fpclassify2_test.c +++ b/lib/libc/tests/gen/fpclassify2_test.c @@ -22,8 +22,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <math.h> diff --git a/lib/libc/tests/gen/fts_blocks_test.c b/lib/libc/tests/gen/fts_blocks_test.c new file mode 100644 index 000000000000..f020dd8dea45 --- /dev/null +++ b/lib/libc/tests/gen/fts_blocks_test.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <fcntl.h> +#include <fts.h> + +#include <atf-c.h> + +/* + * Create two directories with three files each in lexicographical order, + * then call FTS with a sort block that sorts in reverse lexicographical + * order. This has the least chance of getting a false positive due to + * differing file system semantics. UFS will return the files in the + * order they were created while ZFS will sort them lexicographically; in + * both cases, the order we expect is the reverse. + */ +ATF_TC(fts_blocks_test); +ATF_TC_HEAD(fts_blocks_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test FTS with a block in lieu of a comparison function"); +} +ATF_TC_BODY(fts_blocks_test, tc) +{ + char *args[] = { + "bar", "foo", NULL + }; + char *paths[] = { + "foo", "z", "y", "x", "foo", + "bar", "c", "b", "a", "bar", + NULL + }; + char **expect = paths; + FTS *fts; + FTSENT *ftse; + + ATF_REQUIRE_EQ(0, mkdir("bar", 0755)); + ATF_REQUIRE_EQ(0, close(creat("bar/a", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/b", 0644))); + ATF_REQUIRE_EQ(0, close(creat("bar/c", 0644))); + ATF_REQUIRE_EQ(0, mkdir("foo", 0755)); + ATF_REQUIRE_EQ(0, close(creat("foo/x", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/y", 0644))); + ATF_REQUIRE_EQ(0, close(creat("foo/z", 0644))); + fts = fts_open_b(args, 0, + ^(const FTSENT * const *a, const FTSENT * const *b) { + return (strcmp((*b)->fts_name, (*a)->fts_name)); + }); + ATF_REQUIRE_MSG(fts != NULL, "fts_open_b(): %m"); + while ((ftse = fts_read(fts)) != NULL && *expect != NULL) { + ATF_CHECK_STREQ(*expect, ftse->fts_name); + expect++; + } + ATF_CHECK_EQ(NULL, ftse); + ATF_CHECK_EQ(NULL, *expect); + ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, fts_blocks_test); + return (atf_no_error()); +} 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 new file mode 100644 index 000000000000..fc3015138a49 --- /dev/null +++ b/lib/libc/tests/gen/fts_options_test.c @@ -0,0 +1,394 @@ +/*- + * 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" + +static char *all_paths[] = { + "dir", + "dirl", + "file", + "filel", + "dead", + "noent", + NULL +}; + +/* + * Prepare the files and directories we will be inspecting. + */ +static void +fts_options_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("file", 0644))); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("..", "dir/up")); + ATF_REQUIRE_EQ(0, symlink("dir", "dirl")); + ATF_REQUIRE_EQ(0, symlink("file", "filel")); + ATF_REQUIRE_EQ(0, symlink("noent", "dead")); +} + +ATF_TC(fts_options_logical); +ATF_TC_HEAD(fts_options_logical, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL"); +} +ATF_TC_BODY(fts_options_logical, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_F, "file", "dir/up/file" }, + { FTS_F, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_F, "file", "dirl/up/file" }, + { FTS_F, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_logical_nostat); +ATF_TC_HEAD(fts_options_logical_nostat, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_NOSTAT"); +} +ATF_TC_BODY(fts_options_logical_nostat, tc) +{ + /* + * While FTS_LOGICAL is not documented as being incompatible with + * FTS_NOSTAT, and FTS does not clear FTS_NOSTAT if FTS_LOGICAL is + * set, FTS_LOGICAL effectively nullifies FTS_NOSTAT by overriding + * the follow check in fts_stat(). In theory, FTS could easily be + * changed to only stat links (to check what they point to) in the + * FTS_LOGICAL | FTS_NOSTAT case, which would produce a different + * result here, so keep the test around in case that ever happens. + */ + atf_tc_expect_fail("FTS_LOGICAL nullifies FTS_NOSTAT"); + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL | FTS_NOSTAT, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_NSOK, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_NSOK, "file", "dir/up/file" }, + { FTS_NSOK, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_NSOK, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_NSOK, "file", "dirl/up/file" }, + { FTS_NSOK, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_logical_seedot); +ATF_TC_HEAD(fts_options_logical_seedot, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_SEEDOT"); +} +ATF_TC_BODY(fts_options_logical_seedot, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_LOGICAL | FTS_SEEDOT, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_DOT, ".", "dir/." }, + { FTS_DOT, "..", "dir/.." }, + { FTS_F, "file", "dir/file" }, + { FTS_D, "up", "dir/up" }, + { FTS_DOT, ".", "dir/up/." }, + { FTS_DOT, "..", "dir/up/.." }, + { FTS_DL, "dead", "dir/up/dead" }, + { FTS_DC, "dir", "dir/up/dir" }, + { FTS_DC, "dirl", "dir/up/dirl" }, + { FTS_F, "file", "dir/up/file" }, + { FTS_F, "filel", "dir/up/filel" }, + { FTS_DP, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_DOT, ".", "dirl/." }, + { FTS_DOT, "..", "dirl/.." }, + { FTS_F, "file", "dirl/file" }, + { FTS_D, "up", "dirl/up" }, + { FTS_DOT, ".", "dirl/up/." }, + { FTS_DOT, "..", "dirl/up/.." }, + { FTS_DL, "dead", "dirl/up/dead" }, + { FTS_DC, "dir", "dirl/up/dir" }, + { FTS_DC, "dirl", "dirl/up/dirl" }, + { FTS_F, "file", "dirl/up/file" }, + { FTS_F, "filel", "dirl/up/filel" }, + { FTS_DP, "up", "dirl/up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical); +ATF_TC_HEAD(fts_options_physical, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL"); +} +ATF_TC_BODY(fts_options_physical, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nochdir); +ATF_TC_HEAD(fts_options_physical_nochdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOCHDIR"); +} +ATF_TC_BODY(fts_options_physical_nochdir, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOCHDIR, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "dir/file" }, + { FTS_SL, "up", "dir/up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_comfollow); +ATF_TC_HEAD(fts_options_physical_comfollow, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOW"); +} +ATF_TC_BODY(fts_options_physical_comfollow, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_COMFOLLOW, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_F, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_comfollowdir); +ATF_TC_HEAD(fts_options_physical_comfollowdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOWDIR"); +} +ATF_TC_BODY(fts_options_physical_comfollowdir, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_COMFOLLOWDIR, + (struct fts_expect[]){ + { FTS_DL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_D, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nostat); +ATF_TC_HEAD(fts_options_physical_nostat, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT"); +} +ATF_TC_BODY(fts_options_physical_nostat, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOSTAT, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_NSOK, "file", "file" }, + { FTS_NSOK, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_nostat_type); +ATF_TC_HEAD(fts_options_physical_nostat_type, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT_TYPE"); +} +ATF_TC_BODY(fts_options_physical_nostat_type, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_NOSTAT_TYPE, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +ATF_TC(fts_options_physical_seedot); +ATF_TC_HEAD(fts_options_physical_seedot, tc) +{ + atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_SEEDOT"); +} +ATF_TC_BODY(fts_options_physical_seedot, tc) +{ + fts_options_prepare(tc); + fts_test(tc, &(struct fts_testcase){ + all_paths, + FTS_PHYSICAL | FTS_SEEDOT, + (struct fts_expect[]){ + { FTS_SL, "dead", "dead" }, + { FTS_D, "dir", "dir" }, + { FTS_DOT, ".", "." }, + { FTS_DOT, "..", ".." }, + { FTS_F, "file", "file" }, + { FTS_SL, "up", "up" }, + { FTS_DP, "dir", "dir" }, + { FTS_SL, "dirl", "dirl" }, + { FTS_F, "file", "file" }, + { FTS_SL, "filel", "filel" }, + { FTS_NS, "noent", "noent" }, + { 0 } + }, + }); +} + +/* + * TODO: Add tests for FTS_XDEV and FTS_WHITEOUT + */ + +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); + ATF_TP_ADD_TC(tp, fts_options_physical); + ATF_TP_ADD_TC(tp, fts_options_physical_nochdir); + ATF_TP_ADD_TC(tp, fts_options_physical_comfollow); + ATF_TP_ADD_TC(tp, fts_options_physical_comfollowdir); + ATF_TP_ADD_TC(tp, fts_options_physical_nostat); + ATF_TP_ADD_TC(tp, fts_options_physical_nostat_type); + ATF_TP_ADD_TC(tp, fts_options_physical_seedot); + return (atf_no_error()); +} 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 */ diff --git a/lib/libc/tests/gen/ftw_test.c b/lib/libc/tests/gen/ftw_test.c index b120f01ff4f1..3d2cf3446dee 100644 --- a/lib/libc/tests/gen/ftw_test.c +++ b/lib/libc/tests/gen/ftw_test.c @@ -28,9 +28,6 @@ * Limited test program for nftw() as specified by IEEE Std. 1003.1-2008. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/wait.h> #include <err.h> #include <errno.h> diff --git a/lib/libc/tests/gen/getentropy_test.c b/lib/libc/tests/gen/getentropy_test.c index 1290e6e50529..6ac9d5678ea6 100644 --- a/lib/libc/tests/gen/getentropy_test.c +++ b/lib/libc/tests/gen/getentropy_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> * All rights reserved. @@ -26,11 +26,9 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> +#include <limits.h> #include <signal.h> #include <unistd.h> @@ -65,13 +63,13 @@ ATF_TC_BODY(getentropy_sizes, tc) char buf[512]; ATF_REQUIRE_EQ(getentropy(buf, sizeof(buf)), -1); - ATF_REQUIRE_EQ(errno, EIO); - ATF_REQUIRE_EQ(getentropy(buf, 257), -1); - ATF_REQUIRE_EQ(errno, EIO); + ATF_REQUIRE_EQ(errno, EINVAL); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX + 1), -1); + ATF_REQUIRE_EQ(errno, EINVAL); /* Smaller sizes always succeed: */ - ATF_REQUIRE_EQ(getentropy(buf, 256), 0); - ATF_REQUIRE_EQ(getentropy(buf, 128), 0); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX), 0); + ATF_REQUIRE_EQ(getentropy(buf, GETENTROPY_MAX / 2), 0); ATF_REQUIRE_EQ(getentropy(buf, 0), 0); } diff --git a/lib/libc/tests/gen/getmntinfo_test.c b/lib/libc/tests/gen/getmntinfo_test.c index 183fa84ed0e6..06e1091d8a15 100644 --- a/lib/libc/tests/gen/getmntinfo_test.c +++ b/lib/libc/tests/gen/getmntinfo_test.c @@ -28,9 +28,6 @@ * Limited test program for getmntinfo(3), a non-standard BSDism. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/mount.h> #include <sys/ucred.h> diff --git a/lib/libc/tests/gen/glob2_test.c b/lib/libc/tests/gen/glob2_test.c index dfcce0eed3da..ff1b36b830b8 100644 --- a/lib/libc/tests/gen/glob2_test.c +++ b/lib/libc/tests/gen/glob2_test.c @@ -24,13 +24,13 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> +#include <sys/stat.h> + #include <errno.h> #include <fcntl.h> #include <glob.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -105,10 +105,80 @@ ATF_TC_BODY(glob_pathological_test, tc) } } +ATF_TC(glob_period); +ATF_TC_HEAD(glob_period, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test behaviour when matching files that start with a period" + "(documented in the glob(3) CAVEATS section)."); +} +ATF_TC_BODY(glob_period, tc) +{ + int i; + glob_t g; + + atf_utils_create_file(".test", ""); + glob(".", 0, NULL, &g); + ATF_REQUIRE_MSG(g.gl_matchc == 1, + "glob(3) shouldn't match files starting with a period when using '.'"); + for (i = 0; i < g.gl_matchc; i++) + printf("%s\n", g.gl_pathv[i]); + glob(".*", 0, NULL, &g); + ATF_REQUIRE_MSG(g.gl_matchc == 3 && strcmp(g.gl_pathv[2], ".test") == 0, + "glob(3) should match files starting with a period when using '.*'"); +} + +static bool glob_callback_invoked; + +static int +errfunc(const char *path, int err) +{ + ATF_CHECK_STREQ(path, "test/"); + ATF_CHECK(err == EACCES); + glob_callback_invoked = true; + /* Suppress EACCES errors. */ + return (0); +} + +ATF_TC(glob_callback); +ATF_TC_HEAD(glob_callback, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test ability of callback function to suppress errors"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(glob_callback, tc) +{ + glob_t g; + int rv; + + ATF_REQUIRE_EQ(0, mkdir("test", 0755)); + ATF_REQUIRE_EQ(0, symlink("foo", "test/foo")); + ATF_REQUIRE_EQ(0, chmod("test", 0)); + + glob_callback_invoked = false; + rv = glob("test/*", 0, errfunc, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback function"); + ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv, + "callback function failed to suppress EACCES"); + globfree(&g); + + /* GLOB_ERR should ignore the suppressed error. */ + glob_callback_invoked = false; + rv = glob("test/*", GLOB_ERR, errfunc, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback function"); + ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv, + "GLOB_ERR didn't override callback function"); + globfree(&g); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, glob_pathological_test); - + ATF_TP_ADD_TC(tp, glob_period); + ATF_TP_ADD_TC(tp, glob_callback); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/glob_blocks_test.c b/lib/libc/tests/gen/glob_blocks_test.c new file mode 100644 index 000000000000..629b90bee762 --- /dev/null +++ b/lib/libc/tests/gen/glob_blocks_test.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <errno.h> +#include <glob.h> +#include <stdbool.h> + +#include <atf-c.h> + +ATF_TC(glob_b_callback); +ATF_TC_HEAD(glob_b_callback, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test ability of callback block to suppress errors"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(glob_b_callback, tc) +{ + static bool glob_callback_invoked; + static int (^errblk)(const char *, int) = + ^(const char *path, int err) { + ATF_CHECK_STREQ(path, "test/"); + ATF_CHECK(err == EACCES); + glob_callback_invoked = true; + /* Suppress EACCES errors. */ + return (0); + }; + glob_t g; + int rv; + + ATF_REQUIRE_EQ(0, mkdir("test", 0755)); + ATF_REQUIRE_EQ(0, symlink("foo", "test/foo")); + ATF_REQUIRE_EQ(0, chmod("test", 0)); + + glob_callback_invoked = false; + rv = glob_b("test/*", 0, errblk, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback block"); + ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv, + "callback function failed to suppress EACCES"); + globfree(&g); + + /* GLOB_ERR should ignore the suppressed error. */ + glob_callback_invoked = false; + rv = glob_b("test/*", GLOB_ERR, errblk, &g); + ATF_CHECK_MSG(glob_callback_invoked, + "glob(3) failed to invoke callback block"); + ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv, + "GLOB_ERR didn't override callback block"); + globfree(&g); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, glob_b_callback); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/makecontext_test.c b/lib/libc/tests/gen/makecontext_test.c index 50d835d15cbe..23e3cf85f677 100644 --- a/lib/libc/tests/gen/makecontext_test.c +++ b/lib/libc/tests/gen/makecontext_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 John H. Baldwin <jhb@FreeBSD.org> * @@ -25,9 +25,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <atf-c.h> #include <ucontext.h> diff --git a/lib/libc/tests/gen/opendir_test.c b/lib/libc/tests/gen/opendir_test.c new file mode 100644 index 000000000000..b7481255654f --- /dev/null +++ b/lib/libc/tests/gen/opendir_test.c @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +/* + * Create a directory with a single subdirectory. + */ +static void +opendir_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755)); +} + +/* + * Assuming dirp represents the directory created by opendir_prepare(), + * verify that readdir() returns what we expected to see there. + */ +static void +opendir_check(const struct atf_tc *tc, DIR *dirp) +{ + struct dirent *ent; + + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(1, ent->d_namlen); + ATF_CHECK_STREQ(".", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(2, ent->d_namlen); + ATF_CHECK_STREQ("..", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_REQUIRE((ent = readdir(dirp)) != NULL); + ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen); + ATF_CHECK_STREQ("subdir", ent->d_name); + ATF_CHECK_EQ(DT_DIR, ent->d_type); + ATF_CHECK(readdir(dirp) == NULL); + ATF_CHECK(readdir(dirp) == NULL); +} + +ATF_TC(opendir_ok); +ATF_TC_HEAD(opendir_ok, tc) +{ + atf_tc_set_md_var(tc, "descr", "Open a directory."); +} +ATF_TC_BODY(opendir_ok, tc) +{ + DIR *dirp; + + opendir_prepare(tc); + ATF_REQUIRE((dirp = opendir("dir")) != NULL); + opendir_check(tc, dirp); + ATF_CHECK_EQ(0, closedir(dirp)); +} + +ATF_TC(opendir_fifo); +ATF_TC_HEAD(opendir_fifo, tc) +{ + atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe."); +} +ATF_TC_BODY(opendir_fifo, tc) +{ + DIR *dirp; + int fd; + + ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0); + ATF_REQUIRE_EQ(0, close(fd)); + ATF_REQUIRE((dirp = opendir("fifo")) == NULL); + ATF_CHECK_EQ(ENOTDIR, errno); +} + +ATF_TC(fdopendir_ok); +ATF_TC_HEAD(fdopendir_ok, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from a directory descriptor."); +} +ATF_TC_BODY(fdopendir_ok, tc) +{ + DIR *dirp; + int dd; + + opendir_prepare(tc); + ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ATF_REQUIRE((dirp = fdopendir(dd)) != NULL); + opendir_check(tc, dirp); + ATF_CHECK_EQ(dd, fdclosedir(dirp)); + ATF_CHECK_EQ(0, close(dd)); +} + +ATF_TC(fdopendir_ebadf); +ATF_TC_HEAD(fdopendir_ebadf, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from an invalid descriptor."); +} +ATF_TC_BODY(fdopendir_ebadf, tc) +{ + DIR *dirp; + int dd; + + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ATF_CHECK_EQ(0, close(dd)); + ATF_REQUIRE((dirp = fdopendir(dd)) == NULL); + ATF_CHECK_EQ(EBADF, errno); +} + +ATF_TC(fdopendir_enotdir); +ATF_TC_HEAD(fdopendir_enotdir, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Open a directory from a non-directory descriptor."); +} +ATF_TC_BODY(fdopendir_enotdir, tc) +{ + DIR *dirp; + int fd; + + ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0); + ATF_REQUIRE((dirp = fdopendir(fd)) == NULL); + ATF_CHECK_EQ(ENOTDIR, errno); + ATF_CHECK_EQ(0, close(fd)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, opendir_ok); + ATF_TP_ADD_TC(tp, fdopendir_ok); + ATF_TP_ADD_TC(tp, fdopendir_ebadf); + ATF_TP_ADD_TC(tp, fdopendir_enotdir); + ATF_TP_ADD_TC(tp, opendir_fifo); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/popen_test.c b/lib/libc/tests/gen/popen_test.c index 5c615b7146e9..43eadd380f39 100644 --- a/lib/libc/tests/gen/popen_test.c +++ b/lib/libc/tests/gen/popen_test.c @@ -29,9 +29,6 @@ * with BSD extensions. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/wait.h> #include <errno.h> diff --git a/lib/libc/tests/gen/posix_spawn/Makefile b/lib/libc/tests/gen/posix_spawn/Makefile index 21feba9dce05..df428876708b 100644 --- a/lib/libc/tests/gen/posix_spawn/Makefile +++ b/lib/libc/tests/gen/posix_spawn/Makefile @@ -1,5 +1,3 @@ -# $FreeBSD$ - .include <bsd.own.mk> BINDIR= ${TESTSDIR} diff --git a/lib/libc/tests/gen/posix_spawn/Makefile.depend b/lib/libc/tests/gen/posix_spawn/Makefile.depend index 10e58b789640..e89a5c52c82a 100644 --- a/lib/libc/tests/gen/posix_spawn/Makefile.depend +++ b/lib/libc/tests/gen/posix_spawn/Makefile.depend @@ -1,4 +1,3 @@ -# $FreeBSD$ # Autogenerated - do NOT edit! DIRDEPS = \ diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c index 46259cbf8cde..22133cf1d59a 100644 --- a/lib/libc/tests/gen/posix_spawn_test.c +++ b/lib/libc/tests/gen/posix_spawn_test.c @@ -29,11 +29,11 @@ * IEEE Std. 1003.1-2008. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - +#include <sys/param.h> +#include <sys/stat.h> #include <sys/wait.h> #include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,6 +41,10 @@ __FBSDID("$FreeBSD$"); #include <atf-c.h> +static const char true_script[] = + "#!/usr/bin/env\n" + "/usr/bin/true\n"; + char *myenv[2] = { "answer=42", NULL }; ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test); @@ -127,6 +131,48 @@ ATF_TC_BODY(posix_spawnp_enoexec_fallback_null_argv0, tc) ATF_REQUIRE(error == EINVAL); } +ATF_TC(posix_spawnp_eacces); +ATF_TC_HEAD(posix_spawnp_eacces, tc) +{ + atf_tc_set_md_var(tc, "descr", "Verify EACCES behavior in posix_spawnp"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} +ATF_TC_BODY(posix_spawnp_eacces, tc) +{ + const struct spawnp_eacces_tc { + const char *pathvar; + int error_expected; + } spawnp_eacces_tests[] = { + { ".", EACCES }, /* File exists, but not +x */ + { "unsearchable", ENOENT }, /* File exists, dir not +x */ + }; + char *myargs[2] = { "eacces", NULL }; + int error; + + error = mkdir("unsearchable", 0755); + ATF_REQUIRE(error == 0); + error = symlink("/usr/bin/true", "unsearchable/eacces"); + ATF_REQUIRE(error == 0); + + (void)chmod("unsearchable", 0444); + + /* this will create a non-executable file */ + atf_utils_create_file("eacces", true_script); + + for (size_t i = 0; i < nitems(spawnp_eacces_tests); i++) { + const struct spawnp_eacces_tc *tc = &spawnp_eacces_tests[i]; + pid_t pid; + + error = setenv("PATH", tc->pathvar, 1); + ATF_REQUIRE_EQ(0, error); + + error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, + myenv); + ATF_CHECK_INTEQ_MSG(tc->error_expected, error, + "path '%s'", tc->pathvar); + } +} + ATF_TP_ADD_TCS(tp) { @@ -134,6 +180,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test); ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback); ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback_null_argv0); + ATF_TP_ADD_TC(tp, posix_spawnp_eacces); return (atf_no_error()); } diff --git a/lib/libc/tests/gen/realpath2_test.c b/lib/libc/tests/gen/realpath2_test.c index 82ad7f870697..f89dd99cbb72 100644 --- a/lib/libc/tests/gen/realpath2_test.c +++ b/lib/libc/tests/gen/realpath2_test.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <errno.h> #include <fcntl.h> diff --git a/lib/libc/tests/gen/scandir_blocks_test.c b/lib/libc/tests/gen/scandir_blocks_test.c new file mode 100644 index 000000000000..b94270bc410e --- /dev/null +++ b/lib/libc/tests/gen/scandir_blocks_test.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <fcntl.h> +#include <stdlib.h> + +#include <atf-c.h> + +static void +scandir_blocks_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("file", "dir/link")); + ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755)); +} + +static void +scandir_blocks_verify(const struct atf_tc *tc, int n, struct dirent **namelist) +{ + ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n); + ATF_CHECK_STREQ("link", namelist[0]->d_name); + ATF_CHECK_STREQ("file", namelist[1]->d_name); + ATF_CHECK_STREQ("dir", namelist[2]->d_name); + ATF_CHECK_STREQ("..", namelist[3]->d_name); + ATF_CHECK_STREQ(".", namelist[4]->d_name); +} + +ATF_TC(scandir_b_test); +ATF_TC_HEAD(scandir_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandir_b()"); +} +ATF_TC_BODY(scandir_b_test, tc) +{ + struct dirent **namelist = NULL; + int i, ret; + + scandir_blocks_prepare(tc); + ret = scandir_b("dir", &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); +} + +ATF_TC(fdscandir_b_test); +ATF_TC_HEAD(fdscandir_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fdscandir_b()"); +} +ATF_TC_BODY(fdscandir_b_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_blocks_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ret = fdscandir_b(fd, &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TC(scandirat_b_test); +ATF_TC_HEAD(scandirat_b_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandirat_b()"); +} +ATF_TC_BODY(scandirat_b_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_blocks_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0); + ret = scandirat_b(fd, ".", &namelist, + ^(const struct dirent *ent) { + return (strcmp(ent->d_name, "skip") != 0); + }, + ^(const struct dirent **a, const struct dirent **b) { + return (strcmp((*b)->d_name, (*a)->d_name)); + }); + scandir_blocks_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, scandir_b_test); + ATF_TP_ADD_TC(tp, fdscandir_b_test); + ATF_TP_ADD_TC(tp, scandirat_b_test); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/scandir_test.c b/lib/libc/tests/gen/scandir_test.c new file mode 100644 index 000000000000..afd25bf7c0b2 --- /dev/null +++ b/lib/libc/tests/gen/scandir_test.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <atf-c.h> + +static void +scandir_prepare(const struct atf_tc *tc) +{ + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755)); + ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644))); + ATF_REQUIRE_EQ(0, symlink("file", "dir/link")); + ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755)); +} + +static void +scandir_verify(const struct atf_tc *tc, int n, struct dirent **namelist) +{ + ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n); + ATF_CHECK_STREQ("link", namelist[0]->d_name); + ATF_CHECK_STREQ("file", namelist[1]->d_name); + ATF_CHECK_STREQ("dir", namelist[2]->d_name); + ATF_CHECK_STREQ("..", namelist[3]->d_name); + ATF_CHECK_STREQ(".", namelist[4]->d_name); +} + +static int +scandir_select(const struct dirent *ent) +{ + return (strcmp(ent->d_name, "skip") != 0); +} + +static int +scandir_compare(const struct dirent **a, const struct dirent **b) +{ + return (strcmp((*b)->d_name, (*a)->d_name)); +} + +ATF_TC(scandir_test); +ATF_TC_HEAD(scandir_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandir()"); +} +ATF_TC_BODY(scandir_test, tc) +{ + struct dirent **namelist = NULL; + int i, ret; + + scandir_prepare(tc); + ret = scandir("dir", &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); +} + +ATF_TC(fdscandir_test); +ATF_TC_HEAD(fdscandir_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fdscandir()"); +} +ATF_TC_BODY(fdscandir_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + ret = fdscandir(fd, &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +ATF_TC(scandirat_test); +ATF_TC_HEAD(scandirat_test, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test scandirat()"); +} +ATF_TC_BODY(scandirat_test, tc) +{ + struct dirent **namelist = NULL; + int fd, i, ret; + + scandir_prepare(tc); + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0); + ret = scandirat(fd, ".", &namelist, scandir_select, scandir_compare); + scandir_verify(tc, ret, namelist); + for (i = 0; i < ret; i++) + free(namelist[i]); + free(namelist); + ATF_REQUIRE_EQ(0, close(fd)); +} + +static int +scandir_none(const struct dirent *ent __unused) +{ + return (0); +} + +ATF_TC(scandir_none); +ATF_TC_HEAD(scandir_none, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test scandir() when no entries are selected"); +} +ATF_TC_BODY(scandir_none, tc) +{ + struct dirent **namelist = NULL; + + ATF_REQUIRE_EQ(0, scandir(".", &namelist, scandir_none, alphasort)); + ATF_REQUIRE(namelist); + free(namelist); +} + +/* + * Test that scandir() propagates errors from readdir(): we create a + * directory with enough entries that it can't be read in a single + * getdirentries() call, then abuse the selection callback to close the + * file descriptor scandir() is using after the first call, causing the + * next one to fail, and verify that readdir() returns an error instead of + * a partial result. We make two passes, one in which nothing was + * selected before the error occurred, and one in which everything was. + */ +static int scandir_error_count; +static int scandir_error_fd; +static int scandir_error_select_return; + +static int +scandir_error_select(const struct dirent *ent __unused) +{ + if (scandir_error_count++ == 0) + close(scandir_error_fd); + return (scandir_error_select_return); +} + +ATF_TC(scandir_error); +ATF_TC_HEAD(scandir_error, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that scandir() propagates errors from readdir()"); +} +ATF_TC_BODY(scandir_error, tc) +{ + char path[16]; + struct dirent **namelist = NULL; + int fd, i; + + ATF_REQUIRE_EQ(0, mkdir("dir", 0755)); + for (i = 0; i < 1024; i++) { + snprintf(path, sizeof(path), "dir/%04x", i); + ATF_REQUIRE_EQ(0, symlink(path + 4, path)); + } + + /* first pass, select nothing */ + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + scandir_error_count = 0; + scandir_error_fd = fd; + scandir_error_select_return = 0; + ATF_CHECK_ERRNO(EBADF, + fdscandir(fd, &namelist, scandir_error_select, NULL) < 0); + ATF_CHECK_EQ(NULL, namelist); + + /* second pass, select everything */ + ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0); + scandir_error_count = 0; + scandir_error_fd = fd; + scandir_error_select_return = 1; + ATF_CHECK_ERRNO(EBADF, + fdscandir(fd, &namelist, scandir_error_select, NULL) < 0); + ATF_CHECK_EQ(NULL, namelist); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, scandir_test); + ATF_TP_ADD_TC(tp, fdscandir_test); + ATF_TP_ADD_TC(tp, scandirat_test); + ATF_TP_ADD_TC(tp, scandir_none); + ATF_TP_ADD_TC(tp, scandir_error); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/sig2str_test.c b/lib/libc/tests/gen/sig2str_test.c new file mode 100644 index 000000000000..00b6ebb2349a --- /dev/null +++ b/lib/libc/tests/gen/sig2str_test.c @@ -0,0 +1,213 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Ricardo Branco <rbranco@suse.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#include <atf-c.h> + +static void +test_roundtrip(int signum) +{ + char str[SIG2STR_MAX]; + int sig; + + ATF_REQUIRE_EQ_MSG(sig2str(signum, str), 0, + "sig2str(%d) failed", signum); + ATF_REQUIRE_EQ_MSG(str2sig(str, &sig), 0, + "str2sig(\"%s\") failed", str); + ATF_REQUIRE_INTEQ_MSG(sig, signum, + "Mismatch: roundtrip conversion gave %d instead of %d", + sig, signum); +} + +ATF_TC_WITHOUT_HEAD(sig2str_valid); +ATF_TC_BODY(sig2str_valid, tc) +{ + int sig; + + for (sig = 1; sig < sys_nsig; sig++) { + test_roundtrip(sig); + } +} + +ATF_TC_WITHOUT_HEAD(sig2str_invalid); +ATF_TC_BODY(sig2str_invalid, tc) +{ + char buf[SIG2STR_MAX]; + + ATF_CHECK(sig2str(0, buf) != 0); + ATF_CHECK(sig2str(-1, buf) != 0); + ATF_CHECK(sig2str(SIGRTMAX + 1, buf) != 0); +} + +ATF_TC_WITHOUT_HEAD(str2sig_rtmin_rtmax); +ATF_TC_BODY(str2sig_rtmin_rtmax, tc) +{ + int sig; + + ATF_CHECK_MSG(str2sig("RTMIN", &sig) == 0, + "str2sig(\"RTMIN\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN, + "RTMIN mapped to %d, expected %d", sig, SIGRTMIN); + + ATF_CHECK_MSG(str2sig("RTMAX", &sig) == 0, + "str2sig(\"RTMAX\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX, + "RTMAX mapped to %d, expected %d", sig, SIGRTMAX); + + ATF_CHECK_MSG(str2sig("RTMIN+1", &sig) == 0, + "str2sig(\"RTMIN+1\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN + 1, + "RTMIN+1 mapped to %d, expected %d", sig, SIGRTMIN + 1); + + ATF_CHECK_MSG(str2sig("RTMAX-1", &sig) == 0, + "str2sig(\"RTMAX-1\") failed"); + ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX - 1, + "RTMAX-1 mapped to %d, expected %d", sig, SIGRTMAX - 1); +} + +ATF_TC_WITHOUT_HEAD(str2sig_invalid_rt); +ATF_TC_BODY(str2sig_invalid_rt, tc) +{ + int i, sig; + + const char *invalid[] = { + "RTMIN+0", + "RTMAX-0", + "RTMIN-777", + "RTMIN+777", + "RTMAX-777", + "RTMAX+777", + "RTMIN-", + "RTMAX-", + "RTMIN0", + "RTMAX1", + "RTMIN+abc", + "RTMIN-abc", + NULL + }; + + for (i = 0; invalid[i] != NULL; i++) { + ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0, + "str2sig(\"%s\") unexpectedly succeeded", invalid[i]); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_fullname); +ATF_TC_BODY(str2sig_fullname, tc) +{ + char fullname[SIG2STR_MAX + 3]; + int n, sig; + + for (sig = 1; sig < sys_nsig; sig++) { + snprintf(fullname, sizeof(fullname), "SIG%s", sys_signame[sig]); + + ATF_CHECK_MSG(str2sig(fullname, &n) == 0, + "str2sig(\"%s\") failed with errno %d (%s)", + fullname, errno, strerror(errno)); + + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: %s = %d, str2sig(\"%s\") = %d", + sys_signame[sig], sig, fullname, n); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_lowercase); +ATF_TC_BODY(str2sig_lowercase, tc) +{ + char fullname[SIG2STR_MAX + 3]; + int n, sig; + + for (sig = 1; sig < sys_nsig; sig++) { + snprintf(fullname, sizeof(fullname), "sig%s", sys_signame[sig]); + for (size_t i = 3; i < strlen(fullname); i++) + fullname[i] = toupper((unsigned char)fullname[i]); + + ATF_CHECK_MSG(str2sig(fullname, &n) == 0, + "str2sig(\"%s\") failed with errno %d (%s)", + fullname, errno, strerror(errno)); + + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: %s = %d, str2sig(\"%s\") = %d", + sys_signame[sig], sig, fullname, n); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_numeric); +ATF_TC_BODY(str2sig_numeric, tc) +{ + char buf[16]; + int n, sig; + + for (sig = NSIG; sig < SIGRTMIN; sig++) { + snprintf(buf, sizeof(buf), "%d", sig); + ATF_CHECK_MSG(str2sig(buf, &n) == 0, + "str2sig(\"%s\") failed", buf); + ATF_CHECK_INTEQ_MSG(n, sig, + "Mismatch: str2sig(\"%s\") = %d, expected %d", + buf, n, sig); + } +} + +ATF_TC_WITHOUT_HEAD(str2sig_invalid); +ATF_TC_BODY(str2sig_invalid, tc) +{ + const char *invalid[] = { + "SIGDOESNOTEXIST", + "DOESNOTEXIST", + "INTERRUPT", + "", + "SIG", + "123abc", + "sig1extra", + NULL + }; + int i, sig; + + for (i = 0; invalid[i] != NULL; i++) { + ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0, + "str2sig(\"%s\") unexpectedly succeeded", invalid[i]); + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, sig2str_valid); + ATF_TP_ADD_TC(tp, sig2str_invalid); + ATF_TP_ADD_TC(tp, str2sig_rtmin_rtmax); + ATF_TP_ADD_TC(tp, str2sig_invalid_rt); + ATF_TP_ADD_TC(tp, str2sig_fullname); + ATF_TP_ADD_TC(tp, str2sig_lowercase); + ATF_TP_ADD_TC(tp, str2sig_numeric); + ATF_TP_ADD_TC(tp, str2sig_invalid); + return (atf_no_error()); +} diff --git a/lib/libc/tests/gen/sigsetops_test.c b/lib/libc/tests/gen/sigsetops_test.c index ba9abed403b0..a22c4b3f4f59 100644 --- a/lib/libc/tests/gen/sigsetops_test.c +++ b/lib/libc/tests/gen/sigsetops_test.c @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> * All rights reserved. @@ -26,9 +26,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <errno.h> #include <signal.h> #include <stdbool.h> diff --git a/lib/libc/tests/gen/spawnp_enoexec.sh b/lib/libc/tests/gen/spawnp_enoexec.sh index 02941633e108..1050b7a6f944 100755 --- a/lib/libc/tests/gen/spawnp_enoexec.sh +++ b/lib/libc/tests/gen/spawnp_enoexec.sh @@ -1,4 +1,3 @@ -# $FreeBSD$ # Intentionally no interpreter exit 42 diff --git a/lib/libc/tests/gen/test-fnmatch.c b/lib/libc/tests/gen/test-fnmatch.c index 7771ab37f0a0..1a6c6ed7efdf 100644 --- a/lib/libc/tests/gen/test-fnmatch.c +++ b/lib/libc/tests/gen/test-fnmatch.c @@ -24,9 +24,6 @@ * SUCH DAMAGE. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c index 3ccc67774c7f..a8b9d5509633 100644 --- a/lib/libc/tests/gen/wordexp_test.c +++ b/lib/libc/tests/gen/wordexp_test.c @@ -29,9 +29,6 @@ * IEEE Std. 1003.1-2001. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/wait.h> #include <errno.h> #include <signal.h> @@ -295,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc) ATF_REQUIRE(r == 0); } +ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test); +ATF_TC_BODY(with_SIGCHILD_ignore_test, tc) +{ + struct sigaction sa; + wordexp_t we; + int r; + + /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */ + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); + r = wordexp("hello world", &we, 0); + ATF_REQUIRE(r == 0); + ATF_REQUIRE(we.we_wordc == 2); + ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0); + ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0); + ATF_REQUIRE(we.we_wordv[2] == NULL); + wordfree(&we); + sa.sa_handler = SIG_DFL; + r = sigaction(SIGCHLD, &sa, NULL); + ATF_REQUIRE(r == 0); +} + ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test); ATF_TC_BODY(with_unused_non_default_IFS_test, tc) { @@ -353,6 +375,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test); ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test); ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test); + ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test); ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test); ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test); |