diff --git a/README.md b/README.md index 92b4b79..552cbf5 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ It runs these steps, in this order, and every one of them is idempotent: | 5. First theme | links `~/wallpapers` to the checkout, applies `flats` headless, picks a background, and links the btop and Neovim theme files, so the first login is not a blank desktop | | 6. User units | installs the session services into `~/.config/systemd/user` and enables them | | 7. systemd drop-ins | writes the shutdown timeouts, oomd thresholds, plocate prune paths, and sleep hooks under `/etc` | -| 8. System services | enables NetworkManager, resolved, bluetooth, cups, avahi, docker, power-profiles-daemon, and oomd, masks `NetworkManager-wait-online`, and sets the boot splash to `branding/blob_boot.png` | +| 8. System services | enables NetworkManager, resolved, bluetooth, cups, avahi, docker, power-profiles-daemon, and oomd, masks `NetworkManager-wait-online`, sets the boot splash to `branding/blob_boot.png`, and sets GRUB up with every other installed OS in its menu | | 9. Login screen | installs the session entry and the SDDM config, enables `sddm.service`, and sets the default target to `graphical.target` | | 10. Reload | reloads systemd, restarts the running user services, and in a running session re-renders the theme, reloads Hyprland, and restarts the Blob shell | | 11. Launch | starts the login screen, so the desktop comes up without a reboot | diff --git a/bin/blob-boot b/bin/blob-boot index c1450fc..e2b3674 100755 --- a/bin/blob-boot +++ b/bin/blob-boot @@ -2,7 +2,7 @@ # # blob-boot - boot splash and bootloader management. # -# blob-boot [image] Apply a Plymouth boot splash image (default action) +# blob-boot [image] Apply a boot splash, set up GRUB, detect other OSes # blob-boot grub Install GRUB and detect every other OS on the machine. # Migrates off Limine when it is there; on a machine # that never had it, only GRUB is installed @@ -65,19 +65,64 @@ apply_splash() { log "Rebuilding initramfs" rebuild_initramfs - report_kernel_cmdline - - # Under GRUB the menu references the initramfs by path, so it only needs - # regenerating if the file set changed - but it is cheap and keeps the menu - # honest after a kernel or os-prober change. - if using_grub; then - log "Refreshing the GRUB menu" - sudo grub-mkconfig -o /boot/grub/grub.cfg - fi + setup_grub_boot ok "Boot splash successfully updated!" } +setup_grub_boot() { + if [ ! -d /sys/firmware/efi ]; then + warn "Not booted in UEFI mode, so GRUB is not set up automatically." + report_kernel_cmdline + return 0 + fi + + if ! using_grub; then + log "GRUB is not installed; installing it and detecting other systems" + migrate_to_grub + return 0 + fi + + install_grub_packages + configure_grub_scripts + ensure_grub_splash_settings + generate_menu + echo + info "GRUB menu entries:" + list_menu_entries +} + +ensure_grub_splash_settings() { + log "Checking the GRUB settings" + set_grub_key GRUB_DISABLE_OS_PROBER 'false' + + local current param missing=() + current=$(sed -n 's/^GRUB_CMDLINE_LINUX_DEFAULT=//p' /etc/default/grub | tail -n 1 | tr -d "\"'") + for param in quiet splash vt.global_cursor_default=0; do + [[ " $current " == *" $param "* ]] || missing+=("$param") + done + + if (( ${#missing[@]} == 0 )); then + info "kernel command line already carries the splash parameters" + return 0 + fi + + local updated="$current ${missing[*]}" + set_grub_key GRUB_CMDLINE_LINUX_DEFAULT "\"${updated# }\"" +} + +set_grub_key() { + local key=$1 val=$2 + if grep -q "^${key}=" /etc/default/grub; then + sudo sed -i "s|^${key}=.*|${key}=${val}|" /etc/default/grub + elif grep -qE "^#\s*${key}=" /etc/default/grub; then + sudo sed -i "0,/^#\s*${key}=.*/s||${key}=${val}|" /etc/default/grub + else + echo "${key}=${val}" | sudo tee -a /etc/default/grub >/dev/null + fi + info "${key}=${val}" +} + install_theme() { local image_path=$1 @@ -444,18 +489,6 @@ install_grub() { local esp_uuid=$1 log "Configuring GRUB" - set_grub_key() { - local key=$1 val=$2 - if grep -q "^${key}=" /etc/default/grub; then - sudo sed -i "s|^${key}=.*|${key}=${val}|" /etc/default/grub - elif grep -qE "^#\s*${key}=" /etc/default/grub; then - sudo sed -i "0,/^#\s*${key}=.*/s||${key}=${val}|" /etc/default/grub - else - echo "${key}=${val}" | sudo tee -a /etc/default/grub >/dev/null - fi - info "${key}=${val}" - } - # Carry over the exact kernel command line Limine was booting, so Plymouth # and the quiet splash behave the way they do today. set_grub_key GRUB_CMDLINE_LINUX_DEFAULT '"rtc_cmos.use_acpi_alarm=1 initramfs_async=0 quiet splash loglevel=0 systemd.show_status=false rd.udev.log_level=0 vt.global_cursor_default=0"' diff --git a/docs/commands.md b/docs/commands.md index 73793ac..668f6e3 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -60,7 +60,7 @@ of the `blob` listing. | Command | Does | Arguments | | --- | --- | --- | -| `blob-boot` | - | - | +| `blob-boot` | Apply a boot splash, set up GRUB, and detect other operating systems | [image] \| grub [--purge] \| detect \| cleanup \| status | ## branding diff --git a/docs/install.md b/docs/install.md index 3fdf56e..a062953 100644 --- a/docs/install.md +++ b/docs/install.md @@ -15,7 +15,7 @@ with `--check`. | `install/steps/packages.sh` | repo and AUR packages, and the yay bootstrap | | `install/steps/config.sh` | the `BLOB_PATH` symlink, everything under `~/.config`, and the login shell profile | | `install/steps/services.sh` | system services, systemd drop-ins, user units | -| `install/steps/boot.sh` | the Plymouth boot splash | +| `install/steps/boot.sh` | the Plymouth boot splash, GRUB, and other-OS detection | | `install/steps/theme.sh` | the wallpaper link, the first theme, the first background | | `install/steps/login.sh` | SDDM, the session entry, and the first launch | | `install/steps/reload.sh` | reloading systemd, the user services, and a running session | @@ -81,7 +81,8 @@ with `--check`. holds the console and leaves the machine with neither a greeter nor a TTY. The installer then applies `branding/blob_boot.png` as the boot splash through `blob boot`, which installs the theme, adds the mkinitcpio hook, - unmasks the plymouth units and rebuilds the initramfs. It is skipped when + unmasks the plymouth units, rebuilds the initramfs, and sets GRUB up with + os-prober so other installed systems appear in the boot menu. It is skipped when the blob theme is already the default with the same image, and once it is in place the plymouth units are no longer masked on later runs. See [packages.md](packages.md#the-boot-splash). diff --git a/docs/packages.md b/docs/packages.md index 40e2be6..8456c4a 100644 --- a/docs/packages.md +++ b/docs/packages.md @@ -152,9 +152,24 @@ TTY. `install.sh` therefore masks `plymouth-start.service` and `plymouth-quit-wait.service` until the splash is configured, and `blob boot` unmasks them as part of configuring everything else - the theme in `default/plymouth/`, the `plymouth` mkinitcpio hook, and the initramfs rebuild. -It finishes by printing the kernel parameters your bootloader still needs -(`quiet splash vt.global_cursor_default=0`), because that line is the one thing -it will not rewrite for a bootloader other than GRUB. + +Every splash update then sets GRUB up to boot the machine and everything else +on it: + +- With GRUB already installed, it makes sure `os-prober` is installed and + `GRUB_DISABLE_OS_PROBER=false`, adds whichever of `quiet splash + vt.global_cursor_default=0` is missing from `GRUB_CMDLINE_LINUX_DEFAULT` + without touching the rest of the line, and regenerates the menu. os-prober + finds other systems, Windows gets an explicit chainload entry when os-prober + misses it on a shared ESP, and the run stops if the menu has no Arch entry. +- Without GRUB, it runs the same migration as `blob boot grub`: GRUB is + installed, other systems are detected, and GRUB is armed for one test boot + with Limine left as the standing default. Once that boot works, + `blob boot cleanup` retires Limine. +- On a machine not booted in UEFI mode GRUB is left alone and the kernel + parameters the bootloader still needs are printed instead. + +`blob boot detect` reruns only the OS detection. ## Updating