Fix install-breaking and live-boot bugs, verified on real hardware
All checks were successful
Mirror to GitHub / mirror (push) Successful in 3s
All checks were successful
Mirror to GitHub / mirror (push) Successful in 3s
Boot-critical (each confirmed with a real boot/install cycle, not just code review): - Live ISO's liveuser shell is zsh, but Hyprland autostart was written to .bash_profile (never runs) — moved to .zprofile, and switched to start-hyprland (Hyprland's own watchdog wrapper; raw `exec Hyprland` is no longer the recommended launch method). - copytoram (self-enables on most real hardware: non-optical boot + image < 4GiB + enough free RAM) unmounts /run/archiso/bootmnt, which unpackfs.conf and bos-copy-kernel both hardcoded as their source — broke the installer outright on real hardware, confirmed by forcing copytoram=y. Added a resolver step for unpackfs, and switched the kernel copy to /usr/lib/modules/$(uname -r)/vmlinuz (part of the live squashfs itself, unaffected by copytoram). - BIOS installs got no bootloader — post-install.sh only ever ran the UEFI grub-install path despite BOS shipping bios.syslinux. Added a BIOS branch with disk auto-detection. - @snapshots/@log/@cache were never real: iso/partition.conf's btrfsSubvolumes key isn't part of this Calamares version's partition module schema at all (same class of bug as the userShell fix below — silently ignored). Calamares only natively creates @ and @home. post-install.sh now creates the three subvolumes by hand after unpackfs, migrates existing /var/log + /var/cache content into them before mounting over, and adds the fstab entries — verified end to end on real hardware, including grub-btrfs generating bootable snapshot menu entries. The unmount step in the existing snapper create-config dance also gained retry + lazy-unmount fallback after a real chroot run hit a transient busy-mount race. - Default shell was bash instead of zsh post-install: users.conf's top-level `userShell` key isn't part of this Calamares version's users module schema either — the real key is nested (user.shell). - graphical-session.target ships RefuseManualStart=yes (systemd convention), so the earlier attempt to activate it from hyprland.lua silently failed and breadclipd (WantedBy=graphical-session.target) never started. Starts breadclipd.service directly instead. - /etc/os-release was never set (showed "Arch Linux"); live boot never had quiet/splash/plymouth wired in (raw kernel scroll the whole time) despite BOS already shipping a complete bread-logo+spinner plymouth theme for the installed system. Also: generalized build-local.sh's per-service skel baking (previously only breadd.service was hand-committed; breadbox-sync/breadmill/ breadclipd never shipped), added the four new bakery packages to BREAD_BINS, removed the redundant cliphist/fzf clipboard pipeline in favor of breadclip, mirrored fastfetch's bread-logo config into skel, and fixed a stale bos-update comment.
This commit is contained in:
parent
81f2f3545a
commit
a8f1592e75
24 changed files with 373 additions and 56 deletions
|
|
@ -5,22 +5,14 @@ efiSystemPartitionName: "EFI"
|
|||
|
||||
defaultFileSystemType: "btrfs"
|
||||
|
||||
btrfsSubvolumes:
|
||||
- mountPoint: /
|
||||
subvolume: "@"
|
||||
mountOptions: "noatime,compress=zstd,space_cache=v2"
|
||||
- mountPoint: /home
|
||||
subvolume: "@home"
|
||||
mountOptions: "noatime,compress=zstd,space_cache=v2"
|
||||
- mountPoint: /.snapshots
|
||||
subvolume: "@snapshots"
|
||||
mountOptions: "noatime,compress=zstd,space_cache=v2"
|
||||
- mountPoint: /var/log
|
||||
subvolume: "@log"
|
||||
mountOptions: "noatime,compress=zstd,space_cache=v2"
|
||||
- mountPoint: /var/cache
|
||||
subvolume: "@cache"
|
||||
mountOptions: "noatime,compress=zstd,space_cache=v2"
|
||||
# NOTE: there is no `btrfsSubvolumes:` key in this Calamares version's
|
||||
# partition module schema (confirmed against /usr/share/calamares/modules/
|
||||
# partition.conf and on real hardware — zero mentions of "subvolume"
|
||||
# anywhere in the stock reference config). A previous version of this file
|
||||
# had one; Calamares silently ignored it. Calamares' partition module only
|
||||
# natively creates @ (root) and @home (home) when btrfs + separate /home is
|
||||
# selected — nothing else. @snapshots/@log/@cache are created by hand in
|
||||
# post-install.sh instead, after unpackfs has populated the filesystem.
|
||||
|
||||
userSwapChoices:
|
||||
- none
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
# Runs before unpackfs so it can hand it a source path that survives
|
||||
# copytoram unmounting /run/archiso/bootmnt. See bos-resolve-airootfs.
|
||||
dontChroot: true
|
||||
timeout: 30
|
||||
|
||||
script:
|
||||
- "/usr/bin/bash /usr/local/bin/bos-resolve-airootfs"
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
---
|
||||
# Unpack the live squashfs onto the target partition.
|
||||
# "arch" matches profiledef.sh install_dir; adjust if that changes.
|
||||
# The source is a symlink written by shellprocess@resolve-source (see
|
||||
# bos-resolve-airootfs) rather than a path under /run/archiso/bootmnt directly
|
||||
# — that mount gets torn down by archiso's own copytoram handling, which
|
||||
# self-enables on most real hardware, so a hardcoded bootmnt path would point
|
||||
# at nothing on exactly the machines this install is meant to run on.
|
||||
unpack:
|
||||
- source: "/run/archiso/bootmnt/arch/x86_64/airootfs.sfs"
|
||||
- source: "/run/archiso/resolved-airootfs.sfs"
|
||||
sourcefs: "squashfs"
|
||||
destination: ""
|
||||
|
|
|
|||
|
|
@ -38,4 +38,11 @@ passwordRequirements:
|
|||
- minlen=6
|
||||
|
||||
allowWeakPasswords: false
|
||||
userShell: /bin/zsh
|
||||
|
||||
# `userShell` (top-level) is not a real key in this Calamares version's users
|
||||
# module schema (3.4.2) — it's silently ignored, and an installed user gets
|
||||
# whatever the module's own default is (bash), confirmed on real hardware.
|
||||
# The actual key is nested: user.shell. See /usr/share/calamares/modules/users.conf
|
||||
# for the documented schema.
|
||||
user:
|
||||
shell: /usr/bin/zsh
|
||||
|
|
|
|||
|
|
@ -79,31 +79,137 @@ fi
|
|||
mkinitcpio -P || echo "WARN: mkinitcpio -P failed"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Install GRUB (UEFI). /boot now has the kernel + initramfs, and the mount
|
||||
# module has bind-mounted /proc /sys /dev /run + efivars into this chroot, so
|
||||
# Install GRUB. /boot now has the kernel + initramfs, and the mount module has
|
||||
# bind-mounted /proc /sys /dev /run (+ efivars on UEFI) into this chroot, so
|
||||
# both grub-install passes and grub-mkconfig succeed.
|
||||
# 1. NVRAM entry (EFI/BOS/grubx64.efi + a firmware boot entry)
|
||||
# 2. --removable copy to EFI/BOOT/BOOTX64.EFI, so firmware that ignores/loses
|
||||
# the NVRAM entry (the "no boot device / PXE fallback" failure) still finds
|
||||
# a bootloader.
|
||||
#
|
||||
# BOS ships a syslinux BIOS boot mode on the ISO (profiledef.sh bootmodes
|
||||
# includes bios.syslinux), but this only ever ran the UEFI grub-install path —
|
||||
# a BIOS install would complete successfully and then have no bootloader at
|
||||
# all. Branch on /sys/firmware/efi (present only when booted UEFI) and install
|
||||
# the matching GRUB target; on BIOS, grub-install needs the whole disk, not a
|
||||
# partition, so it's derived from the mounted root via lsblk.
|
||||
# UEFI: 1. NVRAM entry (EFI/BOS/grubx64.efi + a firmware boot entry)
|
||||
# 2. --removable copy to EFI/BOOT/BOOTX64.EFI, so firmware that
|
||||
# ignores/loses the NVRAM entry still finds a bootloader.
|
||||
# BIOS: MBR install onto the disk hosting /.
|
||||
# ---------------------------------------------------------------------------
|
||||
if command -v grub-install &>/dev/null; then
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
||||
--bootloader-id=BOS --recheck \
|
||||
|| echo "WARN: grub-install (nvram) failed"
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
||||
--removable --recheck \
|
||||
|| echo "WARN: grub-install (removable) failed"
|
||||
if [[ -d /sys/firmware/efi ]]; then
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
||||
--bootloader-id=BOS --recheck \
|
||||
|| echo "WARN: grub-install (nvram) failed"
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
||||
--removable --recheck \
|
||||
|| echo "WARN: grub-install (removable) failed"
|
||||
else
|
||||
ROOT_DEV="$(findmnt -no SOURCE / | sed 's/\[.*\]//')"
|
||||
ROOT_DISK="$(lsblk -no pkname "$ROOT_DEV" 2>/dev/null)"
|
||||
if [[ -n "$ROOT_DISK" ]]; then
|
||||
grub-install --target=i386-pc --recheck "/dev/$ROOT_DISK" \
|
||||
|| echo "WARN: grub-install (BIOS) failed"
|
||||
else
|
||||
echo "WARN: could not determine the disk hosting / (root device: ${ROOT_DEV:-unknown}) — BIOS grub-install skipped"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if command -v grub-mkconfig &>/dev/null; then
|
||||
grub-mkconfig -o /boot/grub/grub.cfg || echo "WARN: grub-mkconfig failed"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Create @snapshots, @log, @cache as top-level btrfs subvolumes (peers of @,
|
||||
# not nested under it — so snapshots of @ don't recursively include
|
||||
# themselves, and log/cache churn doesn't bloat @'s snapshot history).
|
||||
#
|
||||
# iso/partition.conf's `btrfsSubvolumes:` key does NOT do this — verified on
|
||||
# real hardware that it's not a recognized key in this Calamares version's
|
||||
# partition module schema at all (same class of bug as the `userShell` fix
|
||||
# below: Calamares silently ignores unknown top-level keys). Calamares' own
|
||||
# btrfs support only natively creates @ and @home; everything else has to be
|
||||
# done by hand, here, after unpackfs has populated / but before anything
|
||||
# reads/writes /var/log or /var/cache going forward. Existing content in
|
||||
# those two dirs (real files already unpacked from the squashfs) is migrated
|
||||
# into the new subvolumes before mounting over them, so nothing is lost —
|
||||
# just shadowed by the mount, same as any other mountpoint.
|
||||
# ---------------------------------------------------------------------------
|
||||
if command -v btrfs &>/dev/null; then
|
||||
ROOT_DEV="$(findmnt -no SOURCE / | sed 's/\[.*\]//')"
|
||||
ROOT_UUID="$(blkid -s UUID -o value "$ROOT_DEV" 2>/dev/null)"
|
||||
BTRFS_TOP=/.btrfs-top-tmp
|
||||
|
||||
if [[ -z "$ROOT_UUID" ]]; then
|
||||
echo "WARN: could not determine root filesystem UUID — skipping @snapshots/@log/@cache creation"
|
||||
else
|
||||
mkdir -p "$BTRFS_TOP"
|
||||
if mount -o subvolid=5 "$ROOT_DEV" "$BTRFS_TOP"; then
|
||||
for sv in @snapshots @log @cache; do
|
||||
if ! btrfs subvolume show "$BTRFS_TOP/$sv" &>/dev/null; then
|
||||
btrfs subvolume create "$BTRFS_TOP/$sv" || echo "WARN: creating $sv failed"
|
||||
fi
|
||||
done
|
||||
rsync -aAX /var/log/ "$BTRFS_TOP/@log/" || echo "WARN: migrating /var/log into @log failed"
|
||||
rsync -aAX /var/cache/ "$BTRFS_TOP/@cache/" || echo "WARN: migrating /var/cache into @cache failed"
|
||||
umount "$BTRFS_TOP"
|
||||
rmdir "$BTRFS_TOP"
|
||||
|
||||
OPTS="noatime,compress=zstd,space_cache=v2"
|
||||
grep -q "@snapshots" /etc/fstab || echo "UUID=$ROOT_UUID /.snapshots btrfs subvol=/@snapshots,$OPTS 0 0" >> /etc/fstab
|
||||
grep -q "@log" /etc/fstab || echo "UUID=$ROOT_UUID /var/log btrfs subvol=/@log,$OPTS 0 0" >> /etc/fstab
|
||||
grep -q "@cache" /etc/fstab || echo "UUID=$ROOT_UUID /var/cache btrfs subvol=/@cache,$OPTS 0 0" >> /etc/fstab
|
||||
|
||||
mkdir -p /.snapshots
|
||||
mount /.snapshots || echo "WARN: mounting /.snapshots failed"
|
||||
mount /var/log || echo "WARN: mounting /var/log failed"
|
||||
mount /var/cache || echo "WARN: mounting /var/cache failed"
|
||||
else
|
||||
echo "WARN: could not mount btrfs top-level — skipping @snapshots/@log/@cache creation"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Snapper root config (root is btrfs).
|
||||
#
|
||||
# @snapshots is now mounted at /.snapshots (created above) — a dedicated
|
||||
# top-level subvolume, a peer of @ rather than nested under it, so snapshots
|
||||
# aren't themselves recursively snapshotted. `snapper create-config` insists
|
||||
# on creating that subvolume itself and refuses whenever /.snapshots already
|
||||
# exists, mounted or not — silently, so without this dance every downstream
|
||||
# sed below is a no-op and BOS ships with its advertised auto-snapshot/
|
||||
# rollback feature entirely non-functional.
|
||||
# Unmount the real subvolume, let snapper create + own its nested one, then
|
||||
# discard that and remount the real @snapshots in its place (fstab entry was
|
||||
# added above, right after the subvolume was created).
|
||||
#
|
||||
# Confirmed on real hardware: a plain `umount /.snapshots` here can
|
||||
# transiently fail inside the Calamares chroot (the same mount unmounts
|
||||
# cleanly moments later once booted normally — a chroot-specific busy-mount
|
||||
# race, not a logic error), which cascades into snapper create-config
|
||||
# refusing because .snapshots "already exists". Retry a few times, then
|
||||
# fall back to a lazy unmount (detaches the mountpoint immediately even if
|
||||
# something still transiently references it) rather than give up.
|
||||
# ---------------------------------------------------------------------------
|
||||
if command -v snapper &>/dev/null; then
|
||||
unmounted=0
|
||||
for _ in 1 2 3 4 5; do
|
||||
if umount /.snapshots 2>/dev/null; then
|
||||
unmounted=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [[ "$unmounted" != "1" ]]; then
|
||||
echo "WARN: umount /.snapshots failed after retries, forcing lazy unmount"
|
||||
umount -l /.snapshots || echo "WARN: lazy umount /.snapshots also failed"
|
||||
fi
|
||||
rmdir /.snapshots || echo "WARN: rmdir /.snapshots failed"
|
||||
snapper -c root create-config / || echo "WARN: snapper create-config failed"
|
||||
if [[ -d /.snapshots ]]; then
|
||||
btrfs subvolume delete /.snapshots || echo "WARN: deleting snapper's own .snapshots subvolume failed"
|
||||
fi
|
||||
mkdir -p /.snapshots
|
||||
mount /.snapshots || echo "WARN: remounting the real @snapshots subvolume failed"
|
||||
if [[ -f /etc/snapper/configs/root ]]; then
|
||||
sed -i 's/TIMELINE_CREATE="yes"/TIMELINE_CREATE="no"/' /etc/snapper/configs/root
|
||||
sed -i 's/NUMBER_CLEANUP="no"/NUMBER_CLEANUP="yes"/' /etc/snapper/configs/root
|
||||
|
|
|
|||
|
|
@ -3,10 +3,16 @@ modules-search: [/etc/calamares/modules, /usr/lib/calamares/modules]
|
|||
|
||||
# Second shellprocess instance: copies the live kernel into the target /boot
|
||||
# (archiso keeps it out of the squashfs) before the bootloader step runs.
|
||||
# Third: resolves the live squashfs's real location before unpackfs runs —
|
||||
# copytoram unmounts /run/archiso/bootmnt, so a hardcoded path there can point
|
||||
# at nothing depending on how the medium was booted.
|
||||
instances:
|
||||
- id: kernel
|
||||
module: shellprocess
|
||||
config: shellprocess-kernel.conf
|
||||
- id: resolve-source
|
||||
module: shellprocess
|
||||
config: shellprocess-resolve-source.conf
|
||||
|
||||
sequence:
|
||||
- show:
|
||||
|
|
@ -19,6 +25,7 @@ sequence:
|
|||
- exec:
|
||||
- partition
|
||||
- mount
|
||||
- shellprocess@resolve-source
|
||||
- unpackfs
|
||||
- machineid
|
||||
- fstab
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue