1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
/*
* This source code is released into the public domain.
*/
#include "exec.hh"
#include "jail.hh"
#include "generic_error.hh"
#include "fileutils.hh"
#include "jail_zfs.hh"
#include "spawn.hh"
namespace {
using namespace lfjail;
// Get the jails storage directory.
auto get_jails_dir(context const &ctx) -> std::string {
return ctx.path("jails");
}
// Get the config file for a jail.
auto jail_config_file(context const &ctx,
std::string_view jailname)
-> std::string
{
return std::format("{}/{}.ucl", get_jails_dir(ctx), jailname);
}
// Make sure our jails config path exists.
void ensure_jails_dir(context const &ctx) {
ensure_dir(ctx, get_jails_dir(ctx));
}
} // anonymous namespace
namespace lfjail {
auto get_jail_config(context const &ctx, std::string_view jailname)
-> std::optional<jail>
{
ensure_jails_dir(ctx);
auto file = jail_config_file(ctx, jailname);
// Load the configuration text.
std::string config_text;
try {
read_file(file, std::back_inserter(config_text));
} catch (io_error const &exc) {
if (exc.error == std::errc::no_such_file_or_directory)
return {};
throw;
}
// Parse the UCL.
std::string err;
auto uclconfig = ucl::Ucl::parse(config_text, err);
jail ret;
ret.name = jailname;
if (!uclconfig)
throw generic_error("{0}: {1}", file, err);
for (auto const &uclvalue : uclconfig) {
throw generic_error("{}: unknown option '{}'",
file, uclvalue.key());
}
return {ret};
}
void set_jail_config(context const &ctx, jail const &jailconf) {
// The UCL C++ API doesn't seem to support creating new objects
// from scratch, so we use the C API here.
auto ucl = ::ucl_object_typed_new(UCL_OBJECT);
auto ucl_guard = guard([ucl] { ::ucl_object_unref(ucl); });
// We could add some jail options here...
// Dump the UCL object to a string.
auto *ucl_c_text = reinterpret_cast<char *>(
::ucl_object_emit(ucl, UCL_EMIT_CONFIG));
//NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
auto ucl_text_guard = guard([ucl_c_text] { ::free(ucl_c_text); });
std::string ucl_text(ucl_c_text);
// Write the object to a file.
auto file = jail_config_file(ctx, jailconf.name);
safe_write_file(file, ucl_text);
}
auto jail_exists(context const &ctx, std::string_view name) -> bool {
return static_cast<bool>(get_jail_config(ctx, name));
}
void jail_destroy(context const &ctx, jail const &jailconf) {
auto file = jail_config_file(ctx, jailconf.name);
::unlink(file.c_str());
zfs::destroy_for_jail(ctx, jailconf);
}
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");
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
|