improve throughout.
This commit is contained in:
		
							parent
							
								
									c29225d40b
								
							
						
					
					
						commit
						81bc66e905
					
				
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							@ -39,9 +39,6 @@ sudo apt-get install exfat-fuse exfat-utils
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# For XFS support
 | 
					# For XFS support
 | 
				
			||||||
sudo apt-get install xfsprogs
 | 
					sudo apt-get install xfsprogs
 | 
				
			||||||
 | 
					 | 
				
			||||||
# For forensic analysis tools
 | 
					 | 
				
			||||||
sudo apt-get install sleuthkit
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Preset Layouts
 | 
					## Preset Layouts
 | 
				
			||||||
@ -131,12 +128,18 @@ The script will:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Checking filesystem tool availability...
 | 
					Checking filesystem tool availability...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ✓ NTFS    (mkfs.ntfs available)
 | 
					  ✓ FAT12/16 (mkfs.fat available)
 | 
				
			||||||
  ✓ FAT32   (mkfs.vfat available)
 | 
					  ✓ FAT32   (mkfs.vfat available)
 | 
				
			||||||
  ✓ exFAT   (mkfs.exfat available)
 | 
					  ✓ exFAT   (mkfs.exfat available)
 | 
				
			||||||
  ✓ ext2/3/4 (mkfs.ext4 available)
 | 
					  ✓ NTFS    (mkfs.ntfs available)
 | 
				
			||||||
 | 
					  ✓ ext2    (mke2fs/mkfs.ext2 available)
 | 
				
			||||||
 | 
					  ✓ ext3    (mke2fs/mkfs.ext3 available)
 | 
				
			||||||
 | 
					  ✓ ext4    (mkfs.ext4 available)
 | 
				
			||||||
  ✓ XFS     (mkfs.xfs available)
 | 
					  ✓ XFS     (mkfs.xfs available)
 | 
				
			||||||
 | 
					  ✓ HFS+    (mkfs.hfsplus available)
 | 
				
			||||||
 | 
					  ✓ APFS    (limited Linux support; creation typically requires macOS)
 | 
				
			||||||
  ✓ swap    (mkswap available)
 | 
					  ✓ swap    (mkswap available)
 | 
				
			||||||
 | 
					  ✓ Unallocated (no mkfs required)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Enter output filename (default: forensic_disk.dd): win11.dd
 | 
					Enter output filename (default: forensic_disk.dd): win11.dd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										165
									
								
								cleanup.sh
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								cleanup.sh
									
									
									
									
									
								
							@ -67,49 +67,166 @@ show_user_loop_devices() {
 | 
				
			|||||||
    return 0
 | 
					    return 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Helper to list processes blocking a device (if possible)
 | 
				
			||||||
 | 
					list_blocking_processes() {
 | 
				
			||||||
 | 
					    local dev="$1"
 | 
				
			||||||
 | 
					    if command -v fuser >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        fuser -v "$dev" 2>/dev/null || true
 | 
				
			||||||
 | 
					    elif command -v lsof >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        lsof "$dev" 2>/dev/null || true
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        print_info "Install 'psmisc' (provides fuser) or 'lsof' to list blocking processes"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Function to unmount all partitions of a loop device
 | 
					# Function to unmount all partitions of a loop device
 | 
				
			||||||
unmount_loop_partitions() {
 | 
					unmount_loop_partitions() {
 | 
				
			||||||
    local loop_device=$1
 | 
					    local loop_device=$1
 | 
				
			||||||
    local unmounted=0
 | 
					    local unmounted=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Try both naming conventions
 | 
					    # Build a list of partition nodes for this loop device
 | 
				
			||||||
    for part in ${loop_device}p* ${loop_device}[0-9]*; do
 | 
					    local parts=()
 | 
				
			||||||
        if [ -e "$part" ]; then
 | 
					    for p in "${loop_device}p"* "${loop_device}"[0-9]*; do
 | 
				
			||||||
            local mount_point=$(findmnt -n -o TARGET "$part" 2>/dev/null || true)
 | 
					        # Only consider block device nodes that actually exist
 | 
				
			||||||
 | 
					        if [ -b "$p" ]; then
 | 
				
			||||||
 | 
					            parts+=("$p")
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ ${#parts[@]} -eq 0 ]; then
 | 
				
			||||||
 | 
					        print_info "No partition block devices found for $loop_device"
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for part in "${parts[@]}"; do
 | 
				
			||||||
 | 
					        # Determine if the partition is mounted
 | 
				
			||||||
 | 
					        local mount_point
 | 
				
			||||||
 | 
					        mount_point=$(findmnt -n -o TARGET --source "$part" 2>/dev/null || true)
 | 
				
			||||||
        if [ -n "$mount_point" ]; then
 | 
					        if [ -n "$mount_point" ]; then
 | 
				
			||||||
            print_info "Unmounting $part from $mount_point"
 | 
					            print_info "Unmounting $part from $mount_point"
 | 
				
			||||||
                if umount "$part"; then
 | 
					            if umount "$part" 2>/dev/null; then
 | 
				
			||||||
                print_success "Unmounted $part"
 | 
					                print_success "Unmounted $part"
 | 
				
			||||||
                unmounted=$((unmounted + 1))
 | 
					                unmounted=$((unmounted + 1))
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                    print_warning "Failed to unmount $part"
 | 
					                print_warning "Regular umount failed for $part - attempting lazy unmount"
 | 
				
			||||||
 | 
					                if umount -l "$part" 2>/dev/null; then
 | 
				
			||||||
 | 
					                    print_success "Lazy-unmounted $part"
 | 
				
			||||||
 | 
					                    unmounted=$((unmounted + 1))
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    print_warning "Failed to unmount $part even with lazy unmount"
 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            print_info "Partition $part does not appear to be mounted"
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Attempt to remove partition mappings so kernel releases device nodes
 | 
				
			||||||
 | 
					    if command -v partx >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        partx -d "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					    elif command -v kpartx >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        kpartx -d "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Give udev a moment to remove stale device nodes
 | 
				
			||||||
 | 
					    if command -v udevadm >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        udevadm settle 2>/dev/null || true
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return $unmounted
 | 
					    return $unmounted
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Function to detach loop device
 | 
					# Function to detach loop device
 | 
				
			||||||
detach_loop_device() {
 | 
					detach_loop_device() {
 | 
				
			||||||
    local loop_device=$1
 | 
					    local loop_device=$1
 | 
				
			||||||
 | 
					    local force=${2:-false}  # second optional argument: "true" to forcibly kill blockers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print_info "Detaching $loop_device"
 | 
					    print_info "Detaching $loop_device"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Check if device still exists in losetup output
 | 
					    # If the device is not present in losetup listing, consider it already detached
 | 
				
			||||||
    if ! losetup -l | grep -q "^$loop_device "; then
 | 
					    if ! losetup -l -n -O NAME 2>/dev/null | awk '{print $1}' | grep -qxF "$loop_device"; then
 | 
				
			||||||
        print_success "Loop device already detached"
 | 
					        print_success "Loop device already detached"
 | 
				
			||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if losetup -d "$loop_device"; then
 | 
					    # Try a normal detach first
 | 
				
			||||||
 | 
					    if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
        print_success "Detached $loop_device"
 | 
					        print_success "Detached $loop_device"
 | 
				
			||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        print_error "Failed to detach $loop_device"
 | 
					 | 
				
			||||||
        return 1
 | 
					 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_warning "Initial detach failed for $loop_device; attempting recovery steps"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Try removing partition mappings and let udev settle
 | 
				
			||||||
 | 
					    if command -v partx >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        partx -d "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					    elif command -v kpartx >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        kpartx -d "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    if command -v udevadm >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					        udevadm settle 2>/dev/null || true
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					    sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Second detach attempt
 | 
				
			||||||
 | 
					    if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
 | 
					        print_success "Detached $loop_device"
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If allowed, try to kill processes referencing the loop device (SIGTERM then SIGKILL)
 | 
				
			||||||
 | 
					    if [ "$force" = "true" ]; then
 | 
				
			||||||
 | 
					        if command -v fuser >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					            print_info "Killing processes using $loop_device (SIGTERM)"
 | 
				
			||||||
 | 
					            fuser -k -TERM "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					            sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Try detach again
 | 
				
			||||||
 | 
					            if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
 | 
					                print_success "Detached $loop_device after killing blockers"
 | 
				
			||||||
 | 
					                return 0
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            print_info "Killing any remaining processes using $loop_device (SIGKILL)"
 | 
				
			||||||
 | 
					            fuser -k -KILL "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					            sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
 | 
					                print_success "Detached $loop_device after force-killing blockers"
 | 
				
			||||||
 | 
					                return 0
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					        elif command -v lsof >/dev/null 2>&1; then
 | 
				
			||||||
 | 
					            print_info "Listing processes using $loop_device via lsof"
 | 
				
			||||||
 | 
					            lsof "$loop_device" 2>/dev/null || true
 | 
				
			||||||
 | 
					            local pids
 | 
				
			||||||
 | 
					            pids=$(lsof -t "$loop_device" 2>/dev/null || true)
 | 
				
			||||||
 | 
					            if [ -n "$pids" ]; then
 | 
				
			||||||
 | 
					                print_info "Sending SIGTERM to: $pids"
 | 
				
			||||||
 | 
					                kill -TERM $pids 2>/dev/null || true
 | 
				
			||||||
 | 
					                sleep 1
 | 
				
			||||||
 | 
					                if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
 | 
					                    print_success "Detached $loop_device after killing blockers"
 | 
				
			||||||
 | 
					                    return 0
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                print_info "Sending SIGKILL to: $pids"
 | 
				
			||||||
 | 
					                kill -KILL $pids 2>/dev/null || true
 | 
				
			||||||
 | 
					                sleep 1
 | 
				
			||||||
 | 
					                if losetup -d "$loop_device" 2>/dev/null; then
 | 
				
			||||||
 | 
					                    print_success "Detached $loop_device after force-killing blockers"
 | 
				
			||||||
 | 
					                    return 0
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            print_warning "No 'fuser' or 'lsof' available; cannot automatically kill blocking processes"
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_error "Failed to detach $loop_device. The device is likely still referenced by processes or the kernel"
 | 
				
			||||||
 | 
					    print_info "Processes referencing $loop_device (if any):"
 | 
				
			||||||
 | 
					    list_blocking_processes "$loop_device"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Automatic mode
 | 
					# Automatic mode
 | 
				
			||||||
@ -149,9 +266,10 @@ auto_cleanup() {
 | 
				
			|||||||
        local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
 | 
					        local file=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        echo "Processing: $device"
 | 
					        echo "Processing: $device"
 | 
				
			||||||
        unmount_loop_partitions "$device"
 | 
					        unmount_loop_partitions "$device" || true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if detach_loop_device "$device"; then
 | 
					        # In automatic cleanup assume we are allowed to force-kill blockers when necessary
 | 
				
			||||||
 | 
					        if detach_loop_device "$device" "true"; then
 | 
				
			||||||
            success=$((success+1))
 | 
					            success=$((success+1))
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            failed=$((failed+1))
 | 
					            failed=$((failed+1))
 | 
				
			||||||
@ -188,8 +306,16 @@ manual_cleanup() {
 | 
				
			|||||||
    print_info "Found loop device: $loop_device"
 | 
					    print_info "Found loop device: $loop_device"
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unmount_loop_partitions "$loop_device"
 | 
					    unmount_loop_partitions "$loop_device" || true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Ask user whether to force if needed
 | 
				
			||||||
 | 
					    read -p "Force-kill processes using $loop_device if necessary? (y/N): " force_ans
 | 
				
			||||||
 | 
					    force_ans=${force_ans:-N}
 | 
				
			||||||
 | 
					    if [ "$force_ans" = "y" ] || [ "$force_ans" = "Y" ]; then
 | 
				
			||||||
 | 
					        detach_loop_device "$loop_device" "true"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
        detach_loop_device "$loop_device"
 | 
					        detach_loop_device "$loop_device"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
    print_success "Cleanup complete for: $target"
 | 
					    print_success "Cleanup complete for: $target"
 | 
				
			||||||
@ -251,8 +377,15 @@ interactive_cleanup() {
 | 
				
			|||||||
    print_info "Cleaning up: $device -> $file"
 | 
					    print_info "Cleaning up: $device -> $file"
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unmount_loop_partitions "$device"
 | 
					    unmount_loop_partitions "$device" || true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    read -p "Force-kill processes using $device if necessary? (y/N): " force_ans
 | 
				
			||||||
 | 
					    force_ans=${force_ans:-N}
 | 
				
			||||||
 | 
					    if [ "$force_ans" = "y" ] || [ "$force_ans" = "Y" ]; then
 | 
				
			||||||
 | 
					        detach_loop_device "$device" "true"
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
        detach_loop_device "$device"
 | 
					        detach_loop_device "$device"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
    print_success "Cleanup complete"
 | 
					    print_success "Cleanup complete"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										357
									
								
								pseudodisk.sh
									
									
									
									
									
								
							
							
						
						
									
										357
									
								
								pseudodisk.sh
									
									
									
									
									
								
							@ -4,7 +4,8 @@
 | 
				
			|||||||
# Creates disk images with various filesystems for forensic analysis practice
 | 
					# Creates disk images with various filesystems for forensic analysis practice
 | 
				
			||||||
# Now with improved UX, sanity checks, and extended filesystem support
 | 
					# Now with improved UX, sanity checks, and extended filesystem support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#set -e  # Exit on error
 | 
					set -e
 | 
				
			||||||
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Color codes for output
 | 
					# Color codes for output
 | 
				
			||||||
RED='\033[0;31m'
 | 
					RED='\033[0;31m'
 | 
				
			||||||
@ -15,6 +16,9 @@ CYAN='\033[0;36m'
 | 
				
			|||||||
MAGENTA='\033[0;35m'
 | 
					MAGENTA='\033[0;35m'
 | 
				
			||||||
NC='\033[0m' # No Color
 | 
					NC='\033[0m' # No Color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Initialize mount points array to avoid bad-substitution errors when cleanup runs
 | 
				
			||||||
 | 
					MOUNT_POINTS=()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Function to print colored messages
 | 
					# Function to print colored messages
 | 
				
			||||||
print_info() {
 | 
					print_info() {
 | 
				
			||||||
    echo -e "${BLUE}[INFO]${NC} $1"
 | 
					    echo -e "${BLUE}[INFO]${NC} $1"
 | 
				
			||||||
@ -101,68 +105,48 @@ check_filesystem_tools() {
 | 
				
			|||||||
    echo "Checking filesystem tool availability..."
 | 
					    echo "Checking filesystem tool availability..."
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # FAT12/16
 | 
					    # Each entry: Display Name | space-separated candidate commands | install hint / note
 | 
				
			||||||
    if command -v mkfs.fat >/dev/null 2>&1 || command -v mkfs.vfat >/dev/null 2>&1; then
 | 
					    local checks=(
 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} FAT12/16 (mkfs.fat available)"
 | 
					        "FAT12/16|mkfs.fat mkfs.msdos mkfs.vfat|sudo apt-get install dosfstools"
 | 
				
			||||||
    else
 | 
					        "FAT32|mkfs.vfat mkfs.fat|sudo apt-get install dosfstools"
 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} FAT12/16 (install: sudo apt-get install dosfstools)"
 | 
					        "exFAT|mkfs.exfat mkfs.exfatprogs mkfs.exfat-utils|sudo apt-get install exfatprogs or exfat-utils"
 | 
				
			||||||
 | 
					        "NTFS|mkfs.ntfs mkntfs|sudo apt-get install ntfs-3g"
 | 
				
			||||||
 | 
					        "ext2|mkfs.ext2 mke2fs|sudo apt-get install e2fsprogs"
 | 
				
			||||||
 | 
					        "ext3|mkfs.ext3 mke2fs|sudo apt-get install e2fsprogs"
 | 
				
			||||||
 | 
					        "ext4|mkfs.ext4 mke2fs|sudo apt-get install e2fsprogs"
 | 
				
			||||||
 | 
					        "XFS|mkfs.xfs|sudo apt-get install xfsprogs"
 | 
				
			||||||
 | 
					        "HFS+|mkfs.hfsplus newfs_hfs|sudo apt-get install hfsprogs"
 | 
				
			||||||
 | 
					        "APFS|mkfs.apfs apfs-fuse|limited support — creation typically requires macOS or specialized tools"
 | 
				
			||||||
 | 
					        "swap|mkswap|should be present in util-linux"
 | 
				
			||||||
 | 
					        "Unallocated|:|no mkfs required"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    local entry name cmds hint cmd found
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for entry in "${checks[@]}"; do
 | 
				
			||||||
 | 
					        # Split the packed entry into three fields
 | 
				
			||||||
 | 
					        IFS='|' read -r name cmds hint <<< "$entry"
 | 
				
			||||||
 | 
					        found=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # If cmds is a single colon, treat it as 'no tool required'
 | 
				
			||||||
 | 
					        if [ "$cmds" = ":" ]; then
 | 
				
			||||||
 | 
					            printf "  %b %s (%s)\n" "${GREEN}✓${NC}" "$name" "$hint"
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # FAT32
 | 
					        # Check each candidate command for the filesystem
 | 
				
			||||||
    if command -v mkfs.vfat >/dev/null 2>&1; then
 | 
					        for cmd in $cmds; do
 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} FAT32    (mkfs.vfat available)"
 | 
					            if command -v "$cmd" >/dev/null 2>&1; then
 | 
				
			||||||
    else
 | 
					                printf "  %b %-12s (%s available)\n" "${GREEN}✓${NC}" "$name" "$cmd"
 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} FAT32    (install: sudo apt-get install dosfstools)"
 | 
					                found=1
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
 | 
					        done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # exFAT
 | 
					        if [ "$found" -eq 0 ]; then
 | 
				
			||||||
    if command -v mkfs.exfat >/dev/null 2>&1; then
 | 
					            printf "  %b %-12s (install: %s)\n" "${YELLOW}✗${NC}" "$name" "$hint"
 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} exFAT    (mkfs.exfat available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} exFAT    (install: sudo apt-get install exfatprogs)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # NTFS
 | 
					 | 
				
			||||||
    if command -v mkfs.ntfs >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} NTFS     (mkfs.ntfs available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} NTFS     (install: sudo apt-get install ntfs-3g)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # ext2/3/4
 | 
					 | 
				
			||||||
    if command -v mkfs.ext4 >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} ext2/3/4 (mkfs.ext4 available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} ext2/3/4 (install: sudo apt-get install e2fsprogs)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # XFS
 | 
					 | 
				
			||||||
    if command -v mkfs.xfs >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} XFS      (mkfs.xfs available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} XFS      (install: sudo apt-get install xfsprogs)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # HFS+
 | 
					 | 
				
			||||||
    if command -v mkfs.hfsplus >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} HFS+     (mkfs.hfsplus available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} HFS+     (install: sudo apt-get install hfsprogs)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # APFS
 | 
					 | 
				
			||||||
    if command -v mkfs.apfs >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} APFS     (mkfs.apfs available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} APFS     (limited Linux support - not recommended)"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # swap
 | 
					 | 
				
			||||||
    if command -v mkswap >/dev/null 2>&1; then
 | 
					 | 
				
			||||||
        echo -e "  ${GREEN}✓${NC} swap     (mkswap available)"
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        echo -e "  ${YELLOW}✗${NC} swap     (should be in util-linux)"
 | 
					 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
 | 
					    done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -296,16 +280,30 @@ get_filename() {
 | 
				
			|||||||
    read -p "Enter output filename (default: forensic_disk.dd): " FILENAME
 | 
					    read -p "Enter output filename (default: forensic_disk.dd): " FILENAME
 | 
				
			||||||
    FILENAME=${FILENAME:-forensic_disk.dd}
 | 
					    FILENAME=${FILENAME:-forensic_disk.dd}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Validate filename
 | 
					    # Strip whitespace
 | 
				
			||||||
    if [[ "$FILENAME" =~ [^a-zA-Z0-9._-] ]]; then
 | 
					    FILENAME=$(echo "$FILENAME" | xargs)
 | 
				
			||||||
        print_warning "Filename contains special characters. This may cause issues."
 | 
					
 | 
				
			||||||
        read -p "Continue with this filename? (y/n): " continue
 | 
					    # Reject invalid characters (allow only safe chars)
 | 
				
			||||||
        if [ "$continue" != "y" ]; then
 | 
					    if [[ ! "$FILENAME" =~ ^[a-zA-Z0-9._-]+$ ]]; then
 | 
				
			||||||
 | 
					        print_error "Filename can only contain: letters, numbers, dots, underscores, hyphens"
 | 
				
			||||||
        get_filename
 | 
					        get_filename
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Prevent path traversal and absolute paths
 | 
				
			||||||
 | 
					    if [[ "$FILENAME" == *".."* ]] || [[ "$FILENAME" == /* ]]; then
 | 
				
			||||||
 | 
					        print_error "Path traversal not allowed"
 | 
				
			||||||
 | 
					        get_filename
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Ensure .dd extension
 | 
				
			||||||
 | 
					    if [[ "$FILENAME" != *.dd ]]; then
 | 
				
			||||||
 | 
					        FILENAME="${FILENAME}.dd"
 | 
				
			||||||
 | 
					        print_info "Added .dd extension: $FILENAME"
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Check if file exists
 | 
				
			||||||
    if [ -f "$FILENAME" ]; then
 | 
					    if [ -f "$FILENAME" ]; then
 | 
				
			||||||
        print_warning "File already exists: $FILENAME"
 | 
					        print_warning "File already exists: $FILENAME"
 | 
				
			||||||
        read -p "Overwrite? (y/n): " OVERWRITE
 | 
					        read -p "Overwrite? (y/n): " OVERWRITE
 | 
				
			||||||
@ -337,20 +335,39 @@ get_disk_size() {
 | 
				
			|||||||
        4) DISK_SIZE_MB=5120 ;;
 | 
					        4) DISK_SIZE_MB=5120 ;;
 | 
				
			||||||
        5) DISK_SIZE_MB=10240 ;;
 | 
					        5) DISK_SIZE_MB=10240 ;;
 | 
				
			||||||
        6)
 | 
					        6)
 | 
				
			||||||
 | 
					            while true; do
 | 
				
			||||||
                read -p "Enter size in MB: " DISK_SIZE_MB
 | 
					                read -p "Enter size in MB: " DISK_SIZE_MB
 | 
				
			||||||
            if ! [[ "$DISK_SIZE_MB" =~ ^[0-9]+$ ]] || [ "$DISK_SIZE_MB" -lt 10 ]; then
 | 
					
 | 
				
			||||||
                print_error "Invalid size. Must be at least 10 MB"
 | 
					                # Validate input
 | 
				
			||||||
                get_disk_size
 | 
					                if ! [[ "$DISK_SIZE_MB" =~ ^[0-9]+$ ]]; then
 | 
				
			||||||
                return
 | 
					                    print_error "Invalid input. Enter a number."
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
            if [ "$DISK_SIZE_MB" -gt 102400 ]; then
 | 
					
 | 
				
			||||||
                print_warning "Very large disk size (>100GB). This may take a while."
 | 
					                if [ "$DISK_SIZE_MB" -lt 10 ]; then
 | 
				
			||||||
                read -p "Continue? (y/n): " continue
 | 
					                    print_error "Minimum size is 10 MB"
 | 
				
			||||||
                if [ "$continue" != "y" ]; then
 | 
					                    continue
 | 
				
			||||||
                    get_disk_size
 | 
					 | 
				
			||||||
                    return
 | 
					 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Maximum 10TB (reasonable limit)
 | 
				
			||||||
 | 
					                if [ "$DISK_SIZE_MB" -gt 10485760 ]; then
 | 
				
			||||||
 | 
					                    print_error "Maximum size is 10TB (10485760 MB)"
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Check available disk space
 | 
				
			||||||
 | 
					                local available_kb
 | 
				
			||||||
 | 
					                available_kb=$(df --output=avail -k "." | tail -1)
 | 
				
			||||||
 | 
					                local required_kb=$((DISK_SIZE_MB * 1024))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if [ "$available_kb" -lt "$required_kb" ]; then
 | 
				
			||||||
 | 
					                    local available_mb=$((available_kb / 1024))
 | 
				
			||||||
 | 
					                    print_error "Not enough disk space. Available: ${available_mb}MB"
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            done
 | 
				
			||||||
            ;;
 | 
					            ;;
 | 
				
			||||||
        *)
 | 
					        *)
 | 
				
			||||||
            print_error "Invalid choice"
 | 
					            print_error "Invalid choice"
 | 
				
			||||||
@ -601,12 +618,19 @@ apply_preset() {
 | 
				
			|||||||
            ;;
 | 
					            ;;
 | 
				
			||||||
        9)  # Linux with /home
 | 
					        9)  # Linux with /home
 | 
				
			||||||
            local root_size=$((DISK_SIZE_MB / 4))
 | 
					            local root_size=$((DISK_SIZE_MB / 4))
 | 
				
			||||||
            if [ "$root_size" -lt 5120 ]; then
 | 
					            local min_root=5120
 | 
				
			||||||
                root_size=5120  # Minimum 5GB for root
 | 
					
 | 
				
			||||||
 | 
					            if [ "$root_size" -lt "$min_root" ]; then
 | 
				
			||||||
 | 
					                # Check if disk is large enough for minimum
 | 
				
			||||||
 | 
					                if [ "$DISK_SIZE_MB" -lt "$((min_root + 1024))" ]; then
 | 
				
			||||||
 | 
					                    # Disk too small, use proportional sizing
 | 
				
			||||||
 | 
					                    root_size=$((DISK_SIZE_MB * 2 / 3))
 | 
				
			||||||
 | 
					                    print_warning "Disk too small for 5GB root, using ${root_size}MB"
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    root_size=$min_root
 | 
				
			||||||
                fi
 | 
					                fi
 | 
				
			||||||
            if [ "$root_size" -gt $((DISK_SIZE_MB - 1024)) ]; then
 | 
					 | 
				
			||||||
                root_size=$((DISK_SIZE_MB / 2))  # If not enough space, use half
 | 
					 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            PARTITION_CONFIGS+=("vfat|260|EFI")
 | 
					            PARTITION_CONFIGS+=("vfat|260|EFI")
 | 
				
			||||||
            PARTITION_CONFIGS+=("ext4|${root_size}|rootfs")
 | 
					            PARTITION_CONFIGS+=("ext4|${root_size}|rootfs")
 | 
				
			||||||
            PARTITION_CONFIGS+=("ext4|remaining|home")
 | 
					            PARTITION_CONFIGS+=("ext4|remaining|home")
 | 
				
			||||||
@ -938,36 +962,65 @@ create_disk_image() {
 | 
				
			|||||||
    case $INIT_METHOD in
 | 
					    case $INIT_METHOD in
 | 
				
			||||||
        fallocate)
 | 
					        fallocate)
 | 
				
			||||||
            if command -v fallocate >/dev/null 2>&1; then
 | 
					            if command -v fallocate >/dev/null 2>&1; then
 | 
				
			||||||
                fallocate -l ${DISK_SIZE_MB}M "$FILENAME"
 | 
					                if ! fallocate -l ${DISK_SIZE_MB}M "$FILENAME"; then
 | 
				
			||||||
 | 
					                    print_error "Failed to create disk image with fallocate"
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                print_warning "fallocate not available, falling back to /dev/zero"
 | 
					                print_warning "fallocate not available, falling back to /dev/zero"
 | 
				
			||||||
                dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
 | 
					                if ! dd if=/dev/zero of="$FILENAME" bs=1M count="$DISK_SIZE_MB" status=progress; then
 | 
				
			||||||
 | 
					                    print_error "Failed to create disk image"
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
            ;;
 | 
					            ;;
 | 
				
			||||||
        zero)
 | 
					        zero)
 | 
				
			||||||
            dd if=/dev/zero of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
 | 
					            if ! dd if=/dev/zero of="$FILENAME" bs=1M count="$DISK_SIZE_MB" status=progress; then
 | 
				
			||||||
 | 
					                print_error "Failed to create disk image"
 | 
				
			||||||
 | 
					                exit 1
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
            ;;
 | 
					            ;;
 | 
				
			||||||
        random)
 | 
					        random)
 | 
				
			||||||
            print_warning "Using /dev/urandom - this will be SLOW!"
 | 
					            print_warning "Using /dev/urandom - this will be SLOW!"
 | 
				
			||||||
            dd if=/dev/urandom of="$FILENAME" bs=1M count=$DISK_SIZE_MB status=progress 2>&1 | grep -v "records"
 | 
					            if ! dd if=/dev/urandom of="$FILENAME" bs=1M count="$DISK_SIZE_MB" status=progress; then
 | 
				
			||||||
 | 
					                print_error "Failed to create disk image"
 | 
				
			||||||
 | 
					                exit 1
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
            ;;
 | 
					            ;;
 | 
				
			||||||
    esac
 | 
					    esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print_success "Disk image created with $INIT_METHOD"
 | 
					    # Verify file was created with correct size
 | 
				
			||||||
 | 
					    if [ ! -f "$FILENAME" ]; then
 | 
				
			||||||
 | 
					        print_error "Disk image file was not created"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    local actual_size
 | 
				
			||||||
 | 
					    actual_size=$(stat -c%s "$FILENAME" 2>/dev/null || stat -f%z "$FILENAME" 2>/dev/null || echo 0)
 | 
				
			||||||
 | 
					    local expected_size=$((DISK_SIZE_MB * 1024 * 1024))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if [ "$actual_size" -ne "$expected_size" ]; then
 | 
				
			||||||
 | 
					        print_error "Disk image size mismatch (expected ${expected_size} bytes, got ${actual_size})"
 | 
				
			||||||
 | 
					        rm -f "$FILENAME"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_success "Disk image created and verified"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Setup loop device
 | 
					# Setup loop device
 | 
				
			||||||
setup_loop_device() {
 | 
					setup_loop_device() {
 | 
				
			||||||
    print_info "Setting up loop device..."
 | 
					    print_info "Setting up loop device..."
 | 
				
			||||||
    LOOP_DEVICE=$(losetup -f)
 | 
					
 | 
				
			||||||
 | 
					    # Use atomic operation (find + attach in one command)
 | 
				
			||||||
 | 
					    LOOP_DEVICE=$(losetup -f --show "$FILENAME" 2>/dev/null || true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if [ -z "$LOOP_DEVICE" ]; then
 | 
					    if [ -z "$LOOP_DEVICE" ]; then
 | 
				
			||||||
        print_error "No free loop devices available"
 | 
					        print_error "Failed to create loop device"
 | 
				
			||||||
        print_info "Try: sudo modprobe loop max_loop=16"
 | 
					        print_info "Try: sudo modprobe loop max_loop=16"
 | 
				
			||||||
        exit 1
 | 
					        exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    losetup "$LOOP_DEVICE" "$FILENAME"
 | 
					 | 
				
			||||||
    print_success "Loop device created: $LOOP_DEVICE"
 | 
					    print_success "Loop device created: $LOOP_DEVICE"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1037,76 +1090,162 @@ create_partitions() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Format the partitions
 | 
					# Format the partitions
 | 
				
			||||||
format_partitions() {
 | 
					format_partitions() {
 | 
				
			||||||
    local part_num=1
 | 
					    local config_num=1
 | 
				
			||||||
 | 
					    local actual_part_num=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for config in "${PARTITION_CONFIGS[@]}"; do
 | 
					    for config in "${PARTITION_CONFIGS[@]}"; do
 | 
				
			||||||
        IFS='|' read -r fs size label <<< "$config"
 | 
					        IFS='|' read -r fs size label <<< "$config"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Skip unallocated space - no partition to format
 | 
					 | 
				
			||||||
        if [ "$fs" = "unallocated" ]; then
 | 
					        if [ "$fs" = "unallocated" ]; then
 | 
				
			||||||
            print_info "Skipping unallocated space (no partition to format)"
 | 
					            print_info "Skipping unallocated space in config $config_num"
 | 
				
			||||||
 | 
					            config_num=$((config_num + 1))
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Determine partition device name
 | 
					        # Determine partition device name
 | 
				
			||||||
        PARTITION="${LOOP_DEVICE}p${part_num}"
 | 
					        PARTITION="${LOOP_DEVICE}p${actual_part_num}"
 | 
				
			||||||
        if [ ! -e "$PARTITION" ]; then
 | 
					        if [ ! -e "$PARTITION" ]; then
 | 
				
			||||||
            PARTITION="${LOOP_DEVICE}${part_num}"
 | 
					            PARTITION="${LOOP_DEVICE}${actual_part_num}"
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if [ ! -e "$PARTITION" ]; then
 | 
					        if [ ! -e "$PARTITION" ]; then
 | 
				
			||||||
            print_error "Cannot find partition device for partition $part_num"
 | 
					            print_error "Cannot find partition device for config $config_num (expected ${LOOP_DEVICE}p${actual_part_num} or ${LOOP_DEVICE}${actual_part_num})"
 | 
				
			||||||
            print_info "Expected: ${LOOP_DEVICE}p${part_num} or ${LOOP_DEVICE}${part_num}"
 | 
					 | 
				
			||||||
            cleanup
 | 
					            cleanup
 | 
				
			||||||
            exit 1
 | 
					            exit 1
 | 
				
			||||||
        fi
 | 
					        fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print_info "Formatting partition $part_num ($PARTITION) with $fs filesystem..."
 | 
					        print_info "Formatting config #${config_num} -> partition ${actual_part_num} ($PARTITION) with $fs filesystem..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case $fs in
 | 
					        case $fs in
 | 
				
			||||||
            fat12)
 | 
					            fat12)
 | 
				
			||||||
                # FAT12 requires specific cluster size
 | 
					                output=$(mkfs.fat -F 12 -n "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
                mkfs.fat -F 12 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as FAT12"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            fat16)
 | 
					            fat16)
 | 
				
			||||||
                # FAT16
 | 
					                output=$(mkfs.fat -F 16 -n "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
                mkfs.fat -F 16 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as FAT16"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            vfat)
 | 
					            vfat)
 | 
				
			||||||
                # FAT32
 | 
					                output=$(mkfs.vfat -F 32 -n "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
                mkfs.vfat -F 32 -n "$label" "$PARTITION" 2>&1 | grep -v "^mkfs.fat"
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as FAT32"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            ntfs)
 | 
					            ntfs)
 | 
				
			||||||
                mkfs.ntfs -f -L "$label" "$PARTITION" 2>&1 | grep -E "^(Cluster|Creating|mkntfs completed)"
 | 
					                output=$(mkfs.ntfs -f -L "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as NTFS"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | grep -E "^(Cluster|Creating|mkntfs completed)" || true
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            exfat)
 | 
					            exfat)
 | 
				
			||||||
                mkfs.exfat -n "$label" "$PARTITION" 2>&1 | grep -v "^exfatprogs"
 | 
					                output=$(mkfs.exfat -n "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as exFAT"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            ext2|ext3|ext4)
 | 
					            ext2|ext3|ext4)
 | 
				
			||||||
                mkfs."$fs" -L "$label" "$PARTITION" 2>&1 | grep -E "^(Creating|Writing|mke2fs)"
 | 
					                output=$(mkfs."$fs" -L "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as $fs"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | grep -E "^(Creating|Writing|mke2fs)" || true
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            xfs)
 | 
					            xfs)
 | 
				
			||||||
                mkfs.xfs -f -L "$label" "$PARTITION" 2>&1 | grep -v "^meta-data"
 | 
					                output=$(mkfs.xfs -f -L "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as XFS"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            hfsplus)
 | 
					            hfsplus)
 | 
				
			||||||
                mkfs.hfsplus -v "$label" "$PARTITION" 2>&1
 | 
					                output=$(mkfs.hfsplus -v "$label" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to format partition ${actual_part_num} as HFS+"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | sed -n '1,50p'
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            apfs)
 | 
					            apfs)
 | 
				
			||||||
                print_warning "APFS formatting on Linux is not well supported"
 | 
					                print_warning "APFS formatting on Linux is not well supported"
 | 
				
			||||||
                print_info "Skipping format for APFS partition"
 | 
					                print_info "Skipping format for APFS partition"
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
            swap)
 | 
					            swap)
 | 
				
			||||||
                mkswap -L "SWAP$part_num" "$PARTITION" 2>&1 | grep "^Setting up"
 | 
					                output=$(mkswap -L "SWAP${actual_part_num}" "$PARTITION" 2>&1)
 | 
				
			||||||
 | 
					                ret=$?
 | 
				
			||||||
 | 
					                if [ $ret -ne 0 ]; then
 | 
				
			||||||
 | 
					                    print_error "Failed to set up swap on partition ${actual_part_num}"
 | 
				
			||||||
 | 
					                    echo "$output"
 | 
				
			||||||
 | 
					                    cleanup
 | 
				
			||||||
 | 
					                    exit 1
 | 
				
			||||||
 | 
					                fi
 | 
				
			||||||
 | 
					                echo "$output" | grep -E "^Setting up" || true
 | 
				
			||||||
 | 
					                ;;
 | 
				
			||||||
 | 
					            *)
 | 
				
			||||||
 | 
					                print_warning "Unknown filesystem type: $fs - skipping format"
 | 
				
			||||||
                ;;
 | 
					                ;;
 | 
				
			||||||
        esac
 | 
					        esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print_success "Partition $part_num formatted"
 | 
					        print_success "Partition ${actual_part_num} formatted (config ${config_num})"
 | 
				
			||||||
        part_num=$((part_num + 1))
 | 
					        actual_part_num=$((actual_part_num + 1))
 | 
				
			||||||
 | 
					        config_num=$((config_num + 1))
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Cleanup function
 | 
					# Cleanup function
 | 
				
			||||||
cleanup() {
 | 
					cleanup() {
 | 
				
			||||||
 | 
					    # Unmount any mounted filesystems
 | 
				
			||||||
 | 
					    if [ "${#MOUNT_POINTS[@]}" -gt 0 ]; then
 | 
				
			||||||
 | 
					        print_info "Unmounting filesystems..."
 | 
				
			||||||
 | 
					        for mp in "${MOUNT_POINTS[@]}"; do
 | 
				
			||||||
 | 
					            if mountpoint -q "$mp" 2>/dev/null; then
 | 
				
			||||||
 | 
					                umount "$mp" 2>/dev/null || umount -l "$mp" 2>/dev/null || true
 | 
				
			||||||
 | 
					                print_info "Unmounted $mp"
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
 | 
					            rmdir "$mp" 2>/dev/null || true
 | 
				
			||||||
 | 
					        done
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Detach loop device
 | 
				
			||||||
    if [ -n "$LOOP_DEVICE" ]; then
 | 
					    if [ -n "$LOOP_DEVICE" ]; then
 | 
				
			||||||
        print_info "Cleaning up loop device..."
 | 
					        print_info "Cleaning up loop device..."
 | 
				
			||||||
        losetup -d "$LOOP_DEVICE" 2>/dev/null || true
 | 
					        losetup -d "$LOOP_DEVICE" 2>/dev/null || true
 | 
				
			||||||
@ -1208,7 +1347,7 @@ show_summary() {
 | 
				
			|||||||
        config_num=$((config_num + 1))
 | 
					        config_num=$((config_num + 1))
 | 
				
			||||||
    done
 | 
					    done
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
 | 
					    if [ "${#MOUNT_POINTS[@]}" -gt 0 ]; then
 | 
				
			||||||
        echo ""
 | 
					        echo ""
 | 
				
			||||||
        echo "Mount Points:"
 | 
					        echo "Mount Points:"
 | 
				
			||||||
        for mp in "${MOUNT_POINTS[@]}"; do
 | 
					        for mp in "${MOUNT_POINTS[@]}"; do
 | 
				
			||||||
@ -1239,7 +1378,7 @@ show_summary() {
 | 
				
			|||||||
    echo "  xxd -s 0x1BE -l 64 $FILENAME      # MBR partition table"
 | 
					    echo "  xxd -s 0x1BE -l 64 $FILENAME      # MBR partition table"
 | 
				
			||||||
    echo ""
 | 
					    echo ""
 | 
				
			||||||
    echo "Clean up (when done):"
 | 
					    echo "Clean up (when done):"
 | 
				
			||||||
    if [ ${#MOUNT_POINTS[@]} -gt 0 ]; then
 | 
					    if [ "${#MOUNT_POINTS[@]}" -gt 0 ]; then
 | 
				
			||||||
        for mp in "${MOUNT_POINTS[@]}"; do
 | 
					        for mp in "${MOUNT_POINTS[@]}"; do
 | 
				
			||||||
            echo "  sudo umount $mp"
 | 
					            echo "  sudo umount $mp"
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user