~nabijaczleweli/klapki

bfaaf3b0ee87d924825987cdd6449a38d6d9627e — наб 1 year, 2 days ago 5bf2a47
Sort our boot entries. Handle KLAPKI_EFI_ROOT better maybe?
3 files changed, 69 insertions(+), 38 deletions(-)

M src/config.cpp
M src/context_save.cpp
M src/context_state.cpp
M src/config.cpp => src/config.cpp +12 -2
@@ 93,8 93,18 @@ static std::variant<std::string_view, std::string> find_esp() {


std::string klapki::config::news_efi_dir() const {
	// TODO: rethink this potentially
	return fmt::format("\\klapki\\{}\\", std::getenv("KLAPKI_EFI_ROOT") ?: this->host);
	std::string broot;
	std::string_view vroot = "klapki";
	if(auto root = std::getenv("KLAPKI_EFI_ROOT")) {
		while(*root == '\\' || *root == '/')
			++root;
		broot = root;
		std::transform(std::begin(broot), std::end(broot), std::begin(broot), [](auto c) { return c == '/' ? '\\' : c; });
		while(!broot.empty() && broot.back() == '\\')
			broot.pop_back();
		vroot = broot;
	}
	return fmt::format("\\{}{}{}\\", vroot, vroot.empty() ? "" : "\\", this->host);
}



M src/context_save.cpp => src/context_save.cpp +55 -35
@@ 175,8 175,6 @@ std::optional<std::string> klapki::context::context::save(const config & cfg, st
		                      reinterpret_cast<std::uint8_t *>(cmdline.data()), cmdline.size() * sizeof(std::uint16_t)) < 0)
			return fmt::format("Making load option for {:04X}: {}", bootnum, strerror(errno));

		// write(open("oot", O_WRONLY | O_CREAT | O_DSYNC | O_TRUNC), bent->second.load_option.get(), bent->second.load_option_len);

		SHA1(bent->second.load_option.get(), bent->second.load_option_len, bent->second.load_option_sha);
		if(std::memcmp(bent->second.load_option_sha, skern->load_option_sha, sizeof(sha_t)))
			fmt::print("Entry {:04X} changed\n", bootnum);


@@ 186,39 184,61 @@ std::optional<std::string> klapki::context::context::save(const config & cfg, st

	if(cfg.verbose)
		fmt::print("Bootorder pre : {}\n", state.order);
	state.order =
	    std::visit(klapki::overload{
	                   [&](klapki::state::boot_order_flat && bof) {
		                   fmt::print(stderr, "wisen(): flat bootorder?\n");  // Weird, but that's what we want anyway
		                   return std::move(bof);
	                   },
	                   [&](klapki::state::boot_order_structured && bos) {
		                   std::vector<std::uint16_t> bents[2];
		                   for(auto && [cluster, ours] : std::move(bos.order))
			                   if(bents[ours].empty())
				                   bents[ours] = std::move(cluster);
			                   else
				                   bents[ours].insert(std::end(bents[ours]), std::begin(cluster), std::end(cluster));

		                   const auto target_pos = std::min(bents[false].size(), static_cast<std::size_t>(state.statecfg.boot_position));
		                   if(bents[false].size() < state.statecfg.boot_position)
			                   fmt::print(stderr, "Not enough entries to be at position {}. Being at {} instead.\n", state.statecfg.boot_position, target_pos);

		                   const auto size = bents[false].size() + bents[true].size();
		                   const std::shared_ptr<std::uint16_t[]> flat{new std::uint16_t[size]};
		                   std::memset(flat.get(), 0xFA, size * 2);

		                   // TODO: sort by version? variant?
		                   auto curs = std::copy_n(bents[false].data(), target_pos, flat.get());
		                   curs      = std::copy_n(bents[true].data(), bents[true].size(), curs);
		                   curs      = std::copy_n(bents[false].data() + target_pos, bents[false].size() - target_pos, curs);
		                   if(curs != flat.get() + size)  // This is an assert() but asserts blow ass, so it's a throw instead
			                   throw __func__;

		                   return state::boot_order_flat{flat, size};
	                   },
	               },
	               std::move(state.order));
	state.order = std::visit(
	    klapki::overload{
	        [&](klapki::state::boot_order_flat && bof) {
		        fmt::print(stderr, "wisen(): flat bootorder?\n");  // Weird, but that's what we want anyway
		        return std::move(bof);
	        },
	        [&](klapki::state::boot_order_structured && bos) {
		        std::vector<std::uint16_t> bents[2];
		        for(auto && [cluster, ours] : std::move(bos.order))
			        if(bents[ours].empty())
				        bents[ours] = std::move(cluster);
			        else
				        bents[ours].insert(std::end(bents[ours]), std::begin(cluster), std::end(cluster));

		        const auto target_pos = std::min(bents[false].size(), static_cast<std::size_t>(state.statecfg.boot_position));
		        if(bents[false].size() < state.statecfg.boot_position)
			        fmt::print(stderr, "Not enough entries to be at position {}. Being at {} instead.\n", state.statecfg.boot_position, target_pos);

		        const auto size = bents[false].size() + bents[true].size();
		        const std::shared_ptr<std::uint16_t[]> flat{new std::uint16_t[size]};

		        // By biggest version, then variant index.
		        std::sort(std::begin(bents[true]), std::end(bents[true]), [&](auto && lhs, auto && rhs) {
			        auto lskern = std::find_if(std::begin(state.statecfg.wanted_entries), std::end(state.statecfg.wanted_entries),
			                                   [&](auto && skern) { return skern.bootnum_hint == lhs; });
			        if(lskern == std::end(state.statecfg.wanted_entries))
				        throw __func__;
			        auto rskern = std::find_if(std::begin(state.statecfg.wanted_entries), std::end(state.statecfg.wanted_entries),
			                                   [&](auto && skern) { return skern.bootnum_hint == rhs; });
			        if(rskern == std::end(state.statecfg.wanted_entries))
				        throw __func__;

			        if(lskern->version != rskern->version)
				        return lskern->version > rskern->version;

			        auto lvar = lskern->variant == "" ? -1 : std::find_if(std::begin(state.statecfg.variants), std::end(state.statecfg.variants), [&](auto && var) {
				                                                 return var == lskern->variant;
			                                                 }) - std::begin(state.statecfg.variants);
			        auto rvar = rskern->variant == "" ? -1 : std::find_if(std::begin(state.statecfg.variants), std::end(state.statecfg.variants), [&](auto && var) {
				                                                 return var == rskern->variant;
			                                                 }) - std::begin(state.statecfg.variants);

			        return lvar < rvar;
		        });

		        auto curs = std::copy_n(bents[false].data(), target_pos, flat.get());
		        curs      = std::copy_n(bents[true].data(), bents[true].size(), curs);
		        curs      = std::copy_n(bents[false].data() + target_pos, bents[false].size() - target_pos, curs);
		        if(curs != flat.get() + size)  // This is an assert() but asserts blow ass, so it's a throw instead
			        throw __func__;

		        return state::boot_order_flat{flat, size};
	        },
	    },
	    std::move(state.order));
	if(cfg.verbose)
		fmt::print("Bootorder post: {}\n", state.order);


M src/context_state.cpp => src/context_state.cpp +2 -1
@@ 123,7 123,8 @@ std::variant<klapki::state::state, std::string> klapki::context::resolve_state_c
			                                      else {
				                                      std::vector<std::uint16_t> bns{*cur};
				                                      bns.swap(bootnums);
				                                      ret.order.emplace_back(std::move(bns), ours);
				                                      if(!bns.empty())
					                                      ret.order.emplace_back(std::move(bns), ours);
				                                      ours = our;
			                                      }
		                                      }