aboutsummaryrefslogtreecommitdiffstats
path: root/liblfjail
diff options
context:
space:
mode:
Diffstat (limited to 'liblfjail')
-rw-r--r--liblfjail/command_map.cc10
-rw-r--r--liblfjail/exec.cc14
-rw-r--r--liblfjail/exec.hh16
-rw-r--r--liblfjail/fd.cc16
-rw-r--r--liblfjail/fd.hh4
-rw-r--r--liblfjail/jail.cc23
-rw-r--r--liblfjail/spawn.hh4
-rw-r--r--liblfjail/split.hh64
-rw-r--r--liblfjail/zfs.cc55
-rw-r--r--liblfjail/zfs.hh18
10 files changed, 79 insertions, 145 deletions
diff --git a/liblfjail/command_map.cc b/liblfjail/command_map.cc
index 96883a0..82b2fe0 100644
--- a/liblfjail/command_map.cc
+++ b/liblfjail/command_map.cc
@@ -23,13 +23,13 @@ struct node {
node(std::string command);
// Run the handler for this node.
- int invoke(context const &ctx, int argc, char **argv) const;
+ auto invoke(context const &ctx, int argc, char **argv) const -> int;
// Create a new node under this one, or return it if it already exists.
// If path is empty, return this node.
- node &create_node(std::string_view path);
+ auto create_node(std::string_view path) -> node&;
- void print_usage(std::string prefix) const;
+ auto print_usage(std::string prefix) const -> void;
private:
std::map<std::string_view, node> commands;
@@ -50,7 +50,7 @@ auto node::invoke(context const &ctx, int argc, char **argv) const -> int {
auto const &child = it->second;
// If the child has a handler, invoke it.
- if (child.handler)
+ if (child.handler != nullptr)
return child.handler->invoke(ctx, argc, argv);
--argc;
@@ -84,7 +84,7 @@ auto node::create_node(std::string_view path) -> node& {
}
void node::print_usage(std::string prefix) const {
- if (handler)
+ if (handler != nullptr)
std::print("{}{}\n", prefix, command);
for (auto const &it : commands)
diff --git a/liblfjail/exec.cc b/liblfjail/exec.cc
index a1c9a4d..d86559e 100644
--- a/liblfjail/exec.cc
+++ b/liblfjail/exec.cc
@@ -35,27 +35,27 @@ auto fexecv::exec(this fexecv &self) noexcept -> void {
/*
* execv()
*/
-auto execv(std::string file, argv &&argv) -> fexecv {
- auto const ret = ::open(file.c_str(), O_EXEC);
+auto execv(std::string const &path, argv &&argv) -> fexecv {
+ auto const ret = ::open(path.c_str(), O_EXEC);
if (ret == -1)
- throw executable_not_found(file);
- return fexecv(fd(ret), std::move(argv));
+ throw executable_not_found(path);
+ return {fd(ret), std::move(argv)};
}
/*
* execvp()
*/
-auto execvp(std::string file, argv &&argv) -> fexecv {
+auto execvp(std::string const &file, argv &&argv) -> fexecv {
auto execfd = find_in_path(file);
if (!execfd)
throw executable_not_found(file);
- return fexecv(std::move(*execfd), std::move(argv));
+ return {std::move(*execfd), std::move(argv)};
}
/*
* shell
*/
-auto shell(std::string command) -> fexecv {
+auto shell(std::string const &command) -> fexecv {
return execl("/bin/sh", "sh", "-c", command);
}
diff --git a/liblfjail/exec.hh b/liblfjail/exec.hh
index 18a2dd7..caadb66 100644
--- a/liblfjail/exec.hh
+++ b/liblfjail/exec.hh
@@ -64,38 +64,36 @@ static_assert(executor<fexecv>);
* execv: equivalent to fexecv(), except the command is passed as
* a pathname instead of a file descriptor. Does not search $PATH.
*/
-auto execv(std::string path, argv &&argv) -> fexecv;
+auto execv(std::string const &path, argv &&argv) -> fexecv;
/*
* execvp: equivalent to fexecv(), except the command is passed as
* a filename instead of a file descriptor. If the filename is not
* an absolute path, it will be searched for in $PATH.
*/
-auto execvp(std::string file, argv &&argv) -> fexecv;
+auto execvp(std::string const &file, argv &&argv) -> fexecv;
/*
* execl: equivalent to execv, except the arguments are passed as a
* variadic pack of string-like objects.
*/
-auto execl(std::string path, auto &&...args) {
- return execv(std::move(path),
- argv::from_args({std::string_view(args)...}));
+auto execl(std::string const &path, auto &&...args) {
+ return execv(path, argv::from_args({std::string_view(args)...}));
}
/*
* execlp: equivalent to execvp, except the arguments are passed as a
* variadic pack of string-like objects.
*/
-auto execlp(std::string file, auto &&...args) {
- return execvp(std::move(file),
- argv::from_args({std::string_view(args)...}));
+auto execlp(std::string const &file, auto &&...args) {
+ return execvp(file, argv::from_args({std::string_view(args)...}));
}
/*
* shell: run the process by invoking /bin/sh -c with the single argument,
* equivalent to system(3).
*/
-auto shell(std::string command) -> fexecv;
+auto shell(std::string const &command) -> fexecv;
} // namespace lfjail
diff --git a/liblfjail/fd.cc b/liblfjail/fd.cc
index 058a62d..df6119d 100644
--- a/liblfjail/fd.cc
+++ b/liblfjail/fd.cc
@@ -14,14 +14,14 @@ fd::fd(fd &&other) noexcept
: _fd(std::exchange(other._fd, _invalid_fd))
{}
-auto fd::operator=(this fd &self, fd &&other) noexcept -> fd & {
- if (&self != &other)
- self._fd = std::exchange(other._fd, _invalid_fd);
- return self;
+auto fd::operator=(fd &&other) noexcept -> fd & {
+ if (this != &other)
+ _fd = std::exchange(other._fd, _invalid_fd);
+ return *this;
}
fd::operator bool(this fd const &self) noexcept {
- return self._fd != self._invalid_fd;
+ return self._fd != _invalid_fd;
}
fd::~fd() {
@@ -40,10 +40,10 @@ auto fd::get(this fd const &self) -> int {
return self._fd;
}
-auto fd::release(this fd &&self) -> int {
- if (!self)
+auto fd::release() && noexcept -> int {
+ if (!*this)
std::abort();
- return std::exchange(self._fd, _invalid_fd);
+ return std::exchange(_fd, _invalid_fd);
}
// Create a copy of this fd by calling dup().
diff --git a/liblfjail/fd.hh b/liblfjail/fd.hh
index 7437a24..f20acb8 100644
--- a/liblfjail/fd.hh
+++ b/liblfjail/fd.hh
@@ -27,7 +27,7 @@ struct fd final {
// Move from another fd, leaving the moved-from fd in an invalid state.
fd(fd &&other) noexcept;
- auto operator=(this fd &self, fd &&other) noexcept -> fd &;
+ auto operator=(fd &&other) noexcept -> fd &;
// Not copyable.
fd(fd const &) = delete;
@@ -44,7 +44,7 @@ struct fd final {
// Release the stored fd and return it. The caller must close
// the fd.
- auto release(this fd &&self) -> int;
+ auto release() && noexcept -> int;
private:
static constexpr int _invalid_fd = -1;
diff --git a/liblfjail/jail.cc b/liblfjail/jail.cc
index 82bec5c..cf5d600 100644
--- a/liblfjail/jail.cc
+++ b/liblfjail/jail.cc
@@ -7,6 +7,7 @@
#include "generic_error.hh"
#include "fileutils.hh"
#include "jail_zfs.hh"
+#include "spawn.hh"
namespace {
@@ -102,26 +103,18 @@ void jail_destroy(context const &ctx, jail const &jailconf) {
zfs::destroy_for_jail(ctx, jailconf);
}
-void jail_install(context const &, jail const &/*jailconf*/) {
- auto sout = std::string();
- auto serr = std::string();
-
- throw generic_error("not implemented");
-#if 0
- int ret = lfjail::cexecl(
- std::back_inserter(sout),
- std::back_inserter(serr),
- "/usr/sbin/pkg",
+void jail_install(context const &, jail const &jailconf) {
+ auto executor = exec::execl("/usr/sbin/pkg",
"pkg", "-r", jailconf.root_path, "install", "-y",
"FreeBSD-runtime", "FreeBSD-utilities", "FreeBSD-periodic",
"FreeBSD-rc", "FreeBSD-syslogd", "FreeBSD-newsyslog",
"FreeBSD-pkg-bootstrap", "pkg");
- if (!serr.empty())
- throw generic_error("pkg install failed: {}", serr);
- if (ret != 0)
- throw generic_error("pkg install failed: {}", ret);
-#endif
+ auto output = std::string();
+ auto ret = spawn(std::move(executor),
+ capture(STDOUT_FILENO, output)).wait();
+ if (!ret)
+ throw generic_error("pkg install failed");
}
} // namespace lfjail
diff --git a/liblfjail/spawn.hh b/liblfjail/spawn.hh
index 606ccf9..affa035 100644
--- a/liblfjail/spawn.hh
+++ b/liblfjail/spawn.hh
@@ -164,11 +164,11 @@ private:
}
-auto capture(int fd, std::string &s) {
+inline auto capture(int fd, std::string &s) {
return detail::capture(fd, std::back_inserter(s));
}
-auto capture(int fd, std::output_iterator<char> auto &&it) {
+inline auto capture(int fd, std::output_iterator<char> auto &&it) {
return detail::capture(fd, std::forward<decltype(it)>(it));
}
diff --git a/liblfjail/split.hh b/liblfjail/split.hh
deleted file mode 100644
index 419b479..0000000
--- a/liblfjail/split.hh
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-#ifndef LFJAIL_SPLIT_HH
-#define LFJAIL_SPLIT_HH
-
-#include "generator.hh"
-
-namespace lfjail {
-
-/*
- * split: split a range of items on a given predicate and return each element
- * as a subrange. This is intended to be used with strings, but in theory it
- * can accept any range.
- *
- * The input range is never copied, so the returned ranges reference the
- * input range.
- */
-
-template<std::ranges::range Range,
- std::indirect_unary_predicate<std::ranges::iterator_t<Range>> Pred>
-auto split(Range &&range, Pred &&pred)
- -> std::generator<decltype(std::ranges::subrange(range))>
-{
- auto pos = std::ranges::begin(range);
- auto end = std::ranges::end(range);
-
- for (;;) {
- // Skip leading separators.
- while (pos != end && pred(*pos))
- ++pos;
-
- if (pos == end)
- co_return;
-
- auto const split_point = std::find_if(pos, end, pred);
-
- // Yield this value.
- co_yield std::ranges::subrange(pos, split_point);
-
- pos = split_point;
- }
-}
-
-/*
- * split_string: helper function to make split() a bit more useful for strings.
- * Instead of returning subranges, it returns basic_string_views.
- */
-auto split_string(std::ranges::contiguous_range auto &&string, auto pred)
- -> std::generator<
- std::basic_string_view<
- std::ranges::range_value_t<decltype(string)>>>
-{
- using sv_type = std::basic_string_view<
- std::ranges::range_value_t<decltype(string)>>;
-
- for (auto const &&subrange : split(string, pred))
- co_yield sv_type(subrange);
-}
-
-} // namespace lfjail
-
-#endif // !LFJAIL_SPLIT_HH
diff --git a/liblfjail/zfs.cc b/liblfjail/zfs.cc
index 5ecd826..bc0caee 100644
--- a/liblfjail/zfs.cc
+++ b/liblfjail/zfs.cc
@@ -28,12 +28,12 @@ namespace {
constexpr std::string path_zpool = "/sbin/zpool";
constexpr std::string path_zfs = "/sbin/zfs";
-// Run a command (probably a zfs command), split its output into lines,
-// and return each line.
-//
-// The spawn_how argument is the same as lfjail::spawn().
-auto spawn_lines(exec::executor auto &&executor)
- -> std::generator<std::string_view>
+/*
+ * Run a command and split each line of output into whitespace-separated
+ * columns.
+ */
+auto columns(exec::executor auto &&executor)
+ -> std::generator<std::vector<std::string_view>>
{
std::string output;
@@ -43,17 +43,9 @@ auto spawn_lines(exec::executor auto &&executor)
if (!result)
throw zfs_error("failed to run zfs command");
- co_yield std::ranges::elements_of(words(output, '\n'));
-}
-
-// Like spawn_lines, but each line is returned as a vector of words.
-auto spawn_words(auto &&spawn_how)
- -> std::generator<std::vector<std::string_view>>
-{
- auto lines = spawn_lines(std::forward<decltype(spawn_how)>(spawn_how));
-
- for (auto &&line : lines)
+ for (auto &&line : words(output, '\n')) {
co_yield std::vector(std::from_range, words(line));
+ }
}
// Run a command which produces two columns of output, assumed to be
@@ -61,7 +53,7 @@ auto spawn_words(auto &&spawn_how)
// each line.
auto set_values(auto &&map, std::string command, auto &&...args) -> void
{
- auto lines = spawn_words(
+ auto lines = columns(
exec::execl(std::move(command), std::move(args)...));
for (auto &&words : lines) {
@@ -86,22 +78,22 @@ auto get_pool(std::string_view name) -> pool {
std::pair{"name"sv, [&ret](auto &&v) { ret.name = v; }},
};
- set_values(handlers, path_zpool, "zpool", "get",
- "-H", "-oproperty,value", "all", name);
+ set_values(handlers, path_zpool,
+ "zpool", "get", "-H", "-oproperty,value", "all", name);
return ret;
}
auto get_pools() -> std::generator<pool> {
- auto lines = spawn_words(
- exec::execl(path_zpool, "zpool", "get", "-H", "-o", "name"));
+ auto lines = columns(exec::execl(path_zpool,
+ "zpool", "get", "-H", "-o", "name"));
for (auto &&words : lines)
co_yield get_pool(words[0]);
}
-auto get_filesystem(std::string_view name) -> filesystem {
- auto ret = filesystem{};
+auto get_dataset(std::string_view name) -> dataset {
+ auto ret = dataset{};
auto handlers = std::unordered_map{
std::pair{"name"sv, [&ret](auto &&v) { ret.name = v; }},
@@ -113,12 +105,21 @@ auto get_filesystem(std::string_view name) -> filesystem {
return ret;
}
-auto get_filesystems() -> std::generator<filesystem> {
- auto lines = spawn_words(
- exec::execl(path_zfs, "zfs", "get", "-H", "-o", "name"));
+auto get_dataset_names() -> std::generator<std::string> {
+ auto lines = columns(exec::execl(path_zfs,
+ "zfs", "get", "-H", "-o", "name"));
for (auto &&words : lines)
- co_yield get_filesystem(words[0]);
+ co_yield std::string(words[0]);
+}
+
+auto get_datasets() -> std::generator<dataset> {
+ for (auto &&dataset : get_dataset_names())
+ co_yield get_dataset(dataset);
+}
+
+auto dataset_exists(std::string name) -> bool {
+ return std::ranges::contains(get_dataset_names(), name);
}
} // namespace lfjail::zfs
diff --git a/liblfjail/zfs.hh b/liblfjail/zfs.hh
index 30bd457..915e042 100644
--- a/liblfjail/zfs.hh
+++ b/liblfjail/zfs.hh
@@ -34,18 +34,24 @@ auto get_pool(std::string_view name) -> pool;
auto get_pools() -> std::generator<pool>;
/*
- * Filesystems.
+ * Datasets.
*/
-struct filesystem {
+struct dataset {
std::string name;
};
-/* Fetch details for a specific filesystem by name. */
-auto get_filesystem(std::string_view name) -> filesystem;
+/* Return true if a dataset by this name exists. */
+auto dataset_exists(std::string_view name) -> bool;
-/* Fetch details for all filesystems on the system. */
-auto get_filesystems() -> std::generator<filesystem>;
+/* Fetch details for a specific dataset by name. */
+auto get_dataset(std::string_view name) -> dataset;
+
+/* Fetch names for all datasets on the system. */
+auto get_dataset_names() -> std::generator<std::string>;
+
+/* Fetch details for all datasets on the system. */
+auto get_datasets() -> std::generator<dataset>;
} // namespace lfjail::zfs