bugfix
This commit is contained in:
		
							parent
							
								
									81bc66e905
								
							
						
					
					
						commit
						f60cf35235
					
				
							
								
								
									
										264
									
								
								pseudodisk.sh
									
									
									
									
									
								
							
							
						
						
									
										264
									
								
								pseudodisk.sh
									
									
									
									
									
								
							@ -496,7 +496,7 @@ get_preset_or_custom() {
 | 
			
		||||
            PARTITION_SCHEME="msdos"
 | 
			
		||||
            PARTITION_COUNT=1
 | 
			
		||||
            print_info "Preset: MS-DOS (MBR)"
 | 
			
		||||
            print_note "Single FAT12 partition (max 16MB)"
 | 
			
		||||
            print_note "Single FAT12 partition"
 | 
			
		||||
            if [ "$DISK_SIZE_MB" -gt 16 ]; then
 | 
			
		||||
                print_warning "MS-DOS typically uses FAT12 which is limited to 16MB"
 | 
			
		||||
                print_info "Consider reducing disk size or the partition will use FAT16"
 | 
			
		||||
@ -707,7 +707,7 @@ get_partition_count() {
 | 
			
		||||
get_partition_configs() {
 | 
			
		||||
    PARTITION_CONFIGS=()
 | 
			
		||||
    local total_allocated=0
 | 
			
		||||
    local available_space=$((DISK_SIZE_MB - 2))  # Reserve 2MB for partition table
 | 
			
		||||
    local available_space=$((DISK_SIZE_MB - PARTITION_TABLE_RESERVED_MB))  # Reserve for partition table / metadata
 | 
			
		||||
    
 | 
			
		||||
    for i in $(seq 1 $PARTITION_COUNT); do
 | 
			
		||||
        echo ""
 | 
			
		||||
@ -1012,8 +1012,14 @@ create_disk_image() {
 | 
			
		||||
setup_loop_device() {
 | 
			
		||||
    print_info "Setting up loop device..."
 | 
			
		||||
 | 
			
		||||
    # Use atomic operation (find + attach in one command)
 | 
			
		||||
    LOOP_DEVICE=$(losetup -f --show "$FILENAME" 2>/dev/null || true)
 | 
			
		||||
    # Try to attach the image and ask the kernel to create partition devices (-P) when supported.
 | 
			
		||||
    # Fall back to a plain attach if -P is not available.
 | 
			
		||||
    LOOP_DEVICE=$(losetup -f --show -P "$FILENAME" 2>/dev/null || true)
 | 
			
		||||
 | 
			
		||||
    if [ -z "$LOOP_DEVICE" ]; then
 | 
			
		||||
        # older losetup may not support -P; attach without it then trigger partprobe later
 | 
			
		||||
        LOOP_DEVICE=$(losetup -f --show "$FILENAME" 2>/dev/null || true)
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ -z "$LOOP_DEVICE" ]; then
 | 
			
		||||
        print_error "Failed to create loop device"
 | 
			
		||||
@ -1027,64 +1033,252 @@ setup_loop_device() {
 | 
			
		||||
# Create partition table and partitions
 | 
			
		||||
create_partitions() {
 | 
			
		||||
    print_info "Creating $PARTITION_SCHEME partition table..."
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    parted -s "$LOOP_DEVICE" mklabel "$PARTITION_SCHEME"
 | 
			
		||||
    
 | 
			
		||||
    local start_mb=1
 | 
			
		||||
    local part_num=1
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    # Reserve a small margin at the end of the disk to avoid creating partitions that
 | 
			
		||||
    # extend into GPT backup header / metadata. This mirrors the -2MB reserve used
 | 
			
		||||
    # interactively elsewhere in the script.
 | 
			
		||||
    local PARTITION_TABLE_RESERVED_MB=2
 | 
			
		||||
    if [ "$DISK_SIZE_MB" -le $PARTITION_TABLE_RESERVED_MB ]; then
 | 
			
		||||
        print_error "Disk size (${DISK_SIZE_MB}MB) too small to reserve required metadata space"
 | 
			
		||||
        cleanup
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    local usable_mb=$((DISK_SIZE_MB - PARTITION_TABLE_RESERVED_MB))
 | 
			
		||||
 | 
			
		||||
    # Parse PARTITION_CONFIGS into arrays for easier processing
 | 
			
		||||
    local fs size label
 | 
			
		||||
    local -a fs_arr size_arr label_arr
 | 
			
		||||
    for config in "${PARTITION_CONFIGS[@]}"; do
 | 
			
		||||
        IFS='|' read -r fs size label <<< "$config"
 | 
			
		||||
        
 | 
			
		||||
        if [ "$size" = "remaining" ]; then
 | 
			
		||||
            end="100%"
 | 
			
		||||
        fs_arr+=("$fs")
 | 
			
		||||
        size_arr+=("$size")
 | 
			
		||||
        label_arr+=("$label")
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    local count=${#fs_arr[@]}
 | 
			
		||||
    if [ "$count" -eq 0 ]; then
 | 
			
		||||
        print_info "No partition configurations provided"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Convert sizes: numeric values stay numeric; 'remaining' will be resolved below
 | 
			
		||||
    local -a numeric_size
 | 
			
		||||
    local total_fixed=0
 | 
			
		||||
    local -a remaining_idxs
 | 
			
		||||
    for i in $(seq 0 $((count - 1))); do
 | 
			
		||||
        s="${size_arr[$i]}"
 | 
			
		||||
        if [ "$s" = "remaining" ]; then
 | 
			
		||||
            numeric_size[$i]=-1
 | 
			
		||||
            remaining_idxs+=("$i")
 | 
			
		||||
        else
 | 
			
		||||
            end=$(echo "$start_mb + $size" | bc)
 | 
			
		||||
            end="${end}MiB"
 | 
			
		||||
            # sanitize numeric sizes (should be integer MB)
 | 
			
		||||
            if ! [[ "$s" =~ ^[0-9]+$ ]]; then
 | 
			
		||||
                print_error "Invalid partition size for entry $((i+1)): '$s'"
 | 
			
		||||
                cleanup
 | 
			
		||||
                exit 1
 | 
			
		||||
            fi
 | 
			
		||||
            numeric_size[$i]=$s
 | 
			
		||||
            total_fixed=$((total_fixed + s))
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Distribute remaining space among 'remaining' entries using the usable space
 | 
			
		||||
    if [ "${#remaining_idxs[@]}" -gt 0 ]; then
 | 
			
		||||
        local free_space=$((usable_mb - total_fixed))
 | 
			
		||||
        if [ "$free_space" -le 0 ]; then
 | 
			
		||||
            print_error "Not enough space to satisfy 'remaining' partitions (free: ${free_space}MB)"
 | 
			
		||||
            cleanup
 | 
			
		||||
            exit 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        local rem_count=${#remaining_idxs[@]}
 | 
			
		||||
        local base=$((free_space / rem_count))
 | 
			
		||||
        local leftover=$((free_space - base * rem_count))
 | 
			
		||||
 | 
			
		||||
        for idx in "${remaining_idxs[@]}"; do
 | 
			
		||||
            numeric_size[$idx]=$base
 | 
			
		||||
            if [ "$leftover" -gt 0 ]; then
 | 
			
		||||
                numeric_size[$idx]=$((numeric_size[$idx] + 1))
 | 
			
		||||
                leftover=$((leftover - 1))
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Find last index that will actually produce a partition entry (skip 'unallocated')
 | 
			
		||||
    local last_mkpart_idx=-1
 | 
			
		||||
    for i in $(seq 0 $((count - 1))); do
 | 
			
		||||
        if [ "${fs_arr[$i]}" != "unallocated" ]; then
 | 
			
		||||
            last_mkpart_idx=$i
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # If everything is unallocated, nothing to do
 | 
			
		||||
    if [ "$last_mkpart_idx" -eq -1 ]; then
 | 
			
		||||
        print_info "All configured space is unallocated - no partition entries will be created"
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Compute how much explicit unallocated space is trailing after the last mkpart so we can reserve it
 | 
			
		||||
    local trailing_unalloc_sum=0
 | 
			
		||||
    for i in $(seq $((last_mkpart_idx + 1)) $((count - 1))); do
 | 
			
		||||
        if [ "$i" -ge 0 ] && [ "${fs_arr[$i]}" = "unallocated" ]; then
 | 
			
		||||
            trailing_unalloc_sum=$((trailing_unalloc_sum + numeric_size[$i]))
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    # Sanity checks: ensure no numeric sizes are negative and the requested layout fits within usable space
 | 
			
		||||
    local sum_all=0
 | 
			
		||||
    for i in $(seq 0 $((count - 1))); do
 | 
			
		||||
        if [ -z "${numeric_size[$i]}" ] || [ "${numeric_size[$i]}" -lt 0 ]; then
 | 
			
		||||
            print_error "Internal error: unresolved partition size for entry $((i+1))"
 | 
			
		||||
            cleanup
 | 
			
		||||
            exit 1
 | 
			
		||||
        fi
 | 
			
		||||
        sum_all=$((sum_all + numeric_size[$i]))
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    if [ "$sum_all" -gt "$usable_mb" ]; then
 | 
			
		||||
        print_error "Configured partitions (${sum_all}MB) exceed usable disk space (${usable_mb}MB) (reserved ${PARTITION_TABLE_RESERVED_MB}MB for metadata)"
 | 
			
		||||
        cleanup
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Create partitions. We'll iterate in forward order, but the last mkpart will be explicitly ended
 | 
			
		||||
    # before any trailing unallocated space so that 'unallocated' regions remain as requested.
 | 
			
		||||
    local start_mb=1
 | 
			
		||||
    local part_num=1
 | 
			
		||||
 | 
			
		||||
    # Attempt to create a partition, retrying with shrinking end boundary when parted
 | 
			
		||||
    # complains the end is outside the device (handles alignment/metadata rounding)
 | 
			
		||||
    try_mkpart() {
 | 
			
		||||
        local loopdev="$1"
 | 
			
		||||
        local start_mb="$2"
 | 
			
		||||
        local end_mb="$3"   # numeric MB
 | 
			
		||||
        local fstype="$4"   # optional parted fs type (e.g. ntfs, ext4)
 | 
			
		||||
 | 
			
		||||
        local max_attempts=8
 | 
			
		||||
        local attempt_end=$end_mb
 | 
			
		||||
        local output ret last_output
 | 
			
		||||
 | 
			
		||||
        for ((try=0; try<max_attempts; try++)); do
 | 
			
		||||
            local end_str="${attempt_end}MiB"
 | 
			
		||||
 | 
			
		||||
            if [ -n "$fstype" ]; then
 | 
			
		||||
                output=$(parted -s "$loopdev" mkpart primary "$fstype" "${start_mb}MiB" "$end_str" 2>&1)
 | 
			
		||||
                ret=$?
 | 
			
		||||
            else
 | 
			
		||||
                output=$(parted -s "$loopdev" mkpart primary "${start_mb}MiB" "$end_str" 2>&1)
 | 
			
		||||
                ret=$?
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            if [ $ret -eq 0 ]; then
 | 
			
		||||
                return 0
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            last_output="$output"
 | 
			
		||||
 | 
			
		||||
            # If the error looks like 'outside device' / 'not enough space' try shrinking the end
 | 
			
		||||
            if echo "$output" | grep -Ei 'outside|out of range|not enough space|beyond|außerhalb|außer' >/dev/null 2>&1; then
 | 
			
		||||
                print_warning "parted failed to create partition with end ${end_str} - retrying with ${attempt_end-1}MiB: $output"
 | 
			
		||||
                attempt_end=$((attempt_end - 1))
 | 
			
		||||
 | 
			
		||||
                if [ "$attempt_end" -le "$start_mb" ]; then
 | 
			
		||||
                    print_error "Cannot allocate partition: insufficient space after retries"
 | 
			
		||||
                    echo "$last_output"
 | 
			
		||||
                    cleanup
 | 
			
		||||
                    exit 1
 | 
			
		||||
                fi
 | 
			
		||||
 | 
			
		||||
                continue
 | 
			
		||||
            else
 | 
			
		||||
                print_error "parted failed creating partition: $output"
 | 
			
		||||
                cleanup
 | 
			
		||||
                exit 1
 | 
			
		||||
            fi
 | 
			
		||||
        done
 | 
			
		||||
 | 
			
		||||
        print_error "Failed to create partition after ${max_attempts} retries: $last_output"
 | 
			
		||||
        cleanup
 | 
			
		||||
        exit 1
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for i in $(seq 0 $((count - 1))); do
 | 
			
		||||
        fs="${fs_arr[$i]}"
 | 
			
		||||
        size_mb=${numeric_size[$i]}
 | 
			
		||||
        label="${label_arr[$i]}"
 | 
			
		||||
 | 
			
		||||
        if [ "$fs" = "unallocated" ]; then
 | 
			
		||||
            print_info "Leaving ${size_mb}MB unallocated (no partition entry)"
 | 
			
		||||
            start_mb=$((start_mb + size_mb))
 | 
			
		||||
            continue
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # determine end for this partition
 | 
			
		||||
        if [ "$i" -eq "$last_mkpart_idx" ]; then
 | 
			
		||||
            # Make sure last mkpart ends before any trailing unallocated space and within usable area
 | 
			
		||||
            end_mb=$((usable_mb - trailing_unalloc_sum))
 | 
			
		||||
            if [ "$start_mb" -ge "$end_mb" ]; then
 | 
			
		||||
                print_error "Not enough space to create partition $((i+1)): needed ${size_mb}MB, available $((end_mb - start_mb))MB"
 | 
			
		||||
                cleanup
 | 
			
		||||
                exit 1
 | 
			
		||||
            fi
 | 
			
		||||
            end="${end_mb}MiB"
 | 
			
		||||
            numeric_end_mb=$end_mb
 | 
			
		||||
        else
 | 
			
		||||
            end_val=$((start_mb + size_mb))
 | 
			
		||||
            # ensure we don't exceed usable area (should be caught by earlier checks)
 | 
			
		||||
            if [ "$end_val" -gt "$usable_mb" ]; then
 | 
			
		||||
                print_error "Partition $((i+1)) would exceed usable disk area (end ${end_val}MB > usable ${usable_mb}MB)"
 | 
			
		||||
                cleanup
 | 
			
		||||
                exit 1
 | 
			
		||||
            fi
 | 
			
		||||
            end="${end_val}MiB"
 | 
			
		||||
            numeric_end_mb=$end_val
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        print_info "Creating partition $part_num: ${start_mb}MiB -> $end"
 | 
			
		||||
        
 | 
			
		||||
        # Set partition type based on filesystem
 | 
			
		||||
 | 
			
		||||
        case $fs in
 | 
			
		||||
            swap)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary linux-swap "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" linux-swap
 | 
			
		||||
                ;;
 | 
			
		||||
            fat12|fat16|vfat)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary fat32 "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" fat32
 | 
			
		||||
                ;;
 | 
			
		||||
            ntfs)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary ntfs "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" ntfs
 | 
			
		||||
                ;;
 | 
			
		||||
            ext2|ext3|ext4)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary ext4 "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" ext4
 | 
			
		||||
                ;;
 | 
			
		||||
            xfs)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary xfs "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" xfs
 | 
			
		||||
                ;;
 | 
			
		||||
            hfsplus)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary hfs+ "${start_mb}MiB" "$end"
 | 
			
		||||
                ;;
 | 
			
		||||
            unallocated)
 | 
			
		||||
                # Don't create a partition for unallocated space - just leave it empty
 | 
			
		||||
                print_info "Leaving space unallocated (no partition entry)"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" hfs+
 | 
			
		||||
                ;;
 | 
			
		||||
            *)
 | 
			
		||||
                parted -s "$LOOP_DEVICE" mkpart primary "${start_mb}MiB" "$end"
 | 
			
		||||
                try_mkpart "$LOOP_DEVICE" "$start_mb" "$numeric_end_mb" ""
 | 
			
		||||
                ;;
 | 
			
		||||
        esac
 | 
			
		||||
        
 | 
			
		||||
        if [ "$size" != "remaining" ]; then
 | 
			
		||||
            start_mb=$(echo "$start_mb + $size" | bc)
 | 
			
		||||
 | 
			
		||||
        # advance start pointer for next partition (skip this for the explicitly-ended last mkpart)
 | 
			
		||||
        if [ "$i" -ne "$last_mkpart_idx" ]; then
 | 
			
		||||
            start_mb=$((start_mb + size_mb))
 | 
			
		||||
        else
 | 
			
		||||
            start_mb=$((end_mb))
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        part_num=$((part_num + 1))
 | 
			
		||||
    done
 | 
			
		||||
    
 | 
			
		||||
    # Inform kernel about partition table changes
 | 
			
		||||
 | 
			
		||||
    # Inform kernel about partition table changes and give it a moment to create /dev nodes
 | 
			
		||||
    partprobe "$LOOP_DEVICE" 2>/dev/null || true
 | 
			
		||||
    sleep 2
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    print_success "Partitions created"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user