1185 lines
35 KiB
Bash
Executable file
1185 lines
35 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# build-recovery-squashfs.sh
|
|
#
|
|
# Builds the minimal live environment for BastionGuard Recovery.
|
|
#
|
|
# Secure Boot modes:
|
|
# auto -> detect firmware keys and choose shim or custom
|
|
# shim -> force Microsoft/Debian shim chain
|
|
# custom -> force custom firmware-trusted EFI signing
|
|
# off -> no Secure Boot signing requirements
|
|
# =============================================================================
|
|
|
|
set -Eeuo pipefail
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Global configuration
|
|
# -----------------------------------------------------------------------------
|
|
|
|
CHROOT_DIR="/tmp/bg-recovery-chroot"
|
|
OUTPUT_DIR="/boot/bastionguard-recovery"
|
|
LIVE_DIR="$OUTPUT_DIR/live"
|
|
SQUASHFS="$LIVE_DIR/filesystem.squashfs"
|
|
FILESYSTEM_SIZE="$LIVE_DIR/filesystem.size"
|
|
LOG_FILE="/tmp/bastionguard-recovery-build.log"
|
|
|
|
DISTRO="trixie"
|
|
ARCH="amd64"
|
|
MIRROR="https://deb.debian.org/debian"
|
|
|
|
SOURCE_ZIP="/usr/share/bastionguard-backup/grub/bastionguard-backup.zip"
|
|
SOURCE_ZIP_BASENAME="bastionguard-backup.zip"
|
|
|
|
MESON_PREFIX="/usr"
|
|
MESON_SYSCONFDIR="/etc"
|
|
MESON_LOCALSTATEDIR="/var"
|
|
MESON_LOCALDIR="/usr/share/locale"
|
|
|
|
SECUREBOOT_MODE="${SECUREBOOT_MODE:-auto}" # auto | shim | custom | off
|
|
CUSTOM_SIGN_BACKEND="${CUSTOM_SIGN_BACKEND:-auto}" # auto | sbctl | sbsign
|
|
ENROLL_MOK_ON_BUILD="${ENROLL_MOK_ON_BUILD:-yes}" # yes | no
|
|
MOK_PASSWORD="${MOK_PASSWORD:-bastionguard}"
|
|
|
|
SECUREBOOT_DIR="/etc/bastionguard-backup/secureboot"
|
|
MOK_KEY="$SECUREBOOT_DIR/MOK.key"
|
|
MOK_CRT="$SECUREBOOT_DIR/MOK.crt"
|
|
MOK_DER="$SECUREBOOT_DIR/MOK.der"
|
|
|
|
CUSTOM_SB_DIR="/etc/bastionguard-backup/custom-secureboot"
|
|
CUSTOM_EFI_KEY="$CUSTOM_SB_DIR/DB.key"
|
|
CUSTOM_EFI_CRT="$CUSTOM_SB_DIR/DB.crt"
|
|
CUSTOM_EFI_DER="$CUSTOM_SB_DIR/DB.der"
|
|
|
|
SB_EFFECTIVE_MODE=""
|
|
SB_FIRMWARE_MODE="bios"
|
|
SB_ENABLED="no"
|
|
SB_HAS_MS_KEYS="no"
|
|
SB_HAS_CUSTOM_KEYS="no"
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbsign"
|
|
|
|
# Asset installati da Meson
|
|
PLYMOUTH_THEME_NAME="bastionguard"
|
|
PLYMOUTH_THEME_DIR="/usr/share/plymouth/themes/bastionguard"
|
|
PLYMOUTH_THEME_FILE="/usr/share/plymouth/themes/bastionguard/bastionguard.plymouth"
|
|
WALLPAPER_INSTALLED="/usr/share/bastionguard-backup/data/wallpapers/bastionguard-wallpapers.png"
|
|
WALLPAPER_DST="/usr/share/backgrounds/bastionguard-wallpapers.png"
|
|
|
|
# Pacchetti runtime
|
|
BASE_PACKAGES=(
|
|
"linux-image-amd64"
|
|
"live-boot"
|
|
"live-boot-initramfs-tools"
|
|
"systemd-sysv"
|
|
"udev"
|
|
"ca-certificates"
|
|
"curl"
|
|
"bash"
|
|
"passwd"
|
|
"coreutils"
|
|
"util-linux"
|
|
"e2fsprogs"
|
|
"parted"
|
|
"rsync"
|
|
"debianutils"
|
|
"cronie"
|
|
"psmisc"
|
|
"findutils"
|
|
"grep"
|
|
"sed"
|
|
"gawk"
|
|
"gzip"
|
|
"xz-utils"
|
|
"shim-signed"
|
|
"grub-efi-amd64-signed"
|
|
"grub-efi-amd64"
|
|
"grub-common"
|
|
"grub2-common"
|
|
"efibootmgr"
|
|
"os-prober"
|
|
"mokutil"
|
|
"sbsigntool"
|
|
"plymouth"
|
|
"plymouth-themes"
|
|
"initramfs-tools"
|
|
)
|
|
|
|
GUI_PACKAGES=(
|
|
"xinit"
|
|
"xserver-xorg-core"
|
|
"xserver-xorg-video-fbdev"
|
|
"xserver-xorg-input-libinput"
|
|
"openbox"
|
|
"dbus-x11"
|
|
"xterm"
|
|
"polkitd"
|
|
"pkexec"
|
|
"libgtk-4-1"
|
|
"libvte-2.91-gtk4-0"
|
|
"libgee-0.8-2"
|
|
"libjson-glib-1.0-0"
|
|
"fonts-dejavu-core"
|
|
"network-manager"
|
|
"network-manager-gnome"
|
|
"network-manager-applet"
|
|
"nm-connection-editor"
|
|
"libnm0"
|
|
"libsecret-1-0"
|
|
"gnome-keyring"
|
|
"conky-all"
|
|
"feh"
|
|
)
|
|
|
|
BUILD_PACKAGES=(
|
|
"build-essential"
|
|
"meson"
|
|
"ninja-build"
|
|
"pkg-config"
|
|
"valac"
|
|
"unzip"
|
|
"gettext"
|
|
"help2man"
|
|
"desktop-file-utils"
|
|
"appstream"
|
|
"itstool"
|
|
"xsltproc"
|
|
"libgtk-4-dev"
|
|
"libgee-0.8-dev"
|
|
"libjson-glib-dev"
|
|
"libvte-2.91-gtk4-dev"
|
|
"libglib2.0-dev"
|
|
"libcairo2-dev"
|
|
"libgdk-pixbuf-2.0-dev"
|
|
)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Logging / errors
|
|
# -----------------------------------------------------------------------------
|
|
|
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
|
CURRENT_STEP="startup"
|
|
|
|
log() {
|
|
echo "[INFO] $*"
|
|
}
|
|
|
|
warn() {
|
|
echo "[WARN] $*" >&2
|
|
}
|
|
|
|
die() {
|
|
echo
|
|
echo "[ERROR] Step: $CURRENT_STEP" >&2
|
|
echo "[ERROR] $*" >&2
|
|
echo "[ERROR] Full log: $LOG_FILE" >&2
|
|
exit 1
|
|
}
|
|
|
|
on_error() {
|
|
local exit_code=$?
|
|
local line_no=$1
|
|
echo
|
|
echo "[FATAL] Build failed." >&2
|
|
echo "[FATAL] Step: $CURRENT_STEP" >&2
|
|
echo "[FATAL] Exit code: $exit_code" >&2
|
|
echo "[FATAL] Line: $line_no" >&2
|
|
echo "[FATAL] See full log: $LOG_FILE" >&2
|
|
exit "$exit_code"
|
|
}
|
|
trap 'on_error $LINENO' ERR
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Helpers
|
|
# -----------------------------------------------------------------------------
|
|
|
|
cleanup() {
|
|
set +e
|
|
umount -lf "$CHROOT_DIR/dev/pts" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/dev" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/proc" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/sys" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/run" 2>/dev/null || true
|
|
rm -f "$CHROOT_DIR/usr/sbin/policy-rc.d" 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
require_cmd() {
|
|
local cmd="$1"
|
|
local pkg_hint="${2:-}"
|
|
command -v "$cmd" >/dev/null 2>&1 || {
|
|
[ -n "$pkg_hint" ] \
|
|
&& die "Required command not found: $cmd (install package: $pkg_hint)" \
|
|
|| die "Required command not found: $cmd"
|
|
}
|
|
}
|
|
|
|
retry_cmd() {
|
|
local max_attempts="$1"
|
|
shift
|
|
|
|
local attempt=1
|
|
while true; do
|
|
if "$@"; then
|
|
return 0
|
|
fi
|
|
|
|
if [ "$attempt" -ge "$max_attempts" ]; then
|
|
die "Command failed after $attempt attempts: $*"
|
|
fi
|
|
|
|
warn "Attempt $attempt failed, retrying in 5 seconds: $*"
|
|
attempt=$((attempt + 1))
|
|
sleep 5
|
|
done
|
|
}
|
|
|
|
assert_file() {
|
|
local path="$1"
|
|
[ -f "$path" ] || die "Expected file not found: $path"
|
|
}
|
|
|
|
find_first_existing() {
|
|
local path
|
|
for path in "$@"; do
|
|
if [ -f "$path" ]; then
|
|
echo "$path"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Secure Boot detection / signing
|
|
# -----------------------------------------------------------------------------
|
|
|
|
detect_firmware_mode() {
|
|
if [ -d /sys/firmware/efi ]; then
|
|
SB_FIRMWARE_MODE="uefi"
|
|
else
|
|
SB_FIRMWARE_MODE="bios"
|
|
fi
|
|
}
|
|
|
|
detect_secure_boot_state() {
|
|
SB_ENABLED="no"
|
|
[ "$SB_FIRMWARE_MODE" = "uefi" ] || return 0
|
|
|
|
if command -v mokutil >/dev/null 2>&1; then
|
|
if mokutil --sb-state 2>/dev/null | grep -qi "SecureBoot enabled"; then
|
|
SB_ENABLED="yes"
|
|
return 0
|
|
fi
|
|
if mokutil --sb-state 2>/dev/null | grep -qi "SecureBoot disabled"; then
|
|
SB_ENABLED="no"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
local sb_var
|
|
sb_var="$(find /sys/firmware/efi/efivars -maxdepth 1 -name 'SecureBoot-*' 2>/dev/null | head -n1 || true)"
|
|
if [ -n "$sb_var" ] && [ -r "$sb_var" ]; then
|
|
local value
|
|
value="$(od -An -t u1 -j4 -N1 "$sb_var" 2>/dev/null | tr -d ' ')"
|
|
if [ "${value:-0}" = "1" ]; then
|
|
SB_ENABLED="yes"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
detect_microsoft_keys() {
|
|
SB_HAS_MS_KEYS="no"
|
|
[ "$SB_FIRMWARE_MODE" = "uefi" ] || return 0
|
|
|
|
if command -v efi-readvar >/dev/null 2>&1; then
|
|
local tmp_db tmp_kek
|
|
tmp_db="$(mktemp)"
|
|
tmp_kek="$(mktemp)"
|
|
|
|
efi-readvar -v db >"$tmp_db" 2>/dev/null || true
|
|
efi-readvar -v KEK >"$tmp_kek" 2>/dev/null || true
|
|
|
|
if grep -Eqi 'Microsoft|Windows UEFI CA|Microsoft Corporation UEFI' "$tmp_db" "$tmp_kek"; then
|
|
SB_HAS_MS_KEYS="yes"
|
|
fi
|
|
|
|
rm -f "$tmp_db" "$tmp_kek"
|
|
else
|
|
warn "efi-readvar not found on host; Microsoft key detection skipped."
|
|
fi
|
|
}
|
|
|
|
detect_custom_signing_material() {
|
|
if [ -f "$CUSTOM_EFI_KEY" ] && [ -f "$CUSTOM_EFI_CRT" ]; then
|
|
SB_HAS_CUSTOM_KEYS="yes"
|
|
else
|
|
SB_HAS_CUSTOM_KEYS="no"
|
|
fi
|
|
}
|
|
|
|
detect_custom_sign_backend() {
|
|
case "$CUSTOM_SIGN_BACKEND" in
|
|
sbctl)
|
|
command -v sbctl >/dev/null 2>&1 || die "CUSTOM_SIGN_BACKEND=sbctl but sbctl not found"
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbctl"
|
|
;;
|
|
sbsign)
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbsign"
|
|
;;
|
|
auto)
|
|
if command -v sbctl >/dev/null 2>&1; then
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbctl"
|
|
else
|
|
CUSTOM_SIGN_BACKEND_EFFECTIVE="sbsign"
|
|
fi
|
|
;;
|
|
*)
|
|
die "Invalid CUSTOM_SIGN_BACKEND: $CUSTOM_SIGN_BACKEND"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
ensure_mok_keys() {
|
|
CURRENT_STEP="ensure_mok_keys"
|
|
|
|
mkdir -p "$SECUREBOOT_DIR"
|
|
chmod 700 "$SECUREBOOT_DIR"
|
|
|
|
if [ ! -f "$MOK_KEY" ] || [ ! -f "$MOK_CRT" ]; then
|
|
log "Generating new BastionGuard MOK key..."
|
|
openssl req \
|
|
-new -x509 -newkey rsa:2048 \
|
|
-keyout "$MOK_KEY" \
|
|
-out "$MOK_CRT" \
|
|
-nodes \
|
|
-days 3650 \
|
|
-subj "/CN=BastionGuard Secure Boot/"
|
|
chmod 600 "$MOK_KEY"
|
|
chmod 644 "$MOK_CRT"
|
|
else
|
|
log "Using existing BastionGuard MOK key."
|
|
fi
|
|
|
|
openssl x509 -outform DER -in "$MOK_CRT" -out "$MOK_DER"
|
|
chmod 644 "$MOK_DER"
|
|
assert_file "$MOK_DER"
|
|
}
|
|
|
|
ensure_custom_keys() {
|
|
CURRENT_STEP="ensure_custom_keys"
|
|
assert_file "$CUSTOM_EFI_KEY"
|
|
assert_file "$CUSTOM_EFI_CRT"
|
|
|
|
mkdir -p "$CUSTOM_SB_DIR"
|
|
chmod 700 "$CUSTOM_SB_DIR"
|
|
|
|
openssl x509 -outform DER -in "$CUSTOM_EFI_CRT" -out "$CUSTOM_EFI_DER"
|
|
chmod 644 "$CUSTOM_EFI_DER"
|
|
assert_file "$CUSTOM_EFI_DER"
|
|
}
|
|
|
|
decide_secureboot_mode() {
|
|
CURRENT_STEP="decide_secureboot_mode"
|
|
|
|
detect_firmware_mode
|
|
detect_secure_boot_state
|
|
detect_microsoft_keys
|
|
detect_custom_signing_material
|
|
detect_custom_sign_backend
|
|
|
|
log "Secure Boot detection:"
|
|
log " Firmware mode : $SB_FIRMWARE_MODE"
|
|
log " Secure Boot : $SB_ENABLED"
|
|
log " Microsoft keys : $SB_HAS_MS_KEYS"
|
|
log " Custom keypair : $SB_HAS_CUSTOM_KEYS"
|
|
log " Requested mode : $SECUREBOOT_MODE"
|
|
log " Sign backend : $CUSTOM_SIGN_BACKEND_EFFECTIVE"
|
|
|
|
if [ "$SB_FIRMWARE_MODE" != "uefi" ]; then
|
|
SB_EFFECTIVE_MODE="off"
|
|
log " Effective mode : off (legacy BIOS)"
|
|
return 0
|
|
fi
|
|
|
|
case "$SECUREBOOT_MODE" in
|
|
off)
|
|
SB_EFFECTIVE_MODE="off"
|
|
;;
|
|
shim)
|
|
if [ "$SB_ENABLED" = "yes" ] && [ "$SB_HAS_MS_KEYS" != "yes" ]; then
|
|
die "shim mode requested, but Microsoft keys were not detected in firmware."
|
|
fi
|
|
SB_EFFECTIVE_MODE="shim"
|
|
;;
|
|
custom)
|
|
ensure_custom_keys
|
|
SB_EFFECTIVE_MODE="custom"
|
|
;;
|
|
auto)
|
|
if [ "$SB_ENABLED" != "yes" ]; then
|
|
SB_EFFECTIVE_MODE="off"
|
|
elif [ "$SB_HAS_MS_KEYS" = "yes" ]; then
|
|
SB_EFFECTIVE_MODE="shim"
|
|
elif [ "$SB_HAS_CUSTOM_KEYS" = "yes" ]; then
|
|
ensure_custom_keys
|
|
SB_EFFECTIVE_MODE="custom"
|
|
else
|
|
die "Secure Boot enabled, Microsoft keys not detected, and no custom signing keys available."
|
|
fi
|
|
;;
|
|
*)
|
|
die "Invalid SECUREBOOT_MODE: $SECUREBOOT_MODE"
|
|
;;
|
|
esac
|
|
|
|
log " Effective mode : $SB_EFFECTIVE_MODE"
|
|
}
|
|
|
|
sign_file_with_sbsign() {
|
|
local input="$1"
|
|
local key="$2"
|
|
local crt="$3"
|
|
local output="${input}.signed"
|
|
|
|
assert_file "$input"
|
|
assert_file "$key"
|
|
assert_file "$crt"
|
|
|
|
sbsign --key "$key" --cert "$crt" --output "$output" "$input"
|
|
assert_file "$output"
|
|
mv -f "$output" "$input"
|
|
}
|
|
|
|
sign_file_custom() {
|
|
local input="$1"
|
|
|
|
assert_file "$input"
|
|
|
|
case "$CUSTOM_SIGN_BACKEND_EFFECTIVE" in
|
|
sbctl)
|
|
sbctl sign -s "$input"
|
|
;;
|
|
sbsign)
|
|
sign_file_with_sbsign "$input" "$CUSTOM_EFI_KEY" "$CUSTOM_EFI_CRT"
|
|
;;
|
|
*)
|
|
die "Unsupported custom sign backend: $CUSTOM_SIGN_BACKEND_EFFECTIVE"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
sign_recovery_kernel_for_mode() {
|
|
CURRENT_STEP="sign_recovery_kernel_for_mode"
|
|
|
|
local kernel_path="$1"
|
|
assert_file "$kernel_path"
|
|
|
|
case "$SB_EFFECTIVE_MODE" in
|
|
off)
|
|
log "Skipping kernel signing (mode=off)."
|
|
;;
|
|
shim)
|
|
ensure_mok_keys
|
|
log "Signing kernel with BastionGuard MOK..."
|
|
sign_file_with_sbsign "$kernel_path" "$MOK_KEY" "$MOK_CRT"
|
|
;;
|
|
custom)
|
|
ensure_custom_keys
|
|
log "Signing kernel with custom firmware-trusted certificate..."
|
|
sign_file_custom "$kernel_path"
|
|
;;
|
|
*)
|
|
die "Unsupported Secure Boot mode for kernel signing: $SB_EFFECTIVE_MODE"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
write_main_grub_cfg() {
|
|
mkdir -p "$OUTPUT_DIR/grub"
|
|
|
|
cat > "$OUTPUT_DIR/grub/grub.cfg" << 'ENDGRUBCFG'
|
|
set default=0
|
|
set timeout=5
|
|
|
|
menuentry "BastionGuard Recovery" {
|
|
search --no-floppy --label --set=root bastionguard-recovery
|
|
linux /bastionguard-recovery/vmlinuz boot=live components quiet splash bastionguard.recovery=1 live-media-path=/bastionguard-recovery/live
|
|
initrd /bastionguard-recovery/initrd.img
|
|
}
|
|
|
|
menuentry "BastionGuard Recovery (debug)" {
|
|
search --no-floppy --label --set=root bastionguard-recovery
|
|
linux /bastionguard-recovery/vmlinuz boot=live components bastionguard.recovery=1 live-media-path=/bastionguard-recovery/live
|
|
initrd /bastionguard-recovery/initrd.img
|
|
}
|
|
ENDGRUBCFG
|
|
}
|
|
|
|
write_grub_stub_cfg() {
|
|
local stub_path="$1"
|
|
mkdir -p "$(dirname "$stub_path")"
|
|
|
|
cat > "$stub_path" << 'ENDSTUB'
|
|
search --no-floppy --label --set=root bastionguard-recovery
|
|
set prefix=($root)/bastionguard-recovery/grub
|
|
configfile ($root)/bastionguard-recovery/grub/grub.cfg
|
|
ENDSTUB
|
|
}
|
|
|
|
build_efi_layout_shim() {
|
|
CURRENT_STEP="build_efi_layout_shim"
|
|
log "Building EFI layout in shim mode..."
|
|
|
|
local efi_dir="$OUTPUT_DIR/EFI/BOOT"
|
|
mkdir -p "$efi_dir"
|
|
|
|
local shim_src
|
|
local mok_src
|
|
local grub_signed_src
|
|
|
|
shim_src="$(find_first_existing \
|
|
"$CHROOT_DIR/usr/lib/shim/shimx64.efi.signed" \
|
|
"$CHROOT_DIR/usr/lib/shim/shimx64.efi" \
|
|
"$(find "$CHROOT_DIR/usr/lib" -type f -name 'shimx64.efi.signed' 2>/dev/null | head -n1)" \
|
|
"$(find "$CHROOT_DIR" -type f -name 'shimx64.efi.signed' 2>/dev/null | head -n1)"
|
|
)" || true
|
|
[ -n "${shim_src:-}" ] || die "shim EFI binary not found in chroot."
|
|
|
|
mok_src="$(find_first_existing \
|
|
"$CHROOT_DIR/usr/lib/shim/mmx64.efi" \
|
|
"$CHROOT_DIR/usr/lib/shim/mmx64.efi.signed" \
|
|
"$(find "$CHROOT_DIR/usr/lib" -type f -name 'mmx64.efi*' 2>/dev/null | head -n1)"
|
|
)" || true
|
|
|
|
grub_signed_src="$(find_first_existing \
|
|
"$CHROOT_DIR/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed" \
|
|
"$CHROOT_DIR/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed" \
|
|
"$(find "$CHROOT_DIR/usr/lib/grub" -type f -name 'grubx64.efi.signed' 2>/dev/null | head -n1)"
|
|
)" || true
|
|
[ -n "${grub_signed_src:-}" ] || die "Signed GRUB EFI binary not found in chroot."
|
|
|
|
cp "$shim_src" "$efi_dir/BOOTx64.EFI"
|
|
[ -n "${mok_src:-}" ] && cp "$mok_src" "$efi_dir/mmx64.efi"
|
|
cp "$grub_signed_src" "$efi_dir/grubx64.efi"
|
|
|
|
assert_file "$efi_dir/BOOTx64.EFI"
|
|
assert_file "$efi_dir/grubx64.efi"
|
|
|
|
write_main_grub_cfg
|
|
write_grub_stub_cfg "$efi_dir/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/EFI/debian/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/grub.cfg"
|
|
}
|
|
|
|
build_efi_layout_custom() {
|
|
CURRENT_STEP="build_efi_layout_custom"
|
|
log "Building EFI layout in custom-key mode..."
|
|
|
|
local efi_dir="$OUTPUT_DIR/EFI/BOOT"
|
|
mkdir -p "$efi_dir"
|
|
|
|
local grub_unsigned_src
|
|
grub_unsigned_src="$(find_first_existing \
|
|
"$CHROOT_DIR/usr/lib/grub/x86_64-efi/monolithic/grubx64.efi" \
|
|
"$CHROOT_DIR/usr/lib/grub/x86_64-efi/grub.efi" \
|
|
"$(find "$CHROOT_DIR/usr/lib/grub" -type f \( -name 'grubx64.efi' -o -name 'grub.efi' \) 2>/dev/null | head -n1)"
|
|
)" || true
|
|
[ -n "${grub_unsigned_src:-}" ] || die "Custom-signable GRUB EFI binary not found in chroot."
|
|
|
|
cp "$grub_unsigned_src" "$efi_dir/BOOTx64.EFI"
|
|
assert_file "$efi_dir/BOOTx64.EFI"
|
|
|
|
ensure_custom_keys
|
|
sign_file_custom "$efi_dir/BOOTx64.EFI"
|
|
|
|
cp "$efi_dir/BOOTx64.EFI" "$efi_dir/grubx64.efi"
|
|
assert_file "$efi_dir/grubx64.efi"
|
|
|
|
write_main_grub_cfg
|
|
write_grub_stub_cfg "$efi_dir/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/EFI/debian/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/grub.cfg"
|
|
}
|
|
|
|
build_efi_layout_for_mode() {
|
|
CURRENT_STEP="build_efi_layout_for_mode"
|
|
|
|
case "$SB_EFFECTIVE_MODE" in
|
|
off)
|
|
log "Building EFI layout without Secure Boot chain..."
|
|
mkdir -p "$OUTPUT_DIR/EFI/BOOT"
|
|
write_main_grub_cfg
|
|
write_grub_stub_cfg "$OUTPUT_DIR/EFI/BOOT/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/EFI/debian/grub.cfg"
|
|
write_grub_stub_cfg "$OUTPUT_DIR/grub.cfg"
|
|
;;
|
|
shim)
|
|
build_efi_layout_shim
|
|
;;
|
|
custom)
|
|
build_efi_layout_custom
|
|
;;
|
|
*)
|
|
die "Invalid SB_EFFECTIVE_MODE: $SB_EFFECTIVE_MODE"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# UI / live environment helpers
|
|
# -----------------------------------------------------------------------------
|
|
|
|
prepare_live_root() {
|
|
CURRENT_STEP="prepare_live_root"
|
|
|
|
log "Preparing live root..."
|
|
|
|
umount -lf "$CHROOT_DIR/dev/pts" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/dev" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/proc" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/sys" 2>/dev/null || true
|
|
umount -lf "$CHROOT_DIR/run" 2>/dev/null || true
|
|
|
|
mkdir -p \
|
|
"$CHROOT_DIR/dev" \
|
|
"$CHROOT_DIR/proc" \
|
|
"$CHROOT_DIR/sys" \
|
|
"$CHROOT_DIR/run" \
|
|
"$CHROOT_DIR/tmp" \
|
|
"$CHROOT_DIR/etc/network" \
|
|
"$CHROOT_DIR/var/log" \
|
|
"$CHROOT_DIR/var/cache/apt"
|
|
|
|
chmod 1777 "$CHROOT_DIR/tmp"
|
|
: > "$CHROOT_DIR/etc/network/interfaces"
|
|
}
|
|
|
|
configure_locale() {
|
|
CURRENT_STEP="configure_locale"
|
|
log "Setting locale inside chroot..."
|
|
|
|
mkdir -p "$CHROOT_DIR/etc"
|
|
cat > "$CHROOT_DIR/etc/default/locale" <<EOF
|
|
LANG=C.UTF-8
|
|
LC_ALL=C.UTF-8
|
|
EOF
|
|
}
|
|
|
|
create_desktop_notes() {
|
|
CURRENT_STEP="create_desktop_notes"
|
|
mkdir -p "$CHROOT_DIR/root"
|
|
|
|
cat > "$CHROOT_DIR/root/.conkyrc" << 'ENDCONKY'
|
|
conky.config = {
|
|
background = true,
|
|
double_buffer = true,
|
|
own_window = true,
|
|
own_window_type = 'desktop',
|
|
own_window_transparent = true,
|
|
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
|
|
alignment = 'top_left',
|
|
gap_x = 24,
|
|
gap_y = 24,
|
|
minimum_width = 760,
|
|
maximum_width = 980,
|
|
draw_shades = false,
|
|
draw_outline = false,
|
|
draw_borders = false,
|
|
use_xft = true,
|
|
font = 'DejaVu Sans Mono:size=11',
|
|
xftalpha = 1.0,
|
|
update_interval = 60,
|
|
cpu_avg_samples = 1,
|
|
net_avg_samples = 1,
|
|
default_color = 'white',
|
|
};
|
|
|
|
conky.text = [[
|
|
${font DejaVu Sans:bold:size=16}BastionGuard Recovery${font}
|
|
|
|
${font DejaVu Sans:bold:size=13}Recommended procedure after restore${font}
|
|
1. Complete the restore with BastionGuard Backup
|
|
2. Check disks and partitions with: lsblk -f
|
|
3. Reinstall GRUB on the installed system
|
|
4. Reboot and verify normal startup
|
|
|
|
Automatic script:
|
|
bastionguard-reinstall-grub
|
|
]];
|
|
ENDCONKY
|
|
}
|
|
|
|
create_grub_restore_helper() {
|
|
CURRENT_STEP="create_grub_restore_helper"
|
|
|
|
mkdir -p "$CHROOT_DIR/usr/local/bin"
|
|
cat > "$CHROOT_DIR/usr/local/bin/bastionguard-reinstall-grub" << 'ENDGRUBHELP'
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
cleanup_mounts() {
|
|
umount -lf /mnt/dev 2>/dev/null || true
|
|
umount -lf /mnt/proc 2>/dev/null || true
|
|
umount -lf /mnt/sys 2>/dev/null || true
|
|
umount -lf /mnt/run 2>/dev/null || true
|
|
umount -lf /mnt/boot/efi 2>/dev/null || true
|
|
umount -lf /mnt/boot 2>/dev/null || true
|
|
umount -lf /mnt 2>/dev/null || true
|
|
}
|
|
|
|
die() {
|
|
echo "ERROR: $*"
|
|
cleanup_mounts
|
|
exit 1
|
|
}
|
|
|
|
trap cleanup_mounts EXIT
|
|
|
|
echo "Available partitions:"
|
|
lsblk -f
|
|
ENDGRUBHELP
|
|
chmod +x "$CHROOT_DIR/usr/local/bin/bastionguard-reinstall-grub"
|
|
}
|
|
|
|
install_plymouth_and_wallpaper() {
|
|
CURRENT_STEP="install_plymouth_and_wallpaper"
|
|
log "Setting Plymouth theme and wallpaper inside chroot..."
|
|
|
|
chroot "$CHROOT_DIR" env LANG=C.UTF-8 LC_ALL=C.UTF-8 bash -lc "
|
|
set -Eeuo pipefail
|
|
|
|
THEME_NAME='$PLYMOUTH_THEME_NAME'
|
|
THEME_FILE='$PLYMOUTH_THEME_FILE'
|
|
WALLPAPER_SRC='$WALLPAPER_INSTALLED'
|
|
WALLPAPER_DST='$WALLPAPER_DST'
|
|
|
|
# --- Wallpaper: indipendente dal tema Plymouth ---
|
|
if [ -f \"\$WALLPAPER_SRC\" ]; then
|
|
mkdir -p /usr/share/backgrounds
|
|
cp -f \"\$WALLPAPER_SRC\" \"\$WALLPAPER_DST\"
|
|
echo '[INFO] Wallpaper installed:' \"\$WALLPAPER_DST\"
|
|
else
|
|
echo '[WARN] Wallpaper not found:' \"\$WALLPAPER_SRC\" >&2
|
|
fi
|
|
|
|
# --- Plymouth theme ---
|
|
if [ ! -f \"\$THEME_FILE\" ]; then
|
|
echo '[WARN] Plymouth theme file not found:' \"\$THEME_FILE\" >&2
|
|
exit 0
|
|
fi
|
|
|
|
if command -v plymouth-set-default-theme >/dev/null 2>&1; then
|
|
plymouth-set-default-theme \"\$THEME_NAME\"
|
|
else
|
|
mkdir -p /etc/plymouth
|
|
printf '[Daemon]\nTheme=%s\n' \"\$THEME_NAME\" > /etc/plymouth/plymouthd.conf
|
|
fi
|
|
|
|
update-initramfs -u
|
|
|
|
# --- Verifica: tema attivo? ---
|
|
if command -v plymouth-set-default-theme >/dev/null 2>&1; then
|
|
current=\"\$(plymouth-set-default-theme 2>/dev/null || true)\"
|
|
if [ \"\$current\" != \"\$THEME_NAME\" ]; then
|
|
echo \"[WARN] Plymouth default theme is '\$current', expected '\$THEME_NAME'\" >&2
|
|
fi
|
|
fi
|
|
|
|
# --- Verifica: tema dentro l'initrd appena rigenerato? ---
|
|
initrd=\"\$(ls /boot/initrd.img-* 2>/dev/null | sort -V | tail -1 || true)\"
|
|
if [ -n \"\$initrd\" ] && command -v lsinitramfs >/dev/null 2>&1; then
|
|
if lsinitramfs \"\$initrd\" | grep -q \"plymouth/themes/\$THEME_NAME/\"; then
|
|
echo \"[INFO] Plymouth theme '\$THEME_NAME' present in \$initrd\"
|
|
else
|
|
echo \"[WARN] Plymouth theme '\$THEME_NAME' NOT found in \$initrd — splash will fall back to default\" >&2
|
|
fi
|
|
fi
|
|
"
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Main build
|
|
# -----------------------------------------------------------------------------
|
|
|
|
main() {
|
|
CURRENT_STEP="prerequisites"
|
|
|
|
[ "$EUID" -eq 0 ] || die "Run as root (sudo or pkexec)."
|
|
|
|
echo "========================================================"
|
|
echo " BastionGuard Recovery — Squashfs environment build"
|
|
echo "========================================================"
|
|
echo " Log file: $LOG_FILE"
|
|
echo
|
|
|
|
require_cmd debootstrap debootstrap
|
|
require_cmd mksquashfs squashfs-tools
|
|
require_cmd chroot coreutils
|
|
require_cmd mount util-linux
|
|
require_cmd umount util-linux
|
|
require_cmd awk gawk
|
|
require_cmd openssl openssl
|
|
require_cmd sbsign sbsigntool
|
|
require_cmd unzip unzip
|
|
require_cmd cp coreutils
|
|
require_cmd ls coreutils
|
|
require_cmd find findutils
|
|
require_cmd tee coreutils
|
|
require_cmd du coreutils
|
|
|
|
if [ "$ENROLL_MOK_ON_BUILD" = "yes" ]; then
|
|
require_cmd mokutil mokutil
|
|
fi
|
|
|
|
assert_file "$SOURCE_ZIP"
|
|
|
|
CURRENT_STEP="cleanup_previous"
|
|
log "Cleaning previous build directories..."
|
|
cleanup
|
|
rm -rf "$CHROOT_DIR" "$OUTPUT_DIR"
|
|
mkdir -p "$CHROOT_DIR" "$OUTPUT_DIR" "$LIVE_DIR"
|
|
|
|
CURRENT_STEP="debootstrap"
|
|
log "Running debootstrap..."
|
|
retry_cmd 3 debootstrap \
|
|
--arch="$ARCH" \
|
|
--variant=minbase \
|
|
--include="$(IFS=,; echo "${BASE_PACKAGES[*]}")" \
|
|
"$DISTRO" \
|
|
"$CHROOT_DIR" \
|
|
"$MIRROR"
|
|
|
|
assert_file "$CHROOT_DIR/usr/bin/apt-get"
|
|
|
|
CURRENT_STEP="apt_config"
|
|
log "Configuring apt..."
|
|
mkdir -p "$CHROOT_DIR/etc/apt/apt.conf.d"
|
|
cat > "$CHROOT_DIR/etc/apt/apt.conf.d/80retries" << 'EOF'
|
|
Acquire::Retries "5";
|
|
Acquire::http::Timeout "30";
|
|
Acquire::https::Timeout "30";
|
|
APT::Get::Assume-Yes "true";
|
|
EOF
|
|
|
|
CURRENT_STEP="mount_pseudofs"
|
|
log "Mounting pseudo-filesystems..."
|
|
mkdir -p "$CHROOT_DIR/dev" "$CHROOT_DIR/dev/pts" "$CHROOT_DIR/proc" "$CHROOT_DIR/sys" "$CHROOT_DIR/run"
|
|
mount --bind /dev "$CHROOT_DIR/dev"
|
|
mount --bind /dev/pts "$CHROOT_DIR/dev/pts"
|
|
mount -t proc /proc "$CHROOT_DIR/proc"
|
|
mount -t sysfs /sys "$CHROOT_DIR/sys"
|
|
mount --bind /run "$CHROOT_DIR/run"
|
|
|
|
if [ -f /etc/resolv.conf ]; then
|
|
cp /etc/resolv.conf "$CHROOT_DIR/etc/resolv.conf"
|
|
fi
|
|
|
|
mkdir -p "$CHROOT_DIR/usr/sbin"
|
|
cat > "$CHROOT_DIR/usr/sbin/policy-rc.d" << 'EOF'
|
|
#!/bin/sh
|
|
exit 101
|
|
EOF
|
|
chmod +x "$CHROOT_DIR/usr/sbin/policy-rc.d"
|
|
|
|
CURRENT_STEP="install_packages"
|
|
log "Installing runtime and build packages in chroot..."
|
|
retry_cmd 5 chroot "$CHROOT_DIR" apt-get update -o Acquire::Retries=5
|
|
retry_cmd 5 env DEBIAN_FRONTEND=noninteractive \
|
|
chroot "$CHROOT_DIR" apt-get install -y --fix-missing \
|
|
"${GUI_PACKAGES[@]}" \
|
|
"${BUILD_PACKAGES[@]}"
|
|
|
|
# Plugin label per i temi Plymouth basati su script che renderizzano testo.
|
|
# Installazione non bloccante: il nome del pacchetto varia tra le release.
|
|
env DEBIAN_FRONTEND=noninteractive \
|
|
chroot "$CHROOT_DIR" apt-get install -y plymouth-label-ft 2>/dev/null \
|
|
|| env DEBIAN_FRONTEND=noninteractive \
|
|
chroot "$CHROOT_DIR" apt-get install -y plymouth-label 2>/dev/null \
|
|
|| warn "Plymouth label plugin not available (theme text rendering may not work)."
|
|
|
|
configure_locale
|
|
|
|
CURRENT_STEP="copy_source"
|
|
log "Copying source archive into chroot..."
|
|
mkdir -p "$CHROOT_DIR/root/src"
|
|
cp -f "$SOURCE_ZIP" "$CHROOT_DIR/root/src/$SOURCE_ZIP_BASENAME"
|
|
assert_file "$CHROOT_DIR/root/src/$SOURCE_ZIP_BASENAME"
|
|
|
|
CURRENT_STEP="extract_source"
|
|
log "Extracting source archive in chroot..."
|
|
chroot "$CHROOT_DIR" env LANG=C.UTF-8 LC_ALL=C.UTF-8 bash -lc "
|
|
set -Eeuo pipefail
|
|
cd /root/src
|
|
rm -rf bastionguard-backup extracted-src
|
|
mkdir -p extracted-src
|
|
cd extracted-src
|
|
unzip -q ../$SOURCE_ZIP_BASENAME
|
|
topdir=\$(find . -mindepth 1 -maxdepth 1 -type d | head -n1)
|
|
[ -n \"\$topdir\" ] || { echo 'ERROR: no extracted top-level directory found'; exit 1; }
|
|
mv \"\$topdir\" ../bastionguard-backup
|
|
|
|
# Fix timestamps imported from ZIP archive.
|
|
find /root/src/bastionguard-backup -exec touch -h {} +
|
|
|
|
[ -f /root/src/bastionguard-backup/meson.build ] || { echo 'ERROR: meson.build not found after extraction'; exit 1; }
|
|
"
|
|
|
|
CURRENT_STEP="build_project"
|
|
log "Building bastionguard-backup in chroot..."
|
|
chroot "$CHROOT_DIR" env LANG=C.UTF-8 LC_ALL=C.UTF-8 bash -lc "
|
|
set -Eeuo pipefail
|
|
cd /root/src/bastionguard-backup
|
|
rm -rf build
|
|
meson setup build \
|
|
--prefix=$MESON_PREFIX \
|
|
--sysconfdir=$MESON_SYSCONFDIR \
|
|
--localstatedir=$MESON_LOCALSTATEDIR \
|
|
--localedir=$MESON_LOCALDIR
|
|
ninja -C build
|
|
ninja -C build install
|
|
command -v bastionguard-backup-gtk >/dev/null 2>&1 || test -x /usr/bin/bastionguard-backup-gtk
|
|
"
|
|
|
|
CURRENT_STEP="install_launcher"
|
|
log "Configuring recovery launcher..."
|
|
mkdir -p "$CHROOT_DIR/usr/bin"
|
|
cat > "$CHROOT_DIR/usr/bin/bastionguard-launcher" << 'ENDLAUNCHER'
|
|
#!/bin/bash
|
|
exec bastionguard-backup-gtk --recovery
|
|
ENDLAUNCHER
|
|
chmod +x "$CHROOT_DIR/usr/bin/bastionguard-launcher"
|
|
|
|
mkdir -p "$CHROOT_DIR/root/.config/openbox"
|
|
|
|
cat > "$CHROOT_DIR/root/.config/openbox/menu.xml" << 'ENDMENU'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<openbox_menu xmlns="http://openbox.org/3.4/menu">
|
|
<menu id="root-menu" label="BastionGuard Recovery">
|
|
<item label="BastionGuard Backup">
|
|
<action name="Execute">
|
|
<command>/usr/bin/bastionguard-launcher</command>
|
|
</action>
|
|
</item>
|
|
<item label="Restore GRUB">
|
|
<action name="Execute">
|
|
<command>xterm -fa "Monospace" -fs 12 -e /usr/local/bin/bastionguard-reinstall-grub</command>
|
|
</action>
|
|
</item>
|
|
<separator/>
|
|
<item label="Terminal">
|
|
<action name="Execute">
|
|
<command>xterm -fa "Monospace" -fs 12</command>
|
|
</action>
|
|
</item>
|
|
<item label="Network (NetworkManager)">
|
|
<action name="Execute">
|
|
<command>nm-connection-editor</command>
|
|
</action>
|
|
</item>
|
|
<separator/>
|
|
<item label="Reboot">
|
|
<action name="Execute">
|
|
<command>reboot</command>
|
|
</action>
|
|
</item>
|
|
<item label="Power off">
|
|
<action name="Execute">
|
|
<command>poweroff</command>
|
|
</action>
|
|
</item>
|
|
</menu>
|
|
</openbox_menu>
|
|
ENDMENU
|
|
|
|
cat > "$CHROOT_DIR/root/.config/openbox/autostart" << ENDAUTO
|
|
if [ -f "$WALLPAPER_DST" ]; then
|
|
feh --no-fehbg --bg-fill "$WALLPAPER_DST"
|
|
else
|
|
xsetroot -solid "#1a1a2e"
|
|
fi
|
|
nm-applet --indicator &
|
|
conky &
|
|
/usr/bin/bastionguard-launcher &
|
|
ENDAUTO
|
|
|
|
cat > "$CHROOT_DIR/root/.xinitrc" << 'ENDXINIT'
|
|
#!/bin/bash
|
|
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/0}"
|
|
mkdir -p "$XDG_RUNTIME_DIR"
|
|
chmod 700 "$XDG_RUNTIME_DIR"
|
|
eval "$(dbus-launch --sh-syntax)"
|
|
export DBUS_SESSION_BUS_ADDRESS
|
|
eval "$(gnome-keyring-daemon --start --components=secrets)"
|
|
export GNOME_KEYRING_CONTROL
|
|
export GNOME_KEYRING_PID
|
|
exec openbox-session
|
|
ENDXINIT
|
|
chmod +x "$CHROOT_DIR/root/.xinitrc"
|
|
|
|
create_desktop_notes
|
|
create_grub_restore_helper
|
|
|
|
CURRENT_STEP="live_config"
|
|
log "Configuring live system..."
|
|
mkdir -p "$CHROOT_DIR/etc/live"
|
|
cat > "$CHROOT_DIR/etc/live/config" << 'ENDLIVE'
|
|
LIVE_HOSTNAME="bastionguard-recovery"
|
|
LIVE_USERNAME="root"
|
|
LIVE_USER_FULLNAME="BastionGuard Recovery"
|
|
LIVE_NOCONFIGS="True"
|
|
ENDLIVE
|
|
|
|
mkdir -p "$CHROOT_DIR/etc/systemd/system/getty@tty1.service.d"
|
|
cat > "$CHROOT_DIR/etc/systemd/system/getty@tty1.service.d/autologin.conf" << 'ENDGETTY'
|
|
[Service]
|
|
ExecStart=
|
|
ExecStart=-/sbin/agetty --autologin root --noclear %I $TERM
|
|
ENDGETTY
|
|
|
|
cat > "$CHROOT_DIR/root/.bash_profile" << 'ENDBASH'
|
|
if [ -z "$DISPLAY" ] && [ "$(tty)" = "/dev/tty1" ]; then
|
|
export XDG_RUNTIME_DIR="/run/user/0"
|
|
mkdir -p "$XDG_RUNTIME_DIR"
|
|
chmod 700 "$XDG_RUNTIME_DIR"
|
|
exec startx /root/.xinitrc -- :0 vt1 -nolisten tcp 2>/tmp/xorg.log
|
|
fi
|
|
ENDBASH
|
|
|
|
echo "bastionguard-recovery" > "$CHROOT_DIR/etc/hostname"
|
|
|
|
if [ ! -x "$CHROOT_DIR/usr/sbin/chpasswd" ]; then
|
|
die "chpasswd missing in chroot (install package: passwd)"
|
|
fi
|
|
printf 'root:root\n' | chroot "$CHROOT_DIR" /usr/sbin/chpasswd
|
|
|
|
chroot "$CHROOT_DIR" systemctl disable \
|
|
apt-daily.timer \
|
|
apt-daily-upgrade.timer \
|
|
man-db.timer \
|
|
2>/dev/null || true
|
|
|
|
chroot "$CHROOT_DIR" systemctl enable NetworkManager 2>/dev/null || true
|
|
|
|
mkdir -p "$CHROOT_DIR/etc/NetworkManager/conf.d"
|
|
cat > "$CHROOT_DIR/etc/NetworkManager/conf.d/10-recovery.conf" << 'ENDNM'
|
|
[main]
|
|
plugins=keyfile
|
|
|
|
[keyfile]
|
|
unmanaged-devices=none
|
|
ENDNM
|
|
|
|
mkdir -p "$CHROOT_DIR/etc/polkit-1/rules.d"
|
|
cat > "$CHROOT_DIR/etc/polkit-1/rules.d/50-nm-recovery.rules" << 'ENDPOLKIT'
|
|
polkit.addRule(function(action, subject) {
|
|
if (action.id.indexOf("org.freedesktop.NetworkManager.") === 0 &&
|
|
subject.user === "root") {
|
|
return polkit.Result.YES;
|
|
}
|
|
});
|
|
ENDPOLKIT
|
|
|
|
CURRENT_STEP="cleanup_build_artifacts"
|
|
log "Removing source tree and build-only packages from chroot..."
|
|
chroot "$CHROOT_DIR" env LANG=C.UTF-8 LC_ALL=C.UTF-8 bash -lc "
|
|
set -Eeuo pipefail
|
|
|
|
rm -rf /root/src/bastionguard-backup
|
|
rm -rf /root/src/extracted-src
|
|
rm -f /root/src/$SOURCE_ZIP_BASENAME
|
|
|
|
apt-get purge -y ${BUILD_PACKAGES[*]}
|
|
apt-get autoremove -y --purge
|
|
apt-get clean
|
|
|
|
rm -rf /var/lib/apt/lists/*
|
|
rm -rf /var/cache/apt/*
|
|
rm -rf /tmp/*
|
|
rm -rf /var/tmp/*
|
|
find /var/log -type f -delete 2>/dev/null || true
|
|
"
|
|
|
|
install_plymouth_and_wallpaper
|
|
|
|
CURRENT_STEP="extract_kernel_initrd"
|
|
log "Extracting kernel and initrd..."
|
|
local kernel_file initrd_file
|
|
kernel_file="$(ls "$CHROOT_DIR/boot"/vmlinuz-* 2>/dev/null | sort -V | tail -1 || true)"
|
|
initrd_file="$(ls "$CHROOT_DIR/boot"/initrd.img-* 2>/dev/null | sort -V | tail -1 || true)"
|
|
|
|
if [ -z "${kernel_file:-}" ] || [ -z "${initrd_file:-}" ]; then
|
|
warn "Kernel/initrd not found in chroot; using host fallback."
|
|
kernel_file="$(ls /boot/vmlinuz-* 2>/dev/null | sort -V | tail -1 || true)"
|
|
initrd_file="$(ls /boot/initrd.img-* 2>/dev/null | sort -V | tail -1 || true)"
|
|
[ -n "${kernel_file:-}" ] || die "No kernel found in chroot or host."
|
|
[ -n "${initrd_file:-}" ] || die "No initrd found in chroot or host."
|
|
fi
|
|
|
|
cp "$kernel_file" "$OUTPUT_DIR/vmlinuz"
|
|
cp "$initrd_file" "$OUTPUT_DIR/initrd.img"
|
|
assert_file "$OUTPUT_DIR/vmlinuz"
|
|
assert_file "$OUTPUT_DIR/initrd.img"
|
|
|
|
CURRENT_STEP="secureboot_layout"
|
|
decide_secureboot_mode
|
|
sign_recovery_kernel_for_mode "$OUTPUT_DIR/vmlinuz"
|
|
build_efi_layout_for_mode
|
|
|
|
prepare_live_root
|
|
|
|
CURRENT_STEP="filesystem_size"
|
|
log "Calculating filesystem.size..."
|
|
du -sx --block-size=1 "$CHROOT_DIR" | awk '{print $1}' > "$FILESYSTEM_SIZE"
|
|
assert_file "$FILESYSTEM_SIZE"
|
|
|
|
CURRENT_STEP="create_squashfs"
|
|
log "Creating squashfs..."
|
|
mksquashfs \
|
|
"$CHROOT_DIR" \
|
|
"$SQUASHFS" \
|
|
-comp xz \
|
|
-b 1M \
|
|
-Xdict-size 100% \
|
|
-e boot \
|
|
-e var/cache/apt/* \
|
|
-e var/log/* \
|
|
-wildcards \
|
|
-progress
|
|
assert_file "$SQUASHFS"
|
|
|
|
CURRENT_STEP="enroll_mok"
|
|
if [ "$ENROLL_MOK_ON_BUILD" = "yes" ] && [ "$SB_EFFECTIVE_MODE" = "shim" ] && [ -f "$MOK_DER" ]; then
|
|
log "Staging MOK enrollment request with mokutil..."
|
|
printf '%s\n%s\n' "$MOK_PASSWORD" "$MOK_PASSWORD" | mokutil --import "$MOK_DER" || true
|
|
log "MOK import request staged. Enrollment still requires reboot + MokManager confirmation."
|
|
fi
|
|
|
|
CURRENT_STEP="final_cleanup"
|
|
log "Cleaning temporary chroot..."
|
|
cleanup
|
|
rm -rf "$CHROOT_DIR"
|
|
|
|
echo
|
|
echo "========================================================"
|
|
echo " Build completed successfully"
|
|
echo "========================================================"
|
|
echo " Output directory: $OUTPUT_DIR"
|
|
echo " Live directory : $LIVE_DIR"
|
|
echo " Squashfs : $SQUASHFS"
|
|
echo " Log file : $LOG_FILE"
|
|
echo " SecureBoot mode : $SB_EFFECTIVE_MODE"
|
|
echo
|
|
[ -f "$MOK_DER" ] && echo " MOK certificate : $MOK_DER"
|
|
[ -f "$CUSTOM_EFI_DER" ] && echo " Custom cert DER : $CUSTOM_EFI_DER"
|
|
echo
|
|
if [ "$ENROLL_MOK_ON_BUILD" = "yes" ] && [ "$SB_EFFECTIVE_MODE" = "shim" ]; then
|
|
echo " MOK password staged for MokManager: $MOK_PASSWORD"
|
|
echo " Reboot required to complete enrollment in MokManager."
|
|
echo
|
|
fi
|
|
echo " Next step:"
|
|
echo " bash $(dirname "$0")/install-grub-entry.sh"
|
|
echo "========================================================"
|
|
}
|
|
|
|
main "$@"
|