diff options
Diffstat (limited to 'liblfjail/zfs.cc')
| -rw-r--r-- | liblfjail/zfs.cc | 220 |
1 files changed, 206 insertions, 14 deletions
diff --git a/liblfjail/zfs.cc b/liblfjail/zfs.cc index bc0caee..5eaf655 100644 --- a/liblfjail/zfs.cc +++ b/liblfjail/zfs.cc @@ -9,6 +9,7 @@ * on FreeBSD, e.g. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=257222. */ +#include <functional> #include <unordered_map> #include <unistd.h> @@ -24,16 +25,12 @@ namespace lfjail::zfs { namespace { -// Hardcode the program locations so we don't rely on $PATH. -constexpr std::string path_zpool = "/sbin/zpool"; -constexpr std::string path_zfs = "/sbin/zfs"; - /* * 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::generator<std::vector<std::string>> { std::string output; @@ -69,17 +66,146 @@ auto set_values(auto &&map, std::string command, auto &&...args) -> void } } +template<typename T> +struct set_simple; + +template<typename T> +set_simple(T *) -> set_simple<T>; + +template<> +struct set_simple<bool> { + set_simple(bool *valuep_) : valuep(valuep_) {} + + bool *valuep; + + auto operator() (std::string_view newvalue) -> void { + if (newvalue == "on") + *valuep = true; + else if (newvalue == "off") + *valuep = false; + else + throw zfs_error("unexpected boolean value: {}", + newvalue); + } +}; + +template<> +struct set_simple<std::string> { + set_simple(std::string *valuep_) : valuep(valuep_) {} + + std::string *valuep; + + auto operator() (std::string_view newvalue) -> void { + *valuep = newvalue; + } +}; + +template<> +struct set_simple<std::optional<std::string>> { + set_simple(std::optional<std::string> *valuep_) : valuep(valuep_) {} + + std::optional<std::string> *valuep; + + auto operator() (std::string_view newvalue) -> void { + if (newvalue != "-") + *valuep = newvalue; + } +}; + + +template<> +struct set_simple<std::uint64_t> { + set_simple(std::uint64_t *valuep_) : valuep(valuep_) {} + + std::uint64_t *valuep; + + auto operator() (std::string_view newvalue) -> void { + // XXX + std::string cvalue(newvalue); + *valuep = strtoull(cvalue.c_str(), NULL, 10); + } +}; + +template<> +struct set_simple<unsigned> { + set_simple(unsigned *valuep_) : valuep(valuep_) {} + + unsigned *valuep; + + auto operator() (std::string_view newvalue) -> void { + // XXX + std::string cvalue(newvalue); + *valuep = std::strtoul(cvalue.c_str(), NULL, 10); + } +}; + +template<> +struct set_simple<double> { + set_simple(double *valuep_) : valuep(valuep_) {} + + double *valuep; + + auto operator() (std::string_view newvalue) -> void { + // XXX + std::string cvalue(newvalue); + *valuep = std::atof(cvalue.c_str()); + } +}; + +template<typename Tag> +struct set_simple<enumeration<Tag>> { + set_simple(enumeration<Tag> *valuep_) : valuep(valuep_) {} + + enumeration<Tag> *valuep; + + auto operator() (std::string_view newvalue) -> void { + valuep->value = newvalue; + } +}; + } // anonymous namespace auto get_pool(std::string_view name) -> pool { auto ret = pool{}; - - auto handlers = std::unordered_map{ - std::pair{"name"sv, [&ret](auto &&v) { ret.name = v; }}, + ret.name = name; + + static const auto handlers = std::unordered_map<std::string_view, + std::function<void (std::string_view)>>{ + {"guid"sv, set_simple(&ret.guid)}, + {"load_guid"sv, set_simple(&ret.load_guid)}, + {"size"sv, set_simple(&ret.size)}, + {"free"sv, set_simple(&ret.free)}, + {"allocated"sv, set_simple(&ret.allocated)}, + {"altroot"sv, set_simple(&ret.altroot)}, + {"health"sv, set_simple(&ret.health)}, + {"bootfs"sv, set_simple(&ret.bootfs)}, + {"delegation"sv, set_simple(&ret.delegation)}, + {"autoreplace"sv, set_simple(&ret.autoreplace)}, + {"cachefile"sv, set_simple(&ret.cachefile)}, + {"failmode"sv, set_simple(&ret.failmode)}, + {"listsnapshots"sv, set_simple(&ret.listsnapshots)}, + {"autoexpand"sv, set_simple(&ret.autoexpand)}, + {"readonly"sv, set_simple(&ret.readonly)}, + {"ashift"sv, set_simple(&ret.ashift)}, + {"comment"sv, set_simple(&ret.comment)}, + {"expandsize"sv, set_simple(&ret.expandsize)}, + {"freeing"sv, set_simple(&ret.freeing)}, + {"fragmentation"sv, set_simple(&ret.fragmentation)}, + {"leaked"sv, set_simple(&ret.leaked)}, + {"multihost"sv, set_simple(&ret.multihost)}, + {"checkpoint"sv, set_simple(&ret.checkpoint)}, + {"autotrim"sv, set_simple(&ret.autotrim)}, + {"compatibility"sv, set_simple(&ret.compatibility)}, + {"bcloneused"sv, set_simple(&ret.bcloneused)}, + {"bclonesaved"sv, set_simple(&ret.bclonesaved)}, + {"bcloneratio"sv, set_simple(&ret.bcloneratio)}, + {"dedup_table_size"sv, set_simple(&ret.dedup_table_size)}, + {"dedupratio"sv, set_simple(&ret.dedupratio)}, + {"last_scrubbed_txg"sv, set_simple(&ret.last_scrubbed_txg)}, }; set_values(handlers, path_zpool, - "zpool", "get", "-H", "-oproperty,value", "all", name); + "zpool", "get", "-Hp", "-oproperty,value", "all", name); return ret; } @@ -94,13 +220,63 @@ auto get_pools() -> std::generator<pool> { 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; }}, + ret.name = name; + + static const auto handlers = std::unordered_map<std::string_view, + std::function<void (std::string_view)>>{ + {"type"sv, set_simple(&ret.type)}, + {"creation"sv, set_simple(&ret.creation)}, + {"used"sv, set_simple(&ret.used)}, + {"available"sv, set_simple(&ret.available)}, + {"referenced"sv, set_simple(&ret.referenced)}, + {"compressratio"sv, set_simple(&ret.compressratio)}, + {"mounted"sv, set_simple(&ret.mounted)}, + {"quota"sv, set_simple(&ret.quota)}, + {"reservation"sv, set_simple(&ret.reservation)}, + {"recordsize"sv, set_simple(&ret.recordsize)}, + {"sharenfs"sv, set_simple(&ret.sharenfs)}, + {"checksum"sv, set_simple(&ret.checksum)}, + {"compression"sv, set_simple(&ret.compression)}, + {"atime"sv, set_simple(&ret.atime)}, + {"devices"sv, set_simple(&ret.devices)}, + {"exec"sv, set_simple(&ret.exec)}, + {"setuid"sv, set_simple(&ret.setuid)}, + {"readonly"sv, set_simple(&ret.readonly)}, + {"jailed"sv, set_simple(&ret.jailed)}, + {"snapdir"sv, set_simple(&ret.snapdir)}, + {"aclmode"sv, set_simple(&ret.aclmode)}, + {"aclinherit"sv, set_simple(&ret.aclinherit)}, + {"createtxg"sv, set_simple(&ret.createtxg)}, + {"canmount"sv, set_simple(&ret.canmount)}, + {"xattr"sv, set_simple(&ret.xattr)}, + {"copies"sv, set_simple(&ret.copies)}, + {"version"sv, set_simple(&ret.version)}, + {"utf8only"sv, set_simple(&ret.utf8only)}, + {"normalization"sv, set_simple(&ret.normalization)}, + {"vscan"sv, set_simple(&ret.vscan)}, + {"nbmand"sv, set_simple(&ret.nbmand)}, + {"sharesmb"sv, set_simple(&ret.sharesmb)}, + {"refquota"sv, set_simple(&ret.refquota)}, + {"refreservation"sv, set_simple(&ret.refreservation)}, + {"guid"sv, set_simple(&ret.guid)}, + {"primarycache"sv, set_simple(&ret.primarycache)}, + {"secondarycache"sv, set_simple(&ret.secondarycache)}, + {"usedbysnapshots"sv, set_simple(&ret.usedbysnapshots)}, + {"usedbydataset"sv, set_simple(&ret.usedbydataset)}, + {"usedbychildren"sv, set_simple(&ret.usedbychildren)}, + {"usedbyrefreservation"sv, + set_simple(&ret.usedbyrefreservation)}, + {"logbias"sv, set_simple(&ret.logbias)}, + {"objsetid"sv, set_simple(&ret.objsetid)}, + {"dedup"sv, set_simple(&ret.dedup)}, + {"mlslabel"sv, set_simple(&ret.mlslabel)}, + {"sync"sv, set_simple(&ret.sync)}, + {"dnodesize"sv, set_simple(&ret.dnodesize)}, + {"refcompressratio"sv, set_simple(&ret.refcompressratio)}, }; - set_values(handlers, path_zfs, "zfs", "get", "-H", - "-oproperty,value"sv, "all", name); + set_values(handlers, path_zfs, "zfs", "get", "-Hp", + "-oproperty,value", "all", name); return ret; } @@ -122,4 +298,20 @@ auto dataset_exists(std::string name) -> bool { return std::ranges::contains(get_dataset_names(), name); } +/* + * Create a new ZFS dataset. + */ +auto destroy_dataset(std::string const &dsname) -> void { + using namespace std::literals; + + try { + auto ret = spawn(exec::execl(path_zfs, + "zfs", "destroy", "-r", "--", dsname)).wait(); + if (!ret) + throw zfs_error("failed to destroy dataset"); + } catch (std::exception const &exc) { + throw zfs_error("failed to destroy dataset: {}", exc.what()); + } +} + } // namespace lfjail::zfs |
