Page MenuHomeFreeBSD

D55859.diff
No OneTemporary

D55859.diff

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
@@ -143,6 +143,10 @@
mdbuilder.set_string("required_programs", value);
} else if (name == "require.user") {
mdbuilder.set_string("required_user", value);
+ } else if (name == "setup") {
+ mdbuilder.set_string("setup", value);
+ } else if (name == "teardown") {
+ mdbuilder.set_string("teardown", value);
} else if (name == "timeout") {
mdbuilder.set_string("timeout", value);
} else if (name.length() > 2 && name.substr(0, 2) == "X-") {
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
@@ -79,6 +79,8 @@
const strings_set& required_kmods(void) const;
const paths_set& required_programs(void) const;
const std::string& required_user(void) const;
+ const std::string& setup(void) const;
+ const std::string& teardown(void) const;
const utils::datetime::delta& timeout(void) const;
model::properties_map to_properties(void) const;
@@ -125,7 +127,9 @@
metadata_builder& set_required_kmods(const strings_set&);
metadata_builder& set_required_programs(const paths_set&);
metadata_builder& set_required_user(const std::string&);
+ metadata_builder& set_setup(const std::string&);
metadata_builder& set_string(const std::string&, const std::string&);
+ metadata_builder& set_teardown(const std::string&);
metadata_builder& set_timeout(const utils::datetime::delta&);
metadata build(void) const;
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
@@ -259,6 +259,8 @@
tree.define< config::strings_set_node >("required_kmods");
tree.define< paths_set_node >("required_programs");
tree.define< user_node >("required_user");
+ tree.define< config::string_node >("setup");
+ tree.define< config::string_node >("teardown");
tree.define< delta_node >("timeout");
}
@@ -286,6 +288,8 @@
tree.set< config::strings_set_node >("required_kmods", model::strings_set());
tree.set< paths_set_node >("required_programs", model::paths_set());
tree.set< user_node >("required_user", "");
+ tree.set< config::string_node >("setup", ".setup");
+ tree.set< config::string_node >("teardown", ".teardown");
// TODO(jmmv): We shouldn't be setting a default timeout like this. See
// Issue 5 for details.
tree.set< delta_node >("timeout", datetime::delta(300, 0));
@@ -643,6 +647,34 @@
}
+/// Returns setup file name with args.
+///
+/// \return The file name with optional args.
+const std::string&
+model::metadata::setup(void) const
+{
+ if (_pimpl->props.is_set("setup")) {
+ return _pimpl->props.lookup< config::string_node >("setup");
+ } else {
+ return get_defaults().lookup< config::string_node >("setup");
+ }
+}
+
+
+/// Returns teardown file name with args.
+///
+/// \return The file name with optional args.
+const std::string&
+model::metadata::teardown(void) const
+{
+ if (_pimpl->props.is_set("teardown")) {
+ return _pimpl->props.lookup< config::string_node >("teardown");
+ } else {
+ return get_defaults().lookup< config::string_node >("teardown");
+ }
+}
+
+
/// Returns the timeout of the test.
///
/// \return A time delta; should be compared to default_timeout to see if it has
@@ -1104,6 +1136,21 @@
}
+/// Sets setup file name with optional args.
+///
+/// \param name The name of the file.
+///
+/// \return A reference to this builder.
+///
+/// \throw model::error If the value is invalid.
+model::metadata_builder&
+model::metadata_builder::set_setup(const std::string& name)
+{
+ set< config::string_node >(_pimpl->props, "setup", name);
+ return *this;
+}
+
+
/// Sets a metadata property by name from its textual representation.
///
/// \param key The property to set.
@@ -1128,6 +1175,21 @@
}
+/// Sets teardown file name with optional args.
+///
+/// \param name The name of the file.
+///
+/// \return A reference to this builder.
+///
+/// \throw model::error If the value is invalid.
+model::metadata_builder&
+model::metadata_builder::set_teardown(const std::string& name)
+{
+ set< config::string_node >(_pimpl->props, "teardown", name);
+ return *this;
+}
+
+
/// Sets the timeout of the test.
///
/// \param timeout The timeout to set.
diff --git a/contrib/kyua/model/test_program.hpp b/contrib/kyua/model/test_program.hpp
--- a/contrib/kyua/model/test_program.hpp
+++ b/contrib/kyua/model/test_program.hpp
@@ -43,6 +43,7 @@
#include "model/test_case_fwd.hpp"
#include "utils/fs/path_fwd.hpp"
#include "utils/noncopyable.hpp"
+#include "utils/optional_fwd.hpp"
namespace model {
@@ -72,6 +73,9 @@
const model::test_case& find(const std::string&) const;
virtual const model::test_cases_map& test_cases(void) const;
+ utils::optional< utils::fs::path >
+ test_case_setup_file(const std::string&) const;
+ std::string test_case_setup_args(const std::string&) const;
bool operator==(const test_program&) const;
bool operator!=(const test_program&) const;
diff --git a/contrib/kyua/model/test_program.cpp b/contrib/kyua/model/test_program.cpp
--- a/contrib/kyua/model/test_program.cpp
+++ b/contrib/kyua/model/test_program.cpp
@@ -38,13 +38,16 @@
#include "utils/format/containers.ipp"
#include "utils/format/macros.hpp"
#include "utils/fs/path.hpp"
+#include "utils/fs/operations.hpp"
#include "utils/noncopyable.hpp"
+#include "utils/optional.ipp"
#include "utils/sanity.hpp"
#include "utils/text/operations.ipp"
namespace fs = utils::fs;
namespace text = utils::text;
+using utils::optional;
using utils::none;
@@ -236,6 +239,59 @@
}
+/// Gets the path of test case's setup file.
+///
+/// \return The path identified, or none if not found.
+optional< fs::path >
+model::test_program::test_case_setup_file(const std::string& test_case) const
+{
+ const model::test_case& tc = find(test_case);
+
+ std::string name;
+ std::istringstream iss( tc.get_metadata().setup() );
+ iss >> name;
+
+ if (name.empty() || name.size() < 2)
+ return none;
+
+ if (name[0] == '.' && name[1] != '.' && name[1] != '/') {
+ fs::path path(absolute_path().str() + name);
+ if (fs::exists(path))
+ return utils::make_optional(path);
+ else
+ return none;
+ }
+
+ fs::path path = root() / name;
+ if (fs::exists(path))
+ return utils::make_optional(path);
+ else
+ return none;
+}
+
+
+/// Gets the args string for the setup file.
+///
+/// \return The argument string.
+std::string
+model::test_program::test_case_setup_args(const std::string& test_case) const
+{
+ const model::test_case& tc = find(test_case);
+
+ std::string name;
+ std::istringstream iss( tc.get_metadata().setup() );
+ iss >> name;
+
+ if (name.empty() || name.size() < 2)
+ return "";
+
+ std::string args;
+ std::getline(iss, args);
+
+ return args;
+}
+
+
/// Sets the list of test cases of the test program.
///
/// This can only be called once and it may only be called from within
diff --git a/contrib/kyua/os/freebsd/execenv_jail.cpp b/contrib/kyua/os/freebsd/execenv_jail.cpp
--- a/contrib/kyua/os/freebsd/execenv_jail.cpp
+++ b/contrib/kyua/os/freebsd/execenv_jail.cpp
@@ -52,6 +52,16 @@
jail.make_name(_test_program.absolute_path(), _test_case_name),
test_case.get_metadata().execenv_jail_params()
);
+
+ auto setup_file = _test_program.test_case_setup_file(_test_case_name);
+ if (!setup_file)
+ return;
+ jail.jexec(
+ jail.make_name(_test_program.absolute_path(), _test_case_name),
+ "KYUA_TESTDIR=" + _test_program.root().str(),
+ setup_file.get(),
+ _test_program.test_case_setup_args(_test_case_name)
+ );
}
diff --git a/contrib/kyua/os/freebsd/utils/jail.hpp b/contrib/kyua/os/freebsd/utils/jail.hpp
--- a/contrib/kyua/os/freebsd/utils/jail.hpp
+++ b/contrib/kyua/os/freebsd/utils/jail.hpp
@@ -51,6 +51,10 @@
const std::string& test_case_name);
void create(const std::string& jail_name,
const std::string& jail_params);
+ void jexec(const std::string& jail_name,
+ const std::string& env,
+ const fs::path& program,
+ const std::string& program_args);
void exec(const std::string& jail_name,
const fs::path& program,
const args_vector& args) throw() UTILS_NORETURN;
diff --git a/contrib/kyua/os/freebsd/utils/jail.cpp b/contrib/kyua/os/freebsd/utils/jail.cpp
--- a/contrib/kyua/os/freebsd/utils/jail.cpp
+++ b/contrib/kyua/os/freebsd/utils/jail.cpp
@@ -46,6 +46,7 @@
#include <fstream>
#include <iostream>
+#include <sstream>
#include <regex>
#include "model/metadata.hpp"
@@ -227,6 +228,64 @@
}
+/// Prepares and runs jexec.
+///
+/// \param jail_name Name of the jail.
+/// \param program Program path.
+/// \param args Argument vector.
+void
+jail::jexec(const std::string& jail_name,
+ const std::string& env,
+ const fs::path& program,
+ const std::string& program_args)
+{
+ args_vector av;
+
+ // pass work dir prepared by kyua
+ char cwd[PATH_MAX];
+ if (::getcwd(cwd, sizeof(cwd)) == NULL) {
+ std::cerr << "jail::exec: getcwd() errors: "
+ << strerror(errno) << ".\n";
+ std::exit(EXIT_FAILURE);
+ }
+ av.push_back("-d");
+ av.push_back(std::string(cwd));
+
+ // pass env pairs
+ std::istringstream pairs(env);
+ std::string pair;
+ while (pairs >> pair) {
+ av.push_back("-e");
+ av.push_back(pair);
+ }
+
+ // target jail name
+ av.push_back(jail_name);
+
+ // program
+ av.push_back(program.str());
+
+ // program arguments
+ std::istringstream args(program_args);
+ std::string word;
+ while (args >> word)
+ av.push_back(word);
+
+ // invoke jexec
+ std::unique_ptr< process::child > child = child::fork_capture(
+ run(fs::path("/usr/sbin/jexec"), av));
+ process::status status = child->wait();
+
+ std::cerr << child->output().rdbuf();
+
+ // expect success
+ if (status.exited() && status.exitstatus() == EXIT_SUCCESS)
+ return;
+
+ 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.
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -7,6 +7,7 @@
anchor \
counters \
debug \
+ demo \
divert-to \
dup \
ether \
@@ -75,6 +76,9 @@
TEST_METADATA+= execenv="jail"
TEST_METADATA+= execenv_jail_params="vnet allow.raw_sockets allow.read_msgbuf"
+${PACKAGE}SCRIPTS+= demo.setup \
+ demo.atfsh_like_setup
+
${PACKAGE}FILES+= \
bsnmpd.conf \
CVE-2019-5597.py \
diff --git a/tests/sys/netpfil/pf/demo.atfsh_like_setup b/tests/sys/netpfil/pf/demo.atfsh_like_setup
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/demo.atfsh_like_setup
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+. $KYUA_TESTDIR/../../common/vnet.subr
+vnet_init
+
+epair=$(vnet_mkepair)
+ifconfig ${epair}a 192.0.2.1/24 up
+
+vnet_mkjail alcatraz ${epair}b
+jexec alcatraz ifconfig ${epair}b 192.0.2.100/24 up
diff --git a/tests/sys/netpfil/pf/demo.setup b/tests/sys/netpfil/pf/demo.setup
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/demo.setup
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# A setup file is provided with KYUA_TESTDIR to locate common scripts, etc.
+echo "setup file KYUA_TESTDIR: $KYUA_TESTDIR"
+
+# A setup file is running within test case's temporary directory,
+# so that it could communicate details with the test: names, PIDs, IDs, etc
+echo "setup file PWD: $(pwd)"
+
+# A setup file might be provided with optional args
+echo "setup file args: $*"
+
+# Actual setup example
+addr1="${1:-192.0.2.239}"
+ifconfig lo0 $addr1/24 up
+echo $addr1 > ./addr1
+
diff --git a/tests/sys/netpfil/pf/demo.sh b/tests/sys/netpfil/pf/demo.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/demo.sh
@@ -0,0 +1,41 @@
+atf_test_case "one"
+one_head()
+{
+ atf_set descr 'One'
+ atf_set require.user root
+}
+one_body()
+{
+ atf_check -s exit:0 -o ignore ping -c1 192.0.2.239
+}
+
+atf_test_case "two"
+two_head()
+{
+ atf_set descr 'Two'
+ atf_set require.user root
+ atf_set setup '.setup 192.0.2.1'
+}
+two_body()
+{
+ atf_check -s exit:0 -o ignore ping -c1 192.0.2.1
+}
+
+atf_test_case "three"
+three_head()
+{
+ atf_set descr 'Three'
+ atf_set require.user root
+ atf_set setup .atfsh_like_setup
+}
+three_body()
+{
+ atf_check -s exit:0 -o ignore ping -c1 192.0.2.100
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case "one"
+ atf_add_test_case "two"
+ atf_add_test_case "three"
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Jun 13, 1:51 AM (10 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33918548
Default Alt Text
D55859.diff (12 KB)

Event Timeline