Install the boot splash theme and set up GRUB without Limine
This commit is contained in:
+126
-8
@@ -3,7 +3,9 @@
|
|||||||
# blob-boot - boot splash and bootloader management.
|
# blob-boot - boot splash and bootloader management.
|
||||||
#
|
#
|
||||||
# blob-boot [image] Apply a Plymouth boot splash image (default action)
|
# blob-boot [image] Apply a Plymouth boot splash image (default action)
|
||||||
# blob-boot grub Migrate from Limine back to GRUB, detecting every OS
|
# 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
|
||||||
# --purge removes Limine in the same run instead of
|
# --purge removes Limine in the same run instead of
|
||||||
# keeping it for one fallback boot
|
# keeping it for one fallback boot
|
||||||
# blob-boot detect Rescan for other operating systems, rebuild the menu
|
# blob-boot detect Rescan for other operating systems, rebuild the menu
|
||||||
@@ -16,8 +18,12 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
DEFAULT_IMAGE="$HOME/Documents/dotfiles/branding/boot_flash.png"
|
BLOB_PATH="${BLOB_PATH:-$HOME/.local/share/blob}"
|
||||||
PLYMOUTH_LOGO="/usr/share/plymouth/themes/blob/logo.png"
|
DEFAULT_IMAGE="$BLOB_PATH/branding/boot_flash.png"
|
||||||
|
THEME_SOURCE="$BLOB_PATH/default/plymouth"
|
||||||
|
THEME_DIR="/usr/share/plymouth/themes/blob"
|
||||||
|
PLYMOUTH_LOGO="$THEME_DIR/logo.png"
|
||||||
|
MKINITCPIO_DROPIN="/etc/mkinitcpio.conf.d/blob-plymouth.conf"
|
||||||
|
|
||||||
log() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
|
log() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
|
||||||
info() { printf ' %s\n' "$*"; }
|
info() { printf ' %s\n' "$*"; }
|
||||||
@@ -43,17 +49,24 @@ apply_splash() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
[ -f "$image_path" ] || die "File '$image_path' does not exist."
|
[ -f "$image_path" ] || die "File '$image_path' does not exist."
|
||||||
[ -d "$(dirname "$PLYMOUTH_LOGO")" ] || die "Plymouth blob theme is not installed."
|
command -v plymouth-set-default-theme >/dev/null \
|
||||||
|
|| die "The 'plymouth' package is not installed. Install it with: sudo pacman -S plymouth"
|
||||||
|
|
||||||
log "Applying boot splash image: $image_path"
|
log "Applying boot splash image: $image_path"
|
||||||
require_sudo
|
require_sudo
|
||||||
|
|
||||||
sudo cp "$image_path" "$PLYMOUTH_LOGO"
|
install_theme "$image_path"
|
||||||
sudo chmod 644 "$PLYMOUTH_LOGO"
|
install_initramfs_hook
|
||||||
|
enable_plymouth_units
|
||||||
|
|
||||||
|
log "Setting the default Plymouth theme"
|
||||||
|
sudo plymouth-set-default-theme blob
|
||||||
|
|
||||||
log "Rebuilding initramfs"
|
log "Rebuilding initramfs"
|
||||||
rebuild_initramfs
|
rebuild_initramfs
|
||||||
|
|
||||||
|
report_kernel_cmdline
|
||||||
|
|
||||||
# Under GRUB the menu references the initramfs by path, so it only needs
|
# 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
|
# regenerating if the file set changed - but it is cheap and keeps the menu
|
||||||
# honest after a kernel or os-prober change.
|
# honest after a kernel or os-prober change.
|
||||||
@@ -65,6 +78,80 @@ apply_splash() {
|
|||||||
ok "Boot splash successfully updated!"
|
ok "Boot splash successfully updated!"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_theme() {
|
||||||
|
local image_path=$1
|
||||||
|
|
||||||
|
[ -d "$THEME_SOURCE" ] || die "Theme source '$THEME_SOURCE' is missing from the checkout."
|
||||||
|
|
||||||
|
sudo install -d -m 0755 "$THEME_DIR"
|
||||||
|
sudo install -m 0644 "$THEME_SOURCE/blob.plymouth" "$THEME_DIR/blob.plymouth"
|
||||||
|
sudo install -m 0644 "$THEME_SOURCE/blob.script" "$THEME_DIR/blob.script"
|
||||||
|
sudo install -m 0644 "$image_path" "$PLYMOUTH_LOGO"
|
||||||
|
info "installed the blob theme to $THEME_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# A drop-in rather than an edit of HOOKS: mkinitcpio.conf.d is sourced after
|
||||||
|
# the main config, so the hook can be inserted without rewriting a line the
|
||||||
|
# user or another tool owns. plymouth has to come after udev, which starts the
|
||||||
|
# devices it draws on.
|
||||||
|
install_initramfs_hook() {
|
||||||
|
sudo install -d -m 0755 "$(dirname "$MKINITCPIO_DROPIN")"
|
||||||
|
sudo tee "$MKINITCPIO_DROPIN" >/dev/null <<'DROPIN'
|
||||||
|
# Written by blob-boot. Adds the plymouth hook after udev, once.
|
||||||
|
if [[ " ${HOOKS[*]} " != *" plymouth "* ]]; then
|
||||||
|
_hooks=()
|
||||||
|
for _hook in "${HOOKS[@]}"; do
|
||||||
|
_hooks+=("$_hook")
|
||||||
|
[[ $_hook == "udev" || $_hook == "systemd" ]] && _hooks+=("plymouth")
|
||||||
|
done
|
||||||
|
HOOKS=("${_hooks[@]}")
|
||||||
|
unset _hooks _hook
|
||||||
|
fi
|
||||||
|
DROPIN
|
||||||
|
info "wrote $MKINITCPIO_DROPIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
# install.sh masks these so an unconfigured plymouth cannot hold the console and
|
||||||
|
# leave the machine with no greeter and no TTY. A configured one needs them: if
|
||||||
|
# plymouth-quit-wait stays masked the splash never hands the display back.
|
||||||
|
enable_plymouth_units() {
|
||||||
|
local unit
|
||||||
|
for unit in plymouth-start.service plymouth-quit-wait.service; do
|
||||||
|
if [ "$(systemctl is-enabled "$unit" 2>/dev/null)" = "masked" ]; then
|
||||||
|
sudo systemctl unmask "$unit" >/dev/null
|
||||||
|
info "unmasked $unit"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# plymouth only draws when the kernel was told to be quiet and to splash. The
|
||||||
|
# bootloader owns that line, so report rather than rewrite anything but GRUB's.
|
||||||
|
report_kernel_cmdline() {
|
||||||
|
local params="quiet splash vt.global_cursor_default=0"
|
||||||
|
|
||||||
|
if grep -qw splash /proc/cmdline; then
|
||||||
|
info "kernel command line already carries 'splash'"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "One step left: the kernel command line"
|
||||||
|
if using_grub; then
|
||||||
|
warn "GRUB is in charge. Add to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub:"
|
||||||
|
warn " $params"
|
||||||
|
warn "then: sudo grub-mkconfig -o /boot/grub/grub.cfg"
|
||||||
|
elif [ -f /boot/limine.conf ]; then
|
||||||
|
warn "Limine is in charge. Add to the cmdline in /boot/limine.conf:"
|
||||||
|
warn " $params"
|
||||||
|
elif [ -d /boot/loader/entries ]; then
|
||||||
|
warn "systemd-boot is in charge. Add to the options line in /boot/loader/entries/*.conf:"
|
||||||
|
warn " $params"
|
||||||
|
else
|
||||||
|
warn "Add these to your bootloader's kernel command line:"
|
||||||
|
warn " $params"
|
||||||
|
fi
|
||||||
|
warn "Without them the splash is drawn over by kernel messages."
|
||||||
|
}
|
||||||
|
|
||||||
# Call mkinitcpio directly: limine-mkinitcpio-hook installs a wrapper at
|
# Call mkinitcpio directly: limine-mkinitcpio-hook installs a wrapper at
|
||||||
# /usr/local/bin/mkinitcpio that stops to ask whether to rebuild Limine
|
# /usr/local/bin/mkinitcpio that stops to ask whether to rebuild Limine
|
||||||
# entries, which is useless in a script. While Limine is still the active
|
# entries, which is useless in a script. While Limine is still the active
|
||||||
@@ -82,6 +169,26 @@ using_grub() {
|
|||||||
[ -f /boot/grub/grub.cfg ] && [ -f /boot/EFI/GRUB/grubx64.efi ]
|
[ -f /boot/grub/grub.cfg ] && [ -f /boot/EFI/GRUB/grubx64.efi ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Everything Limine-specific below is skipped on a machine that never had it:
|
||||||
|
# reclaiming its space, removing its hooks, and rewriting the mkinitcpio preset
|
||||||
|
# its hooks needed. Rewriting that preset elsewhere would drop the fallback
|
||||||
|
# initramfs for no reason.
|
||||||
|
limine_present() {
|
||||||
|
pacman -Qq limine &>/dev/null || [ -f /boot/limine.conf ] || [ -d /boot/EFI/limine ]
|
||||||
|
}
|
||||||
|
|
||||||
|
install_grub_packages() {
|
||||||
|
local missing=()
|
||||||
|
command -v grub-install >/dev/null || missing+=(grub)
|
||||||
|
command -v os-prober >/dev/null || missing+=(os-prober)
|
||||||
|
|
||||||
|
(( ${#missing[@]} == 0 )) && return 0
|
||||||
|
|
||||||
|
log "Installing ${missing[*]}"
|
||||||
|
sudo pacman -S --needed --noconfirm "${missing[@]}" \
|
||||||
|
|| die "Could not install: ${missing[*]}"
|
||||||
|
}
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Limine -> GRUB migration
|
# Limine -> GRUB migration
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@@ -92,10 +199,9 @@ migrate_to_grub() {
|
|||||||
|
|
||||||
[ -d /sys/firmware/efi ] || die "Not booted in UEFI mode; this script assumes UEFI."
|
[ -d /sys/firmware/efi ] || die "Not booted in UEFI mode; this script assumes UEFI."
|
||||||
mountpoint -q /boot || die "/boot is not mounted."
|
mountpoint -q /boot || die "/boot is not mounted."
|
||||||
command -v grub-install >/dev/null || die "The 'grub' package is not installed."
|
|
||||||
command -v os-prober >/dev/null || die "The 'os-prober' package is not installed."
|
|
||||||
|
|
||||||
require_sudo
|
require_sudo
|
||||||
|
install_grub_packages
|
||||||
|
|
||||||
local machine_id esp_uuid backup
|
local machine_id esp_uuid backup
|
||||||
machine_id=$(</etc/machine-id)
|
machine_id=$(</etc/machine-id)
|
||||||
@@ -111,8 +217,14 @@ migrate_to_grub() {
|
|||||||
sudo efibootmgr -v | sudo tee "$backup/efibootmgr-before.txt" >/dev/null 2>&1 || true
|
sudo efibootmgr -v | sudo tee "$backup/efibootmgr-before.txt" >/dev/null 2>&1 || true
|
||||||
info "saved."
|
info "saved."
|
||||||
|
|
||||||
|
if limine_present; then
|
||||||
reclaim_esp_space "$machine_id" "$backup"
|
reclaim_esp_space "$machine_id" "$backup"
|
||||||
restore_standard_initramfs
|
restore_standard_initramfs
|
||||||
|
else
|
||||||
|
info "Limine is not installed; leaving the initramfs layout alone"
|
||||||
|
log "Building the initramfs"
|
||||||
|
rebuild_initramfs
|
||||||
|
fi
|
||||||
configure_grub_scripts
|
configure_grub_scripts
|
||||||
install_grub "$esp_uuid"
|
install_grub "$esp_uuid"
|
||||||
fix_failing_boot_units
|
fix_failing_boot_units
|
||||||
@@ -529,6 +641,12 @@ set_boot_order() {
|
|||||||
|
|
||||||
# Delete every trace of Limine and hand its EFI fallback path to GRUB.
|
# Delete every trace of Limine and hand its EFI fallback path to GRUB.
|
||||||
purge_limine() {
|
purge_limine() {
|
||||||
|
if ! limine_present; then
|
||||||
|
log "Claiming the removable EFI fallback path for GRUB"
|
||||||
|
sudo grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --removable --recheck
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
log "Removing Limine"
|
log "Removing Limine"
|
||||||
|
|
||||||
drop_limine_pkgs limine limine-mkinitcpio-hook limine-snapper-sync
|
drop_limine_pkgs limine limine-mkinitcpio-hook limine-snapper-sync
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[Plymouth Theme]
|
||||||
|
Name=Blob
|
||||||
|
Description=Blob boot splash
|
||||||
|
ModuleName=script
|
||||||
|
|
||||||
|
[script]
|
||||||
|
ImageDir=/usr/share/plymouth/themes/blob
|
||||||
|
ScriptFile=/usr/share/plymouth/themes/blob/blob.script
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
Window.SetBackgroundTopColor(0.059, 0.063, 0.071);
|
||||||
|
Window.SetBackgroundBottomColor(0.059, 0.063, 0.071);
|
||||||
|
|
||||||
|
screen.width = Window.GetWidth();
|
||||||
|
screen.height = Window.GetHeight();
|
||||||
|
|
||||||
|
logo.image = Image("logo.png");
|
||||||
|
logo.width = logo.image.GetWidth();
|
||||||
|
logo.height = logo.image.GetHeight();
|
||||||
|
|
||||||
|
scale_x = screen.width / logo.width;
|
||||||
|
scale_y = screen.height / logo.height;
|
||||||
|
|
||||||
|
scale = scale_x;
|
||||||
|
if (scale_y < scale_x) {
|
||||||
|
scale = scale_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale != 1) {
|
||||||
|
logo.image = logo.image.Scale(logo.width * scale, logo.height * scale);
|
||||||
|
logo.width = logo.image.GetWidth();
|
||||||
|
logo.height = logo.image.GetHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
logo.sprite = Sprite(logo.image);
|
||||||
|
logo.sprite.SetX((screen.width - logo.width) / 2);
|
||||||
|
logo.sprite.SetY((screen.height - logo.height) / 2);
|
||||||
|
logo.sprite.SetZ(0);
|
||||||
|
|
||||||
|
prompt.sprite = Sprite();
|
||||||
|
prompt.sprite.SetZ(10);
|
||||||
|
message.sprite = Sprite();
|
||||||
|
message.sprite.SetZ(10);
|
||||||
|
|
||||||
|
fun draw_prompt(text) {
|
||||||
|
if (text == "") {
|
||||||
|
prompt.sprite.SetImage(Image.Text(" ", 1, 1, 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.image = Image.Text(text, 0.8, 0.82, 0.85);
|
||||||
|
prompt.sprite.SetImage(prompt.image);
|
||||||
|
prompt.sprite.SetX((screen.width - prompt.image.GetWidth()) / 2);
|
||||||
|
prompt.sprite.SetY(screen.height * 0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun display_password_callback(prompt_text, bullets) {
|
||||||
|
dots = "";
|
||||||
|
index = 0;
|
||||||
|
while (index < bullets) {
|
||||||
|
dots += "*";
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
draw_prompt(prompt_text + " " + dots);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun display_normal_callback() {
|
||||||
|
draw_prompt("");
|
||||||
|
}
|
||||||
|
|
||||||
|
fun message_callback(text) {
|
||||||
|
message.image = Image.Text(text, 0.8, 0.82, 0.85);
|
||||||
|
message.sprite.SetImage(message.image);
|
||||||
|
message.sprite.SetX((screen.width - message.image.GetWidth()) / 2);
|
||||||
|
message.sprite.SetY(screen.height * 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||||
|
Plymouth.SetDisplayNormalFunction(display_normal_callback);
|
||||||
|
Plymouth.SetMessageFunction(message_callback);
|
||||||
+4
-3
@@ -74,9 +74,10 @@ with `--check`.
|
|||||||
avahi, docker, power-profiles-daemon, and oomd.
|
avahi, docker, power-profiles-daemon, and oomd.
|
||||||
`NetworkManager-wait-online.service` is masked so a slow DHCP lease cannot
|
`NetworkManager-wait-online.service` is masked so a slow DHCP lease cannot
|
||||||
hold up the login screen, and `plymouth-start.service` and
|
hold up the login screen, and `plymouth-start.service` and
|
||||||
`plymouth-quit-wait.service` are masked because Blob configures no boot
|
`plymouth-quit-wait.service` are masked because an unconfigured plymouth
|
||||||
splash: an unconfigured plymouth holds the console and leaves the machine
|
holds the console and leaves the machine with neither a greeter nor a TTY.
|
||||||
with neither a greeter nor a TTY. See [packages.md](packages.md).
|
`blob boot` unmasks them when it sets the splash up. See
|
||||||
|
[packages.md](packages.md#the-boot-splash).
|
||||||
9. **The login screen** is SDDM. It has to be installed first: if
|
9. **The login screen** is SDDM. It has to be installed first: if
|
||||||
`sddm.service` is not there, the installer says whether the package is
|
`sddm.service` is not there, the installer says whether the package is
|
||||||
missing or whether systemd has simply not re-read its units yet, and carries
|
missing or whether systemd has simply not re-read its units yet, and carries
|
||||||
|
|||||||
+17
-13
@@ -72,7 +72,7 @@ Two are worth knowing about:
|
|||||||
`install.sh` installs what is missing before it writes any config:
|
`install.sh` installs what is missing before it writes any config:
|
||||||
|
|
||||||
```
|
```
|
||||||
packages/blob.packages 121 packages from core, extra, multilib
|
packages/blob.packages 123 packages from core, extra, multilib
|
||||||
packages/blob-aur.packages 11 packages with no official equivalent
|
packages/blob-aur.packages 11 packages with no official equivalent
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -136,23 +136,27 @@ Omarchy's own package list, because they were installed by hand on this machine:
|
|||||||
|
|
||||||
`playerctl` is in official `extra`, so it sits in the repo list.
|
`playerctl` is in official `extra`, so it sits in the repo list.
|
||||||
|
|
||||||
## No boot splash
|
## The boot splash
|
||||||
|
|
||||||
`plymouth` is deliberately not on either list. Blob configures no splash: there
|
`plymouth` is installed but left inert, and the splash is opt-in through one
|
||||||
is no mkinitcpio hook, no kernel command line, and `default/plymouth/` ships no
|
command:
|
||||||
theme assets, so `blob-plymouth-set` has nothing to publish either. An installed
|
|
||||||
but unconfigured plymouth is not harmless - it takes the console at boot and
|
|
||||||
never hands it back, and `getty@tty1` waits on `plymouth-quit-wait.service`, so
|
|
||||||
the machine reaches neither the greeter nor a TTY.
|
|
||||||
|
|
||||||
`install.sh` masks `plymouth-start.service` and `plymouth-quit-wait.service` for
|
|
||||||
that reason, which un-breaks a machine that already has the package. To go
|
|
||||||
further:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo pacman -Rns plymouth
|
blob boot # branding/boot_flash.png
|
||||||
|
blob boot ~/some/image.png # or any other image
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The reason it is opt-in is that an installed but *unconfigured* plymouth is not
|
||||||
|
harmless: it takes the console at boot and never hands it back, and
|
||||||
|
`getty@tty1` waits on `plymouth-quit-wait.service`, so the machine reaches
|
||||||
|
neither the greeter nor a TTY. `install.sh` therefore masks
|
||||||
|
`plymouth-start.service` and `plymouth-quit-wait.service`, 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.
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ wl-clipboard
|
|||||||
wtype
|
wtype
|
||||||
socat
|
socat
|
||||||
inotify-tools
|
inotify-tools
|
||||||
|
plymouth
|
||||||
polkit
|
polkit
|
||||||
|
|
||||||
# Shell widget backends
|
# Shell widget backends
|
||||||
|
|||||||
Reference in New Issue
Block a user