~nabijaczleweli/klapki

a670da811dfde10367257d1ace354dd3ac94f89b — наб 1 year, 5 days ago 1454595
clean(er)
M src/config.cpp => src/config.cpp +10 -20
@@ 42,7 42,6 @@ extern "C" {
	})


// TODO: propagate no-longer-variance
static std::string get_host() {
	if(auto host = std::getenv("KLAPKI_HOST"))
		return host;


@@ 67,7 66,7 @@ static std::variant<std::string_view, std::string> get_wisom_root() {
		return std::string_view{"/etc/klapki/"};
}

static std::variant<std::pair<dev_t, const char *>, std::string> find_esp() {
static std::variant<std::string_view, std::string> find_esp() {
	const char * esp = "/boot/efi";

	struct stat boot;


@@ 89,23 88,13 @@ static std::variant<std::pair<dev_t, const char *>, std::string> find_esp() {
	if(boot.st_dev == boot_efi.st_dev)
		return fmt::format("find_esp(): {}: not a mount point?", esp);

	return std::pair{boot_efi.st_dev, esp};
}


// TODO: make into a string_view
const char * klapki::config::host() const noexcept {
	return std::visit([](auto && h) { return h.data(); }, this->host_raw);
}

const char * klapki::config::wisdom_root() const noexcept {
	return std::visit([](auto && w) { return w.data(); }, this->wisdom_root_raw);
	return std::string_view{esp};
}


std::string klapki::config::news_efi_dir() const {
	// TODO: rethink this potentially
	return fmt::format("\\klapki\\{}\\", std::getenv("KLAPKI_EFI_ROOT") ?: this->host());
	return fmt::format("\\klapki\\{}\\", std::getenv("KLAPKI_EFI_ROOT") ?: this->host);
}




@@ 132,12 121,13 @@ std::variant<klapki::config, std::string> klapki::config::read(const char ** arg

				case 'h':
					return fmt::format("klapki {}\n"
					                   "Usage: {} [-vh]… [op [arg…]]…\n"
					                   "Usage: {} [-vEnh]… [op [arg…]]…\n"
					                   "\n"
					                   "-v\tVerbose operation\n"
					                   "-E\tIncrease libefivar verbosity level\n"
					                   "-n\tDon't commit\n"
					                   "-h\tShow this help\n"
					                   "Flags:\n"
					                   "  -v\tVerbose operation\n"
					                   "  -E\tIncrease libefivar verbosity level\n"
					                   "  -n\tDon't commit\n"
					                   "  -h\tShow this help\n"
					                   "\n"
					                   "Recognised ops:\n"
					                   "\tdump\n"


@@ 170,5 160,5 @@ std::variant<klapki::config, std::string> klapki::config::read(const char ** arg
	if(ops.empty())
		fmt::print("{}: no operations given, committing cleanly instead.\n", argv0);  // TODO: remove this maybe?

	return config{argv0, verbose, commit, TRY(find_esp()), std::move(ops), get_host(), get_wisom_root()};
	return config{argv0, get_host(), verbose, commit, TRY(find_esp()), std::move(ops), get_wisom_root()};
}

M src/config.hpp => src/config.hpp +9 -13
@@ 34,16 34,14 @@
namespace klapki {
	struct config {
		const char * argv0;
		const char * host() const noexcept;
		const char * wisdom_root() const noexcept;
		std::string host;
		constexpr std::string_view wisdom_root() const noexcept;
		bool verbose;
		bool commit;
		/// Tries /boot/efi, or /boot if that doesn't exist. Must be a mount-point.
		// TODO: nobody's using the device part now
		std::pair<dev_t, const char *> esp;
		std::string_view esp;
		std::vector<ops::op_t> ops;

		std::variant<std::string_view, std::string> host_raw;
		std::variant<std::string_view, std::string> wisdom_root_raw;

		std::string news_efi_dir() const;


@@ 53,19 51,17 @@ namespace klapki {
}


constexpr std::string_view klapki::config::wisdom_root() const noexcept {
	return std::visit([](auto && w) { return std::string_view{w}; }, this->wisdom_root_raw);
}

template <>
struct fmt::formatter<klapki::config> {
	constexpr auto parse(format_parse_context & ctx) { return ctx.begin(); }

	template <typename FormatContext>
	auto format(const klapki::config & cfg, FormatContext & ctx) {
		return format_to(ctx.out(),
		                 "Host   : {}\n"
		                 "Wisdom : {}\n"
		                 "Verbose: {}\n"
		                 "Commit : {}\n"
		                 "ESP    : {}:{} ({})\n"
		                 "Ops    : {}",
		                 cfg.host(), cfg.wisdom_root(), cfg.verbose, cfg.commit, major(cfg.esp.first), minor(cfg.esp.first), cfg.esp.second, klapki::mops{cfg.ops});
		return format_to(ctx.out(), "config{{ host: \"{}\", wisdom: \"{}\", verbose: {}, commit: {}, ESP: {}, ops: [{}] }}",  //
		                 cfg.host, cfg.wisdom_root(), cfg.verbose, cfg.commit, cfg.esp, klapki::mops{cfg.ops});
	}
};

M src/context_commit.cpp => src/context_commit.cpp +5 -5
@@ 82,9 82,9 @@ std::optional<std::string> klapki::context::context::commit(const config & cfg, 
			close(fd);
	}};
	{
		auto esp_fd = open(cfg.esp.second, O_RDONLY | O_DIRECTORY | O_PATH);
		auto esp_fd = open(cfg.esp.data(), O_RDONLY | O_DIRECTORY | O_PATH);
		if(esp_fd < 0)
			return fmt::format("Couldn't open ESP ({}): {}\n", cfg.esp.second, strerror(errno));
			return fmt::format("Couldn't open ESP ({}): {}\n", cfg.esp, strerror(errno));
		quickscope_wrapper esp_fd_deleter{[&] { close(esp_fd); }};

		for(auto && kern : this->our_kernels)


@@ 108,15 108,15 @@ std::optional<std::string> klapki::context::context::commit(const config & cfg, 
				for(auto slash_idx = dir.find('/'); slash_idx != std::string::npos; slash_idx = dir.find('/', slash_idx + 1)) {
					dir[slash_idx] = '\0';
					if(mkdirat(esp_fd, dir.c_str(), 0755) < 0 && errno != EEXIST)
						return fmt::format("Couldn't create {} under ESP ({}): {}\n", dir.c_str(), cfg.esp.second, strerror(errno));
						return fmt::format("Couldn't create {} under ESP ({}): {}\n", dir.c_str(), cfg.esp, strerror(errno));
					dir[slash_idx] = '/';
				}
				if(mkdirat(esp_fd, dir.c_str(), 0755) < 0 && errno != EEXIST)
					return fmt::format("Couldn't create {} under ESP ({}): {}\n", dir, cfg.esp.second, strerror(errno));
					return fmt::format("Couldn't create {} under ESP ({}): {}\n", dir, cfg.esp, strerror(errno));

				auto fd = openat(esp_fd, dir.c_str(), O_RDONLY | O_DIRECTORY | O_PATH);
				if(fd < 0)
					return fmt::format("Couldn't open {} under ESP ({}): {}\n", dir, cfg.esp.second, strerror(errno));
					return fmt::format("Couldn't open {} under ESP ({}): {}\n", dir, cfg.esp, strerror(errno));
				esp_dirs.emplace(kern.second.image_path.first, fd);
			}
	}

M src/context_save.cpp => src/context_save.cpp +1 -15
@@ 40,8 40,6 @@ static constexpr bool isslash(char c) {


std::optional<std::string> klapki::context::context::save(const config & cfg, state::state & state) {
	// const auto esp_blockdev = fmt::format("/dev/block/{}:0", major(cfg.esp.first));

	for(auto && [bootnum, kern] : this->our_kernels) {
		auto skern = std::find_if(std::begin(state.statecfg.wanted_entries), std::end(state.statecfg.wanted_entries),
		                          [bn = bootnum](auto && skern) { return skern.bootnum_hint == bn; });


@@ 51,8 49,7 @@ std::optional<std::string> klapki::context::context::save(const config & cfg, st
		if(bent == std::end(state.entries))
			throw __func__;

		auto image_path =
		    fmt::format("{}/{}{}{}", cfg.esp.second, kern.image_path.first, isslash(kern.image_path.first.back()) ? "" : "\\", kern.image_path.second);
		auto image_path = fmt::format("{}/{}{}{}", cfg.esp, kern.image_path.first, isslash(kern.image_path.first.back()) ? "" : "\\", kern.image_path.second);
		image_path.erase(std::remove_if(std::begin(image_path), std::end(image_path),
		                                [prev = false](auto c) mutable {
			                                auto cur = isslash(c);


@@ 71,17 68,6 @@ std::optional<std::string> klapki::context::context::save(const config & cfg, st
		do {
			devpath.resize(devpath.size() + 512);

			// extern ssize_t efi_generate_file_device_path_from_esp(uint8_t *buf,
			// 	      ssize_t size,
			// 	      const char *devpath,
			// 	      int partition,
			// 	      const char *relpath,
			// 	      uint32_t options, ...)
			// if(auto size = efi_generate_file_device_path_from_esp(devpath.data(), devpath.size(),              //
			//                                                       esp_blockdev.c_str(), minor(cfg.esp.first),  //
			//                                                       image_path.c_str(),                          //
			//                                                       0);

			// extern ssize_t efi_generate_file_device_path(uint8_t *buf, ssize_t size,
			// 	      const char * const filepath,
			// 	      uint32_t options, ...)

M src/context_state.cpp => src/context_state.cpp +2 -5
@@ 48,11 48,8 @@ struct fmt::formatter<sha_f> {

std::variant<klapki::state::state, std::string> klapki::context::resolve_state_context(const state::state & input_state) {
	std::map<std::uint16_t, state::boot_entry> entries{input_state.entries};
	// TODO: parallellise this
	// [02:06] ((наб *)(войд)())(): argh fuck
	// [02:07] ((наб *)(войд)())(): libc++12 from the LLVM repo doesn't have a working <execution>
	// [02:08] Griwes: lmao the only actually shipping and actually working <execution> in existence is the one in the NVHPC toolkit :vv:
	// [02:08] Griwes: ...well, maybe msvc has something, can't remember if they shipped yet
	// When measured (KVM, amd64 on amd64, Xeon E5645 @ 2.40GHz, 6 vCPUs), this took 23`636ns all told for 14 SHAs (+outlier at 207`817);
	// multithreading is much much more expensive: 2`633`277.86ns on same dataset when spawning a std::thread per.
	std::for_each(std::begin(entries), std::end(entries),
	              [](auto & bent) { SHA1(bent.second.load_option.get(), bent.second.load_option_len, bent.second.load_option_sha); });


M src/main.cpp => src/main.cpp +1 -1
@@ 51,7 51,7 @@ namespace klapki {
			fmt::print("{}\n", cfg);


		const auto input_state = TRY(2, state::state::load(cfg.argv0, cfg.host()));
		const auto input_state = TRY(2, state::state::load(cfg.argv0, cfg.host.c_str()));


		auto output_state = TRY(3, context::resolve_state_context(input_state));

M src/state.cpp => src/state.cpp +8 -7
@@ 60,8 60,8 @@ static bool is_boot_order(const efi_guid_t & guid, const char * name) noexcept {
	return guid == efi_guid_global && !std::strcmp(name, "BootOrder");
}

static bool is_our_config(const efi_guid_t & guid, const char * name, const char * us) noexcept {
	return guid == klapki::efi_guid_klapki && !std::strcmp(name, us);
static bool is_our_config(const efi_guid_t & guid, const char * name, std::string_view us) noexcept {
	return guid == klapki::efi_guid_klapki && name == us;
}

template <class F>


@@ 86,21 86,22 @@ static int get_boot_order(klapki::state::boot_order_flat & bord) {
}

static int get_boot_entry(std::map<std::uint16_t, klapki::state::boot_entry> & bents, std::uint16_t num) {
	// TODO: sprintf() and avoid an allocation instead?
	return get_efi_data(efi_guid_global, fmt::format("Boot{:04X}", num).c_str(), [&](auto && data, auto size, auto attr) {
	char name[4 + 4 + 1]{};
	fmt::format_to(name, "Boot{:04X}", num);
	return get_efi_data(efi_guid_global, name, [&](auto && data, auto size, auto attr) {
		bents.emplace(num, klapki::state::boot_entry{std::move(data), size, {}, attr});
		return 0;
	});
}

static int get_our_config(klapki::state::stated_config & statecfg, const char * us) {
	return get_efi_data(klapki::efi_guid_klapki, us,
static int get_our_config(klapki::state::stated_config & statecfg, std::string_view us) {
	return get_efi_data(klapki::efi_guid_klapki, us.data(),
	                    // TODO: error recovery; flag to ignore? force?
	                    [&](auto && data, auto size, auto) { return klapki::state::stated_config::parse(statecfg, data.get(), size); });
}


std::variant<klapki::state::state, std::string> klapki::state::state::load(const char * argv0, const char * us) {
std::variant<klapki::state::state, std::string> klapki::state::state::load(const char * argv0, std::string_view us) {
	if(!efi_variables_supported())
		return fmt::format("{}: EFI not supported?", argv0);


M src/state.hpp => src/state.hpp +1 -1
@@ 93,7 93,7 @@ namespace klapki::state {

		std::optional<std::string> commit(const config & cfg, const state & original_state);

		static std::variant<state, std::string> load(const char * argv0, const char * us);
		static std::variant<state, std::string> load(const char * argv0, std::string_view us);
	};
}


M src/state_commit.cpp => src/state_commit.cpp +1 -1
@@ 45,7 45,7 @@ std::optional<std::string> klapki::state::state::commit(const config & cfg, cons

		auto statecfg_raw = this->statecfg.serialise();

		if(efi_set_variable(klapki::efi_guid_klapki, cfg.host(), statecfg_raw.data(), statecfg_raw.size(),
		if(efi_set_variable(klapki::efi_guid_klapki, cfg.host.c_str(), statecfg_raw.data(), statecfg_raw.size(),
		                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0600) < 0)
			return fmt::format("Couldn't write new state config: {}", strerror(errno));
	}