Updated NoNag for PVE 8.4.5+, and improved logging

Proxmox changed their Nag screen code in 8.4.5, so the fix changed.  The fix is from 0f3b95b3ff

Added a main.log that logs everything, and it still logs specific sections. display_and_log replaces the echo command for most things.
This commit is contained in:
jaminmc 2025-07-22 17:19:32 -04:00
parent 46187c808c
commit 65d027b7f4
1 changed files with 85 additions and 63 deletions

146
setup
View File

@ -35,6 +35,7 @@ set -e
# Constants # Constants
SCRIPT_DIR="/root/OSX-PROXMOX" SCRIPT_DIR="/root/OSX-PROXMOX"
LOGDIR="${SCRIPT_DIR}/logs" LOGDIR="${SCRIPT_DIR}/logs"
MAIN_LOG="${LOGDIR}/main.log"
TMPDIR="${SCRIPT_DIR}/tmp" TMPDIR="${SCRIPT_DIR}/tmp"
HACKPXVERSION="2025.06.27" HACKPXVERSION="2025.06.27"
OCVERSION="1.0.4" OCVERSION="1.0.4"
@ -60,15 +61,26 @@ declare -A MACOS_CONFIG=(
["8"]="Sequoia|15|Mac-7BA5B2D9E42DDD94|00000000000000000|1450M|virtio0" ["8"]="Sequoia|15|Mac-7BA5B2D9E42DDD94|00000000000000000|1450M|virtio0"
) )
# Display and log function
display_and_log() {
local message="$1"
local specific_logfile="$2"
echo "$message"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$MAIN_LOG"
if [[ -n "$specific_logfile" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$specific_logfile"
fi
}
# Cleanup function for mounts and temp files # Cleanup function for mounts and temp files
cleanup() { cleanup() {
local logfile="${LOGDIR}/cleanup.log" local logfile="${LOGDIR}/cleanup.log"
if mountpoint -q /mnt/APPLE 2>/dev/null; then if mountpoint -q /mnt/APPLE 2>/dev/null; then
umount /mnt/APPLE >>"$logfile" 2>&1 || echo "Failed to unmount /mnt/APPLE" | tee -a "$logfile" umount /mnt/APPLE >>"$logfile" 2>&1 || display_and_log "Failed to unmount /mnt/APPLE" "$logfile"
rmdir /mnt/APPLE 2>/dev/null rmdir /mnt/APPLE 2>/dev/null
fi fi
if mountpoint -q /mnt/opencore 2>/dev/null; then if mountpoint -q /mnt/opencore 2>/dev/null; then
umount /mnt/opencore >>"$logfile" 2>&1 || echo "Failed to unmount /mnt/opencore" | tee -a "$logfile" umount /mnt/opencore >>"$logfile" 2>&1 || display_and_log "Failed to unmount /mnt/opencore" "$logfile"
rmdir /mnt/opencore 2>/dev/null rmdir /mnt/opencore 2>/dev/null
fi fi
losetup -a | grep -q "$TMPDIR" && losetup -d $(losetup -j "$TMPDIR"/* | awk -F: '{print $1}') >>"$logfile" 2>&1 losetup -a | grep -q "$TMPDIR" && losetup -d $(losetup -j "$TMPDIR"/* | awk -F: '{print $1}') >>"$logfile" 2>&1
@ -96,7 +108,7 @@ next_power_of_2() {
log_and_exit() { log_and_exit() {
local message=$1 local message=$1
local logfile=$2 local logfile=$2
echo "$message" | tee -a "$logfile" >&2 display_and_log "$message" "$logfile"
exit 1 exit 1
} }
@ -181,7 +193,7 @@ get_available_iso_storages() {
ensure_jq_dependency() { ensure_jq_dependency() {
local logfile="${LOGDIR}/jq-dependency.log" local logfile="${LOGDIR}/jq-dependency.log"
if ! command -v jq >/dev/null 2>&1; then if ! command -v jq >/dev/null 2>&1; then
echo "Installing jq..." | tee -a "$logfile" display_and_log "Installing jq..." "$logfile"
apt-get update >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile" apt-get update >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile"
apt-get install -y jq >>"$logfile" 2>&1 || log_and_exit "Failed to install jq" "$logfile" apt-get install -y jq >>"$logfile" 2>&1 || log_and_exit "Failed to install jq" "$logfile"
fi fi
@ -191,7 +203,7 @@ ensure_jq_dependency() {
set_isodir() { set_isodir() {
local logfile="${LOGDIR}/iso-storage-detection.log" local logfile="${LOGDIR}/iso-storage-detection.log"
ensure_jq_dependency ensure_jq_dependency
local storage_output=$(get_available_iso_storages) || { echo "Failed to retrieve ISO storages"; read -n 1 -s; return 1; } local storage_output=$(get_available_iso_storages) || { display_and_log "Failed to retrieve ISO storages"; read -n 1 -s; return 1; }
local storages=() default_storage="" local storages=() default_storage=""
while IFS= read -r line; do while IFS= read -r line; do
[[ -z "$line" ]] && continue [[ -z "$line" ]] && continue
@ -204,14 +216,14 @@ set_isodir() {
if ((${#storages[@]} == 1)); then if ((${#storages[@]} == 1)); then
storage_iso="${storages[0]%%|*}" storage_iso="${storages[0]%%|*}"
echo "Using ISO storage: $storage_iso" display_and_log "Using ISO storage: $storage_iso" "$logfile"
else else
while true; do while true; do
echo "Available ISO storages:" display_and_log "Available ISO storages:" "$logfile"
for s in "${storages[@]}"; do for s in "${storages[@]}"; do
storage_name="${s%%|*}" storage_name="${s%%|*}"
avail_space="${s##*|}" avail_space="${s##*|}"
echo " - $storage_name ($avail_space GB)" display_and_log " - $storage_name ($avail_space GB)" "$logfile"
done done
read -rp "ISO Storage [${default_storage}]: " storage_iso read -rp "ISO Storage [${default_storage}]: " storage_iso
storage_iso=${storage_iso:-$default_storage} storage_iso=${storage_iso:-$default_storage}
@ -223,10 +235,10 @@ set_isodir() {
fi fi
done done
if $valid; then if $valid; then
echo "Selected ISO storage: $storage_iso" display_and_log "Selected ISO storage: $storage_iso" "$logfile"
break break
else else
echo "Invalid ISO storage. Please try again." display_and_log "Invalid ISO storage. Please try again." "$logfile"
fi fi
done done
fi fi
@ -236,7 +248,7 @@ set_isodir() {
[[ -z "$storage_iso_path" ]] && log_and_exit "Storage path for $storage_iso is empty" "$logfile" [[ -z "$storage_iso_path" ]] && log_and_exit "Storage path for $storage_iso is empty" "$logfile"
ISODIR="${storage_iso_path}/template/iso/" ISODIR="${storage_iso_path}/template/iso/"
mkdir -p "$ISODIR" || log_and_exit "Failed to create ISODIR: $ISODIR" "$logfile" mkdir -p "$ISODIR" || log_and_exit "Failed to create ISODIR: $ISODIR" "$logfile"
echo "ISODIR set to: $ISODIR" | tee -a "$logfile" display_and_log "ISODIR set to: $ISODIR" "$logfile"
} }
# Function to get available bridges # Function to get available bridges
@ -267,17 +279,22 @@ get_available_bridges() {
# Function to initialize directories # Function to initialize directories
init_dirs() { init_dirs() {
mkdir -p "$LOGDIR" "$TMPDIR" || log_and_exit "Failed to create directories" "${LOGDIR}/init-dirs.log" mkdir -p "$LOGDIR" "$TMPDIR" || log_and_exit "Failed to create directories" "${LOGDIR}/init-dirs.log"
touch "$MAIN_LOG" # Ensure main log exists
} }
# Function to check Proxmox version # Function to check Proxmox version
check_proxmox_version() { check_proxmox_version() {
local version_log="${LOGDIR}/proxmox-version.log" local log_file="${LOGDIR}/proxmox-version.log"
if ! pveversion | grep -qE "pve-manager/[7-9]"; then
log_and_exit "Unsupported Proxmox version. Use 7.x, 8.x, or 9.x" "$version_log" # Check supported Proxmox versions
local version=$(pveversion | grep -oE "pve-manager/[0-9.]+")
if [[ "$version" != pve-manager/[7-9].* ]]; then
log_and_exit "Unsupported Proxmox version. Use 7.x, 8.x, or 9.x" "$log_file"
fi fi
if pveversion | grep -q "pve-manager/9"; then # Warn about preliminary Proxmox 9 support
echo "Proxmox 9 is in preliminary testing. Use at your own risk." if [[ "$version" == pve-manager/9.* ]]; then
display_and_log "Proxmox 9 is in preliminary testing. Use at your own risk." "$log_file"
sleep 5 sleep 5
fi fi
} }
@ -319,7 +336,7 @@ setup_prerequisites() {
[ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] && sed -i.backup -z "s/res === null || res === undefined || \!res || res\n\t\t\t.data.status.toLowerCase() \!== 'active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js [ -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] && sed -i.backup -z "s/res === null || res === undefined || \!res || res\n\t\t\t.data.status.toLowerCase() \!== 'active'/false/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
touch /etc/pve/qemu-server/.osx-proxmox touch /etc/pve/qemu-server/.osx-proxmox
update-grub >>"$logfile" 2>&1 || log_and_exit "Failed to update GRUB" "$logfile" update-grub >>"$logfile" 2>&1 || log_and_exit "Failed to update GRUB" "$logfile"
echo "Prerequisites setup complete. Rebooting in 15 seconds..." | tee -a "$logfile" display_and_log "Prerequisites setup complete. Rebooting in 15 seconds..." "$logfile"
sleep 15 && reboot sleep 15 && reboot
} }
@ -329,8 +346,8 @@ download_recovery_image() {
local logfile="${LOGDIR}/crt-recovery-${version_name,,}.log" local logfile="${LOGDIR}/crt-recovery-${version_name,,}.log"
local iso_path="${ISODIR}/recovery-${version_name,,}.iso" local iso_path="${ISODIR}/recovery-${version_name,,}.iso"
[[ -e "$iso_path" ]] && { echo "Recovery image for $version_name exists" | tee -a "$logfile"; return; } [[ -e "$iso_path" ]] && { display_and_log "Recovery image for $version_name exists" "$logfile"; return; }
echo "Creating recovery image for $version_name..." | tee -a "$logfile" display_and_log "Creating recovery image for $version_name..." "$logfile"
fallocate -x -l "$iso_size" "${TMPDIR}/recovery-${version_name,,}.iso" >>"$logfile" 2>&1 || log_and_exit "Failed to allocate image" "$logfile" fallocate -x -l "$iso_size" "${TMPDIR}/recovery-${version_name,,}.iso" >>"$logfile" 2>&1 || log_and_exit "Failed to allocate image" "$logfile"
mkfs.msdos -F 32 "${TMPDIR}/recovery-${version_name,,}.iso" -n "${version_name^^}" >>"$logfile" 2>&1 || log_and_exit "Failed to format image" "$logfile" mkfs.msdos -F 32 "${TMPDIR}/recovery-${version_name,,}.iso" -n "${version_name^^}" >>"$logfile" 2>&1 || log_and_exit "Failed to format image" "$logfile"
local loopdev=$(losetup -f --show "${TMPDIR}/recovery-${version_name,,}.iso") || log_and_exit "Failed to set up loop device" "$logfile" local loopdev=$(losetup -f --show "${TMPDIR}/recovery-${version_name,,}.iso") || log_and_exit "Failed to set up loop device" "$logfile"
@ -344,7 +361,7 @@ download_recovery_image() {
umount /mnt/APPLE >>"$logfile" 2>&1 || log_and_exit "Failed to unmount image" "$logfile" umount /mnt/APPLE >>"$logfile" 2>&1 || log_and_exit "Failed to unmount image" "$logfile"
losetup -d "$loopdev" >>"$logfile" 2>&1 || log_and_exit "Failed to detach loop device" "$logfile" losetup -d "$loopdev" >>"$logfile" 2>&1 || log_and_exit "Failed to detach loop device" "$logfile"
mv "${TMPDIR}/recovery-${version_name,,}.iso" "$iso_path" >>"$logfile" 2>&1 || log_and_exit "Failed to move image" "$logfile" mv "${TMPDIR}/recovery-${version_name,,}.iso" "$iso_path" >>"$logfile" 2>&1 || log_and_exit "Failed to move image" "$logfile"
echo "Recovery image created successfully" | tee -a "$logfile" display_and_log "Recovery image created successfully" "$logfile"
} }
# Function to create VM # Function to create VM
@ -386,12 +403,12 @@ create_vm() {
--ide2 "${storage_iso}:iso/recovery-${version_name,,}.iso,media=cdrom,cache=unsafe,size=${iso_size}" >>"$logfile" 2>&1 || log_and_exit "Failed to create VM" "$logfile" --ide2 "${storage_iso}:iso/recovery-${version_name,,}.iso,media=cdrom,cache=unsafe,size=${iso_size}" >>"$logfile" 2>&1 || log_and_exit "Failed to create VM" "$logfile"
sed -i 's/media=cdrom/media=disk/' "/etc/pve/qemu-server/$vm_id.conf" >>"$logfile" 2>&1 || log_and_exit "Failed to update VM config" "$logfile" sed -i 's/media=cdrom/media=disk/' "/etc/pve/qemu-server/$vm_id.conf" >>"$logfile" 2>&1 || log_and_exit "Failed to update VM config" "$logfile"
echo "VM ($vm_name) created successfully" | tee -a "$logfile" display_and_log "VM ($vm_name) created successfully" "$logfile"
local bridge_ip=$(ip -4 addr show "$bridge" | awk '/inet/ {print $2}' | cut -d'/' -f1 || echo "unknown") local bridge_ip=$(ip -4 addr show "$bridge" | awk '/inet/ {print $2}' | cut -d'/' -f1 || echo "unknown")
if [[ "$version_name" =~ "High Sierra" ]]; then if [[ "$version_name" =~ "High Sierra" ]]; then
printf "\nNOTE: High Sierra has a 'The Recovery Server Could Not Be Contacted' Error!\n - Goto https://mrmacintosh.com/how-to-fix-the-recovery-server-could-not-be-contacted-error-high-sierra-recovery-is-still-online-but-broken/ and do the Fix #3\n\n" display_and_log "\nNOTE: High Sierra has a 'The Recovery Server Could Not Be Contacted' Error!\n - Goto https://mrmacintosh.com/how-to-fix-the-recovery-server-could-not-be-contacted-error-high-sierra-recovery-is-still-online-but-broken/ and do the Fix #3\n\n" "$logfile"
fi fi
echo "Access Proxmox Web Panel: https://$bridge_ip:8006" | tee -a "$logfile" display_and_log "Access Proxmox Web Panel: https://$bridge_ip:8006" "$logfile"
} }
# Function to add Proxmox VE no-subscription repository # Function to add Proxmox VE no-subscription repository
@ -408,33 +425,38 @@ add_no_subscription_repo() {
log_and_exit "Unsupported Proxmox version" "$logfile" log_and_exit "Unsupported Proxmox version" "$logfile"
fi fi
apt update -y >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile" apt update -y >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile"
echo "Repository added successfully" | tee -a "$logfile" display_and_log "Repository added successfully" "$logfile"
read -n 1 -sp "Press any key to return to menu..." read -n 1 -sp "Press any key to return to menu..."
} }
# Function to update OpenCore ISO # Function to update OpenCore ISO
update_opencore_iso() { update_opencore_iso() {
local logfile="${LOGDIR}/update-opencore-iso.log" local logfile="${LOGDIR}/update-opencore-iso.log"
cd "$ISODIR" local iso_url="https://github.com/luchina-gabriel/OSX-PROXMOX/raw/main/EFI/opencore-osx-proxmox-vm.iso"
rm -f opencore-osx-proxmox-vm.iso >>"$logfile" 2>&1 local iso_path="${ISODIR}/opencore-osx-proxmox-vm.iso"
wget -q https://github.com/luchina-gabriel/OSX-PROXMOX/raw/main/EFI/opencore-osx-proxmox-vm.iso >>"$logfile" 2>&1 || log_and_exit "Failed to download OpenCore ISO" "$logfile"
cd ~ rm -f "$iso_path" >>"$logfile" 2>&1
echo "OpenCore ISO updated" | tee -a "$logfile" if ! wget -q -O "$iso_path" "$iso_url" >>"$logfile" 2>&1; then
log_and_exit "Failed to download OpenCore ISO" "$logfile"
fi
display_and_log "OpenCore ISO updated" "$logfile"
sleep 5 sleep 5
} }
# Function to clear recovery images # Function to clear recovery images
clear_recovery_images() { clear_recovery_images() {
rm -f "${ISODIR}/recovery-"*.iso "${LOGDIR}/crt-recovery-"*.log 2>/dev/null find "$ISODIR" -type f -name "recovery-*.iso" -delete
echo "All recovery images cleared" find "$LOGDIR" -type f -name "crt-recovery-*.log" -delete
display_and_log "All recovery images cleared"
read -n 1 -sp "Press any key to return to menu..." read -n 1 -sp "Press any key to return to menu..."
} }
# Function to remove subscription notice # Function to remove subscription notice
remove_subscription_notice() { remove_subscription_notice() {
echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; }; fi\"; };" >/etc/apt/apt.conf.d/no-nag-script echo "DPkg::Post-Invoke { \"if [ -s /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js ] && ! grep -q -F 'NoMoreNagging' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; then echo 'Removing subscription nag from UI...'; sed -i '/data\.status/{s/\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; fi\" };" >/etc/apt/apt.conf.d/no-nag-script
apt --reinstall install proxmox-widget-toolkit &>/dev/null apt --reinstall install proxmox-widget-toolkit &>/dev/null
echo "Subscription notice removed" display_and_log "Subscription notice removed"
read -n 1 -sp "Press any key to return to menu..." read -n 1 -sp "Press any key to return to menu..."
} }
@ -444,16 +466,16 @@ configure_network_bridge() {
# Logging functions # Logging functions
die() { die() {
echo "ERROR: $*" | tee -a "$logfile" >&2 display_and_log "ERROR: $*" "$logfile"
exit 1 exit 1
} }
warn() { warn() {
echo "WARNING: $*" | tee -a "$logfile" >&2 display_and_log "WARNING: $*" "$logfile"
} }
info() { info() {
echo "INFO: $*" | tee -a "$logfile" display_and_log "INFO: $*" "$logfile"
} }
# Restore backup function # Restore backup function
@ -732,7 +754,7 @@ configure_network_bridge() {
echo "$value" echo "$value"
return return
fi fi
echo "Press any key to return to the main menu..." display_and_log "Press any key to return to the main menu..."
read -n 1 -s read -n 1 -s
return 1 return 1
done done
@ -778,7 +800,7 @@ configure_network_bridge() {
[[ "${answer,,}" =~ ^(y|)$ ]] && info "DHCP Range: ${network_info[range_start]} - ${network_info[range_end]}" [[ "${answer,,}" =~ ^(y|)$ ]] && info "DHCP Range: ${network_info[range_start]} - ${network_info[range_end]}"
info "Network config: $NETWORK_INTERFACES_FILE" info "Network config: $NETWORK_INTERFACES_FILE"
[[ "${answer,,}" =~ ^(y|)$ ]] && info "DHCP config: $DHCP_CONF_DIR/vmbr$bridge_num.conf" [[ "${answer,,}" =~ ^(y|)$ ]] && info "DHCP config: $DHCP_CONF_DIR/vmbr$bridge_num.conf"
echo "Press any key to return to the main menu..." display_and_log "Press any key to return to the main menu..."
read -n 1 -s read -n 1 -s
} }
@ -801,7 +823,7 @@ customize_opencore_config() {
read -rp "Remove csr-active-config (unlock SIP)? [Y/N] [N]: " RM_CSR_LOCK read -rp "Remove csr-active-config (unlock SIP)? [Y/N] [N]: " RM_CSR_LOCK
if [[ "${RM_CSR_LOCK:-N}" =~ ^[Yy]$ ]]; then if [[ "${RM_CSR_LOCK:-N}" =~ ^[Yy]$ ]]; then
sed -i '/<key>csr-active-config>/,+1d' "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to remove csr-active-config" "$logfile" sed -i '/<key>csr-active-config>/,+1d' "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to remove csr-active-config" "$logfile"
echo "SIP unlocked. Use 'csrutil disable' in Recovery OS" | tee -a "$logfile" display_and_log "SIP unlocked. Use 'csrutil disable' in Recovery OS" "$logfile"
fi fi
read -rp "Enter timeout [${timeout}]: " NEW_TIMEOUT read -rp "Enter timeout [${timeout}]: " NEW_TIMEOUT
NEW_TIMEOUT=${NEW_TIMEOUT:-$timeout} NEW_TIMEOUT=${NEW_TIMEOUT:-$timeout}
@ -811,7 +833,7 @@ customize_opencore_config() {
diff -u "$config.backup" "$config" || true diff -u "$config.backup" "$config" || true
umount /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to unmount ISO" "$logfile" umount /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to unmount ISO" "$logfile"
losetup -d "$loopdev" >>"$logfile" 2>&1 || log_and_exit "Failed to detach loop device" "$logfile" losetup -d "$loopdev" >>"$logfile" 2>&1 || log_and_exit "Failed to detach loop device" "$logfile"
echo "OpenCore config customized" | tee -a "$logfile" display_and_log "OpenCore config customized" "$logfile"
read -n 1 -sp "Press any key to return to menu..." read -n 1 -sp "Press any key to return to menu..."
} }
@ -824,7 +846,7 @@ configure_macos_vm() {
local default_vm_name="${DEFAULT_VM_PREFIX}$(echo "$version_name" | tr -s ' ' | sed 's/^[ ]*//;s/[ ]*$//;s/[ ]/-/g' | tr '[:lower:]' '[:upper:]' | sed 's/-*$//')" local default_vm_name="${DEFAULT_VM_PREFIX}$(echo "$version_name" | tr -s ' ' | sed 's/^[ ]*//;s/[ ]*$//;s/[ ]/-/g' | tr '[:lower:]' '[:upper:]' | sed 's/-*$//')"
validate_vm_name "$default_vm_name" || log_and_exit "Invalid default VM name: $default_vm_name" "${LOGDIR}/main-menu.log" validate_vm_name "$default_vm_name" || log_and_exit "Invalid default VM name: $default_vm_name" "${LOGDIR}/main-menu.log"
clear clear
echo "macOS $version_name" display_and_log "macOS $version_name"
# VM ID # VM ID
while true; do while true; do
@ -833,7 +855,7 @@ configure_macos_vm() {
if [[ "$VM_ID" =~ ^[0-9]+$ && ! -e "/etc/pve/qemu-server/$VM_ID.conf" ]]; then if [[ "$VM_ID" =~ ^[0-9]+$ && ! -e "/etc/pve/qemu-server/$VM_ID.conf" ]]; then
break break
else else
echo "Invalid or existing VM ID. Please try again." display_and_log "Invalid or existing VM ID. Please try again."
fi fi
done done
@ -844,7 +866,7 @@ configure_macos_vm() {
if validate_vm_name "$VM_NAME"; then if validate_vm_name "$VM_NAME"; then
break break
else else
echo "Invalid VM name. Please use alphanumeric characters, -, _, .; no spaces." display_and_log "Invalid VM name. Please use alphanumeric characters, -, _, .; no spaces."
fi fi
done done
@ -856,30 +878,30 @@ configure_macos_vm() {
if [[ "$SIZEDISK" =~ ^[0-9]+$ ]]; then if [[ "$SIZEDISK" =~ ^[0-9]+$ ]]; then
break break
else else
echo "Disk size must be an integer. Please try again." display_and_log "Disk size must be an integer. Please try again."
fi fi
done done
# Storage Selection # Storage Selection
local storage_output=$(get_available_storages) || { echo "Failed to retrieve storages"; read -n 1 -s; return 1; } local storage_output=$(get_available_storages) || { display_and_log "Failed to retrieve storages"; read -n 1 -s; return 1; }
local storages=() default_storage="" local storages=() default_storage=""
while IFS= read -r line; do while IFS= read -r line; do
[[ -z "$line" ]] && continue [[ -z "$line" ]] && continue
[[ -z "$default_storage" && ! "$line" =~ \| ]] && default_storage="$line" || storages+=("$line") [[ -z "$default_storage" && ! "$line" =~ \| ]] && default_storage="$line" || storages+=("$line")
done <<< "$storage_output" done <<< "$storage_output"
if ((${#storages[@]} == 0)); then if ((${#storages[@]} == 0)); then
echo "No storages found"; read -n 1 -s; return 1 display_and_log "No storages found"; read -n 1 -s; return 1
fi fi
if ((${#storages[@]} == 1)); then if ((${#storages[@]} == 1)); then
STORAGECRTVM="${storages[0]%%|*}" STORAGECRTVM="${storages[0]%%|*}"
echo "Using storage: $STORAGECRTVM" display_and_log "Using storage: $STORAGECRTVM"
else else
while true; do while true; do
echo "Available storages:" display_and_log "Available storages:"
for s in "${storages[@]}"; do for s in "${storages[@]}"; do
storage_name="${s%%|*}" storage_name="${s%%|*}"
avail_space="${s##*|}" avail_space="${s##*|}"
echo " - $storage_name ($avail_space GB)" display_and_log " - $storage_name ($avail_space GB)"
done done
read -rp "Storage [${default_storage}]: " STORAGECRTVM read -rp "Storage [${default_storage}]: " STORAGECRTVM
STORAGECRTVM=${STORAGECRTVM:-$default_storage} STORAGECRTVM=${STORAGECRTVM:-$default_storage}
@ -891,16 +913,16 @@ configure_macos_vm() {
fi fi
done done
if $valid; then if $valid; then
echo "Selected storage: $STORAGECRTVM" display_and_log "Selected storage: $STORAGECRTVM"
break break
else else
echo "Invalid storage. Please try again." display_and_log "Invalid storage. Please try again."
fi fi
done done
fi fi
# Bridge Selection # Bridge Selection
local bridge_output=$(get_available_bridges) || { echo "Failed to retrieve bridges"; read -n 1 -s; return 1; } local bridge_output=$(get_available_bridges) || { display_and_log "Failed to retrieve bridges"; read -n 1 -s; return 1; }
local bridges=() default_bridge="" local bridges=() default_bridge=""
while IFS= read -r line; do while IFS= read -r line; do
line=$(echo "$line" | tr -d '\r') line=$(echo "$line" | tr -d '\r')
@ -912,7 +934,7 @@ configure_macos_vm() {
fi fi
done <<< "$bridge_output" done <<< "$bridge_output"
if ((${#bridges[@]} == 0)); then if ((${#bridges[@]} == 0)); then
echo "No bridges found"; read -n 1 -s; return 1 display_and_log "No bridges found"; read -n 1 -s; return 1
fi fi
declare -A bridge_info declare -A bridge_info
@ -928,27 +950,27 @@ configure_macos_vm() {
name="${sorted_names[0]}" name="${sorted_names[0]}"
ip_info="${bridge_info[$name]}" ip_info="${bridge_info[$name]}"
BRIDGECRTVM="$name" BRIDGECRTVM="$name"
echo "Using bridge: $BRIDGECRTVM ($ip_info)" display_and_log "Using bridge: $BRIDGECRTVM ($ip_info)"
else else
while true; do while true; do
echo "Available bridges:" display_and_log "Available bridges:"
for name in "${sorted_names[@]}"; do for name in "${sorted_names[@]}"; do
bridge_num=${name#vmbr} bridge_num=${name#vmbr}
ip_info="${bridge_info[$name]}" ip_info="${bridge_info[$name]}"
echo " - $bridge_num ($name, $ip_info)" display_and_log " - $bridge_num ($name, $ip_info)"
done done
read -rp "Bridge number [${default_bridge_num}]: " BRIDGE_NUM read -rp "Bridge number [${default_bridge_num}]: " BRIDGE_NUM
BRIDGE_NUM=${BRIDGE_NUM:-$default_bridge_num} BRIDGE_NUM=${BRIDGE_NUM:-$default_bridge_num}
if [[ "$BRIDGE_NUM" =~ ^[0-9]+$ ]]; then if [[ "$BRIDGE_NUM" =~ ^[0-9]+$ ]]; then
BRIDGECRTVM="vmbr$BRIDGE_NUM" BRIDGECRTVM="vmbr$BRIDGE_NUM"
if [[ -v bridge_info[$BRIDGECRTVM] ]]; then if [[ -v bridge_info[$BRIDGECRTVM] ]]; then
echo "Selected bridge: $BRIDGECRTVM" display_and_log "Selected bridge: $BRIDGECRTVM"
break break
else else
echo "Invalid bridge number. Please try again." display_and_log "Invalid bridge number. Please try again."
fi fi
else else
echo "Bridge number must be an integer. Please try again." display_and_log "Bridge number must be an integer. Please try again."
fi fi
done done
fi fi
@ -960,11 +982,11 @@ configure_macos_vm() {
if [[ "$PROC_COUNT" =~ ^[0-9]+$ ]]; then if [[ "$PROC_COUNT" =~ ^[0-9]+$ ]]; then
if ! is_power_of_2 "$PROC_COUNT"; then if ! is_power_of_2 "$PROC_COUNT"; then
PROC_COUNT=$(next_power_of_2 "$PROC_COUNT") PROC_COUNT=$(next_power_of_2 "$PROC_COUNT")
echo "Adjusted to next power of 2: $PROC_COUNT" display_and_log "Adjusted to next power of 2: $PROC_COUNT"
fi fi
break break
else else
echo "CPU cores must be an integer. Please try again." display_and_log "CPU cores must be an integer. Please try again."
fi fi
done done
((PROC_COUNT > MAX_CORES)) && PROC_COUNT=$MAX_CORES ((PROC_COUNT > MAX_CORES)) && PROC_COUNT=$MAX_CORES
@ -977,7 +999,7 @@ configure_macos_vm() {
if [[ "$RAM_SIZE" =~ ^[0-9]+$ ]]; then if [[ "$RAM_SIZE" =~ ^[0-9]+$ ]]; then
break break
else else
echo "RAM must be an integer. Please try again." display_and_log "RAM must be an integer. Please try again."
fi fi
done done