Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions atf-c++/atf-c++.3
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,16 @@ It is possible to get the path to the test case's source directory from any
of its three components by querying the
.Sq srcdir
configuration variable.
.Ss Requiring kernel modules
Aside from the
.Va require.kmods
meta-data variable available in the header only, one can also check for
additional kernel modules in the test case's body by using the
.Fn require_kmod
function, which takes the name of a single module.
If it is not found, the test case will be automatically skipped.
This feature is only available on
.Fx .
.Ss Requiring programs
Aside from the
.Va require.progs
Expand Down
7 changes: 7 additions & 0 deletions atf-c++/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,13 @@ impl::tc::cleanup(void)
{
}

void
impl::tc::require_kmod(const std::string& kmod)
const
{
atf_tc_require_kmod(kmod.c_str());
}

void
impl::tc::require_prog(const std::string& prog)
const
Expand Down
1 change: 1 addition & 0 deletions atf-c++/tests.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class tc {
virtual void body(void) const = 0;
virtual void cleanup(void) const;

void require_kmod(const std::string&) const;
void require_prog(const std::string&) const;

friend struct tc_impl;
Expand Down
4 changes: 4 additions & 0 deletions atf-c++/tests_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ ATF_TEST_CASE_BODY(atf_tp_writer)
expss << "descr: second test case\n";
CHECK;

w.tc_meta_data("require.kmods", "/nonexistent");
expss << "require.kmods: /nonexistent\n";
CHECK;

w.tc_meta_data("require.progs", "/bin/cp");
expss << "require.progs: /bin/cp\n";
CHECK;
Expand Down
15 changes: 15 additions & 0 deletions atf-c/atf-c.3
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
.Nm atf_tc_fail ,
.Nm atf_tc_fail_nonfatal ,
.Nm atf_tc_pass ,
.Nm atf_tc_require_kmod ,
.Nm atf_tc_require_prog ,
.Nm atf_tc_skip ,
.Nm atf_utils_cat_file ,
Expand Down Expand Up @@ -211,6 +212,10 @@
.Fa "void"
.Fc
.Ft void
.Fo atf_tc_require_kmod
.Fa "const char *kmod"
.Fc
.Ft void
.Fo atf_tc_require_prog
.Fa "const char *prog"
.Fc
Expand Down Expand Up @@ -434,6 +439,16 @@ It is possible to get the path to the test case's source directory from any
of its three components by querying the
.Sq srcdir
configuration variable.
.Ss Requiring kernel modules
Aside from the
.Va require.kmods
meta-data variable available in the header only, one can also check for
additional kernel modules in the test case's body by using the
.Fn atf_tc_require_kmod
function, which takes the name of a single kernel module.
If it is not found, the test case will be automatically skipped.
This feature is only available on
.Fx .
.Ss Requiring programs
Aside from the
.Va require.progs
Expand Down
68 changes: 68 additions & 0 deletions atf-c/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "atf-c/tc.h"

#include <sys/types.h>
#if defined(__FreeBSD__)
#include <sys/linker.h>
#include <sys/module.h>
#endif
#include <sys/stat.h>
#include <sys/uio.h>

Expand Down Expand Up @@ -103,6 +107,7 @@ static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
static void errno_test(struct context *, const char *, const size_t,
const int, const char *, const bool,
void (*)(struct context *, atf_dynstr_t *));
static atf_error_t check_kmod(struct context *, const char *);
static atf_error_t check_prog_in_dir(const char *, void *);
static atf_error_t check_prog(struct context *, const char *);

Expand Down Expand Up @@ -460,6 +465,54 @@ errno_test(struct context *ctx, const char *file, const size_t line,
}
}

#if defined(__FreeBSD__)
atf_error_t
check_kmod(struct context *ctx, const char *kmod)
{
struct kld_file_stat fstat = { .version = sizeof(fstat) };
struct module_stat mstat = { .version = sizeof(mstat) };
atf_dynstr_t reason;
size_t len = strlen(kmod);
int fid, mid;

for (fid = kldnext(0); fid > 0; fid = kldnext(fid)) {
if (kldstat(fid, &fstat) != 0)
continue;

if (strcmp(fstat.name, kmod) == 0)
goto done;

if (strncmp(fstat.name, kmod, 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, kmod) == 0)
goto done;
}
}
format_reason_fmt(&reason, NULL, 0,
"The required kmod %s is not loaded", kmod);
fail_requirement(ctx, &reason);

