diff --git a/contrib/atf/atf-c/tc.h b/contrib/atf/atf-c/tc.h --- a/contrib/atf/atf-c/tc.h +++ b/contrib/atf/atf-c/tc.h @@ -106,6 +106,9 @@ ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2); void atf_tc_pass(void) ATF_DEFS_ATTRIBUTE_NORETURN; +#ifdef __FreeBSD__ +void atf_tc_require_module(const char *); +#endif void atf_tc_require_prog(const char *); void atf_tc_skip(const char *, ...) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2) diff --git a/contrib/atf/atf-c/tc.c b/contrib/atf/atf-c/tc.c --- a/contrib/atf/atf-c/tc.c +++ b/contrib/atf/atf-c/tc.c @@ -26,6 +26,10 @@ #include "atf-c/tc.h" #include +#ifdef __FreeBSD__ +#include +#include +#endif #include #include @@ -103,6 +107,9 @@ static void errno_test(struct context *, const char *, const size_t, const int, const char *, const bool, void (*)(struct context *, atf_dynstr_t *)); +#ifdef __FreeBSD__ +static atf_error_t check_module(struct context *, const char *); +#endif static atf_error_t check_prog_in_dir(const char *, void *); static atf_error_t check_prog(struct context *, const char *); @@ -460,6 +467,39 @@ } } +#ifdef __FreeBSD__ +static atf_error_t +check_module(struct context *ctx, const char *module) +{ + struct kld_file_stat fstat = { .version = sizeof(fstat) }; + struct module_stat mstat = { .version = sizeof(mstat) }; + atf_dynstr_t reason; + size_t len = strlen(module); + int fid, mid; + + for (fid = kldnext(0); fid > 0; fid = kldnext(fid)) { + if (kldstat(fid, &fstat) != 0) + continue; + if (strcmp(fstat.name, module) == 0) + goto done; + if (strncmp(fstat.name, module, len) == 0 && + strcmp(fstat.name + len, ".ko") == 0) + goto done; + for (mid = kldfirstmod(fid); mid > 0; mid = modfnext(mid)) { + if (modstat(mid, &mstat) != 0) + continue; + if (strcmp(mstat.name, module) == 0) + goto done; + } + } + format_reason_fmt(&reason, NULL, 0, "The required module %s " + "is not loaded", module); + fail_requirement(ctx, &reason); +done: + return atf_no_error(); +} +#endif + struct prog_found_pair { const char *prog; bool found; @@ -829,6 +869,9 @@ static void _atf_tc_fail_requirement(struct context *, const char *, const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; +#ifdef __FreeBSD__ +static void _atf_tc_require_module(struct context *, const char *); +#endif static void _atf_tc_require_prog(struct context *, const char *); static void _atf_tc_skip(struct context *, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; @@ -908,6 +951,14 @@ UNREACHABLE; } +#ifdef __FreeBSD__ +static void +_atf_tc_require_module(struct context *ctx, const char *module) +{ + check_fatal_error(check_module(ctx, module)); +} +#endif + static void _atf_tc_require_prog(struct context *ctx, const char *prog) { @@ -1154,6 +1205,16 @@ _atf_tc_pass(&Current); } +#ifdef __FreeBSD__ +void +atf_tc_require_module(const char *module) +{ + PRE(Current.tc != NULL); + + _atf_tc_require_module(&Current, module); +} +#endif + void atf_tc_require_prog(const char *prog) { diff --git a/contrib/atf/atf-sh/libatf-sh.subr b/contrib/atf/atf-sh/libatf-sh.subr --- a/contrib/atf/atf-sh/libatf-sh.subr +++ b/contrib/atf/atf-sh/libatf-sh.subr @@ -353,6 +353,18 @@ esac } +# +# atf_require_module module +# +# Checks that the given kernel module is loaded. If it is not, +# automatically skips the test case with an appropriate message. +# +atf_require_module() +{ + kldstat -q "${1}" || \ + atf_skip "The required module ${1} is not loaded" +} + # # atf_set varname val1 [.. valN] # diff --git a/contrib/kyua/engine/atf_list.cpp b/contrib/kyua/engine/atf_list.cpp --- a/contrib/kyua/engine/atf_list.cpp +++ b/contrib/kyua/engine/atf_list.cpp @@ -133,6 +133,10 @@ mdbuilder.set_string("allowed_platforms", value); } else if (name == "require.memory") { mdbuilder.set_string("required_memory", value); +#ifdef __FreeBSD__ + } else if (name == "require.modules") { + mdbuilder.set_string("required_modules", value); +#endif } else if (name == "require.progs") { mdbuilder.set_string("required_programs", value); } else if (name == "require.user") { diff --git a/contrib/kyua/engine/requirements.cpp b/contrib/kyua/engine/requirements.cpp --- a/contrib/kyua/engine/requirements.cpp +++ b/contrib/kyua/engine/requirements.cpp @@ -41,6 +41,10 @@ #include "utils/sanity.hpp" #include "utils/units.hpp" +#ifdef __FreeBSD__ +#include +#endif + namespace config = utils::config; namespace fs = utils::fs; namespace passwd = utils::passwd; @@ -220,6 +224,26 @@ } +#ifdef __FreeBSD__ +/// Checks if all required modules are loaded. +/// +/// \param required_programs Set of modules. +/// +/// \return Empty if the required modules are all loaded or an error +/// message otherwise. +static std::string +check_required_modules(const model::strings_set& required_modules) +{ + for (model::strings_set::const_iterator iter = required_modules.begin(); + iter != required_modules.end(); iter++) { + if (!kld_isloaded((*iter).c_str())) + return F("Required module '%s' not loaded") % *iter; + } + return ""; +} +#endif + + /// Checks if the current system has the specified amount of memory. /// /// \param required_memory Amount of required physical memory, or zero if not @@ -312,6 +336,12 @@ if (!reason.empty()) return reason; +#ifdef __FreeBSD__ + reason = check_required_modules(md.required_modules()); + if (!reason.empty()) + return reason; +#endif + reason = check_required_memory(md.required_memory()); if (!reason.empty()) return reason; diff --git a/contrib/kyua/model/metadata.hpp b/contrib/kyua/model/metadata.hpp --- a/contrib/kyua/model/metadata.hpp +++ b/contrib/kyua/model/metadata.hpp @@ -76,6 +76,9 @@ const utils::units::bytes& required_disk_space(void) const; const paths_set& required_files(void) const; const utils::units::bytes& required_memory(void) const; +#ifdef __FreeBSD__ + const strings_set& required_modules(void) const; +#endif const paths_set& required_programs(void) const; const std::string& required_user(void) const; const utils::datetime::delta& timeout(void) const; @@ -121,6 +124,9 @@ metadata_builder& set_required_disk_space(const utils::units::bytes&); metadata_builder& set_required_files(const paths_set&); metadata_builder& set_required_memory(const utils::units::bytes&); +#ifdef __FreeBSD__ + metadata_builder& set_required_modules(const strings_set&); +#endif metadata_builder& set_required_programs(const paths_set&); metadata_builder& set_required_user(const std::string&); metadata_builder& set_string(const std::string&, const std::string&); diff --git a/contrib/kyua/model/metadata.cpp b/contrib/kyua/model/metadata.cpp --- a/contrib/kyua/model/metadata.cpp +++ b/contrib/kyua/model/metadata.cpp @@ -256,6 +256,9 @@ tree.define< bytes_node >("required_disk_space"); tree.define< paths_set_node >("required_files"); tree.define< bytes_node >("required_memory"); +#ifdef __FreeBSD__ + tree.define< config::strings_set_node >("required_modules"); +#endif tree.define< paths_set_node >("required_programs"); tree.define< user_node >("required_user"); tree.define< delta_node >("timeout"); @@ -282,6 +285,9 @@ tree.set< bytes_node >("required_disk_space", units::bytes(0)); tree.set< paths_set_node >("required_files", model::paths_set()); tree.set< bytes_node >("required_memory", units::bytes(0)); +#ifdef __FreeBSD__ + tree.set< config::strings_set_node >("required_modules", model::strings_set()); +#endif tree.set< paths_set_node >("required_programs", model::paths_set()); tree.set< user_node >("required_user", ""); // TODO(jmmv): We shouldn't be setting a default timeout like this. See @@ -597,6 +603,22 @@ } +#ifdef __FreeBSD__ +/// Returns the list of modules needed by the test. +/// +/// \return Set of strings. +const model::strings_set& +model::metadata::required_modules(void) const +{ + if (_pimpl->props.is_set("required_modules")) { + return _pimpl->props.lookup< config::strings_set_node >("required_modules"); + } else { + return get_defaults().lookup< config::strings_set_node >("required_modules"); + } +} +#endif + + /// Returns the list of programs needed by the test. /// /// \return Set of paths. diff --git a/tests/sys/fs/tarfs/tarfs_test.sh b/tests/sys/fs/tarfs/tarfs_test.sh --- a/tests/sys/fs/tarfs/tarfs_test.sh +++ b/tests/sys/fs/tarfs/tarfs_test.sh @@ -48,7 +48,6 @@ } tarfs_setup() { - kldload -n tarfs || atf_skip "This test requires tarfs and could not load it" mkdir "${mnt}" } @@ -60,6 +59,7 @@ tarfs_basic_head() { atf_set "descr" "Basic function test" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_basic_body() { tarfs_setup @@ -87,6 +87,7 @@ tarfs_basic_gnu_head() { atf_set "descr" "Basic function test using GNU tar" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "gtar" } tarfs_basic_gnu_body() { @@ -101,6 +102,7 @@ tarfs_notdir_device_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_notdir_device_body() { tarfs_setup @@ -121,6 +123,7 @@ tarfs_notdir_device_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_device_gnu_body() { @@ -135,6 +138,7 @@ tarfs_notdir_dot_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_notdir_dot_body() { tarfs_setup @@ -155,6 +159,7 @@ tarfs_notdir_dot_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_dot_gnu_body() { @@ -169,6 +174,7 @@ tarfs_notdir_dotdot_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_notdir_dotdot_body() { tarfs_setup @@ -189,6 +195,7 @@ tarfs_notdir_dotdot_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_dotdot_gnu_body() { @@ -203,6 +210,7 @@ tarfs_notdir_file_head() { atf_set "descr" "Regression test for PR 269519 and 269561" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_notdir_file_body() { tarfs_setup @@ -223,6 +231,7 @@ tarfs_notdir_file_gnu_head() { atf_set "descr" "Regression test for PR 269519 and 269561 using GNU tar" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "gtar" } tarfs_notdir_file_gnu_body() { @@ -237,6 +246,7 @@ tarfs_emptylink_head() { atf_set "descr" "Regression test for PR 277360: empty link target" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_emptylink_body() { tarfs_setup @@ -256,6 +266,7 @@ tarfs_linktodir_head() { atf_set "descr" "Regression test for PR 277360: link to directory" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_linktodir_body() { tarfs_setup @@ -276,6 +287,7 @@ tarfs_linktononexistent_head() { atf_set "descr" "Regression test for PR 277360: link to nonexistent target" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_linktononexistent_body() { tarfs_setup @@ -293,6 +305,7 @@ tarfs_checksum_head() { atf_set "descr" "Verify that the checksum covers header padding" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_checksum_body() { tarfs_setup @@ -313,6 +326,7 @@ tarfs_long_names_head() { atf_set "descr" "Verify that tarfs supports long file names" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_long_names_body() { tarfs_setup @@ -337,6 +351,7 @@ tarfs_long_paths_head() { atf_set "descr" "Verify that tarfs supports long paths" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" } tarfs_long_paths_body() { tarfs_setup @@ -361,6 +376,7 @@ tarfs_git_archive_head() { atf_set "descr" "Verify that tarfs supports archives created by git" atf_set "require.user" "root" + atf_set "require.modules" "tarfs" atf_set "require.progs" "git" } tarfs_git_archive_body() { diff --git a/tests/sys/net/if_wg.sh b/tests/sys/net/if_wg.sh --- a/tests/sys/net/if_wg.sh +++ b/tests/sys/net/if_wg.sh @@ -34,6 +34,7 @@ { atf_set descr 'Create a wg(4) tunnel over an epair and pass traffic between jails' atf_set require.user root + atf_set require.modules if_wg } wg_basic_body() @@ -41,8 +42,6 @@ local epair pri1 pri2 pub1 pub2 wg1 wg2 local endpoint1 endpoint2 tunnel1 tunnel2 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -97,6 +96,7 @@ { atf_set descr 'Create a wg(4) tunnel over an epair and pass traffic between jails with netmap' atf_set require.user root + atf_set require.modules if_wg netmap } wg_basic_netmap_body() @@ -105,9 +105,6 @@ local endpoint1 endpoint2 tunnel1 tunnel2 tunnel3 tunnel4 local pid status - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - kldload -n netmap || atf_skip "This test requires netmap and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -190,6 +187,7 @@ { atf_set descr 'Create a wg(4) interface with a shared pubkey between device and a peer' atf_set require.user root + atf_set require.modules if_wg } wg_key_peerdev_shared_body() @@ -197,8 +195,6 @@ local epair pri1 pub1 wg1 local endpoint1 tunnel1 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) endpoint1=192.168.2.1 @@ -238,8 +234,6 @@ local epair pri1 pub1 pri2 wg1 wg2 local endpoint1 tunnel1 - kldload -n if_wg || atf_skip "This test requires if_wg and could not load it" - pri1=$(wg genkey) pri2=$(wg genkey) @@ -283,6 +277,7 @@ { atf_set descr 'Create a wg(4) tunnel without epairs and pass traffic between jails' atf_set require.user root + atf_set require.modules if_wg } wg_vnet_parent_routing_body() @@ -290,8 +285,6 @@ local pri1 pri2 pub1 pub2 wg1 wg2 local tunnel1 tunnel2 - kldload -n if_wg - pri1=$(wg genkey) pri2=$(wg genkey) diff --git a/usr.bin/kyua/Makefile b/usr.bin/kyua/Makefile --- a/usr.bin/kyua/Makefile +++ b/usr.bin/kyua/Makefile @@ -13,7 +13,7 @@ PACKAGE= tests PROG_CXX= kyua SRCS= main.cpp -LIBADD= lutok sqlite3 +LIBADD= lutok sqlite3 util MAN= kyua-about.1 \ kyua-config.1 \