Attempt to fix more problems with the install to disk script.
This commit is contained in:
+369
-248
@@ -1,20 +1,49 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Stormux Gaming Image - USB to Disk Cloner
|
# Stormux Gaming Image - Ultra-Reliable Disk Installer
|
||||||
# Clones the entire USB system to an internal disk
|
# Clones USB system to internal disk with proper bootloader installation
|
||||||
|
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Initialize logging
|
||||||
|
LOGDIR="/home/stormux/Logs"
|
||||||
|
LOGFILE="$LOGDIR/install_to_disk_$(date +%Y-%m-%d_%H-%M-%S).log"
|
||||||
|
mkdir -p "$LOGDIR"
|
||||||
|
|
||||||
|
# Logging function
|
||||||
|
log() {
|
||||||
|
local msg
|
||||||
|
msg="[$(date +%H:%M:%S)] $*"
|
||||||
|
echo "$msg" | tee -a "$LOGFILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
local msg
|
||||||
|
msg="[ERROR] $*"
|
||||||
|
echo "$msg" | tee -a "$LOGFILE" >&2
|
||||||
|
}
|
||||||
|
|
||||||
error_exit() {
|
error_exit() {
|
||||||
echo "Error: $1"
|
log_error "$1"
|
||||||
|
echo "Installation failed. Log file: $LOGFILE"
|
||||||
|
restore_speech
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Speech management
|
||||||
|
disable_speech() {
|
||||||
|
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_speech() {
|
||||||
|
echo "command toggletempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
# Function to find the source USB device
|
# Function to find the source USB device
|
||||||
find_source_device() {
|
find_source_device() {
|
||||||
# Look for the device we're currently running from
|
|
||||||
local root_device
|
local root_device
|
||||||
root_device=$(findmnt -n -o SOURCE /)
|
root_device=$(findmnt -n -o SOURCE /)
|
||||||
|
|
||||||
if [[ "$root_device" =~ ^/dev/(sd[a-z]|nvme[0-9]n[0-9]|mmcblk[0-9]) ]]; then
|
if [[ "$root_device" =~ ^/dev/(sd[a-z]|nvme[0-9]n[0-9]|mmcblk[0-9]) ]]; then
|
||||||
# Extract just the device name (remove partition number)
|
# Extract just the device name (remove partition number)
|
||||||
echo "$root_device" | sed 's/[0-9]*$//' | sed 's/p$//'
|
echo "$root_device" | sed 's/[0-9]*$//' | sed 's/p$//'
|
||||||
@@ -34,17 +63,19 @@ find_source_device() {
|
|||||||
detect_target_disks() {
|
detect_target_disks() {
|
||||||
local source_device="$1"
|
local source_device="$1"
|
||||||
local disks=()
|
local disks=()
|
||||||
|
|
||||||
while IFS= read -r disk; do
|
while IFS= read -r disk; do
|
||||||
# Skip if it's a partition, loop device, CD-ROM, or the source device
|
# Skip partitions, loop devices, CD-ROMs, and source device
|
||||||
# For partitions: skip sda1, nvme0n1p1, mmcblk0p1, but keep sda, nvme0n1, mmcblk0
|
if [[ ! "$disk" =~ (sd[a-z][0-9]+|nvme[0-9]+n[0-9]+p[0-9]+|mmcblk[0-9]+p[0-9]+)$ ]] && \
|
||||||
if [[ ! "$disk" =~ (sd[a-z][0-9]+|nvme[0-9]+n[0-9]+p[0-9]+|mmcblk[0-9]+p[0-9]+)$ ]] && [[ ! "$disk" =~ ^/dev/loop ]] && [[ ! "$disk" =~ ^/dev/sr ]] && [[ "$disk" != "$source_device" ]]; then
|
[[ ! "$disk" =~ ^/dev/loop ]] && \
|
||||||
|
[[ ! "$disk" =~ ^/dev/sr ]] && \
|
||||||
|
[[ "$disk" != "$source_device" ]]; then
|
||||||
if [[ -b "$disk" ]]; then
|
if [[ -b "$disk" ]]; then
|
||||||
disks+=("$disk")
|
disks+=("$disk")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < <(lsblk -dpno NAME 2>/dev/null)
|
done < <(lsblk -dpno NAME 2>/dev/null)
|
||||||
|
|
||||||
printf '%s\n' "${disks[@]}"
|
printf '%s\n' "${disks[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,147 +89,278 @@ get_disk_info() {
|
|||||||
echo "$size - $model"
|
echo "$size - $model"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to regenerate UUIDs and rename partition labels to prevent boot conflicts
|
# Function to detect partitions by filesystem type
|
||||||
regenerate_partition_identifiers() {
|
# shellcheck disable=SC2154
|
||||||
local target_device="$1"
|
detect_partitions() {
|
||||||
echo "Regenerating partition UUIDs and labels to prevent boot conflicts..."
|
local device="$1"
|
||||||
|
# shellcheck disable=SC2178
|
||||||
# Arrays to store old and new UUIDs for fstab update
|
local -n result=$2 # nameref to associative array
|
||||||
declare -A old_uuids
|
|
||||||
declare -A new_uuids
|
log "Detecting partition structure on $device..."
|
||||||
|
|
||||||
# Get all partitions on the target device
|
# Get all partitions
|
||||||
local partitions=()
|
while IFS= read -r line; do
|
||||||
while IFS= read -r partition; do
|
local part fstype label
|
||||||
if [[ "$partition" != "$target_device" && "$partition" =~ ^${target_device}.+ ]]; then
|
part=$(echo "$line" | awk '{print $1}')
|
||||||
partitions+=("$partition")
|
fstype=$(echo "$line" | awk '{print $2}')
|
||||||
fi
|
label=$(echo "$line" | awk '{print $3}')
|
||||||
done < <(lsblk -lpno NAME "$target_device" 2>/dev/null)
|
|
||||||
|
# Skip if it's the device itself, not a partition
|
||||||
# Process each partition
|
[[ "$part" == "$device" ]] && continue
|
||||||
for partition in "${partitions[@]}"; do
|
|
||||||
local fstype
|
|
||||||
local current_label
|
|
||||||
local current_uuid
|
|
||||||
fstype=$(lsblk -no FSTYPE "$partition" 2>/dev/null)
|
|
||||||
current_label=$(lsblk -no LABEL "$partition" 2>/dev/null)
|
|
||||||
current_uuid=$(lsblk -no UUID "$partition" 2>/dev/null)
|
|
||||||
|
|
||||||
# Skip if no filesystem
|
|
||||||
[[ -z "$fstype" ]] && continue
|
|
||||||
|
|
||||||
# Store old UUID if it exists
|
|
||||||
[[ -n "$current_uuid" ]] && old_uuids["$partition"]="$current_uuid"
|
|
||||||
|
|
||||||
# Determine new label based on current label and add -HDD suffix
|
|
||||||
local new_label=""
|
|
||||||
if [[ -n "$current_label" ]]; then
|
|
||||||
case "$current_label" in
|
|
||||||
"STORMUX"|"stormux")
|
|
||||||
new_label="STORMUX-HDD"
|
|
||||||
;;
|
|
||||||
"BOOT"|"boot"|"ESP")
|
|
||||||
new_label="BOOT-HDD"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# For any other label, just add -HDD suffix, truncate if too long
|
|
||||||
new_label="${current_label}-HDD"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle the known 3-partition structure
|
|
||||||
case "$fstype" in
|
case "$fstype" in
|
||||||
"vfat"|"fat32"|"fat16")
|
"")
|
||||||
# Partition 2: FAT32 EFI boot partition
|
# BIOS boot partition (no filesystem)
|
||||||
if [[ -n "$new_label" ]]; then
|
result[bios]="$part"
|
||||||
new_label="${new_label:0:11}" # FAT32 has 11 character limit
|
log " BIOS boot partition: $part"
|
||||||
if command -v fatlabel >/dev/null 2>&1; then
|
;;
|
||||||
sudo fatlabel "$partition" "$new_label" 2>/dev/null || echo "Warning: Could not rename FAT partition $partition"
|
"vfat")
|
||||||
fi
|
# EFI partition
|
||||||
fi
|
result[efi]="$part"
|
||||||
# Generate new UUID for FAT
|
log " EFI partition: $part (label: ${label:-none})"
|
||||||
if command -v mlabel >/dev/null 2>&1; then
|
|
||||||
sudo mlabel -s -i "$partition" :: 2>/dev/null || echo "Warning: Could not change FAT serial on $partition"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
"ext4")
|
"ext4")
|
||||||
# Partition 3: ext4 root filesystem
|
# Root partition
|
||||||
if [[ -n "$new_label" ]]; then
|
result[root]="$part"
|
||||||
new_label="${new_label:0:16}" # ext4 has 16 character limit
|
log " Root partition: $part (label: ${label:-none})"
|
||||||
if command -v tune2fs >/dev/null 2>&1; then
|
|
||||||
sudo tune2fs -L "$new_label" "$partition" 2>/dev/null || echo "Warning: Could not rename ext4 partition $partition"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Generate new UUID for ext4
|
|
||||||
if command -v tune2fs >/dev/null 2>&1; then
|
|
||||||
sudo tune2fs -U random "$partition" 2>/dev/null || echo "Warning: Could not change UUID on $partition"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"")
|
|
||||||
# Partition 1: No filesystem (skip)
|
|
||||||
echo "Skipping partition $partition (no filesystem)"
|
|
||||||
continue
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Warning: Unexpected filesystem type '$fstype' on $partition"
|
log " Unknown partition type: $part ($fstype)"
|
||||||
continue
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
done < <(lsblk -no NAME,FSTYPE,LABEL "$device" 2>/dev/null | tail -n +2)
|
||||||
# Get the new UUID after regeneration
|
|
||||||
|
# Validate we found all required partitions
|
||||||
|
if [[ -z "${result[root]:-}" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to regenerate UUIDs and update labels
|
||||||
|
regenerate_partition_identifiers() {
|
||||||
|
local device="$1"
|
||||||
|
local -n partitions=$2
|
||||||
|
declare -A uuid_map
|
||||||
|
|
||||||
|
log "Regenerating partition UUIDs and labels..."
|
||||||
|
|
||||||
|
# Process EFI partition
|
||||||
|
if [[ -n "${partitions[efi]:-}" ]]; then
|
||||||
|
local efi_part="${partitions[efi]}"
|
||||||
|
local old_uuid
|
||||||
|
old_uuid=$(lsblk -no UUID "$efi_part" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# Change label
|
||||||
|
if command -v fatlabel >/dev/null 2>&1; then
|
||||||
|
sudo fatlabel "$efi_part" "BOOT-HDD" 2>/dev/null || log "Warning: Could not rename EFI partition"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate new UUID for FAT
|
||||||
|
if command -v mlabel >/dev/null 2>&1; then
|
||||||
|
sudo mlabel -s -i "$efi_part" :: 2>/dev/null || log "Warning: Could not change FAT serial"
|
||||||
|
fi
|
||||||
|
|
||||||
local new_uuid
|
local new_uuid
|
||||||
new_uuid=$(lsblk -no UUID "$partition" 2>/dev/null)
|
new_uuid=$(lsblk -no UUID "$efi_part" 2>/dev/null || echo "")
|
||||||
[[ -n "$new_uuid" ]] && new_uuids["$partition"]="$new_uuid"
|
|
||||||
|
if [[ -n "$old_uuid" && -n "$new_uuid" ]]; then
|
||||||
if [[ -n "$current_label" && -n "$new_label" ]]; then
|
uuid_map["$old_uuid"]="$new_uuid"
|
||||||
echo "Updated partition $partition: '$current_label' -> '$new_label'"
|
log " EFI UUID: $old_uuid -> $new_uuid"
|
||||||
fi
|
fi
|
||||||
if [[ -n "$current_uuid" && -n "$new_uuid" && "$current_uuid" != "$new_uuid" ]]; then
|
fi
|
||||||
echo "Regenerated UUID for $partition: $current_uuid -> $new_uuid"
|
|
||||||
|
# Process root partition
|
||||||
|
if [[ -n "${partitions[root]:-}" ]]; then
|
||||||
|
local root_part="${partitions[root]}"
|
||||||
|
local old_uuid
|
||||||
|
old_uuid=$(lsblk -no UUID "$root_part" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# Change label and UUID
|
||||||
|
if command -v tune2fs >/dev/null 2>&1; then
|
||||||
|
sudo tune2fs -L "STORMUX-HDD" "$root_part" 2>/dev/null || log "Warning: Could not rename root partition"
|
||||||
|
sudo tune2fs -U random "$root_part" 2>/dev/null || log "Warning: Could not change root UUID"
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
|
local new_uuid
|
||||||
# Return the UUID mappings for fstab update
|
new_uuid=$(lsblk -no UUID "$root_part" 2>/dev/null || echo "")
|
||||||
for partition in "${!old_uuids[@]}"; do
|
|
||||||
if [[ -n "${new_uuids[$partition]}" ]]; then
|
if [[ -n "$old_uuid" && -n "$new_uuid" ]]; then
|
||||||
echo "UUID_MAPPING:${old_uuids[$partition]}:${new_uuids[$partition]}"
|
uuid_map["$old_uuid"]="$new_uuid"
|
||||||
|
log " Root UUID: $old_uuid -> $new_uuid"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Return UUID mappings
|
||||||
|
for old in "${!uuid_map[@]}"; do
|
||||||
|
echo "UUID_MAP:$old:${uuid_map[$old]}"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Function to update fstab with new UUIDs
|
||||||
|
update_fstab() {
|
||||||
|
local mount_point="$1"
|
||||||
|
shift
|
||||||
|
local mappings=("$@")
|
||||||
|
|
||||||
|
log "Updating fstab with new UUIDs..."
|
||||||
|
|
||||||
|
local fstab="$mount_point/etc/fstab"
|
||||||
|
|
||||||
|
if [[ ! -f "$fstab" ]]; then
|
||||||
|
log_error "fstab not found at $fstab"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Backup original
|
||||||
|
sudo cp "$fstab" "$fstab.backup" || log "Warning: Could not backup fstab"
|
||||||
|
|
||||||
|
# Apply UUID mappings
|
||||||
|
local temp_fstab
|
||||||
|
temp_fstab=$(mktemp)
|
||||||
|
sudo cp "$fstab" "$temp_fstab"
|
||||||
|
|
||||||
|
for mapping in "${mappings[@]}"; do
|
||||||
|
if [[ "$mapping" =~ ^UUID_MAP:([^:]+):([^:]+)$ ]]; then
|
||||||
|
local old_uuid="${BASH_REMATCH[1]}"
|
||||||
|
local new_uuid="${BASH_REMATCH[2]}"
|
||||||
|
|
||||||
|
sed -i "s/UUID=$old_uuid/UUID=$new_uuid/g" "$temp_fstab"
|
||||||
|
log " Updated fstab: $old_uuid -> $new_uuid"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo cp "$temp_fstab" "$fstab"
|
||||||
|
rm -f "$temp_fstab"
|
||||||
|
|
||||||
|
log "fstab updated successfully"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install GRUB in chroot
|
||||||
|
install_grub() {
|
||||||
|
local mount_point="$1"
|
||||||
|
local target_device="$2"
|
||||||
|
local -n parts=$3
|
||||||
|
|
||||||
|
log "Installing GRUB bootloader to $target_device..."
|
||||||
|
|
||||||
|
# Ensure EFI partition is mounted inside chroot
|
||||||
|
if [[ -n "${parts[efi]:-}" ]]; then
|
||||||
|
sudo mkdir -p "$mount_point/boot"
|
||||||
|
if ! mountpoint -q "$mount_point/boot"; then
|
||||||
|
sudo mount "${parts[efi]}" "$mount_point/boot" || error_exit "Failed to mount EFI partition"
|
||||||
|
log " Mounted EFI partition at /boot"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bind mount necessary filesystems for chroot
|
||||||
|
sudo mount --bind /dev "$mount_point/dev" || error_exit "Failed to bind mount /dev"
|
||||||
|
sudo mount --bind /sys "$mount_point/sys" || error_exit "Failed to bind mount /sys"
|
||||||
|
sudo mount --bind /proc "$mount_point/proc" || error_exit "Failed to bind mount /proc"
|
||||||
|
log " Prepared chroot environment"
|
||||||
|
|
||||||
|
# Install GRUB for BIOS (allow to fail gracefully)
|
||||||
|
log " Installing GRUB for BIOS boot (warnings expected on UEFI systems)..."
|
||||||
|
if sudo arch-chroot "$mount_point" grub-install --target=i386-pc --recheck "$target_device" 2>&1 | tee -a "$LOGFILE"; then
|
||||||
|
log " BIOS boot installation succeeded"
|
||||||
|
else
|
||||||
|
log " BIOS boot installation completed with warnings (expected on UEFI systems)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install GRUB for UEFI (must succeed)
|
||||||
|
log " Installing GRUB for UEFI boot..."
|
||||||
|
if ! sudo arch-chroot "$mount_point" grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=STORMUX-HDD --recheck 2>&1 | tee -a "$LOGFILE"; then
|
||||||
|
error_exit "UEFI GRUB installation failed"
|
||||||
|
fi
|
||||||
|
log " UEFI boot installation succeeded"
|
||||||
|
|
||||||
|
# Generate GRUB configuration
|
||||||
|
log " Generating GRUB configuration..."
|
||||||
|
if ! sudo arch-chroot "$mount_point" grub-mkconfig -o /boot/grub/grub.cfg 2>&1 | tee -a "$LOGFILE"; then
|
||||||
|
error_exit "GRUB configuration generation failed"
|
||||||
|
fi
|
||||||
|
log " GRUB configuration generated successfully"
|
||||||
|
|
||||||
|
# Unmount bind mounts
|
||||||
|
sudo umount "$mount_point/proc" 2>/dev/null || true
|
||||||
|
sudo umount "$mount_point/sys" 2>/dev/null || true
|
||||||
|
sudo umount "$mount_point/dev" 2>/dev/null || true
|
||||||
|
|
||||||
|
log "GRUB installation completed successfully"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate installation
|
||||||
|
validate_installation() {
|
||||||
|
local mount_point="$1"
|
||||||
|
|
||||||
|
log "Validating installation..."
|
||||||
|
|
||||||
|
# Check fstab exists and has valid entries
|
||||||
|
if [[ ! -f "$mount_point/etc/fstab" ]]; then
|
||||||
|
log_error "fstab not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check GRUB config exists
|
||||||
|
if [[ ! -f "$mount_point/boot/grub/grub.cfg" ]]; then
|
||||||
|
log_error "GRUB configuration not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for baremetal marker
|
||||||
|
if [[ ! -f "$mount_point/home/stormux/.baremetal" ]]; then
|
||||||
|
log_error "Baremetal marker not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Validation passed"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Main Installation
|
||||||
|
###################
|
||||||
|
|
||||||
# Welcome message
|
|
||||||
clear
|
clear
|
||||||
echo "Stormux Gaming Image - USB to Disk Installer"
|
log "========================================"
|
||||||
echo "This will clone the entire USB system to an internal disk."
|
log "Stormux Gaming Image - Disk Installer"
|
||||||
|
log "========================================"
|
||||||
|
log "Log file: $LOGFILE"
|
||||||
|
echo
|
||||||
|
echo "This will clone the USB system to an internal disk."
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Find source device
|
# Find source device
|
||||||
echo "Detecting source USB device..."
|
log "Detecting source USB device..."
|
||||||
SOURCE_DEVICE=$(find_source_device)
|
SOURCE_DEVICE=$(find_source_device)
|
||||||
if [[ -z "$SOURCE_DEVICE" ]]; then
|
if [[ -z "$SOURCE_DEVICE" ]]; then
|
||||||
error_exit "Could not detect source USB device"
|
error_exit "Could not detect source USB device"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SOURCE_SIZE=$(lsblk -dpno SIZE "$SOURCE_DEVICE" 2>/dev/null | tr -d ' ')
|
SOURCE_SIZE=$(lsblk -dpno SIZE "$SOURCE_DEVICE" 2>/dev/null | tr -d ' ')
|
||||||
|
log "Source device: $SOURCE_DEVICE ($SOURCE_SIZE)"
|
||||||
echo "Source device: $SOURCE_DEVICE ($SOURCE_SIZE)"
|
echo "Source device: $SOURCE_DEVICE ($SOURCE_SIZE)"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Detect target disks
|
# Detect target disks
|
||||||
echo "Detecting target disks..."
|
log "Detecting target disks..."
|
||||||
mapfile -t target_disks < <(detect_target_disks "$SOURCE_DEVICE")
|
mapfile -t target_disks < <(detect_target_disks "$SOURCE_DEVICE")
|
||||||
|
|
||||||
if [[ ${#target_disks[@]} -eq 0 ]]; then
|
if [[ ${#target_disks[@]} -eq 0 ]]; then
|
||||||
error_exit "No suitable target disks found (excluding source USB)"
|
error_exit "No suitable target disks found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Display target disks
|
# Display target disks
|
||||||
echo "Available target disks:"
|
echo "Available target disks:"
|
||||||
|
log "Available target disks:"
|
||||||
for i in "${!target_disks[@]}"; do
|
for i in "${!target_disks[@]}"; do
|
||||||
disk="${target_disks[$i]}"
|
disk="${target_disks[$i]}"
|
||||||
info=$(get_disk_info "$disk")
|
info=$(get_disk_info "$disk")
|
||||||
echo "$((i+1)). $disk - $info"
|
echo "$((i+1)). $disk - $info"
|
||||||
|
log " $((i+1)). $disk - $info"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Get disk selection
|
# Get disk selection
|
||||||
@@ -206,7 +368,7 @@ while true; do
|
|||||||
echo
|
echo
|
||||||
echo "Enter the number of the disk to install to:"
|
echo "Enter the number of the disk to install to:"
|
||||||
read -r selection
|
read -r selection
|
||||||
|
|
||||||
if [[ "$selection" =~ ^[0-9]+$ ]] && [[ "$selection" -ge 1 ]] && [[ "$selection" -le ${#target_disks[@]} ]]; then
|
if [[ "$selection" =~ ^[0-9]+$ ]] && [[ "$selection" -ge 1 ]] && [[ "$selection" -le ${#target_disks[@]} ]]; then
|
||||||
TARGET_DEVICE="${target_disks[$((selection-1))]}"
|
TARGET_DEVICE="${target_disks[$((selection-1))]}"
|
||||||
break
|
break
|
||||||
@@ -215,12 +377,19 @@ while true; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
log "Selected target device: $TARGET_DEVICE"
|
||||||
|
|
||||||
|
# Safety check: ensure target != source
|
||||||
|
if [[ "$TARGET_DEVICE" == "$SOURCE_DEVICE" ]]; then
|
||||||
|
error_exit "Target device cannot be the same as source device"
|
||||||
|
fi
|
||||||
|
|
||||||
# Check target disk size
|
# Check target disk size
|
||||||
TARGET_SIZE_BYTES=$(lsblk -dpno SIZE -b "$TARGET_DEVICE" 2>/dev/null)
|
TARGET_SIZE_BYTES=$(lsblk -dpno SIZE -b "$TARGET_DEVICE" 2>/dev/null)
|
||||||
SOURCE_SIZE_BYTES=$(lsblk -dpno SIZE -b "$SOURCE_DEVICE" 2>/dev/null)
|
SOURCE_SIZE_BYTES=$(lsblk -dpno SIZE -b "$SOURCE_DEVICE" 2>/dev/null)
|
||||||
|
|
||||||
if [[ "$TARGET_SIZE_BYTES" -lt "$SOURCE_SIZE_BYTES" ]]; then
|
if [[ "$TARGET_SIZE_BYTES" -lt "$SOURCE_SIZE_BYTES" ]]; then
|
||||||
error_exit "Target disk is smaller than source USB. Cannot proceed."
|
error_exit "Target disk is smaller than source USB"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Final confirmation
|
# Final confirmation
|
||||||
@@ -231,181 +400,133 @@ echo "Source: $SOURCE_DEVICE ($SOURCE_SIZE)"
|
|||||||
echo "Target: $TARGET_DEVICE ($target_info)"
|
echo "Target: $TARGET_DEVICE ($target_info)"
|
||||||
echo "ALL DATA ON THE TARGET DISK WILL BE PERMANENTLY DESTROYED!"
|
echo "ALL DATA ON THE TARGET DISK WILL BE PERMANENTLY DESTROYED!"
|
||||||
echo
|
echo
|
||||||
|
log "Final confirmation - Target: $TARGET_DEVICE"
|
||||||
echo "Type 'yes' to continue or any other key to cancel:"
|
echo "Type 'yes' to continue or any other key to cancel:"
|
||||||
read -r CONFIRM
|
read -r CONFIRM
|
||||||
|
|
||||||
if [[ "$CONFIRM" != "yes" ]]; then
|
if [[ "$CONFIRM" != "yes" ]]; then
|
||||||
|
log "Installation cancelled by user"
|
||||||
echo "Installation cancelled."
|
echo "Installation cancelled."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rely on progress bar beeps for status
|
log "User confirmed installation"
|
||||||
|
|
||||||
|
# Disable speech during installation
|
||||||
echo
|
echo
|
||||||
echo "Fenrir will be silent during the install process except for progress beeps."
|
echo "Fenrir will be silent during installation except for progress beeps."
|
||||||
echo "To restore speech if needed, press any key."
|
echo "Press Enter to begin..."
|
||||||
echo "Press Enter to begin installation..."
|
|
||||||
read -r
|
read -r
|
||||||
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock 2>/dev/null || true
|
disable_speech
|
||||||
|
|
||||||
# Unmount any mounted partitions on target disk
|
# Unmount any mounted partitions on target disk
|
||||||
echo "Unmounting target disk partitions..."
|
log "Unmounting target disk partitions..."
|
||||||
sudo umount "${TARGET_DEVICE}"* 2>/dev/null || true
|
sudo umount "${TARGET_DEVICE}"* 2>/dev/null || true
|
||||||
|
|
||||||
# Clone the USB to the target disk
|
# Clone the USB to target disk
|
||||||
|
log "Starting disk clone operation..."
|
||||||
echo "Cloning USB system to target disk..."
|
echo "Cloning USB system to target disk..."
|
||||||
echo "This will take several minutes depending on USB size and disk speed."
|
echo "This will take several minutes depending on USB size and disk speed."
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Use dd to clone the entire device
|
if ! sudo dd if="$SOURCE_DEVICE" of="$TARGET_DEVICE" bs=4M oflag=sync status=progress 2>&1 | tee -a "$LOGFILE"; then
|
||||||
if ! sudo dd if="$SOURCE_DEVICE" of="$TARGET_DEVICE" bs=4M oflag=sync status=progress; then
|
|
||||||
error_exit "Failed to clone USB to target disk"
|
error_exit "Failed to clone USB to target disk"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Sync to ensure all data is written
|
log "Disk clone completed successfully"
|
||||||
echo "Syncing data to disk..."
|
|
||||||
|
# Sync and refresh partition table
|
||||||
|
log "Syncing data to disk..."
|
||||||
sudo sync
|
sudo sync
|
||||||
|
|
||||||
# Update the cloned system to remove USB-specific configurations
|
log "Refreshing partition table..."
|
||||||
echo "Finalizing installation..."
|
sudo partprobe "$TARGET_DEVICE" 2>&1 | tee -a "$LOGFILE" || log "Warning: partprobe reported issues"
|
||||||
|
sudo udevadm settle --timeout=10 || log "Warning: udevadm settle timeout"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# Mount the new root partition to make final adjustments
|
# Detect partition structure
|
||||||
if [[ "$TARGET_DEVICE" =~ (nvme|mmcblk) ]]; then
|
log "Analyzing cloned partition structure..."
|
||||||
TARGET_ROOT_PART="${TARGET_DEVICE}p1"
|
declare -A target_partitions
|
||||||
else
|
if ! detect_partitions "$TARGET_DEVICE" target_partitions; then
|
||||||
TARGET_ROOT_PART="${TARGET_DEVICE}1"
|
error_exit "Failed to detect partition structure on target disk"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find the actual root partition (might not be partition 1)
|
# Validate partition structure
|
||||||
echo "Searching for ext4 root partition..."
|
if [[ -z "${target_partitions[root]:-}" ]]; then
|
||||||
for part in "${TARGET_DEVICE}"*; do
|
error_exit "Could not find root partition on target disk"
|
||||||
if [[ "$part" != "$TARGET_DEVICE" ]]; then
|
fi
|
||||||
fstype=$(lsblk -no FSTYPE "$part" 2>/dev/null)
|
|
||||||
echo "Checking $part: filesystem type = $fstype"
|
|
||||||
if [[ "$fstype" == "ext4" ]]; then
|
|
||||||
TARGET_ROOT_PART="$part"
|
|
||||||
echo "Found root partition: $TARGET_ROOT_PART"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Regenerate partition UUIDs and labels to prevent boot conflicts with USB
|
log "Partition detection complete:"
|
||||||
echo "Regenerating partition identifiers..."
|
log " BIOS: ${target_partitions[bios]:-none}"
|
||||||
mapfile -t uuid_mappings < <(regenerate_partition_identifiers "$TARGET_DEVICE")
|
log " EFI: ${target_partitions[efi]:-none}"
|
||||||
echo "Found ${#uuid_mappings[@]} UUID mappings to update"
|
log " Root: ${target_partitions[root]}"
|
||||||
|
|
||||||
# Mount and make final adjustments
|
# Mount root partition
|
||||||
TEMP_MOUNT="/mnt/stormux_target"
|
TEMP_MOUNT="/mnt/stormux_target"
|
||||||
sudo mkdir -p "$TEMP_MOUNT"
|
sudo mkdir -p "$TEMP_MOUNT"
|
||||||
|
|
||||||
echo "Mounting $TARGET_ROOT_PART for final adjustments..."
|
log "Mounting root partition ${target_partitions[root]}..."
|
||||||
if sudo mount "$TARGET_ROOT_PART" "$TEMP_MOUNT" 2>/dev/null; then
|
if ! sudo mount "${target_partitions[root]}" "$TEMP_MOUNT" 2>&1 | tee -a "$LOGFILE"; then
|
||||||
echo "Successfully mounted target partition"
|
error_exit "Failed to mount root partition"
|
||||||
# Remove any USB-specific markers
|
|
||||||
sudo rm -f "$TEMP_MOUNT/home/stormux/.firstboot" 2>/dev/null || true
|
|
||||||
|
|
||||||
# Create .baremetal marker file to indicate installed system
|
|
||||||
echo "Creating baremetal system marker..."
|
|
||||||
sudo touch "$TEMP_MOUNT/home/stormux/.baremetal"
|
|
||||||
sudo chown stormux:stormux "$TEMP_MOUNT/home/stormux/.baremetal" 2>/dev/null || true
|
|
||||||
# Set immutable attribute to prevent accidental deletion
|
|
||||||
sudo chattr +i "$TEMP_MOUNT/home/stormux/.baremetal" 2>/dev/null || echo "Warning: Could not set immutable attribute on .baremetal"
|
|
||||||
|
|
||||||
# Update fstab with new UUIDs if any were generated
|
|
||||||
if [[ ${#uuid_mappings[@]} -gt 0 ]]; then
|
|
||||||
echo "Updating fstab with new UUIDs..."
|
|
||||||
# Backup original fstab
|
|
||||||
sudo cp "$TEMP_MOUNT/etc/fstab" "$TEMP_MOUNT/etc/fstab.backup" || echo "Warning: Could not backup fstab"
|
|
||||||
|
|
||||||
# Apply UUID updates to fstab
|
|
||||||
temp_fstab=$(mktemp)
|
|
||||||
sudo cp "$TEMP_MOUNT/etc/fstab" "$temp_fstab"
|
|
||||||
|
|
||||||
for mapping in "${uuid_mappings[@]}"; do
|
|
||||||
if [[ "$mapping" =~ ^UUID_MAPPING:([^:]+):([^:]+)$ ]]; then
|
|
||||||
old_uuid="${BASH_REMATCH[1]}"
|
|
||||||
new_uuid="${BASH_REMATCH[2]}"
|
|
||||||
|
|
||||||
# Replace old UUID with new UUID in fstab
|
|
||||||
sed -i "s/UUID=$old_uuid/UUID=$new_uuid/g" "$temp_fstab"
|
|
||||||
echo "Updated fstab: $old_uuid -> $new_uuid"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Copy updated fstab back
|
|
||||||
sudo cp "$temp_fstab" "$TEMP_MOUNT/etc/fstab"
|
|
||||||
rm -f "$temp_fstab"
|
|
||||||
echo "fstab updated successfully"
|
|
||||||
else
|
|
||||||
echo "No UUID mappings found - keeping original fstab"
|
|
||||||
sudo cp "$TEMP_MOUNT/etc/fstab" "$TEMP_MOUNT/etc/fstab.backup" || echo "Warning: Could not backup fstab"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Also mount and update GRUB config on EFI partition
|
|
||||||
EFI_MOUNT="/mnt/stormux_efi"
|
|
||||||
sudo mkdir -p "$EFI_MOUNT"
|
|
||||||
|
|
||||||
# Find EFI partition (should be partition 2)
|
|
||||||
if [[ "$TARGET_DEVICE" =~ (nvme|mmcblk) ]]; then
|
|
||||||
EFI_PART="${TARGET_DEVICE}p2"
|
|
||||||
else
|
|
||||||
EFI_PART="${TARGET_DEVICE}2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if sudo mount "$EFI_PART" "$EFI_MOUNT" 2>/dev/null; then
|
|
||||||
echo "Updating GRUB configuration with new UUIDs..."
|
|
||||||
if [[ -f "$EFI_MOUNT/grub/grub.cfg" && ${#uuid_mappings[@]} -gt 0 ]]; then
|
|
||||||
# Backup original grub config
|
|
||||||
sudo cp "$EFI_MOUNT/grub/grub.cfg" "$EFI_MOUNT/grub/grub.cfg.backup" || echo "Warning: Could not backup grub.cfg"
|
|
||||||
|
|
||||||
# Apply UUID updates to grub config
|
|
||||||
grub_temp=$(mktemp)
|
|
||||||
sudo cp "$EFI_MOUNT/grub/grub.cfg" "$grub_temp"
|
|
||||||
|
|
||||||
for mapping in "${uuid_mappings[@]}"; do
|
|
||||||
if [[ "$mapping" =~ ^UUID_MAPPING:([^:]+):([^:]+)$ ]]; then
|
|
||||||
grub_old_uuid="${BASH_REMATCH[1]}"
|
|
||||||
grub_new_uuid="${BASH_REMATCH[2]}"
|
|
||||||
|
|
||||||
# Replace old UUID with new UUID in grub config
|
|
||||||
sed -i "s/${grub_old_uuid}/${grub_new_uuid}/g" "$grub_temp"
|
|
||||||
echo "Updated grub.cfg: $grub_old_uuid -> $grub_new_uuid"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Copy updated grub config back
|
|
||||||
sudo cp "$grub_temp" "$EFI_MOUNT/grub/grub.cfg"
|
|
||||||
rm -f "$grub_temp"
|
|
||||||
echo "GRUB configuration updated successfully"
|
|
||||||
else
|
|
||||||
echo "No GRUB config found or no UUID mappings to update"
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo umount "$EFI_MOUNT"
|
|
||||||
else
|
|
||||||
echo "Warning: Could not mount EFI partition $EFI_PART"
|
|
||||||
fi
|
|
||||||
sudo rmdir "$EFI_MOUNT"
|
|
||||||
|
|
||||||
# Restore speech
|
|
||||||
echo "command toggletempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
|
||||||
|
|
||||||
echo "Unmounting target partition..."
|
|
||||||
sudo umount "$TEMP_MOUNT"
|
|
||||||
else
|
|
||||||
echo "ERROR: Failed to mount target partition $TARGET_ROOT_PART"
|
|
||||||
echo "Installation may have failed - please check the target disk"
|
|
||||||
echo "However, the disk cloning operation completed."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log "Root partition mounted successfully"
|
||||||
|
|
||||||
|
# Regenerate UUIDs and labels
|
||||||
|
log "Regenerating partition identifiers..."
|
||||||
|
mapfile -t uuid_mappings < <(regenerate_partition_identifiers "$TARGET_DEVICE" target_partitions)
|
||||||
|
log "Generated ${#uuid_mappings[@]} UUID mappings"
|
||||||
|
|
||||||
|
# Update fstab with new UUIDs
|
||||||
|
if ! update_fstab "$TEMP_MOUNT" "${uuid_mappings[@]}"; then
|
||||||
|
error_exit "Failed to update fstab"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create baremetal marker
|
||||||
|
log "Creating baremetal system marker..."
|
||||||
|
sudo touch "$TEMP_MOUNT/home/stormux/.baremetal"
|
||||||
|
sudo chown 1000:1000 "$TEMP_MOUNT/home/stormux/.baremetal" 2>/dev/null || true
|
||||||
|
sudo chattr +i "$TEMP_MOUNT/home/stormux/.baremetal" 2>/dev/null || log "Warning: Could not set immutable attribute"
|
||||||
|
|
||||||
|
# Remove USB-specific markers
|
||||||
|
sudo rm -f "$TEMP_MOUNT/home/stormux/.firstboot" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Install GRUB
|
||||||
|
if ! install_grub "$TEMP_MOUNT" "$TARGET_DEVICE" target_partitions; then
|
||||||
|
error_exit "GRUB installation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate installation
|
||||||
|
if ! validate_installation "$TEMP_MOUNT"; then
|
||||||
|
error_exit "Installation validation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unmount EFI partition if mounted
|
||||||
|
if [[ -n "${target_partitions[efi]:-}" ]] && mountpoint -q "$TEMP_MOUNT/boot"; then
|
||||||
|
log "Unmounting EFI partition..."
|
||||||
|
sudo umount "$TEMP_MOUNT/boot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unmount root partition
|
||||||
|
log "Unmounting root partition..."
|
||||||
|
sudo umount "$TEMP_MOUNT"
|
||||||
sudo rmdir "$TEMP_MOUNT"
|
sudo rmdir "$TEMP_MOUNT"
|
||||||
|
|
||||||
# Success message (using Fenrir auto-restore pattern)
|
# Restore speech
|
||||||
|
restore_speech
|
||||||
|
|
||||||
|
# Success message
|
||||||
|
log "========================================="
|
||||||
|
log "Installation completed successfully!"
|
||||||
|
log "========================================="
|
||||||
echo
|
echo
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
echo "Installation completed successfully!"
|
echo "Installation completed successfully!"
|
||||||
echo "The USB system has been cloned to $TARGET_DEVICE"
|
echo "The USB system has been cloned to $TARGET_DEVICE"
|
||||||
echo "You can now reboot and remove the USB drive."
|
echo "You can now reboot and remove the USB drive."
|
||||||
echo "The system will boot from the internal disk."
|
echo "The system will boot from the internal disk."
|
||||||
|
echo
|
||||||
|
echo "Log file: $LOGFILE"
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
echo
|
echo
|
||||||
echo "Press enter to continue..."
|
echo "Press enter to continue..."
|
||||||
|
|||||||
Reference in New Issue
Block a user