diff --git a/usr/local/bin/install_to_disk.sh b/usr/local/bin/install_to_disk.sh index c992832..dade0a5 100755 --- a/usr/local/bin/install_to_disk.sh +++ b/usr/local/bin/install_to_disk.sh @@ -1,20 +1,49 @@ #!/usr/bin/env bash -# Stormux Gaming Image - USB to Disk Cloner -# Clones the entire USB system to an internal disk +# Stormux Gaming Image - Ultra-Reliable Disk Installer +# 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() { - echo "Error: $1" + log_error "$1" + echo "Installation failed. Log file: $LOGFILE" + restore_speech 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 find_source_device() { - # Look for the device we're currently running from local root_device root_device=$(findmnt -n -o SOURCE /) + 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) echo "$root_device" | sed 's/[0-9]*$//' | sed 's/p$//' @@ -34,17 +63,19 @@ find_source_device() { detect_target_disks() { local source_device="$1" local disks=() - + while IFS= read -r disk; do - # Skip if it's a partition, loop device, CD-ROM, or the 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]+)$ ]] && [[ ! "$disk" =~ ^/dev/loop ]] && [[ ! "$disk" =~ ^/dev/sr ]] && [[ "$disk" != "$source_device" ]]; then + # Skip partitions, loop devices, CD-ROMs, and source device + 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 if [[ -b "$disk" ]]; then disks+=("$disk") fi fi done < <(lsblk -dpno NAME 2>/dev/null) - + printf '%s\n' "${disks[@]}" } @@ -58,147 +89,278 @@ get_disk_info() { echo "$size - $model" } -# Function to regenerate UUIDs and rename partition labels to prevent boot conflicts -regenerate_partition_identifiers() { - local target_device="$1" - echo "Regenerating partition UUIDs and labels to prevent boot conflicts..." - - # Arrays to store old and new UUIDs for fstab update - declare -A old_uuids - declare -A new_uuids - - # Get all partitions on the target device - local partitions=() - while IFS= read -r partition; do - if [[ "$partition" != "$target_device" && "$partition" =~ ^${target_device}.+ ]]; then - partitions+=("$partition") - fi - done < <(lsblk -lpno NAME "$target_device" 2>/dev/null) - - # Process each partition - 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 +# Function to detect partitions by filesystem type +# shellcheck disable=SC2154 +detect_partitions() { + local device="$1" + # shellcheck disable=SC2178 + local -n result=$2 # nameref to associative array + + log "Detecting partition structure on $device..." + + # Get all partitions + while IFS= read -r line; do + local part fstype label + part=$(echo "$line" | awk '{print $1}') + fstype=$(echo "$line" | awk '{print $2}') + label=$(echo "$line" | awk '{print $3}') + + # Skip if it's the device itself, not a partition + [[ "$part" == "$device" ]] && continue + case "$fstype" in - "vfat"|"fat32"|"fat16") - # Partition 2: FAT32 EFI boot partition - if [[ -n "$new_label" ]]; then - new_label="${new_label:0:11}" # FAT32 has 11 character limit - 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" - fi - fi - # Generate new UUID for FAT - 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 + "") + # BIOS boot partition (no filesystem) + result[bios]="$part" + log " BIOS boot partition: $part" + ;; + "vfat") + # EFI partition + result[efi]="$part" + log " EFI partition: $part (label: ${label:-none})" ;; "ext4") - # Partition 3: ext4 root filesystem - if [[ -n "$new_label" ]]; then - new_label="${new_label:0:16}" # ext4 has 16 character limit - 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 + # Root partition + result[root]="$part" + log " Root partition: $part (label: ${label:-none})" ;; *) - echo "Warning: Unexpected filesystem type '$fstype' on $partition" - continue + log " Unknown partition type: $part ($fstype)" ;; esac - - # Get the new UUID after regeneration + done < <(lsblk -no NAME,FSTYPE,LABEL "$device" 2>/dev/null | tail -n +2) + + # 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 - new_uuid=$(lsblk -no UUID "$partition" 2>/dev/null) - [[ -n "$new_uuid" ]] && new_uuids["$partition"]="$new_uuid" - - if [[ -n "$current_label" && -n "$new_label" ]]; then - echo "Updated partition $partition: '$current_label' -> '$new_label'" + new_uuid=$(lsblk -no UUID "$efi_part" 2>/dev/null || echo "") + + if [[ -n "$old_uuid" && -n "$new_uuid" ]]; then + uuid_map["$old_uuid"]="$new_uuid" + log " EFI UUID: $old_uuid -> $new_uuid" fi - if [[ -n "$current_uuid" && -n "$new_uuid" && "$current_uuid" != "$new_uuid" ]]; then - echo "Regenerated UUID for $partition: $current_uuid -> $new_uuid" + fi + + # 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 - done - - # Return the UUID mappings for fstab update - for partition in "${!old_uuids[@]}"; do - if [[ -n "${new_uuids[$partition]}" ]]; then - echo "UUID_MAPPING:${old_uuids[$partition]}:${new_uuids[$partition]}" + + local new_uuid + new_uuid=$(lsblk -no UUID "$root_part" 2>/dev/null || echo "") + + if [[ -n "$old_uuid" && -n "$new_uuid" ]]; then + uuid_map["$old_uuid"]="$new_uuid" + log " Root UUID: $old_uuid -> $new_uuid" fi + fi + + # Return UUID mappings + for old in "${!uuid_map[@]}"; do + echo "UUID_MAP:$old:${uuid_map[$old]}" 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 -echo "Stormux Gaming Image - USB to Disk Installer" -echo "This will clone the entire USB system to an internal disk." +log "========================================" +log "Stormux Gaming Image - Disk Installer" +log "========================================" +log "Log file: $LOGFILE" +echo +echo "This will clone the USB system to an internal disk." echo # Find source device -echo "Detecting source USB device..." +log "Detecting source USB device..." SOURCE_DEVICE=$(find_source_device) if [[ -z "$SOURCE_DEVICE" ]]; then error_exit "Could not detect source USB device" fi 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 # Detect target disks -echo "Detecting target disks..." +log "Detecting target disks..." mapfile -t target_disks < <(detect_target_disks "$SOURCE_DEVICE") if [[ ${#target_disks[@]} -eq 0 ]]; then - error_exit "No suitable target disks found (excluding source USB)" + error_exit "No suitable target disks found" fi # Display target disks echo "Available target disks:" +log "Available target disks:" for i in "${!target_disks[@]}"; do disk="${target_disks[$i]}" info=$(get_disk_info "$disk") echo "$((i+1)). $disk - $info" + log " $((i+1)). $disk - $info" done # Get disk selection @@ -206,7 +368,7 @@ while true; do echo echo "Enter the number of the disk to install to:" read -r selection - + if [[ "$selection" =~ ^[0-9]+$ ]] && [[ "$selection" -ge 1 ]] && [[ "$selection" -le ${#target_disks[@]} ]]; then TARGET_DEVICE="${target_disks[$((selection-1))]}" break @@ -215,12 +377,19 @@ while true; do fi 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 TARGET_SIZE_BYTES=$(lsblk -dpno SIZE -b "$TARGET_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 - error_exit "Target disk is smaller than source USB. Cannot proceed." + error_exit "Target disk is smaller than source USB" fi # Final confirmation @@ -231,181 +400,133 @@ echo "Source: $SOURCE_DEVICE ($SOURCE_SIZE)" echo "Target: $TARGET_DEVICE ($target_info)" echo "ALL DATA ON THE TARGET DISK WILL BE PERMANENTLY DESTROYED!" echo +log "Final confirmation - Target: $TARGET_DEVICE" echo "Type 'yes' to continue or any other key to cancel:" read -r CONFIRM if [[ "$CONFIRM" != "yes" ]]; then + log "Installation cancelled by user" echo "Installation cancelled." exit 0 fi -# Rely on progress bar beeps for status +log "User confirmed installation" + +# Disable speech during installation echo -echo "Fenrir will be silent during the install process except for progress beeps." -echo "To restore speech if needed, press any key." -echo "Press Enter to begin installation..." +echo "Fenrir will be silent during installation except for progress beeps." +echo "Press Enter to begin..." 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 -echo "Unmounting target disk partitions..." +log "Unmounting target disk partitions..." 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 "This will take several minutes depending on USB size and disk speed." echo -# Use dd to clone the entire device -if ! sudo dd if="$SOURCE_DEVICE" of="$TARGET_DEVICE" bs=4M oflag=sync status=progress; then +if ! sudo dd if="$SOURCE_DEVICE" of="$TARGET_DEVICE" bs=4M oflag=sync status=progress 2>&1 | tee -a "$LOGFILE"; then error_exit "Failed to clone USB to target disk" fi -# Sync to ensure all data is written -echo "Syncing data to disk..." +log "Disk clone completed successfully" + +# Sync and refresh partition table +log "Syncing data to disk..." sudo sync -# Update the cloned system to remove USB-specific configurations -echo "Finalizing installation..." +log "Refreshing partition table..." +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 -if [[ "$TARGET_DEVICE" =~ (nvme|mmcblk) ]]; then - TARGET_ROOT_PART="${TARGET_DEVICE}p1" -else - TARGET_ROOT_PART="${TARGET_DEVICE}1" +# Detect partition structure +log "Analyzing cloned partition structure..." +declare -A target_partitions +if ! detect_partitions "$TARGET_DEVICE" target_partitions; then + error_exit "Failed to detect partition structure on target disk" fi -# Find the actual root partition (might not be partition 1) -echo "Searching for ext4 root partition..." -for part in "${TARGET_DEVICE}"*; do - if [[ "$part" != "$TARGET_DEVICE" ]]; then - 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 +# Validate partition structure +if [[ -z "${target_partitions[root]:-}" ]]; then + error_exit "Could not find root partition on target disk" +fi -# Regenerate partition UUIDs and labels to prevent boot conflicts with USB -echo "Regenerating partition identifiers..." -mapfile -t uuid_mappings < <(regenerate_partition_identifiers "$TARGET_DEVICE") -echo "Found ${#uuid_mappings[@]} UUID mappings to update" +log "Partition detection complete:" +log " BIOS: ${target_partitions[bios]:-none}" +log " EFI: ${target_partitions[efi]:-none}" +log " Root: ${target_partitions[root]}" -# Mount and make final adjustments +# Mount root partition TEMP_MOUNT="/mnt/stormux_target" sudo mkdir -p "$TEMP_MOUNT" -echo "Mounting $TARGET_ROOT_PART for final adjustments..." -if sudo mount "$TARGET_ROOT_PART" "$TEMP_MOUNT" 2>/dev/null; then - echo "Successfully mounted target 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." +log "Mounting root partition ${target_partitions[root]}..." +if ! sudo mount "${target_partitions[root]}" "$TEMP_MOUNT" 2>&1 | tee -a "$LOGFILE"; then + error_exit "Failed to mount root partition" 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" -# Success message (using Fenrir auto-restore pattern) +# Restore speech +restore_speech + +# Success message +log "=========================================" +log "Installation completed successfully!" +log "=========================================" echo echo "=========================================" echo "Installation completed successfully!" echo "The USB system has been cloned to $TARGET_DEVICE" echo "You can now reboot and remove the USB drive." echo "The system will boot from the internal disk." +echo +echo "Log file: $LOGFILE" echo "=========================================" echo echo "Press enter to continue..."