Page MenuHomeFreeBSD

D42350.id135010.diff
No OneTemporary

D42350.id135010.diff

diff --git a/contrib/kyua/Makefile.am b/contrib/kyua/Makefile.am
--- a/contrib/kyua/Makefile.am
+++ b/contrib/kyua/Makefile.am
@@ -59,6 +59,7 @@
include drivers/Makefile.am.inc
include engine/Makefile.am.inc
include examples/Makefile.am.inc
+include freebsd/Makefile.am.inc
include integration/Makefile.am.inc
include misc/Makefile.am.inc
include model/Makefile.am.inc
@@ -68,7 +69,7 @@
bin_PROGRAMS = kyua
kyua_SOURCES = main.cpp
kyua_CXXFLAGS = $(CLI_CFLAGS) $(ENGINE_CFLAGS) $(UTILS_CFLAGS)
-kyua_LDADD = $(CLI_LIBS) $(ENGINE_LIBS) $(UTILS_LIBS)
+kyua_LDADD = $(CLI_LIBS) $(ENGINE_LIBS) $(FREEBSD_LIBS) $(UTILS_LIBS)
CHECK_ENVIRONMENT = KYUA_CONFDIR="/non-existent" \
KYUA_DOCDIR="$(abs_top_srcdir)" \
diff --git a/contrib/kyua/cli/cmd_config_test.cpp b/contrib/kyua/cli/cmd_config_test.cpp
--- a/contrib/kyua/cli/cmd_config_test.cpp
+++ b/contrib/kyua/cli/cmd_config_test.cpp
@@ -61,6 +61,7 @@
{
config::tree user_config = engine::default_config();
user_config.set_string("architecture", "the-architecture");
+ user_config.set_string("execenv", "the-env");
user_config.set_string("parallelism", "128");
user_config.set_string("platform", "the-platform");
//user_config.set_string("unprivileged_user", "");
@@ -83,12 +84,13 @@
cmdline::ui_mock ui;
ATF_REQUIRE_EQ(EXIT_SUCCESS, cmd.main(&ui, args, fake_config()));
- ATF_REQUIRE_EQ(5, ui.out_log().size());
+ ATF_REQUIRE_EQ(6, ui.out_log().size());
ATF_REQUIRE_EQ("architecture = the-architecture", ui.out_log()[0]);
- ATF_REQUIRE_EQ("parallelism = 128", ui.out_log()[1]);
- ATF_REQUIRE_EQ("platform = the-platform", ui.out_log()[2]);
- ATF_REQUIRE_EQ("test_suites.foo.bar = first", ui.out_log()[3]);
- ATF_REQUIRE_EQ("test_suites.foo.baz = second", ui.out_log()[4]);
+ ATF_REQUIRE_EQ("execenv = the-env", ui.out_log()[1]);
+ ATF_REQUIRE_EQ("parallelism = 128", ui.out_log()[2]);
+ ATF_REQUIRE_EQ("platform = the-platform", ui.out_log()[3]);
+ ATF_REQUIRE_EQ("test_suites.foo.bar = first", ui.out_log()[4]);
+ ATF_REQUIRE_EQ("test_suites.foo.baz = second", ui.out_log()[5]);
ATF_REQUIRE(ui.err_log().empty());
}
diff --git a/contrib/kyua/configure.ac b/contrib/kyua/configure.ac
--- a/contrib/kyua/configure.ac
+++ b/contrib/kyua/configure.ac
@@ -169,5 +169,6 @@
AM_CONDITIONAL(TARGET_SRCDIR_EMPTY, [test -z "${target_srcdir}"])
AC_SUBST([target_srcdir])
+AM_CONDITIONAL([FreeBSD], [test "$(uname -o)" = "FreeBSD"])
AC_OUTPUT
diff --git a/contrib/kyua/drivers/report_junit_test.cpp b/contrib/kyua/drivers/report_junit_test.cpp
--- a/contrib/kyua/drivers/report_junit_test.cpp
+++ b/contrib/kyua/drivers/report_junit_test.cpp
@@ -63,6 +63,8 @@
"allowed_architectures is empty\n"
"allowed_platforms is empty\n"
"description is empty\n"
+ "execenv is empty\n"
+ "execenv_jail is empty\n"
"has_cleanup = false\n"
"is_exclusive = false\n"
"required_configs is empty\n"
@@ -80,6 +82,8 @@
"allowed_architectures is empty\n"
"allowed_platforms is empty\n"
"description = Textual description\n"
+ "execenv is empty\n"
+ "execenv_jail is empty\n"
"has_cleanup = false\n"
"is_exclusive = false\n"
"required_configs is empty\n"
@@ -199,6 +203,8 @@
.add_allowed_architecture("arch1")
.add_allowed_platform("platform1")
.set_description("This is a test")
+ .set_execenv("jail")
+ .set_execenv_jail("vnet")
.set_has_cleanup(true)
.set_is_exclusive(true)
.add_required_config("config1")
@@ -215,6 +221,8 @@
+ "allowed_architectures = arch1\n"
+ "allowed_platforms = platform1\n"
+ "description = This is a test\n"
+ + "execenv = jail\n"
+ + "execenv_jail = vnet\n"
+ "has_cleanup = true\n"
+ "is_exclusive = true\n"
+ "required_configs = config1\n"
diff --git a/contrib/kyua/engine/Makefile.am.inc b/contrib/kyua/engine/Makefile.am.inc
--- a/contrib/kyua/engine/Makefile.am.inc
+++ b/contrib/kyua/engine/Makefile.am.inc
@@ -153,3 +153,5 @@
engine_scheduler_test_CXXFLAGS = $(ENGINE_CFLAGS) $(ATF_CXX_CFLAGS)
engine_scheduler_test_LDADD = $(ENGINE_LIBS) $(ATF_CXX_LIBS)
endif
+
+include engine/execenv/Makefile.am.inc
diff --git a/contrib/kyua/engine/atf.cpp b/contrib/kyua/engine/atf.cpp
--- a/contrib/kyua/engine/atf.cpp
+++ b/contrib/kyua/engine/atf.cpp
@@ -39,6 +39,7 @@
#include "engine/atf_list.hpp"
#include "engine/atf_result.hpp"
#include "engine/exceptions.hpp"
+#include "engine/execenv/execenv.hpp"
#include "model/test_case.hpp"
#include "model/test_program.hpp"
#include "model/test_result.hpp"
@@ -54,6 +55,7 @@
#include "utils/stream.hpp"
namespace config = utils::config;
+namespace execenv = engine::execenv;
namespace fs = utils::fs;
namespace process = utils::process;
@@ -190,7 +192,10 @@
args.push_back(F("-r%s") % (control_directory / result_name));
args.push_back(test_case_name);
- process::exec(test_program.absolute_path(), args);
+
+ auto e = execenv::get(test_program, test_case_name);
+ e->init();
+ e->exec(args);
}
@@ -219,7 +224,9 @@
}
args.push_back(F("%s:cleanup") % test_case_name);
- process::exec(test_program.absolute_path(), args);
+
+ auto e = execenv::get(test_program, test_case_name);
+ e->exec(args);
}
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
@@ -121,6 +121,10 @@
mdbuilder.set_string("has_cleanup", value);
} else if (name == "require.arch") {
mdbuilder.set_string("allowed_architectures", value);
+ } else if (name == "execenv") {
+ mdbuilder.set_string("execenv", value);
+ } else if (name == "execenv.jail") {
+ mdbuilder.set_string("execenv_jail", value);
} else if (name == "require.config") {
mdbuilder.set_string("required_configs", value);
} else if (name == "require.files") {
diff --git a/contrib/kyua/engine/config.cpp b/contrib/kyua/engine/config.cpp
--- a/contrib/kyua/engine/config.cpp
+++ b/contrib/kyua/engine/config.cpp
@@ -35,6 +35,7 @@
#include <stdexcept>
#include "engine/exceptions.hpp"
+#include "engine/execenv/execenv.hpp"
#include "utils/config/exceptions.hpp"
#include "utils/config/parser.hpp"
#include "utils/config/tree.ipp"
@@ -43,6 +44,7 @@
#include "utils/text/operations.ipp"
namespace config = utils::config;
+namespace execenv = engine::execenv;
namespace fs = utils::fs;
namespace passwd = utils::passwd;
namespace text = utils::text;
@@ -59,6 +61,7 @@
init_tree(config::tree& tree)
{
tree.define< config::string_node >("architecture");
+ tree.define< config::strings_set_node >("execenv");
tree.define< config::positive_int_node >("parallelism");
tree.define< config::string_node >("platform");
tree.define< engine::user_node >("unprivileged_user");
@@ -74,6 +77,14 @@
set_defaults(config::tree& tree)
{
tree.set< config::string_node >("architecture", KYUA_ARCHITECTURE);
+
+ std::set< std::string > supported;
+ for (auto em : execenv::execenvs())
+ if (em->is_supported())
+ supported.insert(em->name());
+ supported.insert("host");
+ tree.set< config::strings_set_node >("execenv", supported);
+
// TODO(jmmv): Automatically derive this from the number of CPUs in the
// machine and forcibly set to a value greater than 1. Still testing
// the new parallel implementation as of 2015-02-27 though.
@@ -229,6 +240,13 @@
{
config::tree tree(false);
init_tree(tree);
+
+ // Tests of Kyua itself tend to use an empty config, and they want
+ // to allow running usual host based test cases.
+ std::set< std::string > supported;
+ supported.insert("host");
+ tree.set< config::strings_set_node >("execenv", supported);
+
return tree;
}
diff --git a/contrib/kyua/engine/execenv/Makefile.am.inc b/contrib/kyua/engine/execenv/Makefile.am.inc
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/engine/execenv/Makefile.am.inc
@@ -0,0 +1,32 @@
+# Copyright 2024 The Kyua Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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.
+
+libengine_a_SOURCES += engine/execenv/execenv.hpp
+libengine_a_SOURCES += engine/execenv/execenv.cpp
+libengine_a_SOURCES += engine/execenv/execenv_host.hpp
+libengine_a_SOURCES += engine/execenv/execenv_host.cpp
diff --git a/contrib/kyua/engine/execenv/execenv.hpp b/contrib/kyua/engine/execenv/execenv.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/engine/execenv/execenv.hpp
@@ -0,0 +1,144 @@
+// Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file engine/execenv/execenv.hpp
+/// Execution environment subsystem interface.
+
+#if !defined(ENGINE_EXECENV_EXECENV_HPP)
+#define ENGINE_EXECENV_EXECENV_HPP
+
+#include "model/test_program.hpp"
+#include "utils/optional.ipp"
+#include "utils/process/operations_fwd.hpp"
+
+using utils::process::args_vector;
+using utils::optional;
+
+namespace engine {
+namespace execenv {
+
+/// Abstract interface of an execution environment.
+class interface {
+protected:
+ const model::test_program& _test_program;
+ const std::string& _test_case_name;
+
+public:
+ /// Constructor.
+ ///
+ /// \param program The test program.
+ /// \param test_case_name Name of the test case.
+ interface(const model::test_program& test_program,
+ const std::string& test_case_name) :
+ _test_program(test_program),
+ _test_case_name(test_case_name)
+ {}
+
+ /// Destructor.
+ virtual ~interface() {}
+
+ /// Initializes execution environment.
+ ///
+ /// It's expected to be called inside a fork which runs
+ /// scheduler::interface::exec_test(), so we can fail a test fast if its
+ /// execution environment setup fails, and test execution could use the
+ /// configured proc environment, if expected.
+ virtual void init() const = 0;
+
+ /// Cleanups or removes execution environment.
+ ///
+ /// It's expected to be called inside a fork for execenv cleanup.
+ virtual void cleanup() const = 0;
+
+ /// Executes a test within the execution environment.
+ ///
+ /// It's expected to be called inside a fork which runs
+ /// scheduler::interface::exec_test() or exec_cleanup().
+ ///
+ /// \param args The arguments to pass to the binary.
+ virtual void exec(const args_vector& args) const UTILS_NORETURN = 0;
+};
+
+
+/// Abstract interface of an execution environment manager.
+class manager {
+public:
+ /// Destructor.
+ virtual ~manager() {}
+
+ /// Returns name of an execution environment.
+ virtual const std::string& name() const = 0;
+
+ /// Returns whether this execution environment is actually supported.
+ ///
+ /// It can be compile time and/or runtime check.
+ virtual bool is_supported() const = 0;
+
+ /// Returns execution environment for a test.
+ ///
+ /// It checks if the given test is designed for this execution environment.
+ ///
+ /// \param program The test program.
+ /// \param test_case_name Name of the test case.
+ ///
+ /// \return An execenv object if the test conforms, or none.
+ virtual std::unique_ptr< interface > probe(
+ const model::test_program& test_program,
+ const std::string& test_case_name) const = 0;
+
+ // TODO: execenv related extra metadata could be provided by a manager
+ // not to know how exactly and where it should be added to the kyua
+};
+
+
+/// Registers an execution environment.
+///
+/// \param manager Execution environment manager.
+void register_execenv(const std::shared_ptr< manager > manager);
+
+
+/// Returns list of registered execenv managers, except default host one.
+///
+/// \return A vector of pointers to execenv managers.
+const std::vector< std::shared_ptr< manager> > execenvs();
+
+
+/// Returns execution environment for a test case.
+///
+/// \param program The test program.
+/// \param test_case_name Name of the test case.
+///
+/// \return An execution environment of a test.
+std::unique_ptr< execenv::interface > get(
+ const model::test_program& test_program,
+ const std::string& test_case_name);
+
+
+} // namespace execenv
+} // namespace engine
+
+#endif // !defined(ENGINE_EXECENV_EXECENV_HPP)
diff --git a/contrib/kyua/engine/execenv/execenv.cpp b/contrib/kyua/engine/execenv/execenv.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/engine/execenv/execenv.cpp
@@ -0,0 +1,70 @@
+// Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "engine/execenv/execenv.hpp"
+
+#include "engine/execenv/execenv_host.hpp"
+
+namespace execenv = engine::execenv;
+
+using utils::none;
+
+
+/// List of registered execution environments, except default host one.
+///
+/// Use register_execenv() to add an entry to this global list.
+static std::vector< std::shared_ptr< execenv::manager > >
+ execenv_managers;
+
+
+void
+execenv::register_execenv(const std::shared_ptr< execenv::manager > manager)
+{
+ execenv_managers.push_back(manager);
+}
+
+
+const std::vector< std::shared_ptr< execenv::manager> >
+execenv::execenvs()
+{
+ return execenv_managers;
+}
+
+
+std::unique_ptr< execenv::interface >
+execenv::get(const model::test_program& test_program,
+ const std::string& test_case_name)
+{
+ for (auto m : execenv_managers) {
+ auto e = m->probe(test_program, test_case_name);
+ if (e != nullptr)
+ return e;
+ }
+
+ return std::unique_ptr< execenv::interface >(
+ new execenv::execenv_host(test_program, test_case_name));
+}
diff --git a/contrib/kyua/engine/execenv/execenv_host.hpp b/contrib/kyua/engine/execenv/execenv_host.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/engine/execenv/execenv_host.hpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file engine/execenv/execenv_host.hpp
+/// Default execution environment.
+
+#if !defined(ENGINE_EXECENV_EXECENV_HOST_HPP)
+#define ENGINE_EXECENV_EXECENV_HOST_HPP
+
+#include "engine/execenv/execenv.hpp"
+
+#include "utils/process/operations_fwd.hpp"
+
+namespace execenv = engine::execenv;
+
+using utils::process::args_vector;
+
+namespace engine {
+namespace execenv {
+
+
+class execenv_host : public execenv::interface {
+public:
+ execenv_host(const model::test_program& test_program,
+ const std::string& test_case_name) :
+ execenv::interface(test_program, test_case_name)
+ {}
+
+ void init() const;
+ void cleanup() const;
+ void exec(const args_vector& args) const UTILS_NORETURN;
+};
+
+
+} // namespace execenv
+} // namespace engine
+
+#endif // !defined(ENGINE_EXECENV_EXECENV_HOST_HPP)
diff --git a/contrib/kyua/engine/execenv/execenv_host.cpp b/contrib/kyua/engine/execenv/execenv_host.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/engine/execenv/execenv_host.cpp
@@ -0,0 +1,51 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "engine/execenv/execenv_host.hpp"
+
+#include "utils/fs/path.hpp"
+#include "utils/process/operations.hpp"
+
+void
+execenv::execenv_host::init() const
+{
+ // nothing to do
+}
+
+
+void
+execenv::execenv_host::cleanup() const
+{
+ // nothing to do
+}
+
+
+void
+execenv::execenv_host::exec(const args_vector& args) const
+{
+ utils::process::exec(_test_program.absolute_path(), args);
+}
diff --git a/contrib/kyua/engine/plain.cpp b/contrib/kyua/engine/plain.cpp
--- a/contrib/kyua/engine/plain.cpp
+++ b/contrib/kyua/engine/plain.cpp
@@ -34,6 +34,7 @@
#include <cstdlib>
+#include "engine/execenv/execenv.hpp"
#include "model/test_case.hpp"
#include "model/test_program.hpp"
#include "model/test_result.hpp"
@@ -47,6 +48,7 @@
#include "utils/sanity.hpp"
namespace config = utils::config;
+namespace execenv = engine::execenv;
namespace fs = utils::fs;
namespace process = utils::process;
@@ -104,7 +106,10 @@
}
process::args_vector args;
- process::exec(test_program.absolute_path(), args);
+
+ auto e = execenv::get(test_program, test_case_name);
+ e->init();
+ e->exec(args);
}
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
@@ -100,6 +100,34 @@
}
+/// Checks if test's execenv matches the user configuration.
+///
+/// \param execenv Execution environment name a test is designed for.
+/// \param user_config Runtime user configuration.
+///
+/// \return Empty if the execenv is in the list or an error message otherwise.
+static std::string
+check_execenv(const std::string& execenv, const config::tree& user_config)
+{
+ std::string name = execenv;
+ if (name.empty())
+ name = "host"; // if a test claims nothing then it's host based
+
+ std::set< std::string > execenvs;
+ try {
+ execenvs = user_config.lookup< config::strings_set_node >("execenv");
+ } catch (const config::unknown_key_error&) {
+ // okay, user config does not define it, empty set then
+ }
+
+ if (execenvs.find(name) == execenvs.end())
+ return F("'%s' execenv is not supported or not allowed by "
+ "the runtime user configuration") % name;
+
+ return "";
+}
+
+
/// Checks if the allowed platforms match the current architecture.
///
/// \param allowed_platforms Set of allowed platforms.
@@ -263,6 +291,10 @@
if (!reason.empty())
return reason;
+ reason = check_execenv(md.execenv(), cfg);
+ if (!reason.empty())
+ return reason;
+
reason = check_allowed_platforms(md.allowed_platforms(), cfg);
if (!reason.empty())
return reason;
diff --git a/contrib/kyua/engine/scheduler.hpp b/contrib/kyua/engine/scheduler.hpp
--- a/contrib/kyua/engine/scheduler.hpp
+++ b/contrib/kyua/engine/scheduler.hpp
@@ -262,6 +262,7 @@
extern utils::datetime::delta cleanup_timeout;
+extern utils::datetime::delta execenv_cleanup_timeout;
extern utils::datetime::delta list_timeout;
diff --git a/contrib/kyua/engine/scheduler.cpp b/contrib/kyua/engine/scheduler.cpp
--- a/contrib/kyua/engine/scheduler.cpp
+++ b/contrib/kyua/engine/scheduler.cpp
@@ -40,6 +40,7 @@
#include "engine/config.hpp"
#include "engine/exceptions.hpp"
+#include "engine/execenv/execenv.hpp"
#include "engine/requirements.hpp"
#include "model/context.hpp"
#include "model/metadata.hpp"
@@ -68,6 +69,7 @@
namespace config = utils::config;
namespace datetime = utils::datetime;
+namespace execenv = engine::execenv;
namespace executor = utils::process::executor;
namespace fs = utils::fs;
namespace logging = utils::logging;
@@ -87,6 +89,10 @@
datetime::delta scheduler::cleanup_timeout(60, 0);
+/// Timeout for the test case execenv cleanup operation.
+datetime::delta scheduler::execenv_cleanup_timeout(60, 0);
+
+
/// Timeout for the test case listing operation.
///
/// TODO(jmmv): This is here only for testing purposes. Maybe we should expose
@@ -206,6 +212,18 @@
/// denote that no further attempts shall be made at cleaning this up.
bool needs_cleanup;
+ /// Whether this test case still needs to have its execenv cleanup executed.
+ ///
+ /// This is set externally when the cleanup routine is actually invoked to
+ /// denote that no further attempts shall be made at cleaning this up.
+ bool needs_execenv_cleanup;
+
+ /// Original PID of the test case subprocess.
+ ///
+ /// This is used for the cleanup upon termination by a signal, to reap the
+ /// leftovers and form missing exit_handle.
+ int pid;
+
/// The exit_handle for this test once it has completed.
///
/// This is set externally when the test case has finished, as we need this
@@ -222,12 +240,14 @@
test_exec_data(const model::test_program_ptr test_program_,
const std::string& test_case_name_,
const std::shared_ptr< scheduler::interface > interface_,
- const config::tree& user_config_) :
+ const config::tree& user_config_,
+ const int pid_) :
exec_data(test_program_, test_case_name_),
- interface(interface_), user_config(user_config_)
+ interface(interface_), user_config(user_config_), pid(pid_)
{
const model::test_case& test_case = test_program->find(test_case_name);
needs_cleanup = test_case.get_metadata().has_cleanup();
+ needs_execenv_cleanup = test_case.get_metadata().has_execenv();
}
};
@@ -266,6 +286,40 @@
};
+/// Maintenance data held while a test execenv cleanup is being executed.
+///
+/// Instances of this object are related to a previous test_exec_data, as
+/// cleanup routines can only exist once the test has been run.
+struct execenv_exec_data : public exec_data {
+ /// The exit handle of the test. This is necessary so that we can return
+ /// the correct exit_handle to the user of the scheduler.
+ executor::exit_handle body_exit_handle;
+
+ /// The final result of the test's body. This is necessary to compute the
+ /// right return value for a test with a cleanup routine: the body result is
+ /// respected if it is a "bad" result; else the result of the cleanup
+ /// routine is used if it has failed.
+ model::test_result body_result;
+
+ /// Constructor.
+ ///
+ /// \param test_program_ Test program data for this test case.
+ /// \param test_case_name_ Name of the test case.
+ /// \param body_exit_handle_ If not none, exit handle of the body
+ /// corresponding to the cleanup routine represented by this exec_data.
+ /// \param body_result_ If not none, result of the body corresponding to the
+ /// cleanup routine represented by this exec_data.
+ execenv_exec_data(const model::test_program_ptr test_program_,
+ const std::string& test_case_name_,
+ const executor::exit_handle& body_exit_handle_,
+ const model::test_result& body_result_) :
+ exec_data(test_program_, test_case_name_),
+ body_exit_handle(body_exit_handle_), body_result(body_result_)
+ {
+ }
+};
+
+
/// Shared pointer to exec_data.
///
/// We require this because we want exec_data to not be copyable, and thus we
@@ -492,6 +546,40 @@
};
+/// Functor to execute a test execenv cleanup in a child process.
+class run_execenv_cleanup {
+ /// Test program to execute.
+ const model::test_program _test_program;
+
+ /// Name of the test case to execute.
+ const std::string& _test_case_name;
+
+public:
+ /// Constructor.
+ ///
+ /// \param test_program Test program to execute.
+ /// \param test_case_name Name of the test case to execute.
+ run_execenv_cleanup(
+ const model::test_program_ptr test_program,
+ const std::string& test_case_name) :
+ _test_program(force_absolute_paths(*test_program)),
+ _test_case_name(test_case_name)
+ {
+ }
+
+ /// Body of the subprocess.
+ ///
+ /// \param control_directory The testcase directory where cleanup will be
+ /// run from.
+ void
+ operator()(const fs::path& /* control_directory */)
+ {
+ auto e = execenv::get(_test_program, _test_case_name);
+ e->cleanup();
+ }
+};
+
+
/// Obtains the right scheduler interface for a given test program.
///
/// \param name The name of the interface of the test program.
@@ -835,6 +923,22 @@
% test_data->test_case_name);
}
}
+
+ const test_exec_data_vector td = tests_needing_execenv_cleanup();
+
+ for (test_exec_data_vector::const_iterator iter = td.begin();
+ iter != td.end(); ++iter) {
+ const test_exec_data* test_data = *iter;
+
+ try {
+ sync_execenv_cleanup(test_data);
+ } catch (const std::runtime_error& e) {
+ LW(F("Failed to run execenv cleanup routine for %s:%s on abrupt "
+ "termination")
+ % test_data->test_program->relative_path()
+ % test_data->test_case_name);
+ }
+ }
}
/// Finds any pending exec_datas that correspond to tests needing cleanup.
@@ -856,6 +960,8 @@
if (test_data->needs_cleanup) {
tests_data.push_back(test_data);
test_data->needs_cleanup = false;
+ if (!test_data->exit_handle)
+ test_data->exit_handle = generic.reap(test_data->pid);
}
} catch (const std::bad_cast& e) {
// Do nothing for cleanup_exec_data objects.
@@ -865,6 +971,37 @@
return tests_data;
}
+ /// Finds any pending exec_datas that correspond to tests needing execenv
+ /// cleanup.
+ ///
+ /// \return The collection of test_exec_data objects that have their
+ /// specific execenv property set.
+ test_exec_data_vector
+ tests_needing_execenv_cleanup(void)
+ {
+ test_exec_data_vector tests_data;
+
+ for (exec_data_map::const_iterator iter = all_exec_data.begin();
+ iter != all_exec_data.end(); ++iter) {
+ const exec_data_ptr data = (*iter).second;
+
+ try {
+ test_exec_data* test_data = &dynamic_cast< test_exec_data& >(
+ *data.get());
+ if (test_data->needs_execenv_cleanup) {
+ tests_data.push_back(test_data);
+ test_data->needs_execenv_cleanup = false;
+ if (!test_data->exit_handle)
+ test_data->exit_handle = generic.reap(test_data->pid);
+ }
+ } catch (const std::bad_cast& e) {
+ // Do nothing for other objects.
+ }
+ }
+
+ return tests_data;
+ }
+
/// Cleans up a single test case synchronously.
///
/// \param test_data The data of the previously executed test case to be
@@ -926,6 +1063,61 @@
return handle;
}
+
+ /// Cleans up a single test case execenv synchronously.
+ ///
+ /// \param test_data The data of the previously executed test case to be
+ /// cleaned up.
+ void
+ sync_execenv_cleanup(const test_exec_data* test_data)
+ {
+ // The message in this result should never be seen by the user, but use
+ // something reasonable just in case it leaks and we need to pinpoint
+ // the call site.
+ model::test_result result(model::test_result_broken,
+ "Test case died abruptly");
+
+ const executor::exec_handle cleanup_handle = spawn_execenv_cleanup(
+ test_data->test_program, test_data->test_case_name,
+ test_data->exit_handle.get(), result);
+ generic.wait(cleanup_handle);
+ }
+
+ /// Forks and executes a test case execenv cleanup asynchronously.
+ ///
+ /// \param test_program The container test program.
+ /// \param test_case_name The name of the test case to run.
+ /// \param body_handle The exit handle of the test case's corresponding
+ /// body. The cleanup will be executed in the same context.
+ /// \param body_result The result of the test case's corresponding body.
+ ///
+ /// \return A handle for the background operation. Used to match the result
+ /// of the execution returned by wait_any() with this invocation.
+ executor::exec_handle
+ spawn_execenv_cleanup(const model::test_program_ptr test_program,
+ const std::string& test_case_name,
+ const executor::exit_handle& body_handle,
+ const model::test_result& body_result)
+ {
+ generic.check_interrupt();
+
+ LI(F("Spawning %s:%s (execenv cleanup)")
+ % test_program->absolute_path() % test_case_name);
+
+ const executor::exec_handle handle = generic.spawn_followup(
+ run_execenv_cleanup(test_program, test_case_name),
+ body_handle, execenv_cleanup_timeout);
+
+ const exec_data_ptr data(new execenv_exec_data(
+ test_program, test_case_name, body_handle, body_result));
+ LD(F("Inserting %s into all_exec_data (execenv cleanup)") % handle.pid());
+ INV_MSG(all_exec_data.find(handle.pid()) == all_exec_data.end(),
+ F("PID %s already in all_exec_data; not properly cleaned "
+ "up or reused too fast") % handle.pid());;
+ all_exec_data.insert(exec_data_map::value_type(handle.pid(), data));
+
+ return handle;
+ }
};
@@ -1115,7 +1307,7 @@
unprivileged_user);
const exec_data_ptr data(new test_exec_data(
- test_program, test_case_name, interface, user_config));
+ test_program, test_case_name, interface, user_config, handle.pid()));
LD(F("Inserting %s into all_exec_data") % handle.pid());
INV_MSG(
_pimpl->all_exec_data.find(handle.pid()) == _pimpl->all_exec_data.end(),
@@ -1150,6 +1342,8 @@
_pimpl->generic, handle);
optional< model::test_result > result;
+
+ // test itself
try {
test_exec_data* test_data = &dynamic_cast< test_exec_data& >(
*data.get());
@@ -1185,6 +1379,7 @@
// if the test's body reports a skip (because actions could have
// already been taken).
test_data->needs_cleanup = false;
+ test_data->needs_execenv_cleanup = false;
}
}
if (!result) {
@@ -1209,7 +1404,6 @@
_pimpl->spawn_cleanup(test_data->test_program,
test_data->test_case_name,
test_data->user_config, handle, result.get());
- test_data->needs_cleanup = false;
// TODO(jmmv): Chaining this call is ugly. We'd be better off by
// looping over terminated processes until we got a result suitable
@@ -1218,7 +1412,21 @@
// of test cases do not have cleanup routines.
return wait_any();
}
+
+ if (test_data->needs_execenv_cleanup) {
+ INV(test_case.get_metadata().has_execenv());
+ _pimpl->spawn_execenv_cleanup(test_data->test_program,
+ test_data->test_case_name,
+ handle, result.get());
+ test_data->needs_execenv_cleanup = false;
+ return wait_any();
+ }
} catch (const std::bad_cast& e) {
+ // ok, let's check for another type
+ }
+
+ // test cleanup
+ try {
const cleanup_exec_data* cleanup_data =
&dynamic_cast< const cleanup_exec_data& >(*data.get());
LD(F("Got %s from all_exec_data (cleanup)") % handle.original_pid());
@@ -1257,7 +1465,65 @@
_pimpl->all_exec_data.erase(handle.original_pid());
handle = cleanup_data->body_exit_handle;
+
+ const exec_data_map::iterator it = _pimpl->all_exec_data.find(
+ handle.original_pid());
+ if (it != _pimpl->all_exec_data.end()) {
+ exec_data_ptr d = (*it).second;
+ test_exec_data* test_data = &dynamic_cast< test_exec_data& >(
+ *d.get());
+ const model::test_case& test_case =
+ cleanup_data->test_program->find(cleanup_data->test_case_name);
+ test_data->needs_cleanup = false;
+
+ if (test_data->needs_execenv_cleanup) {
+ INV(test_case.get_metadata().has_execenv());
+ _pimpl->spawn_execenv_cleanup(cleanup_data->test_program,
+ cleanup_data->test_case_name,
+ handle, result.get());
+ test_data->needs_execenv_cleanup = false;
+ return wait_any();
+ }
+ }
+ } catch (const std::bad_cast& e) {
+ // ok, let's check for another type
}
+
+ // execenv cleanup
+ try {
+ const execenv_exec_data* execenv_data =
+ &dynamic_cast< const execenv_exec_data& >(*data.get());
+ LD(F("Got %s from all_exec_data (execenv cleanup)") % handle.original_pid());
+
+ const model::test_result& body_result = execenv_data->body_result;
+ if (body_result.good()) {
+ if (!handle.status()) {
+ result = model::test_result(model::test_result_broken,
+ "Test case execenv cleanup timed out");
+ } else {
+ if (!handle.status().get().exited() ||
+ handle.status().get().exitstatus() != EXIT_SUCCESS) {
+ result = model::test_result(
+ model::test_result_broken,
+ "Test case execenv cleanup did not terminate successfully"); // ?
+ } else {
+ result = body_result;
+ }
+ }
+ } else {
+ result = body_result;
+ }
+
+ LD(F("Removing %s from all_exec_data (execenv cleanup) in favor of %s")
+ % handle.original_pid()
+ % execenv_data->body_exit_handle.original_pid());
+ _pimpl->all_exec_data.erase(handle.original_pid());
+
+ handle = execenv_data->body_exit_handle;
+ } catch (const std::bad_cast& e) {
+ // ok, it was one of the types above
+ }
+
INV(result);
std::shared_ptr< result_handle::bimpl > result_handle_bimpl(
diff --git a/contrib/kyua/engine/tap.cpp b/contrib/kyua/engine/tap.cpp
--- a/contrib/kyua/engine/tap.cpp
+++ b/contrib/kyua/engine/tap.cpp
@@ -35,6 +35,7 @@
#include <cstdlib>
#include "engine/exceptions.hpp"
+#include "engine/execenv/execenv.hpp"
#include "engine/tap_parser.hpp"
#include "model/test_case.hpp"
#include "model/test_program.hpp"
@@ -48,6 +49,7 @@
#include "utils/sanity.hpp"
namespace config = utils::config;
+namespace execenv = engine::execenv;
namespace fs = utils::fs;
namespace process = utils::process;
@@ -151,7 +153,10 @@
}
process::args_vector args;
- process::exec(test_program.absolute_path(), args);
+
+ auto e = execenv::get(test_program, test_case_name);
+ e->init();
+ e->exec(args);
}
diff --git a/contrib/kyua/examples/kyua.conf b/contrib/kyua/examples/kyua.conf
--- a/contrib/kyua/examples/kyua.conf
+++ b/contrib/kyua/examples/kyua.conf
@@ -43,6 +43,9 @@
-- Name of the system architecture (aka processor type).
architecture = "x86_64"
+-- List of execution environments.
+execenv = "host jail"
+
-- Maximum number of jobs (such as test case runs) to execute concurrently.
parallelism = 16
diff --git a/contrib/kyua/freebsd/Makefile.am.inc b/contrib/kyua/freebsd/Makefile.am.inc
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/Makefile.am.inc
@@ -0,0 +1,46 @@
+# Copyright 2024 The Kyua Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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.
+
+FREEBSD_CFLAGS =
+FREEBSD_LIBS = libfreebsd.a
+
+noinst_LIBRARIES += libfreebsd.a
+libfreebsd_a_CPPFLAGS = -DGDB=\"$(GDB)\"
+libfreebsd_a_SOURCES = freebsd/main.hpp
+libfreebsd_a_SOURCES += freebsd/main.cpp
+libfreebsd_a_SOURCES += freebsd/execenv_jail.hpp
+libfreebsd_a_SOURCES += freebsd/execenv_jail_manager.hpp
+libfreebsd_a_SOURCES += freebsd/execenv_jail_manager.cpp
+
+if FreeBSD
+FREEBSD_LIBS += -ljail
+libfreebsd_a_SOURCES += freebsd/execenv_jail.cpp
+include freebsd/utils/Makefile.am.inc
+else
+libfreebsd_a_SOURCES += freebsd/execenv_jail_stub.cpp
+endif
diff --git a/contrib/kyua/freebsd/execenv_jail.hpp b/contrib/kyua/freebsd/execenv_jail.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/execenv_jail.hpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file freebsd/execenv_jail.hpp
+/// FreeBSD jail execution environment.
+
+#if !defined(FREEBSD_EXECENV_JAIL_HPP)
+#define FREEBSD_EXECENV_JAIL_HPP
+
+#include "engine/execenv/execenv.hpp"
+
+#include "utils/process/operations_fwd.hpp"
+
+namespace execenv = engine::execenv;
+
+using utils::process::args_vector;
+
+
+namespace freebsd {
+
+
+extern bool execenv_jail_supported;
+
+
+class execenv_jail : public execenv::interface {
+public:
+ execenv_jail(const model::test_program& test_program,
+ const std::string& test_case_name) :
+ execenv::interface(test_program, test_case_name)
+ {}
+
+ void init() const;
+ void cleanup() const;
+ void exec(const args_vector& args) const UTILS_NORETURN;
+};
+
+
+} // namespace freebsd
+
+#endif // !defined(FREEBSD_EXECENV_JAIL_HPP)
diff --git a/contrib/kyua/freebsd/execenv_jail.cpp b/contrib/kyua/freebsd/execenv_jail.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/execenv_jail.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "freebsd/execenv_jail.hpp"
+
+#include "freebsd/utils/jail.hpp"
+#include "model/metadata.hpp"
+#include "model/test_case.hpp"
+#include "utils/fs/path.hpp"
+
+using freebsd::utils::jail;
+
+
+namespace freebsd {
+
+
+bool execenv_jail_supported = true;
+
+
+void
+execenv_jail::init() const
+{
+ auto test_case = _test_program.find(_test_case_name);
+
+ jail().create(
+ jail().make_name(_test_program.absolute_path(), _test_case_name),
+ test_case.get_metadata().execenv_jail()
+ );
+}
+
+
+void
+execenv_jail::cleanup() const
+{
+ jail().remove(
+ jail().make_name(_test_program.absolute_path(), _test_case_name)
+ );
+}
+
+
+void
+execenv_jail::exec(const args_vector& args) const
+{
+ jail().exec(
+ jail().make_name(_test_program.absolute_path(), _test_case_name),
+ _test_program.absolute_path(),
+ args
+ );
+}
+
+
+} // namespace freebsd
diff --git a/contrib/kyua/freebsd/execenv_jail_manager.hpp b/contrib/kyua/freebsd/execenv_jail_manager.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/execenv_jail_manager.hpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file freebsd/execenv_jail_manager.hpp
+/// FreeBSD jail execution environment manager.
+
+#if !defined(FREEBSD_EXECENV_JAIL_MANAGER_HPP)
+#define FREEBSD_EXECENV_JAIL_MANAGER_HPP
+
+#include "engine/execenv/execenv.hpp"
+
+namespace execenv = engine::execenv;
+
+namespace freebsd {
+
+
+class execenv_jail_manager : public execenv::manager {
+public:
+ const std::string& name() const;
+ bool is_supported() const;
+ std::unique_ptr< execenv::interface > probe(
+ const model::test_program& test_program,
+ const std::string& test_case_name) const;
+};
+
+
+} // namespace freebsd
+
+#endif // !defined(FREEBSD_EXECENV_JAIL_MANAGER_HPP)
diff --git a/contrib/kyua/freebsd/execenv_jail_manager.cpp b/contrib/kyua/freebsd/execenv_jail_manager.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/execenv_jail_manager.cpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "freebsd/execenv_jail_manager.hpp"
+
+#include "model/metadata.hpp"
+#include "model/test_case.hpp"
+#include "freebsd/execenv_jail.hpp"
+
+static const std::string execenv_name = "jail";
+
+const std::string&
+freebsd::execenv_jail_manager::name() const
+{
+ return execenv_name;
+}
+
+
+bool
+freebsd::execenv_jail_manager::is_supported() const
+{
+ return freebsd::execenv_jail_supported;
+}
+
+
+std::unique_ptr< execenv::interface >
+freebsd::execenv_jail_manager::probe(
+ const model::test_program& test_program,
+ const std::string& test_case_name) const
+{
+ auto test_case = test_program.find(test_case_name);
+ if (test_case.get_metadata().execenv() != execenv_name)
+ return nullptr;
+
+ return std::unique_ptr< execenv::interface >(
+ new freebsd::execenv_jail(test_program, test_case_name)
+ );
+}
diff --git a/contrib/kyua/freebsd/execenv_jail_stub.cpp b/contrib/kyua/freebsd/execenv_jail_stub.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/execenv_jail_stub.cpp
@@ -0,0 +1,74 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "freebsd/execenv_jail.hpp"
+
+#include <iostream>
+
+#include "utils/process/operations_fwd.hpp"
+
+using utils::process::args_vector;
+
+
+static inline void requires_freebsd(void) UTILS_NORETURN;
+
+static inline void
+requires_freebsd(void)
+{
+ std::cerr << "execenv=\"jail\" requires FreeBSD with jail feature.\n";
+ std::exit(EXIT_FAILURE);
+}
+
+
+namespace freebsd {
+
+
+bool execenv_jail_supported = false;
+
+
+void
+execenv_jail::init() const
+{
+ requires_freebsd();
+}
+
+
+void
+execenv_jail::cleanup() const
+{
+ requires_freebsd();
+}
+
+
+void
+execenv_jail::exec(const args_vector&) const
+{
+ requires_freebsd();
+}
+
+
+} // namespace freebsd
diff --git a/contrib/kyua/freebsd/main.hpp b/contrib/kyua/freebsd/main.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/main.hpp
@@ -0,0 +1,40 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file freebsd/main.hpp
+/// FreeBSD related features initialization.
+
+#if !defined(FREEBSD_MAIN_HPP)
+#define FREEBSD_MAIN_HPP
+
+namespace freebsd {
+
+int main(const int argc, const char* const* const argv);
+
+} // namespace freebsd
+
+#endif // !defined(FREEBSD_MAIN_HPP)
diff --git a/contrib/kyua/freebsd/main.cpp b/contrib/kyua/freebsd/main.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/main.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "freebsd/main.hpp"
+
+#include "engine/execenv/execenv.hpp"
+#include "freebsd/execenv_jail_manager.hpp"
+
+namespace execenv = engine::execenv;
+
+/// FreeBSD related features initialization.
+///
+/// \param argc The number of arguments passed on the command line.
+/// \param argv NULL-terminated array containing the command line arguments.
+///
+/// \return 0 on success, some other integer on error.
+///
+/// \throw std::exception This throws any uncaught exception. Such exceptions
+/// are bugs, but we let them propagate so that the runtime will abort and
+/// dump core.
+int
+freebsd::main(const int, const char* const* const)
+{
+ execenv::register_execenv(
+ std::shared_ptr< execenv::manager >(new freebsd::execenv_jail_manager())
+ );
+
+ return 0;
+}
diff --git a/contrib/kyua/freebsd/utils/Makefile.am.inc b/contrib/kyua/freebsd/utils/Makefile.am.inc
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/utils/Makefile.am.inc
@@ -0,0 +1,30 @@
+# Copyright 2024 The Kyua Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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.
+
+libfreebsd_a_SOURCES += freebsd/utils/jail.hpp
+libfreebsd_a_SOURCES += freebsd/utils/jail.cpp
diff --git a/contrib/kyua/freebsd/utils/jail.hpp b/contrib/kyua/freebsd/utils/jail.hpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/utils/jail.hpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
+
+/// \file freebsd/utils/jail.hpp
+/// FreeBSD jail utilities.
+
+#if !defined(FREEBSD_UTILS_JAIL_HPP)
+#define FREEBSD_UTILS_JAIL_HPP
+
+#include "utils/defs.hpp"
+#include "utils/fs/path_fwd.hpp"
+#include "utils/process/operations_fwd.hpp"
+
+namespace fs = utils::fs;
+
+using utils::process::args_vector;
+
+namespace freebsd {
+namespace utils {
+
+
+// TODO: do we want a singleton here?
+class jail {
+public:
+ std::vector< std::string > parse_params_string(const std::string& str);
+ std::string make_name(const fs::path& program,
+ const std::string& test_case_name);
+ void create(const std::string& jail_name,
+ const std::string& jail_params);
+ void exec(const std::string& jail_name,
+ const fs::path& program,
+ const args_vector& args) throw() UTILS_NORETURN;
+ void remove(const std::string& jail_name);
+};
+
+
+} // namespace utils
+} // namespace freebsd
+
+#endif // !defined(FREEBSD_UTILS_JAIL_HPP)
diff --git a/contrib/kyua/freebsd/utils/jail.cpp b/contrib/kyua/freebsd/utils/jail.cpp
new file mode 100644
--- /dev/null
+++ b/contrib/kyua/freebsd/utils/jail.cpp
@@ -0,0 +1,323 @@
+// Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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 "freebsd/utils/jail.hpp"
+
+extern "C" {
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+// FreeBSD sysctl facility
+#include <sys/sysctl.h>
+
+// FreeBSD Jail syscalls
+#include <sys/param.h>
+#include <sys/jail.h>
+
+// FreeBSD Jail library
+#include <jail.h>
+}
+
+#include <fstream>
+#include <iostream>
+#include <regex>
+
+#include "model/metadata.hpp"
+#include "model/test_case.hpp"
+#include "model/test_program.hpp"
+#include "utils/fs/path.hpp"
+#include "utils/process/child.ipp"
+#include "utils/format/macros.hpp"
+#include "utils/process/operations.hpp"
+#include "utils/process/status.hpp"
+
+namespace process = utils::process;
+namespace fs = utils::fs;
+
+using utils::process::args_vector;
+using utils::process::child;
+
+
+static const int jail_name_max_len = MAXHOSTNAMELEN - 1;
+static const char* jail_name_prefix = "kyua";
+
+
+/// Functor to run a program.
+class run {
+ /// Program binary absolute path.
+ const utils::fs::path& _program;
+
+ /// Program arguments.
+ const args_vector& _args;
+
+public:
+ /// Constructor.
+ ///
+ /// \param program Program binary absolute path.
+ /// \param args Program arguments.
+ run(
+ const utils::fs::path& program,
+ const args_vector& args) :
+ _program(program),
+ _args(args)
+ {
+ }
+
+ /// Body of the subprocess.
+ void
+ operator()(void)
+ {
+ process::exec(_program, _args);
+ }
+};
+
+
+namespace freebsd {
+namespace utils {
+
+
+std::vector< std::string >
+jail::parse_params_string(const std::string& str)
+{
+ std::vector< std::string > params;
+ std::string p;
+ char quote = 0;
+
+ for (const char& c : str) {
+ // whitespace delimited parameter
+ if (quote == 0) {
+ if (std::isspace(c)) {
+ if (p.empty())
+ continue;
+ params.push_back(p);
+ p = "";
+ }
+ else if (c == '"' || c == '\'') {
+ if (!p.empty())
+ params.push_back(p);
+ p = "";
+ quote = c;
+ }
+ else
+ p += c;
+ }
+
+ // quoted parameter
+ else {
+ if (c == quote) {
+ if (!p.empty())
+ params.push_back(p);
+ p = "";
+ quote = 0;
+ }
+ else
+ p += c;
+ }
+ }
+
+ // leftovers
+ if (!p.empty())
+ params.push_back(p);
+
+ return params;
+}
+
+
+/// Constructs a jail name based on program and test case.
+///
+/// The formula is "kyua" + <program path> + "_" + <test case name>.
+/// All non-alphanumeric chars are replaced with "_".
+///
+/// If a resulting string exceeds maximum allowed length of a jail name,
+/// then it's shortened from the left side keeping the "kyua" prefix.
+///
+/// \param program The test program.
+/// \param test_case_name Name of the test case.
+///
+/// \return A jail name string.
+std::string
+jail::make_name(const fs::path& program,
+ const std::string& test_case_name)
+{
+ std::string name = std::regex_replace(
+ program.str() + "_" + test_case_name,
+ std::regex(R"([^A-Za-z0-9_])"),
+ "_");
+
+ const std::string::size_type limit =
+ jail_name_max_len - strlen(jail_name_prefix);
+ if (name.length() > limit)
+ name.erase(0, name.length() - limit);
+
+ return jail_name_prefix + name;
+}
+
+
+/// Create a jail with a given name and params string.
+///
+/// A new jail will always be 'persist', thus the caller is expected to remove
+/// the jail eventually via remove().
+///
+/// It's expected to be run in a subprocess.
+///
+/// \param jail_name Name of a new jail.
+/// \param jail_params String of jail parameters.
+void
+jail::create(const std::string& jail_name,
+ const std::string& jail_params)
+{
+ args_vector av;
+
+ // creation flag
+ av.push_back("-qc");
+
+ // jail name
+ av.push_back("name=" + jail_name);
+
+ // determine maximum allowed children.max
+ int max;
+ size_t len = sizeof(max);
+ if (::sysctlbyname("security.jail.children.max", &max, &len, NULL, 0) != 0) {
+ std::cerr << "sysctlbyname(security.jail.children.max) errors: "
+ << strerror(errno) << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+ if (len < sizeof(max)) {
+ std::cerr << "sysctlbyname(security.jail.children.max) provides less "
+ "data (" << len << ") than expected (" << sizeof(max) << ").\n";
+ std::exit(EXIT_FAILURE);
+ }
+ if (max < 0) {
+ std::cerr << "sysctlbyname(security.jail.children.max) yields "
+ "abnormal " << max << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+ if (max > 0)
+ max--; // a child jail must have less than parent's children.max
+ av.push_back("children.max=" + std::to_string(max));
+
+ // test defined jail params
+ const std::vector< std::string > params = parse_params_string(jail_params);
+ for (const std::string& p : params)
+ av.push_back(p);
+
+ // it must be persist
+ av.push_back("persist");
+
+ // invoke jail
+ std::auto_ptr< process::child > child = child::fork_capture(
+ run(fs::path("/usr/sbin/jail"), av));
+ process::status status = child->wait();
+
+ // expect success
+ if (status.exited() && status.exitstatus() == EXIT_SUCCESS)
+ return;
+
+ // otherwise, let us know what jail thinks and fail fast
+ std::cerr << child->output().rdbuf();
+ std::exit(EXIT_FAILURE);
+}
+
+
+/// Executes an external binary in a jail and replaces the current process.
+///
+/// \param jail_name Name of the jail to run within.
+/// \param program The test program binary absolute path.
+/// \param args The arguments to pass to the binary, without the program name.
+void
+jail::exec(const std::string& jail_name,
+ const fs::path& program,
+ const args_vector& args) throw()
+{
+ // get work dir prepared by kyua
+ char cwd[PATH_MAX];
+ if (::getcwd(cwd, sizeof(cwd)) == NULL) {
+ std::cerr << "process::jail::exec: getcwd() errors: "
+ << strerror(errno) << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+
+ // get jail id by its name
+ int jid = ::jail_getid(jail_name.c_str());
+ if (jid < 0) {
+ std::cerr << "process::jail::exec: jail_getid() errors: "
+ << strerror(errno) << ": " << jail_errmsg << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+
+ // attach to the jail
+ if (::jail_attach(jid) == -1) {
+ std::cerr << "process::jail::exec: jail_attach() errors: "
+ << strerror(errno) << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+
+ // set back the expected work dir
+ if (::chdir(cwd) == -1) {
+ std::cerr << "process::jail::exec: chdir() errors: "
+ << strerror(errno) << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+
+ process::exec(program, args);
+}
+
+
+/// Removes a jail with a given name.
+///
+/// It's expected to be run in a subprocess.
+///
+/// \param jail_name Name of a jail to remove.
+void
+jail::remove(const std::string& jail_name)
+{
+ args_vector av;
+
+ // removal flag
+ av.push_back("-r");
+
+ // jail name
+ av.push_back(jail_name);
+
+ // invoke jail
+ std::auto_ptr< process::child > child = child::fork_capture(
+ run(fs::path("/usr/sbin/jail"), av));
+ process::status status = child->wait();
+
+ // expect success
+ if (status.exited() && status.exitstatus() == EXIT_SUCCESS)
+ std::exit(EXIT_SUCCESS);
+
+ // otherwise, let us know what jail thinks and fail fast
+ std::cerr << child->output().rdbuf();
+ std::exit(EXIT_FAILURE);
+}
+
+
+} // namespace utils
+} // namespace freebsd
diff --git a/contrib/kyua/integration/cmd_config_test.sh b/contrib/kyua/integration/cmd_config_test.sh
--- a/contrib/kyua/integration/cmd_config_test.sh
+++ b/contrib/kyua/integration/cmd_config_test.sh
@@ -42,6 +42,7 @@
cat >"${HOME}/.kyua/kyua.conf" <<EOF
syntax(2)
architecture = "my-architecture"
+execenv = "my-env1 my-env2"
parallelism = 256
platform = "my-platform"
unprivileged_user = "$(id -u -n)"
@@ -51,6 +52,7 @@
cat >expout <<EOF
architecture = my-architecture
+execenv = my-env1 my-env2
parallelism = 256
platform = my-platform
test_suites.suite1.the_variable = value1
diff --git a/contrib/kyua/integration/cmd_report_junit_test.sh b/contrib/kyua/integration/cmd_report_junit_test.sh
--- a/contrib/kyua/integration/cmd_report_junit_test.sh
+++ b/contrib/kyua/integration/cmd_report_junit_test.sh
@@ -97,6 +97,8 @@
allowed_architectures is empty
allowed_platforms is empty
description is empty
+execenv is empty
+execenv_jail is empty
has_cleanup = false
is_exclusive = false
required_configs is empty
@@ -135,6 +137,8 @@
allowed_architectures is empty
allowed_platforms is empty
description is empty
+execenv is empty
+execenv_jail is empty
has_cleanup = false
is_exclusive = false
required_configs is empty
@@ -211,6 +215,8 @@
allowed_architectures is empty
allowed_platforms is empty
description is empty
+execenv is empty
+execenv_jail is empty
has_cleanup = false
is_exclusive = false
required_configs is empty
@@ -249,6 +255,8 @@
allowed_architectures is empty
allowed_platforms is empty
description is empty
+execenv is empty
+execenv_jail is empty
has_cleanup = false
is_exclusive = false
required_configs is empty
diff --git a/contrib/kyua/integration/cmd_report_test.sh b/contrib/kyua/integration/cmd_report_test.sh
--- a/contrib/kyua/integration/cmd_report_test.sh
+++ b/contrib/kyua/integration/cmd_report_test.sh
@@ -251,6 +251,8 @@
allowed_architectures is empty
allowed_platforms is empty
description is empty
+ execenv is empty
+ execenv_jail is empty
has_cleanup = false
is_exclusive = false
required_configs is empty
diff --git a/contrib/kyua/main.cpp b/contrib/kyua/main.cpp
--- a/contrib/kyua/main.cpp
+++ b/contrib/kyua/main.cpp
@@ -27,6 +27,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "cli/main.hpp"
+#include "freebsd/main.hpp"
/// Program entry point.
@@ -46,5 +47,7 @@
int
main(const int argc, const char* const* const argv)
{
+ freebsd::main(argc, argv);
+
return cli::main(argc, argv);
}
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
@@ -69,6 +69,9 @@
const std::string& description(void) const;
bool has_cleanup(void) const;
bool is_exclusive(void) const;
+ const std::string& execenv(void) const;
+ bool has_execenv(void) const;
+ const std::string& execenv_jail(void) const;
const strings_set& required_configs(void) const;
const utils::units::bytes& required_disk_space(void) const;
const paths_set& required_files(void) const;
@@ -112,6 +115,8 @@
metadata_builder& set_description(const std::string&);
metadata_builder& set_has_cleanup(const bool);
metadata_builder& set_is_exclusive(const bool);
+ metadata_builder& set_execenv(const std::string&);
+ metadata_builder& set_execenv_jail(const std::string&);
metadata_builder& set_required_configs(const strings_set&);
metadata_builder& set_required_disk_space(const utils::units::bytes&);
metadata_builder& set_required_files(const paths_set&);
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
@@ -249,6 +249,8 @@
tree.define< config::string_node >("description");
tree.define< config::bool_node >("has_cleanup");
tree.define< config::bool_node >("is_exclusive");
+ tree.define< config::string_node >("execenv");
+ tree.define< config::string_node >("execenv_jail");
tree.define< config::strings_set_node >("required_configs");
tree.define< bytes_node >("required_disk_space");
tree.define< paths_set_node >("required_files");
@@ -272,6 +274,8 @@
tree.set< config::string_node >("description", "");
tree.set< config::bool_node >("has_cleanup", false);
tree.set< config::bool_node >("is_exclusive", false);
+ tree.set< config::string_node >("execenv", "");
+ tree.set< config::string_node >("execenv_jail", "");
tree.set< config::strings_set_node >("required_configs",
model::strings_set());
tree.set< bytes_node >("required_disk_space", units::bytes(0));
@@ -493,6 +497,45 @@
}
+/// Returns execution environment name.
+///
+/// \return Name of configured execution environment.
+const std::string&
+model::metadata::execenv(void) const
+{
+ if (_pimpl->props.is_set("execenv")) {
+ return _pimpl->props.lookup< config::string_node >("execenv");
+ } else {
+ return get_defaults().lookup< config::string_node >("execenv");
+ }
+}
+
+
+/// Returns whether the test has any specific execenv apart from "host" one.
+///
+/// \return True if there is a non-host execenv configured; false otherwise.
+bool
+model::metadata::has_execenv(void) const
+{
+ const std::string& name = execenv();
+ return !name.empty() && name != "host";
+}
+
+
+/// Returns execenv jail parameters string to run a test with.
+///
+/// \return String of jail parameters.
+const std::string&
+model::metadata::execenv_jail(void) const
+{
+ if (_pimpl->props.is_set("execenv_jail")) {
+ return _pimpl->props.lookup< config::string_node >("execenv_jail");
+ } else {
+ return get_defaults().lookup< config::string_node >("execenv_jail");
+ }
+}
+
+
/// Returns the list of configuration variables needed by the test.
///
/// \return Set of configuration variables.
@@ -920,6 +963,36 @@
}
+/// Sets execution environment name.
+///
+/// \param name Execution environment name.
+///
+/// \return A reference to this builder.
+///
+/// \throw model::error If the value is invalid.
+model::metadata_builder&
+model::metadata_builder::set_execenv(const std::string& name)
+{
+ set< config::string_node >(_pimpl->props, "execenv", name);
+ return *this;
+}
+
+
+/// Sets execenv jail parameters string to run the test with.
+///
+/// \param params String of jail parameters.
+///
+/// \return A reference to this builder.
+///
+/// \throw model::error If the value is invalid.
+model::metadata_builder&
+model::metadata_builder::set_execenv_jail(const std::string& params)
+{
+ set< config::string_node >(_pimpl->props, "execenv_jail", params);
+ return *this;
+}
+
+
/// Sets the list of configuration variables needed by the test.
///
/// \param vars Set of configuration variables.
diff --git a/contrib/kyua/model/metadata_test.cpp b/contrib/kyua/model/metadata_test.cpp
--- a/contrib/kyua/model/metadata_test.cpp
+++ b/contrib/kyua/model/metadata_test.cpp
@@ -315,6 +315,8 @@
props["allowed_platforms"] = "";
props["custom.foo"] = "bar";
props["description"] = "";
+ props["execenv"] = "";
+ props["execenv_jail"] = "";
props["has_cleanup"] = "false";
props["is_exclusive"] = "false";
props["required_configs"] = "";
@@ -406,7 +408,8 @@
std::ostringstream str;
str << model::metadata_builder().build();
ATF_REQUIRE_EQ("metadata{allowed_architectures='', allowed_platforms='', "
- "description='', has_cleanup='false', is_exclusive='false', "
+ "description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='false', "
"required_configs='', "
"required_disk_space='0', required_files='', "
"required_memory='0', "
@@ -428,7 +431,8 @@
.build();
ATF_REQUIRE_EQ(
"metadata{allowed_architectures='abc', allowed_platforms='', "
- "description='', has_cleanup='false', is_exclusive='true', "
+ "description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='true', "
"required_configs='', "
"required_disk_space='0', required_files='bar foo', "
"required_memory='1.00K', "
diff --git a/contrib/kyua/model/test_case_test.cpp b/contrib/kyua/model/test_case_test.cpp
--- a/contrib/kyua/model/test_case_test.cpp
+++ b/contrib/kyua/model/test_case_test.cpp
@@ -200,7 +200,8 @@
ATF_REQUIRE_EQ(
"test_case{name='the-name', "
"metadata=metadata{allowed_architectures='', allowed_platforms='foo', "
- "custom.bar='baz', description='', has_cleanup='false', "
+ "custom.bar='baz', description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', "
"is_exclusive='false', "
"required_configs='', required_disk_space='0', required_files='', "
"required_memory='0', "
diff --git a/contrib/kyua/model/test_program_test.cpp b/contrib/kyua/model/test_program_test.cpp
--- a/contrib/kyua/model/test_program_test.cpp
+++ b/contrib/kyua/model/test_program_test.cpp
@@ -544,7 +544,8 @@
"test_program{interface='plain', binary='binary/path', "
"root='/the/root', test_suite='suite-name', "
"metadata=metadata{allowed_architectures='a', allowed_platforms='', "
- "description='', has_cleanup='false', is_exclusive='false', "
+ "description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='false', "
"required_configs='', required_disk_space='0', required_files='', "
"required_memory='0', "
"required_programs='', required_user='', timeout='300'}, "
@@ -593,21 +594,23 @@
"test_program{interface='plain', binary='binary/path', "
"root='/the/root', test_suite='suite-name', "
"metadata=metadata{allowed_architectures='a', allowed_platforms='', "
- "description='', has_cleanup='false', is_exclusive='false', "
+ "description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='false', "
"required_configs='', required_disk_space='0', required_files='', "
"required_memory='0', "
"required_programs='', required_user='', timeout='300'}, "
"test_cases=map("
"another-name=test_case{name='another-name', "
"metadata=metadata{allowed_architectures='a', allowed_platforms='', "
- "description='', has_cleanup='false', is_exclusive='false', "
+ "description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='false', "
"required_configs='', required_disk_space='0', required_files='', "
"required_memory='0', "
"required_programs='', required_user='', timeout='300'}}, "
"the-name=test_case{name='the-name', "
"metadata=metadata{allowed_architectures='a', allowed_platforms='foo', "
- "custom.bar='baz', description='', has_cleanup='false', "
- "is_exclusive='false', "
+ "custom.bar='baz', description='', execenv='', execenv_jail='', "
+ "has_cleanup='false', is_exclusive='false', "
"required_configs='', required_disk_space='0', required_files='', "
"required_memory='0', "
"required_programs='', required_user='', timeout='300'}})}",
diff --git a/contrib/kyua/utils/config/nodes.ipp b/contrib/kyua/utils/config/nodes.ipp
--- a/contrib/kyua/utils/config/nodes.ipp
+++ b/contrib/kyua/utils/config/nodes.ipp
@@ -382,9 +382,14 @@
template< typename ValueType >
void
config::base_set_node< ValueType >::set_lua(
- lutok::state& /* state */,
- const int /* value_index */)
+ lutok::state& state,
+ const int value_index)
{
+ if (state.is_string(value_index)) {
+ set_string(state.to_string(value_index));
+ return;
+ }
+
UNREACHABLE;
}
diff --git a/contrib/kyua/utils/process/executor.hpp b/contrib/kyua/utils/process/executor.hpp
--- a/contrib/kyua/utils/process/executor.hpp
+++ b/contrib/kyua/utils/process/executor.hpp
@@ -215,6 +215,7 @@
exit_handle wait(const exec_handle);
exit_handle wait_any(void);
+ exit_handle reap(const int);
void check_interrupt(void) const;
};
diff --git a/contrib/kyua/utils/process/executor.cpp b/contrib/kyua/utils/process/executor.cpp
--- a/contrib/kyua/utils/process/executor.cpp
+++ b/contrib/kyua/utils/process/executor.cpp
@@ -689,6 +689,34 @@
data._pimpl->state_owners,
all_exec_handles)));
}
+
+ executor::exit_handle
+ reap(const int original_pid)
+ {
+ const exec_handles_map::iterator iter = all_exec_handles.find(
+ original_pid);
+ exec_handle& data = (*iter).second;
+ data._pimpl->timer.unprogram();
+
+ if (!fs::exists(data.stdout_file())) {
+ std::ofstream new_stdout(data.stdout_file().c_str());
+ }
+ if (!fs::exists(data.stderr_file())) {
+ std::ofstream new_stderr(data.stderr_file().c_str());
+ }
+
+ return exit_handle(std::shared_ptr< exit_handle::impl >(
+ new exit_handle::impl(
+ data.pid(),
+ none,
+ data._pimpl->unprivileged_user,
+ data._pimpl->start_time, datetime::timestamp::now(),
+ data.control_directory(),
+ data.stdout_file(),
+ data.stderr_file(),
+ data._pimpl->state_owners,
+ all_exec_handles)));
+ }
};
@@ -879,6 +907,20 @@
}
+/// Forms exit_handle for the given PID subprocess.
+///
+/// Can be used in the cases when we want to do cleanup(s) of a killed test
+/// subprocess, but we do not have exit handle as we usually do after normal
+/// wait mechanism.
+///
+/// \return A pointer to an object describing the subprocess.
+executor::exit_handle
+executor::executor_handle::reap(const int pid)
+{
+ return _pimpl->reap(pid);
+}
+
+
/// Checks if an interrupt has fired.
///
/// Calls to this function should be sprinkled in strategic places through the
diff --git a/usr.bin/kyua/Makefile b/usr.bin/kyua/Makefile
--- a/usr.bin/kyua/Makefile
+++ b/usr.bin/kyua/Makefile
@@ -128,7 +128,12 @@
engine/scanner.cpp \
engine/tap.cpp \
engine/tap_parser.cpp \
- engine/scheduler.cpp
+ engine/scheduler.cpp \
+ engine/execenv/execenv.cpp \
+ engine/execenv/execenv_host.cpp
+
+SRCS+= freebsd/execenv_jail_manager.cpp\
+ freebsd/main.cpp \
SRCS+= store/dbtypes.cpp \
store/exceptions.cpp \
@@ -161,6 +166,14 @@
cli/config.cpp \
cli/main.cpp
+.if ${MK_JAIL} == "no"
+SRCS+= freebsd/execenv_jail_stub.cpp
+.else
+SRCS+= freebsd/execenv_jail.cpp \
+ freebsd/utils/jail.cpp
+LIBADD+= jail
+.endif
+
FILESGROUPS= DOCS MISC STORE
.if ${MK_EXAMPLES} != "no"

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 24, 3:41 PM (19 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27898089
Default Alt Text
D42350.id135010.diff (89 KB)

Event Timeline