done:
return atf_no_error();
}
#else
atf_error_t
check_kmod(struct context *ctx, const char *kmod ATF_DEFS_ATTRIBUTE_UNUSED)
{
atf_dynstr_t reason;

format_reason_fmt(&reason, NULL, 0,
"This API is only available on FreeBSD");
fail_requirement(ctx, &reason);
return atf_no_error();
}
#endif

struct prog_found_pair {
const char *prog;
bool found;
Expand Down Expand Up @@ -833,6 +886,7 @@ static void _atf_tc_fail_check(struct context *, const char *, const size_t,
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;
static void _atf_tc_require_kmod(struct context *, const char *);
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;
Expand Down Expand Up @@ -912,6 +966,12 @@ _atf_tc_pass(struct context *ctx)
UNREACHABLE;
}

static void
_atf_tc_require_kmod(struct context *ctx, const char *prog)
{
check_fatal_error(check_kmod(ctx, prog));
}

static void
_atf_tc_require_prog(struct context *ctx, const char *prog)
{
Expand Down Expand Up @@ -1158,6 +1218,14 @@ atf_tc_pass(void)
_atf_tc_pass(&Current);
}

void
atf_tc_require_kmod(const char *kmod)
{
PRE(Current.tc != NULL);

_atf_tc_require_kmod(&Current, kmod);
}

void
atf_tc_require_prog(const char *prog)
{
Expand Down
1 change: 1 addition & 0 deletions atf-c/tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ void atf_tc_fail_nonfatal(const char *, ...)
ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2);
void atf_tc_pass(void)
ATF_DEFS_ATTRIBUTE_NORETURN;
void atf_tc_require_kmod(const char *);
void atf_tc_require_prog(const char *);
void atf_tc_skip(const char *, ...)
ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2)
Expand Down
32 changes: 32 additions & 0 deletions atf-c/tc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,34 @@ ATF_TC_BODY(config, tcin)
atf_tc_fini(&tc);
}

#if defined(__FreeBSD__)
ATF_TC(require_kmod_basic);
ATF_TC_HEAD(require_kmod_basic, tc)
{
atf_tc_set_md_var(tc, "descr",
"atf_require_kmod: ensures that a test continues if the target kmod "
"is found.");
}
ATF_TC_BODY(require_kmod_basic, tc)
{
#if 0
atf_tc_require_kmod("kernel");
#endif
}

ATF_TC(require_kmod_negative);
ATF_TC_HEAD(require_kmod_negative, tc)
{
atf_tc_set_md_var(tc, "descr",
"atf_require_kmod: skips test if the target kmod is not found.");
}
ATF_TC_BODY(require_kmod_negative, tc)
{
atf_tc_expect_fail("This should fail.");
atf_tc_require_kmod("nonexistent");
}
#endif

ATF_TC(require_prog_absolute);
ATF_TC_HEAD(require_prog_absolute, tc)
{
Expand Down Expand Up @@ -225,6 +253,10 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, init_pack);
ATF_TP_ADD_TC(tp, vars);
ATF_TP_ADD_TC(tp, config);
#if defined(__FreeBSD__)
ATF_TP_ADD_TC(tp, require_kmod_basic);
ATF_TP_ADD_TC(tp, require_kmod_negative);
#endif
ATF_TP_ADD_TC(tp, require_prog_absolute);
ATF_TP_ADD_TC(tp, require_prog_negative_absolute);
ATF_TP_ADD_TC(tp, require_prog_negative_nonabsolute);
Expand Down
2 changes: 2 additions & 0 deletions atf-sh/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
atf-check
atf-sh
libatf-sh.subr
Kyuafile
File renamed without changes.
30 changes: 30 additions & 0 deletions atf-sh/Makefile.am.inc
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,20 @@ atf_sh_atf_sh_LDADD = $(ATF_CXX_LIBS)
dist_man_MANS += atf-sh/atf-sh.1

