Skip to content

Transfer of major fixes - #39

Closed
justpav05 wants to merge 148 commits into
mainfrom
dev
Closed

justpav05 wants to merge 148 commits into
mainfrom
dev

Conversation

@justpav05

Copy link
Copy Markdown
Collaborator

Key changes:

  • Added more tests
  • Fixed UKI boot format creation and functionality
  • Added GRUB installation
  • Added installation of other bootloaders into the image
  • Added a hook for post-installation and verification
  • Fixed initial image installation: everything is now split into packages

justpav05 and others added 30 commits September 5, 2026 11:09
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
package structure

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fix: addition of functions for understanding the booters

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fix: removed unnecessary constants

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
justpav05 and others added 29 commits September 13, 2026 07:33
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
forcing --removable --no-nvram, matching systemd-boot/refind's own
install tools; update booter.toml's stale rationale comment

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WrittenBootEntry enum (Bls/Uki) so callers branch on the actual
boot-resource kind instead of comparing entry_name against a magic UKI
slot constant

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
installers (refind-install/bootctl), matching grub's already-real
install()

Also wires up install()'s C-ABI entry point for uki/refind/systemd-boot,
which was a hardcoded stub always returning 0 without ever calling the
backend — plugin.install() goes exclusively through this extern "C" fn
in both static and dynamic link modes, so uki's existing register_slot
NVRAM logic never actually ran either. booter.toml gains install_bin for
both plugins; systemd-boot's build.rs now generates both the shared
[boot] and its own [systemd_boot] section like refind already did.

refactor: propagate the real ErrorKind through boot-plugin
request-conversion errors instead of discarding it to a hardcoded
InvalidRequest

Adds From<ErrorKind> for GrubError/UkiError/RefindError/SystemdBootError
(PermissionDenied passes through, everything else still falls back to
InvalidRequest) so try_from(...).map_err(XxxError::from) can reuse it
instead of a closure that threw the conversion error away.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
export boundary
(setup_existing/setup_whole_disk/setup_abi_version/cancel), matching
upac-lib's own export/mod.rs

Renames lib/setup/src/genesis/ to stages/ (source.rs->prepare.rs,
embed.rs->database.rs, entry.rs->boot.rs), extracts SourceArchive into
its own archive.rs, and drops the old genesis/types.rs and data.rs in
favor of SetupExistingData/SetupWholeDiskData built directly from the
new CSetupExistingRequest/CSetupWholeDiskRequest C-ABI types. Real boot
stage: resolves the boot plugin, calls
install()/write_boot_entry()/set_one_shot(), UKI to/from-slot seed-copy.
Manual-mode ESP partition geometry (partition number, starting/ending
LBA, unique GUID) is now auto-detected from the existing GPT via a new
partition::existing_esp_geometry() instead of being silently zeroed, so
TargetSysroot no longer needs Option-wrapped geometry fields at all.
Adds error.rs's missing From<SetupError> for ErrorKind and the crate's
[lib] crate-type (cdylib+rlib), so the new extern "C" fns are actually
exportable for up-sp to link against, either dynamically or statically.
Kernel stage stays a no-op stub — tracked separately

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WrittenBootEntry return type, matching installer/update/rollback's
already-fixed call sites

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
`setup_cancel`

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
C-ABI export functions, mirroring up's own libcore.rs/types::errors
pattern

Reorganizes src/ into upac-cli's types/{mod,errors,progress}.rs shape,
adds libcore.rs (Lib::load() resolving
setup_existing/setup_whole_disk/setup_cancel/setup_abi_version as static
fn pointers — always static-link, genesis has nowhere to dlopen a .so
from on a blank disk) plus a shared invoke() helper.
commands/{auto,manual}.rs (whole_disk.rs renamed to auto.rs) now build
SetupExistingRequest/SetupWholeDiskRequest and cross the C-ABI boundary
directly instead of calling
upac_setup::stages::run_existing/run_whole_disk as plain Rust.
types::errors::LibError/error_kind_message replace the old rich
SetupError Display impl, formatting straight off CError's
domain-agnostic ErrorKind + SetupStateId::from_stage_index — same shape
up already uses, just scoped to one domain. i18n keys swapped to the
generic ErrorKind set to match.

Renames upac-setup's own cancel export to setup_cancel — it collided
with upac-lib's identically-named #[no_mangle] cancel, which also ends
up statically linked into up-sp since upac-setup depends on upac-lib for
its own package-install machinery

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
plugin instead of whichever single one happens to exist

Adds BootResourceKind (Bls/Uki, same axis WrittenBootEntry already uses)
as a new required Booter trait method plus C-ABI query
(boot_resource_kind, BOOT_ABI_VERSION 2->3), implemented by all four
booter plugins (uki -> Uki, grub/systemd-boot/refind -> Bls) and
threaded through BootPlugin/static_link.rs/dynamic_link.rs.
write_boot_entry now takes the wanted kind and filters
get_boot_resources() against it — errors UnsupportedBootResource if the
wanted kind is absent even when a different kind is present,
AmbiguousBootResource only among matches of the wanted kind,
NoBootResource only when the tree has nothing at all.

Reorders all 5 ordinary checkout.rs stages
(installer/update/rollback/files/uninstaller) to resolve the boot plugin
before calling write_boot_entry, since the call now needs
plugin.boot_resource_kind() as an argument — genesis's own
stages/boot.rs already had the right order. Closes the two TODO.md items
about write_boot_entry's resource-selection blindness and the
checkout.rs call ordering

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cancel/version_abi never got renamed to lib_cancel/lib_abi_version)

