@@ 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);
}
@@ 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);