atf_sh_DATA = atf-sh/libatf-sh.subr
libatf_subr_sources = atf-sh/libatf-sh/common.subr
if FreeBSD
libatf_subr_sources += atf-sh/libatf-sh/FreeBSD.subr
else
libatf_subr_sources += atf-sh/libatf-sh/os_stubs.subr
endif
atf_shdir = $(pkgdatadir)
EXTRA_DIST += $(atf_sh_DATA)

CLEANFILES += atf-sh/libatf-sh.subr
atf-sh/libatf-sh.subr:
$(AM_V_GEN)cat ${libatf_subr_sources} > atf-sh/libatf-sh.subr.tmp; \
mv atf-sh/libatf-sh.subr.tmp atf-sh/libatf-sh.subr

dist_man_MANS += atf-sh/atf-sh.3

atf_aclocal_DATA += atf-sh/atf-sh.m4
Expand All @@ -60,6 +71,16 @@ atf-sh/atf-sh.pc: $(srcdir)/atf-sh/atf-sh.pc.in Makefile
mv atf-sh/atf-sh.pc.tmp atf-sh/atf-sh.pc

tests_atf_sh_DATA = atf-sh/Kyuafile
CLEANFILES += atf-sh/Kyuafile
EXTRA_DIST += atf-sh/Kyuafile.in
atf-sh/Kyuafile: $(srcdir)/atf-sh/Kyuafile.in Makefile
$(AM_V_GEN)test -d atf-sh || mkdir -p atf-sh; \
cat $(srcdir)/atf-sh/Kyuafile.in > atf-sh/Kyuafile.tmp
if FreeBSD
$(AM_V_GEN)printf 'atf_test_program{name="kmod_test"}\n' >> atf-sh/Kyuafile.tmp
endif
$(AM_V_GEN)mv atf-sh/Kyuafile.tmp atf-sh/Kyuafile

tests_atf_shdir = $(pkgtestsdir)/atf-sh
EXTRA_DIST += $(tests_atf_sh_DATA)

Expand Down Expand Up @@ -91,6 +112,15 @@ atf-sh/config_test: $(srcdir)/atf-sh/config_test.sh
$(AM_V_GEN)src="$(srcdir)/atf-sh/config_test.sh"; \
dst="atf-sh/config_test"; $(BUILD_SH_TP)

if FreeBSD
tests_atf_sh_SCRIPTS += atf-sh/kmod_test
CLEANFILES += atf-sh/kmod_test
EXTRA_DIST += atf-sh/kmod_test.sh
atf-sh/kmod_test: $(srcdir)/atf-sh/kmod_test.sh
$(AM_V_GEN)src="$(srcdir)/atf-sh/kmod_test.sh"; \
dst="atf-sh/kmod_test"; $(BUILD_SH_TP)
endif

tests_atf_sh_SCRIPTS += atf-sh/integration_test
CLEANFILES += atf-sh/integration_test
EXTRA_DIST += atf-sh/integration_test.sh
Expand Down
13 changes: 12 additions & 1 deletion atf-sh/atf-sh.3
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
.\" 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.
.Dd January 27, 2021
.Dd May 11, 2025
.Dt ATF-SH 3
.Os
.Sh NAME
Expand All @@ -42,6 +42,7 @@
.Nm atf_get ,
.Nm atf_get_srcdir ,
.Nm atf_pass ,
.Nm atf_require_kmod ,
.Nm atf_require_prog ,
.Nm atf_set ,
.Nm atf_skip ,
Expand Down Expand Up @@ -87,6 +88,8 @@
.Qq var_name
.Nm atf_get_srcdir
.Nm atf_pass
.Nm atf_require_kmod
.Qq kmod_name
.Nm atf_require_prog
.Qq prog_name
.Nm atf_set
Expand Down Expand Up @@ -202,6 +205,14 @@ function.
It is interesting to note that this can be used inside
.Nm atf_init_test_cases
to silently include additional helper files from the source directory.
.Ss Requiring kernel modules
Aside from the
.Va require.kmods
meta-data variable available in the header only, one can also check for
additional kernel modules in the test case's body by using the
.Nm atf_require_kmod
function, which takes the name of a single kernel module.
If it is not found, the test case will be automatically skipped.
.Ss Requiring programs
Aside from the
.Va require.progs
Expand Down
Loading
Loading