Fix mirrorsetup function in homelab.sh

This commit is contained in:
myve 2026-10-04 07:46:03 +00:00
commit 59015d9d01

View file

@ -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<pool_count; i++))
do
((pool++))
zpool=${mirrorpool}[@]
say as success "zroot mirror ${pool}: ${!zpool}"
zrootlayout+=($(echo "mirror ${!zpool}"))
local drives="${pools[$i]}"
say as success "zroot mirror $((i+1)): ${drives}"
zrootlayout+=("mirror ${drives}")
done
echo
}