particle-os-tools/bootupd-alternative.sh
robojerk 74c7bede5f Initial commit: Particle-OS tools repository
- Complete Particle-OS rebranding from uBlue-OS
- Professional installation system with standardized paths
- Self-initialization system with --init and --reset commands
- Enhanced error messages and dependency checking
- Comprehensive testing infrastructure
- All source scriptlets updated with runtime improvements
- Clean codebase with redundant files moved to archive
- Complete documentation suite
2025-07-11 21:14:33 -07:00

2634 lines
78 KiB
Bash

#!/bin/bash
################################################################################################################
# #
# WARNING: This file is automatically generated #
# DO NOT modify this file directly as it will be overwritten #
# #
# Ubuntu uBlue bootupd-alternative Tool #
# Generated on: 2025-07-10 22:47:32 #
# #
################################################################################################################
set -euo pipefail
# Ubuntu uBlue bootupd-alternative Tool - Self-contained version
# This script contains all components merged into a single file
# Enhanced bootloader management for Ubuntu uBlue systems
# Supports multiple bootloader types (GRUB, UEFI, LILO, syslinux)
# Version: 25.07.10
# Ubuntu uBlue bootupd-alternative Tool
# Enhanced Bootloader Management
# Source Ubuntu uBlue configuration (if available)
if [[ -f "/usr/local/etc/particle-config.sh" ]]; then
source "/usr/local/etc/particle-config.sh"
log_info "Loaded Ubuntu uBlue configuration" "bootupd-alternative"
else
# Define logging functions if not available
log_info() {
local message="$1"
local script_name="${2:-bootupd-alternative}"
echo "[INFO] [$script_name] $message"
}
log_warning() {
local message="$1"
local script_name="${2:-bootupd-alternative}"
echo "[WARNING] [$script_name] $message" >&2
}
log_error() {
local message="$1"
local script_name="${2:-bootupd-alternative}"
echo "[ERROR] [$script_name] $message" >&2
}
log_debug() {
local message="$1"
local script_name="${2:-bootupd-alternative}"
echo "[DEBUG] [$script_name] $message"
}
log_success() {
local message="$1"
local script_name="${2:-bootupd-alternative}"
echo "[SUCCESS] [$script_name] $message"
}
log_warning "Ubuntu uBlue configuration not found, using defaults" "bootupd-alternative"
fi
# ============================================================================
# Header and Shared Functions
# ============================================================================
# --- END OF SCRIPTLET: 00-header.sh ---
# ============================================================================
# Dependency Checking and Validation
# ============================================================================
# Dependency checking and validation for Ubuntu uBlue bootupd-alternative Tool
check_dependencies() {
log_info "Checking dependencies..." "bootupd-alternative"
local missing_deps=()
# Core dependencies
for dep in mount umount lsblk bc; do
if ! command -v "$dep" >/dev/null 2>&1; then
missing_deps+=("$dep")
fi
done
# Bootloader-specific dependencies
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
if ! command -v efibootmgr >/dev/null 2>&1; then
missing_deps+=("efibootmgr")
fi
;;
"grub")
if ! command -v grub-install >/dev/null 2>&1; then
missing_deps+=("grub-install")
fi
if ! command -v grub-mkconfig >/dev/null 2>&1; then
missing_deps+=("grub-mkconfig")
fi
;;
"lilo")
if ! command -v lilo >/dev/null 2>&1; then
missing_deps+=("lilo")
fi
;;
"syslinux")
if ! command -v syslinux >/dev/null 2>&1; then
missing_deps+=("syslinux")
fi
;;
esac
# Check for kernel modules
check_kernel_modules
if [ ${#missing_deps[@]} -ne 0 ]; then
log_error "Missing dependencies: ${missing_deps[*]}" "bootupd-alternative"
log_info "Install missing packages with: sudo apt install -y ${missing_deps[*]}" "bootupd-alternative"
exit 1
fi
log_success "All dependencies found" "bootupd-alternative"
}
# Check kernel modules
check_kernel_modules() {
log_info "Checking kernel modules..." "bootupd-alternative"
local missing_modules=()
# Check for squashfs module
if ! modprobe -n squashfs >/dev/null 2>&1; then
missing_modules+=("squashfs")
fi
# Check for overlay module
if ! modprobe -n overlay >/dev/null 2>&1; then
missing_modules+=("overlay")
fi
# Check for loop module
if ! modprobe -n loop >/dev/null 2>&1; then
missing_modules+=("loop")
fi
if [ ${#missing_modules[@]} -ne 0 ]; then
log_warning "Missing kernel modules: ${missing_modules[*]}" "bootupd-alternative"
log_info "Load modules with: sudo modprobe ${missing_modules[*]}" "bootupd-alternative"
log_info "Or install with: sudo apt install linux-modules-extra-$(uname -r)" "bootupd-alternative"
else
log_success "All required kernel modules available" "bootupd-alternative"
fi
}
# Check for bootloader integration script
check_bootloader_integration() {
local bootloader_script="/usr/local/bin/bootloader-integration.sh"
if [[ -f "$bootloader_script" ]] && [[ -x "$bootloader_script" ]]; then
log_debug "Bootloader integration script found: $bootloader_script" "bootupd-alternative"
return 0
else
log_warning "Bootloader integration script not found or not executable: $bootloader_script" "bootupd-alternative"
log_info "Advanced bootloader features will not be available" "bootupd-alternative"
return 1
fi
}
# Check for composefs integration script
check_composefs_integration() {
local composefs_script="/usr/local/bin/composefs-alternative.sh"
if [[ -f "$composefs_script" ]] && [[ -x "$composefs_script" ]]; then
log_debug "ComposeFS integration script found: $composefs_script" "bootupd-alternative"
return 0
else
log_warning "ComposeFS integration script not found or not executable: $composefs_script" "bootupd-alternative"
log_info "ComposeFS-based boot images will not be available" "bootupd-alternative"
return 1
fi
}
# Validate boot device
validate_boot_device() {
local device="$1"
# Check if device exists
if [[ ! -b "$device" ]]; then
log_error "Boot device does not exist: $device" "bootupd-alternative"
return 1
fi
# Check if device is readable
if [[ ! -r "$device" ]]; then
log_error "Boot device is not readable: $device" "bootupd-alternative"
return 1
fi
# Check if device has boot partition
local has_boot_partition=false
while IFS= read -r line; do
if [[ "$line" =~ boot ]] || [[ "$line" =~ efi ]]; then
has_boot_partition=true
break
fi
done < <(lsblk -o MOUNTPOINT "$device" 2>/dev/null)
if [[ "$has_boot_partition" == "false" ]]; then
log_warning "No boot partition detected on device: $device" "bootupd-alternative"
log_info "This may be expected for some configurations" "bootupd-alternative"
fi
return 0
}
# Check available disk space
check_disk_space() {
local required_space_mb="$1"
local target_dir="${2:-$BOOTUPD_DIR}"
local available_space_mb
available_space_mb=$(get_available_space "$target_dir")
if [[ $available_space_mb -lt $required_space_mb ]]; then
log_error "Insufficient disk space: ${available_space_mb}MB available, need ${required_space_mb}MB" "bootupd-alternative"
return 1
fi
log_debug "Disk space check passed: ${available_space_mb}MB available" "bootupd-alternative"
return 0
}
# Check if system is bootable
check_system_bootability() {
log_info "Checking system bootability..." "bootupd-alternative"
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
# Check for UEFI firmware
if [[ ! -d "/sys/firmware/efi" ]]; then
log_error "UEFI firmware not detected" "bootupd-alternative"
return 1
fi
# Check for EFI partition
if ! mountpoint -q /boot/efi 2>/dev/null; then
log_warning "EFI partition not mounted at /boot/efi" "bootupd-alternative"
fi
;;
"grub")
# Check for GRUB configuration
if [[ ! -f "/boot/grub/grub.cfg" ]] && [[ ! -f "/boot/grub2/grub.cfg" ]]; then
log_warning "GRUB configuration not found" "bootupd-alternative"
fi
;;
"lilo")
# Check for LILO configuration
if [[ ! -f "/etc/lilo.conf" ]]; then
log_warning "LILO configuration not found" "bootupd-alternative"
fi
;;
"syslinux")
# Check for syslinux configuration
if [[ ! -f "/boot/syslinux/syslinux.cfg" ]]; then
log_warning "syslinux configuration not found" "bootupd-alternative"
fi
;;
"unknown")
log_warning "Unknown bootloader type" "bootupd-alternative"
;;
esac
log_info "System bootability check completed" "bootupd-alternative"
return 0
}
# Check for required filesystems
check_filesystems() {
log_info "Checking required filesystems..." "bootupd-alternative"
# Check for /boot
if [[ ! -d "/boot" ]]; then
log_error "/boot directory not found" "bootupd-alternative"
return 1
fi
# Check for /boot/efi (UEFI systems)
if [[ -d "/sys/firmware/efi" ]] && [[ ! -d "/boot/efi" ]]; then
log_warning "EFI directory not found at /boot/efi" "bootupd-alternative"
fi
# Check for /etc/fstab
if [[ ! -f "/etc/fstab" ]]; then
log_warning "/etc/fstab not found" "bootupd-alternative"
fi
log_success "Filesystem check completed" "bootupd-alternative"
return 0
}
# --- END OF SCRIPTLET: 01-dependencies.sh ---
# ============================================================================
# Bootloader Management
# ============================================================================
# Bootloader-specific operations for Ubuntu uBlue bootupd-alternative Tool
# Provides installation, update, and management for various bootloader types
# Install bootloader to device
install_bootloader() {
local device="$1"
log_info "Installing bootloader to device: $device" "bootupd-alternative"
# Validate device
if ! validate_boot_device "$device"; then
log_error "Invalid boot device: $device" "bootupd-alternative"
exit 1
fi
# Get device information
log_info "Device information:" "bootupd-alternative"
get_device_info "$device"
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
install_uefi_bootloader "$device"
;;
"grub")
install_grub_bootloader "$device"
;;
"lilo")
install_lilo_bootloader "$device"
;;
"syslinux")
install_syslinux_bootloader "$device"
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
log_success "Bootloader installed successfully to $device" "bootupd-alternative"
}
# Find EFI partition
find_efi_partition() {
# Try to find EFI partition using various methods
local efi_partition=""
# Method 1: Check mount point
if mountpoint -q /boot/efi 2>/dev/null; then
efi_partition=$(findmnt -n -o SOURCE /boot/efi 2>/dev/null)
if [[ -n "$efi_partition" ]]; then
echo "$efi_partition"
return 0
fi
fi
# Method 2: Look for EFI partition in /proc/mounts
efi_partition=$(grep " /boot/efi " /proc/mounts | awk '{print $1}')
if [[ -n "$efi_partition" ]]; then
echo "$efi_partition"
return 0
fi
# Method 3: Scan for EFI partition using blkid
if command -v blkid &> /dev/null; then
efi_partition=$(blkid | grep -i "EFI" | head -1 | cut -d: -f1)
if [[ -n "$efi_partition" ]]; then
echo "$efi_partition"
return 0
fi
fi
# Method 4: Look for common EFI partition names
for dev in /dev/sd*1 /dev/nvme*n*p1 /dev/mmcblk*p1; do
if [[ -b "$dev" ]]; then
efi_partition="$dev"
break
fi
done
if [[ -n "$efi_partition" ]]; then
echo "$efi_partition"
return 0
fi
return 1
}
# Install UEFI bootloader
install_uefi_bootloader() {
local device="$1"
log_info "Installing UEFI bootloader..." "bootupd-alternative"
# Check if EFI partition is mounted
if ! mountpoint -q /boot/efi 2>/dev/null; then
log_error "EFI partition not mounted at /boot/efi" "bootupd-alternative"
log_info "Please mount the EFI partition before installing UEFI bootloader" "bootupd-alternative"
exit 1
fi
# Create EFI boot entry
if command -v efibootmgr &> /dev/null; then
log_info "Creating EFI boot entry..." "bootupd-alternative"
# Find EFI partition
local efi_partition
efi_partition=$(find_efi_partition)
if [[ -z "$efi_partition" ]]; then
log_error "Could not find EFI partition" "bootupd-alternative"
exit 1
fi
# Extract device and partition number
local efi_device
local efi_part_num
efi_device=$(echo "$efi_partition" | sed 's/[0-9]*$//')
efi_part_num=$(echo "$efi_partition" | sed 's/.*\([0-9]*\)$/\1/')
# Determine EFI loader path
local efi_loader="/EFI/ubuntu/grubx64.efi"
if [[ ! -f "/boot/efi$efi_loader" ]]; then
# Try alternative paths
for alt_loader in "/EFI/ubuntu/shimx64.efi" "/EFI/boot/bootx64.efi" "/EFI/BOOT/BOOTX64.EFI"; do
if [[ -f "/boot/efi$alt_loader" ]]; then
efi_loader="$alt_loader"
break
fi
done
fi
# Create EFI boot entry
if efibootmgr --create --disk "$efi_device" --part "$efi_part_num" --loader "$efi_loader" --label "Ubuntu uBlue" --unicode "quiet splash"; then
log_success "EFI boot entry created: Ubuntu uBlue" "bootupd-alternative"
else
log_error "Failed to create EFI boot entry" "bootupd-alternative"
exit 1
fi
else
log_warning "efibootmgr not available, skipping EFI boot entry creation" "bootupd-alternative"
fi
log_success "UEFI bootloader installation completed" "bootupd-alternative"
}
# Install GRUB bootloader
install_grub_bootloader() {
local device="$1"
log_info "Installing GRUB bootloader..." "bootupd-alternative"
# Check for GRUB installation tools
if ! command -v grub-install &> /dev/null; then
log_error "grub-install not found" "bootupd-alternative"
exit 1
fi
# Install GRUB to device
if grub-install "$device"; then
log_success "GRUB installed to $device" "bootupd-alternative"
else
log_error "Failed to install GRUB to $device" "bootupd-alternative"
exit 1
fi
# Generate GRUB configuration
if command -v grub-mkconfig &> /dev/null; then
log_info "Generating GRUB configuration..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration generated" "bootupd-alternative"
else
log_warning "Failed to generate GRUB configuration" "bootupd-alternative"
fi
else
log_warning "grub-mkconfig not found, skipping configuration generation" "bootupd-alternative"
fi
log_success "GRUB bootloader installation completed" "bootupd-alternative"
}
# Install LILO bootloader
install_lilo_bootloader() {
local device="$1"
log_info "Installing LILO bootloader..." "bootupd-alternative"
# Check for LILO
if ! command -v lilo &> /dev/null; then
log_error "lilo not found" "bootupd-alternative"
exit 1
fi
# Check for LILO configuration
if [[ ! -f "/etc/lilo.conf" ]]; then
log_error "LILO configuration not found at /etc/lilo.conf" "bootupd-alternative"
exit 1
fi
# Install LILO
if lilo; then
log_success "LILO installed successfully" "bootupd-alternative"
else
log_error "Failed to install LILO" "bootupd-alternative"
exit 1
fi
log_success "LILO bootloader installation completed" "bootupd-alternative"
}
# Install syslinux bootloader
install_syslinux_bootloader() {
local device="$1"
log_info "Installing syslinux bootloader..." "bootupd-alternative"
# Check for syslinux
if ! command -v syslinux &> /dev/null; then
log_error "syslinux not found" "bootupd-alternative"
exit 1
fi
# Install syslinux (try different methods)
local install_success=false
# Method 1: Direct syslinux installation
if syslinux -i "$device" 2>/dev/null; then
install_success=true
# Method 2: extlinux installation (for ext filesystems)
elif command -v extlinux &> /dev/null && extlinux --install /boot/syslinux 2>/dev/null; then
install_success=true
# Method 3: syslinux with different options
elif syslinux "$device" 2>/dev/null; then
install_success=true
fi
if [[ "$install_success" == "true" ]]; then
log_success "syslinux installed to $device" "bootupd-alternative"
else
log_error "Failed to install syslinux to $device" "bootupd-alternative"
exit 1
fi
log_success "syslinux bootloader installation completed" "bootupd-alternative"
}
# Update bootloader configuration
update_bootloader() {
log_info "Updating bootloader configuration..." "bootupd-alternative"
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
update_uefi_bootloader
;;
"grub")
update_grub_bootloader
;;
"lilo")
update_lilo_bootloader
;;
"syslinux")
update_syslinux_bootloader
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
log_success "Bootloader configuration updated successfully" "bootupd-alternative"
}
# Update UEFI bootloader
update_uefi_bootloader() {
log_info "Updating UEFI bootloader..." "bootupd-alternative"
# Update EFI boot entries
if command -v efibootmgr &> /dev/null; then
log_info "Updating EFI boot entries..." "bootupd-alternative"
# Implementation would update EFI boot entries here
log_success "EFI boot entries updated" "bootupd-alternative"
else
log_warning "efibootmgr not available, skipping EFI boot entry updates" "bootupd-alternative"
fi
}
# Update GRUB bootloader
update_grub_bootloader() {
log_info "Updating GRUB bootloader..." "bootupd-alternative"
# Update GRUB configuration
if command -v grub-mkconfig &> /dev/null; then
log_info "Updating GRUB configuration..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration updated" "bootupd-alternative"
else
log_error "Failed to update GRUB configuration" "bootupd-alternative"
exit 1
fi
else
log_error "grub-mkconfig not found" "bootupd-alternative"
exit 1
fi
}
# Update LILO bootloader
update_lilo_bootloader() {
log_info "Updating LILO bootloader..." "bootupd-alternative"
# Update LILO
if command -v lilo &> /dev/null; then
if lilo; then
log_success "LILO updated successfully" "bootupd-alternative"
else
log_error "Failed to update LILO" "bootupd-alternative"
exit 1
fi
else
log_error "lilo not found" "bootupd-alternative"
exit 1
fi
}
# Update syslinux bootloader
update_syslinux_bootloader() {
log_info "Updating syslinux bootloader..." "bootupd-alternative"
# Update syslinux configuration
if command -v syslinux &> /dev/null; then
log_info "Updating syslinux configuration..." "bootupd-alternative"
# Regenerate syslinux configuration if possible
if [[ -f "/boot/syslinux/syslinux.cfg" ]]; then
# Backup current configuration
cp "/boot/syslinux/syslinux.cfg" "/boot/syslinux/syslinux.cfg.backup"
# Try to regenerate configuration
if command -v extlinux &> /dev/null; then
if extlinux --update /boot/syslinux; then
log_success "syslinux configuration updated via extlinux" "bootupd-alternative"
else
log_warning "extlinux update failed, using backup" "bootupd-alternative"
cp "/boot/syslinux/syslinux.cfg.backup" "/boot/syslinux/syslinux.cfg"
fi
else
log_success "syslinux configuration file updated" "bootupd-alternative"
fi
else
log_warning "syslinux configuration not found" "bootupd-alternative"
fi
else
log_error "syslinux not found" "bootupd-alternative"
exit 1
fi
}
# --- END OF SCRIPTLET: 02-bootloader.sh ---
# ============================================================================
# Backup and Restore Operations
# ============================================================================
# Backup and restore functionality for Ubuntu uBlue bootupd-alternative Tool
# Provides comprehensive backup and restore of bootloader configurations
# Create backup of bootloader configuration
create_backup() {
local backup_name="$1"
local backup_dir="$BOOTUPD_DIR/backups/$backup_name"
log_info "Creating backup: $backup_name" "bootupd-alternative"
mkdir -p "$backup_dir"
# Backup GRUB configuration
if [[ -f "/boot/grub/grub.cfg" ]]; then
cp "/boot/grub/grub.cfg" "$backup_dir/grub.cfg"
log_debug "Backed up GRUB configuration" "bootupd-alternative"
fi
if [[ -d "/etc/grub.d" ]]; then
cp -r "/etc/grub.d" "$backup_dir/grub.d"
log_debug "Backed up GRUB.d scripts" "bootupd-alternative"
fi
if [[ -f "/etc/default/grub" ]]; then
cp "/etc/default/grub" "$backup_dir/grub"
log_debug "Backed up GRUB defaults" "bootupd-alternative"
fi
# Backup UEFI entries
if command -v efibootmgr &> /dev/null; then
if efibootmgr --verbose > "$backup_dir/efi_entries.txt" 2>/dev/null; then
log_debug "Backed up EFI boot entries" "bootupd-alternative"
else
log_warning "Failed to backup EFI boot entries" "bootupd-alternative"
fi
else
log_warning "efibootmgr not available, skipping EFI entries backup" "bootupd-alternative"
fi
# Backup LILO configuration
if [[ -f "/etc/lilo.conf" ]]; then
cp "/etc/lilo.conf" "$backup_dir/lilo.conf"
log_debug "Backed up LILO configuration" "bootupd-alternative"
fi
# Backup syslinux configuration
if [[ -f "/boot/syslinux/syslinux.cfg" ]]; then
cp "/boot/syslinux/syslinux.cfg" "$backup_dir/syslinux.cfg"
log_debug "Backed up syslinux configuration" "bootupd-alternative"
fi
# Create backup metadata
cat > "$backup_dir/backup_info.txt" << EOF
Backup created: $(date)
Backup name: $backup_name
Bootloader type: $(detect_bootloader)
Kernel version: $(uname -r)
Architecture: $(uname -m)
EOF
log_success "Backup created: $backup_dir" "bootupd-alternative"
echo "$backup_dir"
}
# Restore backup of bootloader configuration
restore_backup() {
local backup_name="$1"
local backup_dir="$BOOTUPD_DIR/backups/$backup_name"
if [[ ! -d "$backup_dir" ]]; then
log_error "Backup not found: $backup_name" "bootupd-alternative"
return 1
fi
log_info "Restoring backup: $backup_name" "bootupd-alternative"
# Restore GRUB configuration
if [[ -f "$backup_dir/grub.cfg" ]]; then
cp "$backup_dir/grub.cfg" "/boot/grub/grub.cfg"
log_debug "Restored GRUB configuration" "bootupd-alternative"
fi
if [[ -d "$backup_dir/grub.d" ]]; then
cp -r "$backup_dir/grub.d" /etc/
log_debug "Restored GRUB.d scripts" "bootupd-alternative"
fi
if [[ -f "$backup_dir/grub" ]]; then
cp "$backup_dir/grub" "/etc/default/grub"
log_debug "Restored GRUB defaults" "bootupd-alternative"
fi
# Update GRUB configuration after restore
if command -v grub-mkconfig &> /dev/null; then
log_info "Updating GRUB configuration after restore..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration updated" "bootupd-alternative"
else
log_warning "Failed to update GRUB configuration" "bootupd-alternative"
fi
fi
# Restore LILO configuration
if [[ -f "$backup_dir/lilo.conf" ]]; then
cp "$backup_dir/lilo.conf" "/etc/lilo.conf"
log_debug "Restored LILO configuration" "bootupd-alternative"
fi
# Restore syslinux configuration
if [[ -f "$backup_dir/syslinux.cfg" ]]; then
cp "$backup_dir/syslinux.cfg" "/boot/syslinux/syslinux.cfg"
log_debug "Restored syslinux configuration" "bootupd-alternative"
fi
log_success "Backup restored: $backup_name" "bootupd-alternative"
return 0
}
# List available backups
list_backups() {
log_info "Available backups:" "bootupd-alternative"
if [[ ! -d "$BOOTUPD_DIR/backups" ]]; then
log_info "No backups found" "bootupd-alternative"
return 0
fi
local backup_count=0
for backup_dir in "$BOOTUPD_DIR/backups"/*; do
if [[ -d "$backup_dir" ]]; then
local backup_name
backup_name=$(basename "$backup_dir")
local backup_date
backup_date=$(stat -c %y "$backup_dir" | cut -d' ' -f1)
echo " $backup_name (created: $backup_date)"
backup_count=$((backup_count + 1))
fi
done
if [[ $backup_count -eq 0 ]]; then
log_info "No backups found" "bootupd-alternative"
fi
}
# Validate backup integrity
validate_backup() {
local backup_name="$1"
local backup_dir="$BOOTUPD_DIR/backups/$backup_name"
if [[ ! -d "$backup_dir" ]]; then
log_error "Backup not found: $backup_name" "bootupd-alternative"
return 1
fi
log_info "Validating backup: $backup_name" "bootupd-alternative"
local validation_errors=0
# Check for backup metadata
if [[ ! -f "$backup_dir/backup_info.txt" ]]; then
log_warning "Backup metadata not found" "bootupd-alternative"
validation_errors=$((validation_errors + 1))
fi
# Check for at least one configuration file
local has_config=false
for config_file in grub.cfg lilo.conf syslinux.cfg; do
if [[ -f "$backup_dir/$config_file" ]]; then
has_config=true
break
fi
done
if [[ "$has_config" == "false" ]]; then
log_warning "No configuration files found in backup" "bootupd-alternative"
validation_errors=$((validation_errors + 1))
fi
if [[ $validation_errors -eq 0 ]]; then
log_success "Backup validation passed" "bootupd-alternative"
return 0
else
log_warning "Backup validation completed with $validation_errors warnings" "bootupd-alternative"
return 1
fi
}
# Remove backup
remove_backup() {
local backup_name="$1"
local backup_dir="$BOOTUPD_DIR/backups/$backup_name"
if [[ ! -d "$backup_dir" ]]; then
log_error "Backup not found: $backup_name" "bootupd-alternative"
return 1
fi
log_info "Removing backup: $backup_name" "bootupd-alternative"
if rm -rf "$backup_dir"; then
log_success "Backup removed: $backup_name" "bootupd-alternative"
return 0
else
log_error "Failed to remove backup: $backup_name" "bootupd-alternative"
return 1
fi
}
# --- END OF SCRIPTLET: 03-backup.sh ---
# ============================================================================
# Boot Entry Management
# ============================================================================
# Boot entries management for Ubuntu uBlue bootupd-alternative Tool
# Provides management of boot entries for various bootloader types
# Convert device path to GRUB format
convert_device_to_grub_format() {
local device="$1"
if [[ -z "$device" ]]; then
echo "hd0,msdos1" # Default fallback
return 0
fi
# Extract device name and partition
local device_name
local partition_num
device_name=$(echo "$device" | sed 's/[0-9]*$//')
partition_num=$(echo "$device" | sed 's/.*\([0-9]*\)$/\1/')
# Determine disk number (simplified - assumes first disk)
local disk_num=0
# Determine partition table type
local partition_table="msdos"
if command -v parted &> /dev/null; then
if parted "$device_name" print 2>/dev/null | grep -q "gpt"; then
partition_table="gpt"
fi
fi
# Convert to GRUB format
if [[ "$partition_table" == "gpt" ]]; then
echo "hd${disk_num},gpt${partition_num}"
else
echo "hd${disk_num},msdos${partition_num}"
fi
}
# Add boot entry
add_boot_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="$4"
log_info "Adding boot entry: $title" "bootupd-alternative"
# Validate inputs
if ! validate_boot_title "$title"; then
log_error "Invalid boot title: $title" "bootupd-alternative"
exit 1
fi
if [[ ! -f "$kernel_path" ]]; then
log_error "Kernel not found: $kernel_path" "bootupd-alternative"
exit 1
fi
if [[ -n "$initrd_path" && ! -f "$initrd_path" ]]; then
log_error "Initrd not found: $initrd_path" "bootupd-alternative"
exit 1
fi
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
add_uefi_boot_entry "$title" "$kernel_path" "$initrd_path" "$root_device"
;;
"grub")
add_grub_boot_entry "$title" "$kernel_path" "$initrd_path" "$root_device"
;;
"lilo")
add_lilo_boot_entry "$title" "$kernel_path" "$initrd_path" "$root_device"
;;
"syslinux")
add_syslinux_boot_entry "$title" "$kernel_path" "$initrd_path" "$root_device"
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
log_success "Boot entry added: $title" "bootupd-alternative"
}
# Add UEFI boot entry
add_uefi_boot_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="$4"
log_info "Adding UEFI boot entry..." "bootupd-alternative"
if ! command -v efibootmgr &> /dev/null; then
log_error "efibootmgr not available" "bootupd-alternative"
exit 1
fi
# Find EFI partition
local efi_partition
efi_partition=$(find_efi_partition)
if [[ -z "$efi_partition" ]]; then
log_error "Could not find EFI partition" "bootupd-alternative"
exit 1
fi
# Extract device and partition number
local efi_device
local efi_part_num
efi_device=$(echo "$efi_partition" | sed 's/[0-9]*$//')
efi_part_num=$(echo "$efi_partition" | sed 's/.*\([0-9]*\)$/\1/')
# Determine EFI loader path
local efi_loader="/EFI/ubuntu/grubx64.efi"
if [[ ! -f "/boot/efi$efi_loader" ]]; then
# Try alternative paths
for alt_loader in "/EFI/ubuntu/shimx64.efi" "/EFI/boot/bootx64.efi" "/EFI/BOOT/BOOTX64.EFI"; do
if [[ -f "/boot/efi$alt_loader" ]]; then
efi_loader="$alt_loader"
break
fi
done
fi
# Build kernel arguments
local efi_args=""
if [[ -n "$initrd_path" ]]; then
efi_args="initrd=$initrd_path"
fi
if [[ -n "$root_device" ]]; then
if [[ -n "$efi_args" ]]; then
efi_args="$efi_args root=$root_device"
else
efi_args="root=$root_device"
fi
fi
# Create EFI boot entry
if efibootmgr --create --disk "$efi_device" --part "$efi_part_num" --loader "$efi_loader" --label "$title" --unicode "$efi_args"; then
log_success "UEFI boot entry added: $title" "bootupd-alternative"
else
log_error "Failed to create UEFI boot entry: $title" "bootupd-alternative"
exit 1
fi
}
# Add GRUB boot entry
add_grub_boot_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="$4"
log_info "Adding GRUB boot entry..." "bootupd-alternative"
# Create GRUB configuration entry
local grub_entry="/etc/grub.d/40_custom"
# Convert device path to GRUB format
local grub_root
grub_root=$(convert_device_to_grub_format "$root_device")
# Add entry to custom GRUB configuration
cat >> "$grub_entry" << EOF
# Custom entry: $title
menuentry '$title' {
set root='$grub_root'
linux $kernel_path root=$root_device ro
EOF
if [[ -n "$initrd_path" ]]; then
echo " initrd $initrd_path" >> "$grub_entry"
fi
echo "}" >> "$grub_entry"
# Update GRUB configuration
if command -v grub-mkconfig &> /dev/null; then
log_info "Updating GRUB configuration..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration updated" "bootupd-alternative"
else
log_error "Failed to update GRUB configuration" "bootupd-alternative"
exit 1
fi
else
log_warning "grub-mkconfig not found, manual update required" "bootupd-alternative"
fi
log_success "GRUB boot entry added: $title" "bootupd-alternative"
}
# Add LILO boot entry
add_lilo_boot_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="$4"
log_info "Adding LILO boot entry..." "bootupd-alternative"
# Add entry to LILO configuration
local lilo_conf="/etc/lilo.conf"
if [[ ! -f "$lilo_conf" ]]; then
log_error "LILO configuration not found" "bootupd-alternative"
exit 1
fi
# Create backup before modification
cp "$lilo_conf" "$lilo_conf.backup"
# Add entry to LILO configuration
cat >> "$lilo_conf" << EOF
# Custom entry: $title
image=$kernel_path
label=$title
root=$root_device
read-only
EOF
if [[ -n "$initrd_path" ]]; then
echo " initrd=$initrd_path" >> "$lilo_conf"
fi
# Update LILO
if command -v lilo &> /dev/null; then
log_info "Updating LILO..." "bootupd-alternative"
if lilo; then
log_success "LILO updated" "bootupd-alternative"
else
log_error "Failed to update LILO" "bootupd-alternative"
# Restore backup
cp "$lilo_conf.backup" "$lilo_conf"
exit 1
fi
else
log_error "lilo not found" "bootupd-alternative"
exit 1
fi
log_success "LILO boot entry added: $title" "bootupd-alternative"
}
# Add syslinux boot entry
add_syslinux_boot_entry() {
local title="$1"
local kernel_path="$2"
local initrd_path="$3"
local root_device="$4"
log_info "Adding syslinux boot entry..." "bootupd-alternative"
# Add entry to syslinux configuration
local syslinux_cfg="/boot/syslinux/syslinux.cfg"
if [[ ! -f "$syslinux_cfg" ]]; then
log_error "syslinux configuration not found" "bootupd-alternative"
exit 1
fi
# Create backup before modification
cp "$syslinux_cfg" "$syslinux_cfg.backup"
# Add entry to syslinux configuration
cat >> "$syslinux_cfg" << EOF
# Custom entry: $title
LABEL $title
KERNEL $kernel_path
APPEND root=$root_device ro
EOF
if [[ -n "$initrd_path" ]]; then
echo " INITRD $initrd_path" >> "$syslinux_cfg"
fi
log_success "syslinux boot entry added: $title" "bootupd-alternative"
}
# Remove boot entry
remove_boot_entry() {
local title="$1"
log_info "Removing boot entry: $title" "bootupd-alternative"
# Validate title
if ! validate_boot_title "$title"; then
log_error "Invalid boot title: $title" "bootupd-alternative"
exit 1
fi
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
remove_uefi_boot_entry "$title"
;;
"grub")
remove_grub_boot_entry "$title"
;;
"lilo")
remove_lilo_boot_entry "$title"
;;
"syslinux")
remove_syslinux_boot_entry "$title"
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
log_success "Boot entry removed: $title" "bootupd-alternative"
}
# Remove UEFI boot entry
remove_uefi_boot_entry() {
local title="$1"
log_info "Removing UEFI boot entry..." "bootupd-alternative"
if ! command -v efibootmgr &> /dev/null; then
log_error "efibootmgr not available" "bootupd-alternative"
exit 1
fi
# Find boot number for the given title
local boot_num
boot_num=$(efibootmgr --verbose 2>/dev/null | grep -i "$title" | head -1 | sed -n 's/^Boot\([0-9a-fA-F]*\).*/\1/p')
if [[ -z "$boot_num" ]]; then
log_error "UEFI boot entry not found: $title" "bootupd-alternative"
exit 1
fi
# Remove the boot entry
if efibootmgr --delete-bootnum --bootnum "$boot_num"; then
log_success "UEFI boot entry removed: $title (Boot$boot_num)" "bootupd-alternative"
else
log_error "Failed to remove UEFI boot entry: $title" "bootupd-alternative"
exit 1
fi
}
# Remove GRUB boot entry
remove_grub_boot_entry() {
local title="$1"
log_info "Removing GRUB boot entry..." "bootupd-alternative"
# Remove entry from custom GRUB configuration
local grub_entry="/etc/grub.d/40_custom"
if [[ -f "$grub_entry" ]]; then
# Create backup
cp "$grub_entry" "$grub_entry.backup"
# Remove the entry (simplified - in practice would need more sophisticated parsing)
sed -i "/# Custom entry: $title/,/^}/d" "$grub_entry"
# Update GRUB configuration
if command -v grub-mkconfig &> /dev/null; then
log_info "Updating GRUB configuration..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration updated" "bootupd-alternative"
else
log_error "Failed to update GRUB configuration" "bootupd-alternative"
# Restore backup
cp "$grub_entry.backup" "$grub_entry"
exit 1
fi
else
log_warning "grub-mkconfig not found, manual update required" "bootupd-alternative"
fi
fi
log_success "GRUB boot entry removed: $title" "bootupd-alternative"
}
# Remove LILO boot entry
remove_lilo_boot_entry() {
local title="$1"
log_info "Removing LILO boot entry..." "bootupd-alternative"
local lilo_conf="/etc/lilo.conf"
if [[ -f "$lilo_conf" ]]; then
# Create backup
cp "$lilo_conf" "$lilo_conf.backup"
# Remove the entry (simplified - in practice would need more sophisticated parsing)
sed -i "/# Custom entry: $title/,/^$/d" "$lilo_conf"
# Update LILO
if command -v lilo &> /dev/null; then
log_info "Updating LILO..." "bootupd-alternative"
if lilo; then
log_success "LILO updated" "bootupd-alternative"
else
log_error "Failed to update LILO" "bootupd-alternative"
# Restore backup
cp "$lilo_conf.backup" "$lilo_conf"
exit 1
fi
else
log_error "lilo not found" "bootupd-alternative"
exit 1
fi
fi
log_success "LILO boot entry removed: $title" "bootupd-alternative"
}
# Remove syslinux boot entry
remove_syslinux_boot_entry() {
local title="$1"
log_info "Removing syslinux boot entry..." "bootupd-alternative"
local syslinux_cfg="/boot/syslinux/syslinux.cfg"
if [[ -f "$syslinux_cfg" ]]; then
# Create backup
cp "$syslinux_cfg" "$syslinux_cfg.backup"
# Remove the entry (simplified - in practice would need more sophisticated parsing)
sed -i "/# Custom entry: $title/,/^$/d" "$syslinux_cfg"
fi
log_success "syslinux boot entry removed: $title" "bootupd-alternative"
}
# List boot entries
list_boot_entries() {
log_info "Listing boot entries..." "bootupd-alternative"
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
list_uefi_boot_entries
;;
"grub")
list_grub_boot_entries
;;
"lilo")
list_lilo_boot_entries
;;
"syslinux")
list_syslinux_boot_entries
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
}
# List UEFI boot entries
list_uefi_boot_entries() {
log_info "UEFI boot entries:" "bootupd-alternative"
if command -v efibootmgr &> /dev/null; then
efibootmgr --verbose
else
log_warning "efibootmgr not available" "bootupd-alternative"
fi
}
# List GRUB boot entries
list_grub_boot_entries() {
log_info "GRUB boot entries:" "bootupd-alternative"
if [[ -f "/boot/grub/grub.cfg" ]]; then
grep -E "^[[:space:]]*menuentry" /boot/grub/grub.cfg | sed 's/^[[:space:]]*menuentry[[:space:]]*'\''\([^'\'']*\)'\''.*/\1/'
else
log_warning "GRUB configuration not found" "bootupd-alternative"
fi
}
# List LILO boot entries
list_lilo_boot_entries() {
log_info "LILO boot entries:" "bootupd-alternative"
if [[ -f "/etc/lilo.conf" ]]; then
grep -E "^[[:space:]]*label" /etc/lilo.conf | sed 's/^[[:space:]]*label[[:space:]]*\([^[:space:]]*\).*/\1/'
else
log_warning "LILO configuration not found" "bootupd-alternative"
fi
}
# List syslinux boot entries
list_syslinux_boot_entries() {
log_info "syslinux boot entries:" "bootupd-alternative"
if [[ -f "/boot/syslinux/syslinux.cfg" ]]; then
grep -E "^[[:space:]]*LABEL" /boot/syslinux/syslinux.cfg | sed 's/^[[:space:]]*LABEL[[:space:]]*\([^[:space:]]*\).*/\1/'
else
log_warning "syslinux configuration not found" "bootupd-alternative"
fi
}
# Set default boot entry
set_default_entry() {
local title="$1"
log_info "Setting default boot entry: $title" "bootupd-alternative"
# Validate title
if ! validate_boot_title "$title"; then
log_error "Invalid boot title: $title" "bootupd-alternative"
exit 1
fi
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"uefi")
set_uefi_default_entry "$title"
;;
"grub")
set_grub_default_entry "$title"
;;
"lilo")
set_lilo_default_entry "$title"
;;
"syslinux")
set_syslinux_default_entry "$title"
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
exit 1
;;
esac
log_success "Default boot entry set: $title" "bootupd-alternative"
}
# Set UEFI default entry
set_uefi_default_entry() {
local title="$1"
log_info "Setting UEFI default entry..." "bootupd-alternative"
if ! command -v efibootmgr &> /dev/null; then
log_error "efibootmgr not available" "bootupd-alternative"
exit 1
fi
# Find boot number for the given title
local boot_num
boot_num=$(efibootmgr --verbose 2>/dev/null | grep -i "$title" | head -1 | sed -n 's/^Boot\([0-9a-fA-F]*\).*/\1/p')
if [[ -z "$boot_num" ]]; then
log_error "UEFI boot entry not found: $title" "bootupd-alternative"
exit 1
fi
# Set as next boot entry (for one-time boot)
if efibootmgr --bootnext "$boot_num"; then
log_success "UEFI next boot entry set: $title (Boot$boot_num)" "bootupd-alternative"
else
log_error "Failed to set UEFI next boot entry: $title" "bootupd-alternative"
exit 1
fi
# Also set as default boot order (persistent)
local current_order
current_order=$(efibootmgr 2>/dev/null | grep "BootOrder" | cut -d' ' -f2)
if [[ -n "$current_order" ]]; then
local new_order="$boot_num,$current_order"
if efibootmgr --bootorder "$new_order"; then
log_success "UEFI boot order updated: $title (Boot$boot_num) is now first" "bootupd-alternative"
else
log_warning "Failed to update UEFI boot order, but next boot is set" "bootupd-alternative"
fi
fi
}
# Set GRUB default entry
set_grub_default_entry() {
local title="$1"
log_info "Setting GRUB default entry..." "bootupd-alternative"
local grub_default="/etc/default/grub"
if [[ -f "$grub_default" ]]; then
# Create backup
cp "$grub_default" "$grub_default.backup"
# Set default entry
sed -i "s/^GRUB_DEFAULT=.*/GRUB_DEFAULT=\"$title\"/" "$grub_default"
# Update GRUB configuration
if command -v grub-mkconfig &> /dev/null; then
log_info "Updating GRUB configuration..." "bootupd-alternative"
if grub-mkconfig -o /boot/grub/grub.cfg; then
log_success "GRUB configuration updated" "bootupd-alternative"
else
log_error "Failed to update GRUB configuration" "bootupd-alternative"
# Restore backup
cp "$grub_default.backup" "$grub_default"
exit 1
fi
else
log_warning "grub-mkconfig not found, manual update required" "bootupd-alternative"
fi
else
log_error "GRUB defaults file not found" "bootupd-alternative"
exit 1
fi
log_success "GRUB default entry set: $title" "bootupd-alternative"
}
# Set LILO default entry
set_lilo_default_entry() {
local title="$1"
log_info "Setting LILO default entry..." "bootupd-alternative"
local lilo_conf="/etc/lilo.conf"
if [[ -f "$lilo_conf" ]]; then
# Create backup
cp "$lilo_conf" "$lilo_conf.backup"
# Set default entry
sed -i "s/^default=.*/default=$title/" "$lilo_conf"
# Update LILO
if command -v lilo &> /dev/null; then
log_info "Updating LILO..." "bootupd-alternative"
if lilo; then
log_success "LILO updated" "bootupd-alternative"
else
log_error "Failed to update LILO" "bootupd-alternative"
# Restore backup
cp "$lilo_conf.backup" "$lilo_conf"
exit 1
fi
else
log_error "lilo not found" "bootupd-alternative"
exit 1
fi
else
log_error "LILO configuration not found" "bootupd-alternative"
exit 1
fi
log_success "LILO default entry set: $title" "bootupd-alternative"
}
# Set syslinux default entry
set_syslinux_default_entry() {
local title="$1"
log_info "Setting syslinux default entry..." "bootupd-alternative"
local syslinux_cfg="/boot/syslinux/syslinux.cfg"
if [[ -f "$syslinux_cfg" ]]; then
# Create backup
cp "$syslinux_cfg" "$syslinux_cfg.backup"
# Set default entry
sed -i "s/^DEFAULT[[:space:]].*/DEFAULT $title/" "$syslinux_cfg"
else
log_error "syslinux configuration not found" "bootupd-alternative"
exit 1
fi
log_success "syslinux default entry set: $title" "bootupd-alternative"
}
# --- END OF SCRIPTLET: 04-entries.sh ---
# ============================================================================
# Device Management and Information
# ============================================================================
# Device management for Ubuntu uBlue bootupd-alternative Tool
# Provides device validation, information, and management functions
# Validate boot device
validate_boot_device() {
local device="$1"
if [[ -z "$device" ]]; then
log_error "Device path is required" "bootupd-alternative"
return 1
fi
# Check if device exists
if [[ ! -b "$device" ]]; then
log_error "Device not found: $device" "bootupd-alternative"
return 1
fi
# Check if device is readable
if [[ ! -r "$device" ]]; then
log_error "Device not readable: $device" "bootupd-alternative"
return 1
fi
# Check if device is a block device
if ! stat -c "%t" "$device" &> /dev/null; then
log_error "Invalid block device: $device" "bootupd-alternative"
return 1
fi
log_debug "Device validation passed: $device" "bootupd-alternative"
return 0
}
# Get device information
get_device_info() {
local device="$1"
if [[ -z "$device" ]]; then
log_error "Device path is required" "bootupd-alternative"
return 1
fi
log_info "Device Information for: $device" "bootupd-alternative"
# Device size
if command -v blockdev &> /dev/null; then
local size_bytes
size_bytes=$(blockdev --getsize64 "$device" 2>/dev/null)
if [[ -n "$size_bytes" ]]; then
local size_gb
size_gb=$(echo "scale=2; $size_bytes / 1024 / 1024 / 1024" | bc 2>/dev/null || echo "unknown")
echo " Size: ${size_gb} GB"
fi
fi
# Device type
local device_type
device_type=$(stat -c "%t" "$device" 2>/dev/null)
if [[ -n "$device_type" ]]; then
echo " Type: $device_type"
fi
# Device model
if command -v lsblk &> /dev/null; then
local model
model=$(lsblk -d -o MODEL "$device" 2>/dev/null | tail -n +2)
if [[ -n "$model" ]]; then
echo " Model: $model"
fi
fi
# Partition information
if command -v fdisk &> /dev/null; then
echo " Partitions:"
fdisk -l "$device" 2>/dev/null | grep -E "^/dev/" || echo " No partitions found"
fi
# Filesystem information
if command -v blkid &> /dev/null; then
echo " Filesystems:"
blkid "$device"* 2>/dev/null || echo " No filesystem information available"
fi
# Mount points
if command -v findmnt &> /dev/null; then
echo " Mount points:"
findmnt "$device"* 2>/dev/null | grep -v "TARGET" || echo " No mount points found"
fi
}
# Check mount point
check_mount_point() {
local mount_point="$1"
if [[ -z "$mount_point" ]]; then
log_error "Mount point is required" "bootupd-alternative"
return 1
fi
# Check if mount point exists
if [[ ! -d "$mount_point" ]]; then
log_error "Mount point directory not found: $mount_point" "bootupd-alternative"
return 1
fi
# Check if mount point is mounted
if ! mountpoint -q "$mount_point" 2>/dev/null; then
log_warning "Mount point not mounted: $mount_point" "bootupd-alternative"
return 1
fi
# Check mount point permissions
if [[ ! -r "$mount_point" ]]; then
log_error "Mount point not readable: $mount_point" "bootupd-alternative"
return 1
fi
log_debug "Mount point check passed: $mount_point" "bootupd-alternative"
return 0
}
# Calculate disk usage
calculate_disk_usage() {
local path="$1"
if [[ -z "$path" ]]; then
path="/"
fi
if [[ ! -d "$path" ]]; then
log_error "Path not found: $path" "bootupd-alternative"
return 1
fi
if command -v df &> /dev/null; then
log_info "Disk usage for: $path" "bootupd-alternative"
df -h "$path" 2>/dev/null || log_error "Failed to get disk usage" "bootupd-alternative"
else
log_warning "df command not available" "bootupd-alternative"
fi
}
# Get available space
get_available_space() {
local path="$1"
if [[ -z "$path" ]]; then
path="/"
fi
if [[ ! -d "$path" ]]; then
log_error "Path not found: $path" "bootupd-alternative"
return 1
fi
if command -v df &> /dev/null; then
local available_space
available_space=$(df -B1 "$path" 2>/dev/null | awk 'NR==2 {print $4}')
if [[ -n "$available_space" ]]; then
echo "$available_space"
return 0
fi
fi
log_error "Failed to get available space" "bootupd-alternative"
return 1
}
# Check disk space
check_disk_space() {
local path="$1"
local required_space="$2"
if [[ -z "$path" ]]; then
path="/"
fi
if [[ -z "$required_space" ]]; then
required_space="52428800" # 50MB default for bootloader operations
fi
local available_space
available_space=$(get_available_space "$path")
if [[ $? -ne 0 ]]; then
log_error "Failed to check disk space" "bootupd-alternative"
return 1
fi
if [[ $available_space -lt $required_space ]]; then
log_error "Insufficient disk space. Required: $required_space bytes, Available: $available_space bytes" "bootupd-alternative"
return 1
fi
log_debug "Disk space check passed. Available: $available_space bytes" "bootupd-alternative"
return 0
}
# List available devices
list_available_devices() {
log_info "Available block devices:" "bootupd-alternative"
if command -v lsblk &> /dev/null; then
lsblk -d -o NAME,SIZE,TYPE,MOUNTPOINT 2>/dev/null || log_error "Failed to list devices" "bootupd-alternative"
elif command -v fdisk &> /dev/null; then
fdisk -l 2>/dev/null | grep -E "^Disk /" || log_error "Failed to list devices" "bootupd-alternative"
else
log_warning "No device listing tools available" "bootupd-alternative"
fi
}
# Find boot device
find_boot_device() {
log_info "Finding boot device..." "bootupd-alternative"
# Try to find the device mounted at /boot
if mountpoint -q /boot 2>/dev/null; then
local boot_device
boot_device=$(findmnt -n -o SOURCE /boot 2>/dev/null)
if [[ -n "$boot_device" ]]; then
echo "$boot_device"
return 0
fi
fi
# Try to find the device mounted at /
local root_device
root_device=$(findmnt -n -o SOURCE / 2>/dev/null)
if [[ -n "$root_device" ]]; then
echo "$root_device"
return 0
fi
log_error "Could not determine boot device" "bootupd-alternative"
return 1
}
# Validate device for bootloader installation
validate_device_for_bootloader() {
local device="$1"
local bootloader="$2"
if [[ -z "$device" ]]; then
log_error "Device path is required" "bootupd-alternative"
return 1
fi
if [[ -z "$bootloader" ]]; then
log_error "Bootloader type is required" "bootupd-alternative"
return 1
fi
# Basic device validation
if ! validate_boot_device "$device"; then
return 1
fi
# Bootloader-specific validation
case "$bootloader" in
"uefi")
validate_device_for_uefi "$device"
;;
"grub")
validate_device_for_grub "$device"
;;
"lilo")
validate_device_for_lilo "$device"
;;
"syslinux")
validate_device_for_syslinux "$device"
;;
*)
log_error "Unsupported bootloader type: $bootloader" "bootupd-alternative"
return 1
;;
esac
}
# Validate device for UEFI
validate_device_for_uefi() {
local device="$1"
# Check if system supports UEFI
if [[ ! -d "/sys/firmware/efi" ]]; then
log_error "System does not support UEFI" "bootupd-alternative"
return 1
fi
# Check if EFI partition is mounted
if ! mountpoint -q /boot/efi 2>/dev/null; then
log_error "EFI partition not mounted at /boot/efi" "bootupd-alternative"
return 1
fi
log_debug "Device validation for UEFI passed: $device" "bootupd-alternative"
return 0
}
# Validate device for GRUB
validate_device_for_grub() {
local device="$1"
# Check if GRUB tools are available
if ! command -v grub-install &> /dev/null; then
log_error "GRUB installation tools not available" "bootupd-alternative"
return 1
fi
# Check if /boot is accessible
if [[ ! -d "/boot" ]]; then
log_error "/boot directory not found" "bootupd-alternative"
return 1
fi
log_debug "Device validation for GRUB passed: $device" "bootupd-alternative"
return 0
}
# Validate device for LILO
validate_device_for_lilo() {
local device="$1"
# Check if LILO is available
if ! command -v lilo &> /dev/null; then
log_error "LILO not available" "bootupd-alternative"
return 1
fi
# Check if LILO configuration exists
if [[ ! -f "/etc/lilo.conf" ]]; then
log_error "LILO configuration not found" "bootupd-alternative"
return 1
fi
log_debug "Device validation for LILO passed: $device" "bootupd-alternative"
return 0
}
# Validate device for syslinux
validate_device_for_syslinux() {
local device="$1"
# Check if syslinux is available
if ! command -v syslinux &> /dev/null; then
log_error "syslinux not available" "bootupd-alternative"
return 1
fi
# Check if syslinux configuration exists
if [[ ! -f "/boot/syslinux/syslinux.cfg" ]]; then
log_warning "syslinux configuration not found, will be created" "bootupd-alternative"
fi
log_debug "Device validation for syslinux passed: $device" "bootupd-alternative"
return 0
}
# --- END OF SCRIPTLET: 05-devices.sh ---
# ============================================================================
# Status Reporting and Monitoring
# ============================================================================
# Status and monitoring for Ubuntu uBlue bootupd-alternative Tool
# Provides system status, monitoring, and information display functions
# Show system status
show_status() {
log_info "System Status Report" "bootupd-alternative"
echo "========================================"
# System information
get_system_info
# Bootloader information
get_bootloader_status
# Device information
get_device_status
# Backup information
get_backup_status
# Integration status
get_integration_status
echo "========================================"
log_success "Status report completed" "bootupd-alternative"
}
# Get system information
get_system_info() {
log_info "System Information:" "bootupd-alternative"
# Operating system
if [[ -f "/etc/os-release" ]]; then
local os_name
os_name=$(grep "^NAME=" /etc/os-release | cut -d'"' -f2)
echo " OS: $os_name"
fi
# Kernel version
local kernel_version
kernel_version=$(uname -r)
echo " Kernel: $kernel_version"
# Architecture
local architecture
architecture=$(uname -m)
echo " Architecture: $architecture"
# Hostname
local hostname
hostname=$(hostname)
echo " Hostname: $hostname"
# Uptime
if command -v uptime &> /dev/null; then
local uptime
uptime=$(uptime -p 2>/dev/null | sed 's/up //')
echo " Uptime: $uptime"
fi
# Boot mode
if [[ -d "/sys/firmware/efi" ]]; then
echo " Boot Mode: UEFI"
else
echo " Boot Mode: Legacy BIOS"
fi
}
# Get bootloader status
get_bootloader_status() {
log_info "Bootloader Status:" "bootupd-alternative"
# Detect bootloader type
local bootloader
bootloader=$(detect_bootloader)
echo " Type: $bootloader"
case "$bootloader" in
"uefi")
get_uefi_status
;;
"grub")
get_grub_status
;;
"lilo")
get_lilo_status
;;
"syslinux")
get_syslinux_status
;;
*)
echo " Status: Unknown bootloader type"
;;
esac
}
# Get UEFI status
get_uefi_status() {
echo " UEFI Status:"
# Check EFI partition
if mountpoint -q /boot/efi 2>/dev/null; then
echo " EFI Partition: Mounted at /boot/efi"
else
echo " EFI Partition: Not mounted"
fi
# Check efibootmgr
if command -v efibootmgr &> /dev/null; then
echo " efibootmgr: Available"
# Get current boot order
local boot_order
boot_order=$(efibootmgr 2>/dev/null | grep "BootOrder" | cut -d' ' -f2)
if [[ -n "$boot_order" ]]; then
echo " Boot Order: $boot_order"
fi
else
echo " efibootmgr: Not available"
fi
}
# Get GRUB status
get_grub_status() {
echo " GRUB Status:"
# Check GRUB configuration
if [[ -f "/boot/grub/grub.cfg" ]]; then
echo " Configuration: /boot/grub/grub.cfg exists"
local config_size
config_size=$(stat -c %s /boot/grub/grub.cfg 2>/dev/null)
if [[ -n "$config_size" ]]; then
echo " Config Size: ${config_size} bytes"
fi
else
echo " Configuration: /boot/grub/grub.cfg not found"
fi
# Check GRUB tools
if command -v grub-install &> /dev/null; then
echo " grub-install: Available"
else
echo " grub-install: Not available"
fi
if command -v grub-mkconfig &> /dev/null; then
echo " grub-mkconfig: Available"
else
echo " grub-mkconfig: Not available"
fi
# Check GRUB modules
if [[ -d "/boot/grub/x86_64-efi" ]]; then
echo " Modules: EFI modules available"
elif [[ -d "/boot/grub/i386-pc" ]]; then
echo " Modules: Legacy modules available"
else
echo " Modules: No modules found"
fi
}
# Get LILO status
get_lilo_status() {
echo " LILO Status:"
# Check LILO configuration
if [[ -f "/etc/lilo.conf" ]]; then
echo " Configuration: /etc/lilo.conf exists"
local config_size
config_size=$(stat -c %s /etc/lilo.conf 2>/dev/null)
if [[ -n "$config_size" ]]; then
echo " Config Size: ${config_size} bytes"
fi
else
echo " Configuration: /etc/lilo.conf not found"
fi
# Check LILO tool
if command -v lilo &> /dev/null; then
echo " lilo: Available"
else
echo " lilo: Not available"
fi
}
# Get syslinux status
get_syslinux_status() {
echo " syslinux Status:"
# Check syslinux configuration
if [[ -f "/boot/syslinux/syslinux.cfg" ]]; then
echo " Configuration: /boot/syslinux/syslinux.cfg exists"
local config_size
config_size=$(stat -c %s /boot/syslinux/syslinux.cfg 2>/dev/null)
if [[ -n "$config_size" ]]; then
echo " Config Size: ${config_size} bytes"
fi
else
echo " Configuration: /boot/syslinux/syslinux.cfg not found"
fi
# Check syslinux tool
if command -v syslinux &> /dev/null; then
echo " syslinux: Available"
else
echo " syslinux: Not available"
fi
}
# Get device status
get_device_status() {
log_info "Device Status:" "bootupd-alternative"
# Find boot device
local boot_device
boot_device=$(find_boot_device)
if [[ -n "$boot_device" ]]; then
echo " Boot Device: $boot_device"
# Get device information
get_device_info "$boot_device"
else
echo " Boot Device: Could not determine"
fi
# Check mount points
echo " Mount Points:"
if mountpoint -q /boot 2>/dev/null; then
local boot_mount
boot_mount=$(findmnt -n -o SOURCE,TARGET,FSTYPE /boot 2>/dev/null)
echo " /boot: $boot_mount"
else
echo " /boot: Not mounted"
fi
if mountpoint -q /boot/efi 2>/dev/null; then
local efi_mount
efi_mount=$(findmnt -n -o SOURCE,TARGET,FSTYPE /boot/efi 2>/dev/null)
echo " /boot/efi: $efi_mount"
else
echo " /boot/efi: Not mounted"
fi
# Disk usage
calculate_disk_usage "/"
}
# Get backup status
get_backup_status() {
log_info "Backup Status:" "bootupd-alternative"
if [[ ! -d "$BOOTUPD_DIR/backups" ]]; then
echo " Backups: No backup directory found"
return
fi
local backup_count=0
local total_size=0
for backup_dir in "$BOOTUPD_DIR/backups"/*; do
if [[ -d "$backup_dir" ]]; then
backup_count=$((backup_count + 1))
local backup_size
backup_size=$(du -s "$backup_dir" 2>/dev/null | cut -f1)
if [[ -n "$backup_size" ]]; then
total_size=$((total_size + backup_size))
fi
fi
done
echo " Backup Count: $backup_count"
echo " Total Size: ${total_size} KB"
if [[ $backup_count -gt 0 ]]; then
echo " Recent Backups:"
for backup_dir in "$BOOTUPD_DIR/backups"/*; do
if [[ -d "$backup_dir" ]]; then
local backup_name
backup_name=$(basename "$backup_dir")
local backup_date
backup_date=$(stat -c %y "$backup_dir" 2>/dev/null | cut -d' ' -f1)
echo " $backup_name (created: $backup_date)"
fi
done
fi
}
# Get integration status
get_integration_status() {
log_info "Integration Status:" "bootupd-alternative"
# Check Ubuntu uBlue configuration
if [[ -f "/usr/local/etc/ublue-config.sh" ]]; then
echo " Ubuntu uBlue Config: Available"
elif [[ -f "/etc/ublue-config.sh" ]]; then
echo " Ubuntu uBlue Config: Available (system-wide)"
else
echo " Ubuntu uBlue Config: Not found"
fi
# Check ComposeFS integration
if [[ -f "/usr/local/bin/composefs-alternative.sh" ]]; then
echo " ComposeFS Integration: Available"
elif [[ -f "/usr/bin/composefs-alternative.sh" ]]; then
echo " ComposeFS Integration: Available (system-wide)"
else
echo " ComposeFS Integration: Not found"
fi
# Check bootloader integration
if [[ -f "/usr/local/bin/bootc-alternative.sh" ]]; then
echo " Bootloader Integration: Available"
elif [[ -f "/usr/bin/bootc-alternative.sh" ]]; then
echo " Bootloader Integration: Available (system-wide)"
else
echo " Bootloader Integration: Not found"
fi
# Check apt-layer integration
if [[ -f "/usr/local/bin/apt-layer.sh" ]]; then
echo " APT Layer Integration: Available"
elif [[ -f "/usr/bin/apt-layer.sh" ]]; then
echo " APT Layer Integration: Available (system-wide)"
else
echo " APT Layer Integration: Not found"
fi
}
# Check system health
check_system_health() {
log_info "System Health Check:" "bootupd-alternative"
local health_score=100
local issues=()
# Check bootloader
local bootloader
bootloader=$(detect_bootloader)
if [[ "$bootloader" == "unknown" ]]; then
health_score=$((health_score - 20))
issues+=("Unknown bootloader type")
fi
# Check EFI partition for UEFI systems
if [[ "$bootloader" == "uefi" ]]; then
if ! mountpoint -q /boot/efi 2>/dev/null; then
health_score=$((health_score - 15))
issues+=("EFI partition not mounted")
fi
fi
# Check GRUB configuration for GRUB systems
if [[ "$bootloader" == "grub" ]]; then
if [[ ! -f "/boot/grub/grub.cfg" ]]; then
health_score=$((health_score - 15))
issues+=("GRUB configuration missing")
fi
fi
# Check disk space
local available_space
available_space=$(get_available_space "/")
if [[ $? -eq 0 ]]; then
local min_space=104857600 # 100MB
if [[ $available_space -lt $min_space ]]; then
health_score=$((health_score - 10))
issues+=("Low disk space")
fi
else
health_score=$((health_score - 5))
issues+=("Cannot check disk space")
fi
# Check backup directory
if [[ ! -d "$BOOTUPD_DIR/backups" ]]; then
health_score=$((health_score - 5))
issues+=("No backup directory")
fi
# Report health status
if [[ $health_score -ge 90 ]]; then
echo " Health Status: Excellent ($health_score/100)"
elif [[ $health_score -ge 75 ]]; then
echo " Health Status: Good ($health_score/100)"
elif [[ $health_score -ge 60 ]]; then
echo " Health Status: Fair ($health_score/100)"
else
echo " Health Status: Poor ($health_score/100)"
fi
if [[ ${#issues[@]} -gt 0 ]]; then
echo " Issues Found:"
for issue in "${issues[@]}"; do
echo " - $issue"
done
else
echo " Issues Found: None"
fi
}
# Monitor bootloader changes
monitor_bootloader_changes() {
local watch_interval="${1:-60}" # Default 60 seconds
log_info "Starting bootloader change monitoring (interval: ${watch_interval}s)" "bootupd-alternative"
# Create temporary file for tracking changes
local temp_file
temp_file=$(mktemp)
# Initial state
get_bootloader_state > "$temp_file"
while true; do
sleep "$watch_interval"
# Get current state
local current_state
current_state=$(get_bootloader_state)
# Compare with previous state
if ! diff "$temp_file" <(echo "$current_state") > /dev/null 2>&1; then
log_warning "Bootloader configuration changes detected!" "bootupd-alternative"
echo "Changes:"
diff "$temp_file" <(echo "$current_state") || true
# Update state file
echo "$current_state" > "$temp_file"
fi
done
}
# Get bootloader state for monitoring
get_bootloader_state() {
local bootloader
bootloader=$(detect_bootloader)
case "$bootloader" in
"grub")
if [[ -f "/boot/grub/grub.cfg" ]]; then
stat -c "%Y %s" /boot/grub/grub.cfg
fi
;;
"lilo")
if [[ -f "/etc/lilo.conf" ]]; then
stat -c "%Y %s" /etc/lilo.conf
fi
;;
"syslinux")
if [[ -f "/boot/syslinux/syslinux.cfg" ]]; then
stat -c "%Y %s" /boot/syslinux/syslinux.cfg
fi
;;
"uefi")
if command -v efibootmgr &> /dev/null; then
efibootmgr 2>/dev/null | grep "BootOrder"
fi
;;
esac
}
# --- END OF SCRIPTLET: 06-status.sh ---
# ============================================================================
# Main Dispatch and Help
# ============================================================================
# Main execution and command dispatch for Ubuntu uBlue bootupd-alternative Tool
# Show usage information
show_usage() {
cat << EOF
Ubuntu uBlue bootupd-alternative Tool - Enhanced Bootloader Management
Provides advanced bootloader management for Ubuntu uBlue systems
Usage:
bootupd-alternative install <device>
# Install bootloader to specified device
bootupd-alternative update
# Update bootloader configuration
bootupd-alternative status
# Show current bootloader status
bootupd-alternative backup [name]
# Create backup of current bootloader configuration
bootupd-alternative restore <backup-name>
# Restore bootloader configuration from backup
bootupd-alternative list-backups
# List available backups
bootupd-alternative add-entry <title> <kernel> [options]
# Add new boot entry
bootupd-alternative remove-entry <title>
# Remove boot entry
bootupd-alternative list-entries
# List current boot entries
bootupd-alternative set-default <title>
# Set default boot entry
bootupd-alternative info <device>
# Show device information
bootupd-alternative help
# Show this help message
Examples:
# Install bootloader to device
sudo bootupd-alternative install /dev/sda
# Update bootloader configuration
sudo bootupd-alternative update
# Create backup
sudo bootupd-alternative backup before-update
# Restore backup
sudo bootupd-alternative restore before-update
# Add custom boot entry
sudo bootupd-alternative add-entry "Ubuntu Recovery" /boot/vmlinuz-5.15.0-rc1
# Set default boot entry
sudo bootupd-alternative set-default "Ubuntu uBlue"
# Show device information
sudo bootupd-alternative info /dev/sda
Description:
bootupd-alternative provides comprehensive bootloader management for Ubuntu uBlue systems.
It supports multiple bootloader types (GRUB, UEFI, LILO, syslinux) and provides
advanced features like backup/restore, custom boot entries, and device management.
KEY FEATURES:
- Multi-bootloader support (GRUB, UEFI, LILO, syslinux)
- Automatic bootloader detection and configuration
- Backup and restore functionality
- Custom boot entry management
- Device validation and information
- Integration with Ubuntu uBlue configuration system
SECURITY FEATURES:
- Input validation and sanitization
- Path traversal protection
- Privilege escalation prevention
- Secure temporary file handling
INTEGRATION:
- Ubuntu uBlue configuration system
- ComposeFS backend support
- Bootloader integration scripts
- Unified logging system
EOF
}
# Main execution
main() {
# Initialize directories
init_directories
# Check dependencies
check_dependencies
# Check system bootability
check_system_bootability
# Check filesystems
check_filesystems
# Parse command line arguments
case "${1:-}" in
--help|-h)
show_usage
exit 0
;;
install)
if [ -z "${2:-}" ]; then
log_error "Device required for install" "bootupd-alternative"
show_usage
exit 1
fi
install_bootloader "$2"
;;
update)
update_bootloader
;;
status)
show_status
;;
backup)
local backup_name="${2:-backup-$(date +%Y%m%d-%H%M%S)}"
create_backup "$backup_name"
;;
restore)
if [ -z "${2:-}" ]; then
log_error "Backup name required for restore" "bootupd-alternative"
show_usage
exit 1
fi
restore_backup "$2"
;;
list-backups)
list_backups
;;
add-entry)
if [ $# -lt 3 ]; then
log_error "Title and kernel required for add-entry" "bootupd-alternative"
show_usage
exit 1
fi
local title="$2"
local kernel="$3"
shift 3
local options=("$@")
add_boot_entry "$title" "$kernel" "${options[@]}"
;;
remove-entry)
if [ -z "${2:-}" ]; then
log_error "Title required for remove-entry" "bootupd-alternative"
show_usage
exit 1
fi
remove_boot_entry "$2"
;;
list-entries)
list_boot_entries
;;
set-default)
if [ -z "${2:-}" ]; then
log_error "Title required for set-default" "bootupd-alternative"
show_usage
exit 1
fi
set_default_entry "$2"
;;
info)
if [ -z "${2:-}" ]; then
log_error "Device required for info" "bootupd-alternative"
show_usage
exit 1
fi
get_device_info "$2"
;;
"")
log_error "No arguments provided" "bootupd-alternative"
show_usage
exit 1
;;
*)
log_error "Unknown command: $1" "bootupd-alternative"
show_usage
exit 1
;;
esac
}
# Run main function
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
# --- END OF SCRIPTLET: 99-main.sh ---
# ============================================================================
# Embedded Configuration Files
# ============================================================================
# ============================================================================
# External Configuration Loading (Future Enhancement)
# ============================================================================
# Function to load configuration from external files
# Usage: load_config_from_file "config-name"
load_config_from_file() {
local config_name="$1"
local config_file="/etc/bootupd/config/${config_name}.json"
if [[ -f "$config_file" ]]; then
jq -r '.' "$config_file"
else
log_error "Configuration file not found: $config_file" "bootupd-alternative"
exit 1
fi
}