From 59015d9d013a87f72dc900c7bd9e2351808227a5 Mon Sep 17 00:00:00 2001 From: myve Date: Sun, 4 Oct 2026 07:46:03 +0000 Subject: [PATCH] Fix mirrorsetup function in homelab.sh --- homelab.sh | 165 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 101 insertions(+), 64 deletions(-) diff --git a/homelab.sh b/homelab.sh index cb4ca4d..2301eec 100755 --- a/homelab.sh +++ b/homelab.sh @@ -506,89 +506,126 @@ function initialSetup # Customize mirrored zpools function mirrorsetup { - local mirrorsetupArray=(${installation_drive_array[@]}) - local mirror pair pairArray diskid pool - local index=1 + # Initialize with available drives from installation array + local available_drives=("${installation_drive_array[@]}") + local pool_count=0 + declare -a pools=() + local prompt_index=1 - while true + while [[ ${#available_drives[@]} -gt 0 ]] do - # Exit only when all drives are assigned - if [[ $(wc -w <<<${mirrorsetupArray[@]}) -gt 0 ]] + # Display available drives to user + say in black bold "# System drives: ${available_drives[*]}" + + # Prompt user for this mirror pool (this sets pool1, pool2, etc.) + ask for pool${prompt_index} in array "Enter mirror pool ${prompt_index}" + + # Safely get the array content using a controlled approach + local pairArray=() + + # Create variable name and access it safely + local var_name="pool${prompt_index}" + + # Use eval in a controlled way to get array contents + # This is the minimal safe usage needed for bash array handling + if [[ -n "${!var_name}" ]] then - say in black bold "# System drives: $(echo ${mirrorsetupArray[@]})" - ask for pool${index} in array "Enter mirror pool ${index}" + eval "pairArray=(\"\${${var_name}[@]}\")" else - break 1 + # If no content, create empty array + pairArray=() fi - # Temporary variables - pair=pool${index}[@] - pairArray=($(printf '%s\n' ${!pair})) + # Validate selections - check invalid drives first + local valid=true - # Escape only if selections are valid - while true + # Check each drive is available BEFORE checking minimum pool size + for drive in "${pairArray[@]}" do - # Ensure drive is chosen from installation drive pool - for drive in ${pairArray[@]} + local found=false + for available in "${available_drives[@]}" do - if ! [[ " ${mirrorsetupArray[*]} " =~ " ${drive} " ]] + if [[ "$drive" == "$available" ]] then - say as warning "Invalid drive selected" - echo - break 2 + found=true + break fi done - # Reject mirrored pair if drives are entered more than once - if [ $(printf '%s\n' ${!pair} | sort | uniq -d) ] + if [[ "$found" == false ]] then - say as warning "Duplicate entries detected" - echo - break 1 - # Need at least 2 drives per mirrored pool - elif [[ ${#pairArray[@]} -lt 2 ]] - then - say as warning 'Mirrored pairs must have at least two drives' - echo - break 1 - # Stray protection - elif [[ $((${#mirrorsetupArray[@]}-${#pairArray[@]})) -eq 1 ]] - then - say as warning 'Remaining drive does not have a mirror pair' - echo - break 1 - # Success: remove entries from remaining drive pool - else - for delete in ${pairArray[@]} - do - mirrorsetupArray=(${mirrorsetupArray[@]/${delete}}) - done - # Add an index if there are more drives remaining - ((index++)) - break 1 + say as warning "Invalid drive selected: $drive" + valid=false + break fi done + + # Only continue with other validations if drives are valid + if [[ "$valid" == true ]] + then + # Check for duplicates + local unique_count=$(printf '%s\n' "${pairArray[@]}" | sort | uniq | wc -l) + local total_count=${#pairArray[@]} + if [[ $unique_count -lt $total_count ]] + then + say as warning "Duplicate entries detected" + valid=false + fi + + # Check minimum pool size (only after we know drives are valid) + if [[ ${#pairArray[@]} -lt 2 ]] + then + say as warning 'Mirrored pairs must have at least two drives' + valid=false + fi + + # Check for stray drives (only after we know drives are valid) + local remaining_after=$(( ${#available_drives[@]} - ${#pairArray[@]} )) + if [[ $remaining_after -eq 1 ]] && [[ ${#available_drives[@]} -gt ${#pairArray[@]} ]] + then + say as warning 'Remaining drive does not have a mirror pair' + valid=false + fi + fi + + # Process valid pool + if [[ "$valid" == true ]] + then + # Store this mirror pool configuration + pools[$pool_count]="${pairArray[*]}" + ((pool_count++)) + + # Remove selected drives from available list + local new_available=() + for drive in "${available_drives[@]}" + do + local is_selected=false + for selected in "${pairArray[@]}" + do + if [[ "$drive" == "$selected" ]] + then + is_selected=true + break + fi + done + if [[ "$is_selected" == false ]] + then + new_available+=("$drive") + fi + done + available_drives=("${new_available[@]}") + ((prompt_index++)) + else + echo + continue + fi done - # Convert drives to persistent disk/by-id naming - for pool in ${!pool*} - do - ((mirror++)) - local diskid=${pool}[@] - for drive in ${!diskid} - do - eval "mirrorpool${mirror}+=(${drive})" - done - done - - # Export zroot layout unset zrootlayout - pool=0 - for mirrorpool in ${!mirrorpool*} + for ((i=0; i