The static-link path referenced upac::export::{cancel, version_abi} and
upac_abi::ABI_VERSION, none of which exist anymore — upac-lib's own
export/mod.rs already uses lib_cancel/lib_abi_version/LIB_ABI_VERSION,
but the dynamic-plugins dlopen path (which resolves symbols by string
name) had the same stale "cancel"/"version_abi" names too. Both paths
now agree with what upac-lib actually exports; `cargo clippy -p upac-cli
-p upac-lib --no-default-features --features
upac-cli/builtin-all,upac-lib/builtin-all` (the CI "fully static" build)
is clean again

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
earlier refactors

database.rs/orchestrator.rs/scripts_hook.rs imported types from their
pre-refactor locations
(upac_types::{DeclarativeTrigger,FileEntry,FileEntryScope,PackageMeta}
at crate root instead of their actual submodules; ProgressEventBuilder
from upac_abi::hook instead of upac_types::hook;
scripts::load::load_hooks instead of scripts::load_hooks).
plugin_boot_error.rs asserted a BootPluginError::AmbiguousClaim variant
that no longer exists. plugin_boot_manifest.rs and half of
plugin_decoder.rs tested
load_boot_plugin_manifests/load_decoder_manifests as
directory+extension-parameterized free functions — both are now
BootPluginManifests::new()/DecoderManifests::new(), which read
unconditionally from a hardcoded lib.toml-configured path with no way to
inject a test directory, so that style of test isn't reconstructible;
plugin_boot_manifest.rs is deleted and plugin_decoder.rs keeps only its
still-valid build_trigger_table coverage. `cargo test -p upac-lib
--all-targets` is green

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
converted tests to use inline definitions within the module, following
convention
fix: removed the unnecessary CLI structure and replaced it with an enum
fix: renamed folders to use single-word names
new: now can build composefs-setup-root bin as command

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RustToC/CTryToRust assume any field type not listed in SHARED_TYPES has
a separate CXxx composite counterpart to convert through.
InitramfsGenerator
is a plain Copy enum used directly on both sides, like FsKind already is
— add it to SHARED_TYPES so the derives stop looking for a
nonexistent CInitramfsGenerator

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Setup requests hardcoded dracut as the only initramfs generator with no
way to ask for mkinitcpio instead. Add a plain repr(u8)
InitramfsGenerator
enum (Dracut/Mkinitcpio) and thread it through CSetupExistingRequest/
CSetupWholeDiskRequest

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Both auto and manual mode were passing a hardcoded Dracut regardless of
user intent. Add a clap ValueEnum wrapper (InitramfsGeneratorClapArg,
needed for the same orphan-rule reason FsKind already has one) and a
--initramfs-generator flag whose default comes from cli.toml's new
[initramfs] section, mirroring how --deploy-fs already defaults from
disk_defaults

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add initramfs_generator to SetupExistingRequest/SetupWholeDiskRequest so
the new ABI field actually reaches the domain layer. Also fix
SetupStateId's variant order, which had drifted from the real stage
pipeline (Kernel now runs before EmbedDatabase, not after) and was
silently misreporting which stage failed

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
KernelStage needs a real directory on disk to hand to dracut/mkinitcpio,
but only the tree-to-disk direction (import_directory) existed. Add
export_directory plus small per-node-kind helpers (export_leaf/
export_symlink/export_regular_file, and a shared regular_file_content
also reused by read_file) so the recursive walk stays a thin dispatcher
instead of inlining the content-resolution match

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Detect the kernel version from the imported tree, export the whole
prefix tree to a scratch directory, and run dracut or mkinitcpio
(non-hostonly/generic flags, since genesis targets an arbitrary disk,
not the build host) to produce initramfs.img/uki.efi, then import the
result back under lib/modules/<kver>/. Output filenames move to
lib.toml's [genesis] section rather than being hardcoded. Requires
KernelStage to run before EmbedDatabaseStage, since committing the tree
removes PrefixTree from context

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
genesis's system/ import mechanism expects lib/systemd/system/
composefs-setup-root.service in the source tree, but that alone isn't
enough — the initrd needs its own module-setup.sh to pull the binary and
unit into the generated initramfs and wire the initrd-root-fs.target
enablement (systemd running inside the initrd never sees anything
add-wants'd into the real root's own unit tree after switch-root).
Sourced from containers/composefs-rs's own dracut module example
(MIT OR Apache-2.0) rather than hand-rolled, since dracut module
ordering/conditions are easy to get subtly wrong

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
initrd-root-fs.target only exists inside the initrd's own systemd
instance, so a *.target.wants/ symlink written into the real root tree
is a no-op after switch-root — the real root's systemd never processes
it. The dracut module (hooks/dracut/37composefs/) already creates the
actual enablement at initrd-build time via `$SYSTEMCTL --root
"${initdir}" add-wants`, which is the only place it can take effect

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Unlike dracut, mkinitcpio doesn't force systemd inside the initramfs —
confirmed by reading its actual /init (plain busybox ash: run_hook →
mount_handler → run_latehook → switch_root) and composefs-setup-root's
own source (pure rustix syscalls, no systemd dependency at all beyond a
best-effort /run/systemd/volatile-root workaround that no-ops cleanly
without it). Add install/composefs + hooks/composefs mirroring
mkinitcpio's own two-file hook convention (install/ copies the binary
and runscript at build time, hooks/ runs run_latehook() after the real
root device is mounted, before switch_root) — no flags needed, since
composefs-setup-root's --sysroot default already matches mkinitcpio's
own /sysroot convention.

Also fixes REUSE compliance for the two vendored dracut files: they
carry their own upstream license text as prose, not machine-readable
SPDX tags, so reuse lint flagged them as unlicensed. Annotate them
externally in REUSE.toml instead of injecting tags into third-party
code, and vendor the newly-referenced license texts (MIT, Apache-2.0,
LGPL-2.1-or-later) via `reuse download --all`

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@justpav05 justpav05 closed this Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant