From 064e032b82af71146ebe27967dde22f0a3c4a05b Mon Sep 17 00:00:00 2001 From: jaminmc <1310376+jaminmc@users.noreply.github.com> Date: Wed, 23 Jul 2025 09:56:02 -0400 Subject: [PATCH] Auto generate new Serial numbers! Now everyone won't be sharing the same serial! On fresh install, It will prompt if you want to generate a new serial. If you have an install already, and you select "205 - Customize OpenCore config.plist" you will have an option to generate a new serial. I created a CLI for GenSMBIOS, which generated all the serial numbers and stuff so that iMessage should work. For now it is pulling from my branch. That is until the pull request is accepted by corpnewt. The Serial generation prompts for System Product Name, and has a default. The user can change it if they want. IE for MacOS 26, they may want to use MacPro7,1. I have not tested that though. --- .gitmodules | 4 + install.sh | 2 +- setup | 536 +++++++++++++++++++++++++++++++++++++++++------- tools/GenSMBIOS | 1 + 4 files changed, 465 insertions(+), 78 deletions(-) create mode 100644 .gitmodules create mode 160000 tools/GenSMBIOS diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..cda3d53 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "tools/GenSMBIOS"] + path = tools/GenSMBIOS + url = https://github.com/jaminmc/GenSMBIOS.git + branch = AddCli diff --git a/install.sh b/install.sh index 9f5457b..73723a0 100755 --- a/install.sh +++ b/install.sh @@ -67,7 +67,7 @@ check_status "Failed to install git" # Clone repository log_message "Cloning OSX-PROXMOX repository..." -git clone https://github.com/luchina-gabriel/OSX-PROXMOX.git /root/OSX-PROXMOX >> "$LOG_FILE" 2>&1 +git clone --recurse-submodules https://github.com/luchina-gabriel/OSX-PROXMOX.git /root/OSX-PROXMOX >> "$LOG_FILE" 2>&1 check_status "Failed to clone repository" # Ensure directory exists and setup is executable diff --git a/setup b/setup index 9af26b0..3b324a5 100755 --- a/setup +++ b/setup @@ -6,21 +6,21 @@ # https://luchina.com.br # # COPYRIGHT - 2021, 2022 -# -# All rights reserved - You may not copy, reproduce, distribute, publish, display, perform, modify, -# create derivative works, transmit, or in any way exploit any such content, nor may you distribute -# any part of this content over any network, including a local area network, sell or offer it for -# sale, or use such content to construct any kind of database. -# -# You may not alter or remove any copyright or other notice from copies of the content on any scripts -# in the solution of 'OSX-PROXMOX Solution - GABRIEL LUCHINA'. # -# Copying or storing any content except as provided above is expressly prohibited without prior -# written permission of copyright holder identified in the individual content’s copyright notice. -# -# For permission to use the content 'OSX-PROXMOX Solution - GABRIEL LUCHINA', +# All rights reserved - You may not copy, reproduce, distribute, publish, display, perform, modify, +# create derivative works, transmit, or in any way exploit any such content, nor may you distribute +# any part of this content over any network, including a local area network, sell or offer it for +# sale, or use such content to construct any kind of database. +# +# You may not alter or remove any copyright or other notice from copies of the content on any scripts +# in the solution of 'OSX-PROXMOX Solution - GABRIEL LUCHINA'. +# +# Copying or storing any content except as provided above is expressly prohibited without prior +# written permission of copyright holder identified in the individual content’s copyright notice. +# +# For permission to use the content 'OSX-PROXMOX Solution - GABRIEL LUCHINA', # please contact legal@luchina.com.br -# +# # FOR DEV/STUDENT ONLY PURPOSES - NOT COMERCIAL # # Credits: @@ -37,7 +37,7 @@ SCRIPT_DIR="/root/OSX-PROXMOX" LOGDIR="${SCRIPT_DIR}/logs" MAIN_LOG="${LOGDIR}/main.log" TMPDIR="${SCRIPT_DIR}/tmp" -HACKPXVERSION="2025.06.27" +HACKPXVERSION="2025.07.23" OCVERSION="1.0.4" DEFAULT_VM_PREFIX="HACK-" BASE_RAM_SIZE=4096 @@ -48,6 +48,7 @@ MAX_CORES=16 DHCP_CONF_DIR="/etc/dhcp/dhcpd.d" NETWORK_INTERFACES_FILE="/etc/network/interfaces" DHCP_USER="dhcpd" +OPENCORE_ISO="opencore-osx-proxmox-vm.iso" # macOS version configuration declare -A MACOS_CONFIG=( @@ -199,6 +200,26 @@ ensure_jq_dependency() { fi } +# Function to ensure xmlstarlet is installed +ensure_xmlstarlet_dependency() { + local logfile="${LOGDIR}/xmlstarlet-dependency.log" + if ! command -v xmlstarlet >/dev/null 2>&1; then + display_and_log "Installing xmlstarlet..." "$logfile" + apt-get update >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile" + apt-get install -y xmlstarlet >>"$logfile" 2>&1 || log_and_exit "Failed to install xmlstarlet" "$logfile" + fi +} + +# Function to ensure base64 and xxd are available +ensure_base64_xxd_dependency() { + local logfile="${LOGDIR}/base64-xxd-dependency.log" + if ! command -v base64 >/dev/null || ! command -v xxd >/dev/null; then + display_and_log "Installing base64 and xxd..." "$logfile" + apt-get update >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile" + apt-get install -y coreutils xxd vim-common >>"$logfile" 2>&1 || display_and_log "Failed to install base64 and xxd. Editing ROM in base64 format." "$logfile" + fi +} + # Function to set ISODIR based on selected ISO storage set_isodir() { local logfile="${LOGDIR}/iso-storage-detection.log" @@ -317,7 +338,7 @@ setup_prerequisites() { sed -i "s/ftp.$country.debian.org/ftp.debian.org/g" /etc/apt/sources.list apt-get update >>"$logfile" 2>&1 || log_and_exit "Failed to update apt" "$logfile" } - apt-get install -y vim unzip zip sysstat parted wget iptraf git htop ipcalc >>"$logfile" 2>&1 || log_and_exit "Failed to install packages" "$logfile" + apt-get install -y vim unzip zip sysstat parted wget iptraf git htop ipcalc coreutils vim-common xmlstarlet >>"$logfile" 2>&1 || log_and_exit "Failed to install packages" "$logfile" sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=0/g' /etc/default/grub local grub_cmd="quiet" if [[ $OSX_PLATFORM == "AMD" ]]; then @@ -366,8 +387,12 @@ download_recovery_image() { # Function to create VM create_vm() { - local version_name=$1 vm_id=$2 vm_name=$3 disk_size=$4 storage=$5 core_count=$6 ram_size=$7 iso_size=$8 disk_type=$9 bridge=${10} + local iso_file version_name=$1 vm_id=$2 vm_name=$3 disk_size=$4 storage=$5 core_count=$6 ram_size=$7 iso_size=$8 disk_type=$9 bridge=${10} local logfile="${LOGDIR}/crt-vm-${OSX_PLATFORM,,}-${version_name,,}.log" + iso_file="${OPENCORE_ISO}" + if [ ! -f "${ISODIR}/$iso_file" ]; then + update_opencore_iso + fi [[ ! -d "/sys/class/net/$bridge" ]] && log_and_exit "Bridge $bridge does not exist" "$logfile" local cpu_args device_args='-device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -smbios type=2' @@ -399,7 +424,7 @@ create_vm() { --onboot 0 --ostype other --sockets 1 --start 0 --tablet 1 \ --vga vmware --vmgenid 1 --scsihw virtio-scsi-pci \ --"$disk_type" "${storage}:${disk_size},cache=none,discard=on" \ - --ide0 "${storage_iso}:iso/opencore-osx-proxmox-vm.iso,media=cdrom,cache=unsafe,size=96M" \ + --ide0 "${storage_iso}:iso/${iso_file},media=cdrom,cache=unsafe,size=96M" \ --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" @@ -419,8 +444,7 @@ add_no_subscription_repo() { elif pveversion | grep -q "pve-manager/[8]"; then printf "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription\n" > /etc/apt/sources.list.d/pve-no-sub.list elif pveversion | grep -q "pve-manager/[9]"; then - printf "Types: deb\nURIs: http://download.proxmox.com/debian/pve\nSuites: trixie\nComponents: pve-no-subscription\nSigned-By: /usr/share/keyrings/proxmox-archive-keyring.gpg -\n" > /etc/apt/sources.list.d/pve-no-sub.sources + printf "Types: deb\nURIs: http://download.proxmox.com/debian/pve\nSuites: trixie\nComponents: pve-no-subscription\nSigned-By: /usr/share/keyrings/proxmox-archive-keyring.gpg\n" > /etc/apt/sources.list.d/pve-no-sub.sources else log_and_exit "Unsupported Proxmox version" "$logfile" fi @@ -429,16 +453,407 @@ add_no_subscription_repo() { read -n 1 -sp "Press any key to return to menu..." } +# Cleaned function to update the SMBIOS in the OpenCore ISO +update_opencore_smbios() { + local iso_path=$1 oc_json_path=$2 + local logfile="${LOGDIR}/update-opencore-smbios.log" + ensure_xmlstarlet_dependency + ensure_base64_xxd_dependency "$logfile" + ensure_jq_dependency + + if [[ ! -f "$oc_json_path" ]]; then + read -rp "No Serial number generated. Do you want to generate a unique serial number? [Y/n]: " GENSMBIOS + if [[ "${GENSMBIOS:-Y}" =~ ^[Yy]$ ]]; then + SystemProductName="iMacPro1,1" + read -e -p "Enter System Product Name (press Enter to keep current): " -i "$SystemProductName" new_value + if [ -n "$new_value" ] && [ "$new_value" != "$SystemProductName" ]; then + SystemProductName="$new_value" + fi + python3 "$SCRIPT_DIR"/tools/GenSMBIOS/GenSMBIOS.py --install + python3 "$SCRIPT_DIR"/tools/GenSMBIOS/GenSMBIOS.py --generate "$SystemProductName" -j "$oc_json_path" >>"$logfile" 2>&1 || log_and_exit "Failed to generate SMBIOS" "$logfile" + else + display_and_log "Skipping SMBIOS generation" "$logfile" + return + fi + fi + + local loopdev=$(losetup -f --show -P "$iso_path") || log_and_exit "Failed to set up loop device" "$logfile" + mkdir -p /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to create mount point" "$logfile" + mount "${loopdev}p1" /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to mount ISO" "$logfile" + local config="/mnt/opencore/EFI/OC/config.plist" + [[ ! -e "$config.backup" ]] && cp "$config" "$config.backup" >>"$logfile" 2>&1 + + # Temporary file + local TEMP_FILE="${config}.tmp" + cp "$config" "$TEMP_FILE" + + # Define base XPaths + local nvram_xpath="//key[text()='NVRAM']/following-sibling::dict/key[text()='Add']/following-sibling::dict/key[text()='7C436110-AB2A-4BBB-A880-FE41995C9F82']/following-sibling::dict" + local platform_generic_xpath="//key[text()='PlatformInfo']/following-sibling::dict/key[text()='Generic']/following-sibling::dict" + + # Function to read a value from plist + read_plist_value() { + xmlstarlet sel -t -v "${2}/key[text()='${3}']/following-sibling::*[1]" "$1" 2>/dev/null + } + + # Function to update a value in plist + update_plist_value() { + xmlstarlet ed -L -u "${2}/key[text()='${3}']/following-sibling::*[1]" -v "$4" "$1" + } + + # Load and apply JSON values + declare -A json_values + json_values["SystemProductName"]=$(jq -r '.Type // empty' "$oc_json_path") + json_values["SystemSerialNumber"]=$(jq -r '.Serial // empty' "$oc_json_path") + json_values["MLB"]=$(jq -r '."Board Serial" // empty' "$oc_json_path") + json_values["SystemUUID"]=$(jq -r '.SmUUID // empty' "$oc_json_path") + json_values["ROM"]=$(jq -r '.ROM // empty' "$oc_json_path") # HEX + + updated=false + for key in SystemProductName SystemSerialNumber MLB SystemUUID ROM; do + if [ -n "${json_values[$key]}" ]; then + if [ "$key" == "ROM" ]; then + if command -v base64 >/dev/null 2>&1 && command -v xxd >/dev/null 2>&1; then + modified_value=$(echo -n "${json_values[$key]}" | xxd -r -p | base64) + else + display_and_log "Warning: base64 or xxd not available. Skipping ROM update." "$logfile" + continue + fi + else + modified_value="${json_values[$key]}" + fi + update_plist_value "$TEMP_FILE" "$platform_generic_xpath" "$key" "$modified_value" + display_and_log "Updated $key from JSON." "$logfile" + updated=true + fi + done + + # Automatic boot-args adjustment + system_product_name=$(read_plist_value "$TEMP_FILE" "$platform_generic_xpath" "SystemProductName") + boot_args=$(read_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args") + flag=" -nehalem_error_disable" + + if [ "$system_product_name" = "MacPro5,1" ]; then + if [[ ! "$boot_args" =~ $flag ]]; then + new_boot_args="$boot_args$flag" + update_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args" "$new_boot_args" + display_and_log "Automatically added '$flag' to boot-args." "$logfile" + updated=true + fi + else + if [[ "$boot_args" =~ $flag ]]; then + new_boot_args="${boot_args//$flag/}" + update_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args" "$new_boot_args" + display_and_log "Automatically removed '$flag' from boot-args." "$logfile" + updated=true + fi + fi + + if $updated; then + display_and_log "Differences between original and modified file (unified format):" "$logfile" + xmlstarlet fo "$config" > "$config.fmt" || log_and_exit "Failed to format original file" "$logfile" + diff -u "$config.fmt" "$TEMP_FILE" || true + rm "$config.fmt" + + read -p "Do you want to apply these changes to the original file? (y/n): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + mv "$TEMP_FILE" "$config" + display_and_log "Changes applied to $config" "$logfile" + else + display_and_log "Changes discarded." "$logfile" + rm "$TEMP_FILE" + fi + else + display_and_log "No updates needed from JSON." "$logfile" + rm "$TEMP_FILE" + fi + + # Cleanup + 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" +} + +# Cleaned function to customize OpenCore config.plist +customize_opencore_config() { + local oc_json_path iso logfile="${LOGDIR}/custom-oc-config.plist.log" + iso="${ISODIR}/${OPENCORE_ISO}" + oc_json_path="${ISODIR}/.smbios.json" + ensure_xmlstarlet_dependency + ensure_base64_xxd_dependency "$logfile" + ensure_jq_dependency + + local loopdev=$(losetup -f --show -P "$iso") || log_and_exit "Failed to set up loop device" "$logfile" + mkdir -p /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to create mount point" "$logfile" + mount "${loopdev}p1" /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to mount ISO" "$logfile" + local config="/mnt/opencore/EFI/OC/config.plist" + [[ ! -e "$config.backup" ]] && cp "$config" "$config.backup" >>"$logfile" 2>&1 + + # Temporary file + local TEMP_FILE="${config}.tmp" + cp "$config" "$TEMP_FILE" + + # Define base XPaths + local nvram_xpath="//key[text()='NVRAM']/following-sibling::dict/key[text()='Add']/following-sibling::dict/key[text()='7C436110-AB2A-4BBB-A880-FE41995C9F82']/following-sibling::dict" + local misc_boot_xpath="//key[text()='Misc']/following-sibling::dict/key[text()='Boot']/following-sibling::dict" + local platform_generic_xpath="//key[text()='PlatformInfo']/following-sibling::dict/key[text()='Generic']/following-sibling::dict" + + # Define keys and sections + declare -A key_sections=( ["boot-args"]="nvram" ["csr-active-config"]="nvram" ["prev-lang:kbd"]="nvram" ["Timeout"]="misc_boot" ["MLB"]="platform_generic" ["SystemProductName"]="platform_generic" ["SystemSerialNumber"]="platform_generic" ["SystemUUID"]="platform_generic" ["ROM"]="platform_generic" ) + keys=("boot-args" "csr-active-config" "prev-lang:kbd" "Timeout" "MLB" "SystemProductName" "SystemSerialNumber" "SystemUUID" "ROM") + + # Function to read a value from plist + read_plist_value() { + xmlstarlet sel -t -v "${2}/key[text()='${3}']/following-sibling::*[1]" "$1" 2>/dev/null + } + + # Function to update a value in plist + update_plist_value() { + xmlstarlet ed -L -u "${2}/key[text()='${3}']/following-sibling::*[1]" -v "$4" "$1" + } + + # Function to remove a key from plist + remove_plist_key() { + local key_xpath="${2}/key[text()='${3}']" + local value_xpath="${2}/key[text()='${3}']/following-sibling::*[1]" + xmlstarlet ed -L -d "$key_xpath" -d "$value_xpath" "$1" || log_and_exit "Failed to remove $3" "$logfile" + } + + # Integrate JSON logic + generate_new=false + if [ -f "$oc_json_path" ]; then + read -rp "Existing SMBIOS JSON found. Do you want to generate a new serial number? [y/N]: " GENSMBIOS + if [[ "${GENSMBIOS}" =~ ^[Yy]$ ]]; then + generate_new=true + else + # Apply existing JSON + declare -A json_values + json_values["SystemProductName"]=$(jq -r '.Type // empty' "$oc_json_path") + json_values["SystemSerialNumber"]=$(jq -r '.Serial // empty' "$oc_json_path") + json_values["MLB"]=$(jq -r '."Board Serial" // empty' "$oc_json_path") + json_values["SystemUUID"]=$(jq -r '.SmUUID // empty' "$oc_json_path") + json_values["ROM"]=$(jq -r '.ROM // empty' "$oc_json_path") + for key in SystemProductName SystemSerialNumber MLB SystemUUID ROM; do + if [ -n "${json_values[$key]}" ]; then + if [ "$key" == "ROM" ]; then + if command -v base64 >/dev/null 2>&1 && command -v xxd >/dev/null 2>&1; then + modified_value=$(echo -n "${json_values[$key]}" | xxd -r -p | base64) + else + display_and_log "Warning: base64 or xxd not available. Skipping ROM update." "$logfile" + continue + fi + else + modified_value="${json_values[$key]}" + fi + update_plist_value "$TEMP_FILE" "$platform_generic_xpath" "$key" "$modified_value" + display_and_log "Applied $key from existing JSON to temp file." "$logfile" + fi + done + fi + else + read -rp "No Serial number generated. Do you want to generate a unique serial number? [Y/n]: " GENSMBIOS + if [[ "${GENSMBIOS:-Y}" =~ ^[Yy]$ ]]; then + generate_new=true + fi + fi + + # Generate new SMBIOS if requested + if $generate_new; then + SystemProductName="$(read_plist_value "$TEMP_FILE" "$platform_generic_xpath" "SystemProductName")" + read -e -p "Enter System Product Name (press Enter to keep current): " -i "$SystemProductName" new_value + if [ -n "$new_value" ] && [ "$new_value" != "$SystemProductName" ]; then + SystemProductName="$new_value" + fi + python3 "$SCRIPT_DIR"/tools/GenSMBIOS/GenSMBIOS.py --install + python3 "$SCRIPT_DIR"/tools/GenSMBIOS/GenSMBIOS.py --generate "$SystemProductName" -j "$oc_json_path" >>"$logfile" 2>&1 || log_and_exit "Failed to generate SMBIOS" "$logfile" + # Apply new JSON + declare -A json_values + json_values["SystemProductName"]=$(jq -r '.Type // empty' "$oc_json_path") + json_values["SystemSerialNumber"]=$(jq -r '.Serial // empty' "$oc_json_path") + json_values["MLB"]=$(jq -r '."Board Serial" // empty' "$oc_json_path") + json_values["SystemUUID"]=$(jq -r '.SmUUID // empty' "$oc_json_path") + json_values["ROM"]=$(jq -r '.ROM // empty' "$oc_json_path") + for key in SystemProductName SystemSerialNumber MLB SystemUUID ROM; do + if [ -n "${json_values[$key]}" ]; then + if [ "$key" == "ROM" ]; then + if command -v base64 >/dev/null 2>&1 && command -v xxd >/dev/null 2>&1; then + modified_value=$(echo -n "${json_values[$key]}" | xxd -r -p | base64) + else + display_and_log "Warning: base64 or xxd not available. Skipping ROM update." "$logfile" + continue + fi + else + modified_value="${json_values[$key]}" + fi + update_plist_value "$TEMP_FILE" "$platform_generic_xpath" "$key" "$modified_value" + display_and_log "Applied new $key from generated JSON to temp file." "$logfile" + fi + done + fi + + # Prompt for edits + declare -A modified + for key in "${keys[@]}"; do + local section=${key_sections[$key]} + local base_xpath + case $section in + nvram) base_xpath="$nvram_xpath" ;; + misc_boot) base_xpath="$misc_boot_xpath" ;; + platform_generic) base_xpath="$platform_generic_xpath" ;; + esac + value=$(read_plist_value "$TEMP_FILE" "$base_xpath" "$key") + if [ -z "$value" ]; then + display_and_log "Warning: Could not read value for $key" "$logfile" + continue + fi + + if [ "$key" == "csr-active-config" ]; then + current_value="$value" + echo "Current value for $key: $current_value" + read -rp "Remove csr-active-config (unlock SIP)? [Y/N] [N]: " RM_CSR_LOCK + if [[ "${RM_CSR_LOCK:-N}" =~ ^[Yy]$ ]]; then + modified[$key]="remove" + display_and_log "SIP unlocked. Use 'csrutil disable' in Recovery OS" "$logfile" + continue + fi + read -e -p "Edit value (press Enter to keep current): " -i "$current_value" new_value + if [ -n "$new_value" ] && [ "$new_value" != "$current_value" ]; then + modified[$key]="$new_value" + fi + elif [ "$key" == "ROM" ]; then + rom_convert=false + if command -v base64 >/dev/null && command -v xxd >/dev/null; then + rom_convert=true + current_value=$(echo -n "$value" | base64 -d | xxd -p -c 999 | tr -d '\n' | tr 'a-f' 'A-F') + else + current_value="$value" + fi + echo "Current value for $key (${rom_convert:+HEX}base64 if not): $current_value" + read -e -p "Edit value (press Enter to keep current): " -i "$current_value" new_value + if [ -n "$new_value" ] && [ "$new_value" != "$current_value" ]; then + if $rom_convert; then + modified[$key]=$(echo -n "$new_value" | xxd -r -p | base64) + else + modified[$key]="$new_value" + fi + fi + else + current_value="$value" + echo "Current value for $key: $current_value" + read -e -p "Edit value (press Enter to keep current): " -i "$current_value" new_value + if [ -n "$new_value" ] && [ "$new_value" != "$current_value" ]; then + modified[$key]="$new_value" + fi + fi + done + + # Apply user modifications + if [ ${#modified[@]} -gt 0 ]; then + display_and_log "Applying user changes to temporary file..." "$logfile" + for key in "${!modified[@]}"; do + local section=${key_sections[$key]} + local base_xpath + case $section in + nvram) base_xpath="$nvram_xpath" ;; + misc_boot) base_xpath="$misc_boot_xpath" ;; + platform_generic) base_xpath="$platform_generic_xpath" ;; + esac + if [ "${modified[$key]}" == "remove" ]; then + remove_plist_key "$TEMP_FILE" "$base_xpath" "$key" + else + update_plist_value "$TEMP_FILE" "$base_xpath" "$key" "${modified[$key]}" + fi + done + fi + + # Automatic boot-args adjustment + system_product_name=$(read_plist_value "$TEMP_FILE" "$platform_generic_xpath" "SystemProductName") + boot_args=$(read_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args") + flag=" -nehalem_error_disable" + + if [ "$system_product_name" = "MacPro5,1" ]; then + if [[ ! "$boot_args" =~ $flag ]]; then + new_boot_args="$boot_args$flag" + update_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args" "$new_boot_args" + display_and_log "Automatically added '$flag' to boot-args." "$logfile" + fi + else + if [[ "$boot_args" =~ $flag ]]; then + new_boot_args="${boot_args//$flag/}" + update_plist_value "$TEMP_FILE" "$nvram_xpath" "boot-args" "$new_boot_args" + display_and_log "Automatically removed '$flag' from boot-args." "$logfile" + fi + fi + + # Show diff if changes + xmlstarlet fo "$config" > "$config.fmt" + local diff_output=$(diff -u "$config.fmt" "$TEMP_FILE") + rm "$config.fmt" + if [ -n "$diff_output" ]; then + display_and_log "Differences between original and modified file (unified format):" "$logfile" + echo "$diff_output" + + read -rp "Do you want to apply these changes to the original file? (y/n): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + mv "$TEMP_FILE" "$config" + display_and_log "Changes applied to $config" "$logfile" + + # Extract and save to JSON + declare -A extracted + for key in SystemProductName SystemSerialNumber MLB SystemUUID ROM; do + val=$(read_plist_value "$config" "$platform_generic_xpath" "$key") + if [ -z "$val" ]; then + display_and_log "Warning: Could not read $key from plist." "$logfile" + continue + fi + if [ "$key" == "ROM" ]; then + if command -v base64 >/dev/null 2>&1 && command -v xxd >/dev/null 2>&1; then + val=$(echo -n "$val" | base64 -d | xxd -p -c 999 | tr -d '\n' | tr 'a-f' 'A-F') + else + display_and_log "Warning: base64 or xxd not available. Skipping ROM extraction." "$logfile" + continue + fi + fi + extracted[$key]="$val" + done + + jq -n \ + --arg Type "${extracted[SystemProductName]}" \ + --arg Serial "${extracted[SystemSerialNumber]}" \ + --arg board_serial "${extracted[MLB]}" \ + --arg SmUUID "${extracted[SystemUUID]}" \ + --arg ROM "${extracted[ROM]}" \ + '{Type: $Type, Serial: $Serial, "Board Serial": $board_serial, SmUUID: $SmUUID, ROM: $ROM}' > "$oc_json_path" + display_and_log "Updated/Created SMBIOS JSON at $oc_json_path" "$logfile" + else + display_and_log "Changes discarded." "$logfile" + rm "$TEMP_FILE" + fi + else + display_and_log "No changes were made." "$logfile" + rm "$TEMP_FILE" + fi + + # Cleanup + 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" + display_and_log "OpenCore config customized" "$logfile" + read -n 1 -sp "Press any key to return to menu..." +} + # Function to update OpenCore ISO update_opencore_iso() { + local iso_path local logfile="${LOGDIR}/update-opencore-iso.log" local iso_url="https://github.com/luchina-gabriel/OSX-PROXMOX/raw/main/EFI/opencore-osx-proxmox-vm.iso" - local iso_path="${ISODIR}/opencore-osx-proxmox-vm.iso" + iso_path="${ISODIR}/${OPENCORE_ISO}" + oc_json_path="${ISODIR}/.smbios.json" rm -f "$iso_path" >>"$logfile" 2>&1 if ! wget -q -O "$iso_path" "$iso_url" >>"$logfile" 2>&1; then log_and_exit "Failed to download OpenCore ISO" "$logfile" fi + ensure_base64_xxd_dependency + update_opencore_smbios "$iso_path" "$oc_json_path" display_and_log "OpenCore ISO updated" "$logfile" sleep 5 @@ -463,7 +878,7 @@ remove_subscription_notice() { # Function to configure network bridge configure_network_bridge() { local logfile="${LOGDIR}/configure-network-bridge.log" - + # Logging functions die() { display_and_log "ERROR: $*" "$logfile" @@ -505,7 +920,7 @@ configure_network_bridge() { ensure_dependencies() { local deps=("ipcalc") local missing=() - + # Check for isc-dhcp-server if ! dpkg -l isc-dhcp-server &>/dev/null; then deps+=("isc-dhcp-server") @@ -521,7 +936,7 @@ configure_network_bridge() { info "Installing missing dependencies: ${missing[*]}" apt-get update && apt-get install -y "${missing[@]}" >>"$logfile" 2>&1 || die "Failed to install dependencies" fi - + # Ensure DHCP config directory exists mkdir -p "$DHCP_CONF_DIR" chown root:root "$DHCP_CONF_DIR" @@ -532,26 +947,26 @@ configure_network_bridge() { calculate_network() { local subnet=$1 declare -gA network_info - + # Validate subnet format if [[ ! "$subnet" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$ ]]; then warn "Invalid subnet format: $subnet" return 1 fi - + # Get ipcalc output if ! ipcalc_output=$(ipcalc -nb "$subnet"); then warn "ipcalc failed to process subnet: $subnet" return 1 fi - + # Parse network information network_info["network"]=$(echo "$ipcalc_output" | awk '/^Network:/ {print $2}' | cut -d'/' -f1) network_info["netmask"]=$(echo "$ipcalc_output" | awk '/^Netmask:/ {print $2}') network_info["broadcast"]=$(echo "$ipcalc_output" | awk '/^Broadcast:/ {print $2}') network_info["hostmin"]=$(echo "$ipcalc_output" | awk '/^HostMin:/ {print $2}') network_info["hostmax"]=$(echo "$ipcalc_output" | awk '/^HostMax:/ {print $2}') - + # Calculate DHCP range (skip first 50 IPs) IFS='.' read -r i1 i2 i3 i4 <<< "${network_info[hostmin]}" network_info["range_start"]="$i1.$i2.$i3.$((i4 + 50))" @@ -572,7 +987,7 @@ configure_network_bridge() { validate_bridge() { local bridge_num=$1 [[ "$bridge_num" =~ ^[0-9]+$ ]] || { warn "Bridge number must be a positive integer"; return 1; } - + if [[ -d "/sys/class/net/vmbr$bridge_num" || \ -n $(grep -h "^iface vmbr$bridge_num" "$NETWORK_INTERFACES_FILE" 2>/dev/null) ]]; then return 1 # Bridge exists @@ -583,7 +998,7 @@ configure_network_bridge() { # Find next available bridge find_next_bridge() { local bridge_num=0 - while ! validate_bridge "$bridge_num"; do + while ! validate_bridge "$bridge_num"; do ((bridge_num++)) done echo "$bridge_num" @@ -593,10 +1008,10 @@ configure_network_bridge() { validate_subnet() { local subnet=$1 [[ "$subnet" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$ ]] || { warn "Invalid CIDR format"; return 1; } - + IFS='./' read -r ip1 ip2 ip3 ip4 mask <<< "$subnet" (( ip1 <= 255 && ip2 <= 255 && ip3 <= 255 && ip4 <= 255 && mask <= 32 )) || { warn "Invalid IP/Netmask"; return 1; } - + # Check for conflicts while read -r existing; do if [[ -n "$existing" ]]; then @@ -606,7 +1021,7 @@ configure_network_bridge() { fi fi done < <(get_existing_subnets) - + return 0 } @@ -643,7 +1058,7 @@ configure_network_bridge() { for conf in "$DHCP_CONF_DIR"/*.conf; do [[ -f "$conf" ]] && interfaces+=("$(basename "${conf%.conf}")") done - + # Update interfaces list printf "INTERFACESv4=\"%s\"\n" "${interfaces[*]}" > /etc/default/isc-dhcp-server } @@ -652,12 +1067,12 @@ configure_network_bridge() { configure_dhcp() { local bridge_name=$1 local subnet=$2 - + if ! calculate_network "$subnet"; then warn "Failed to calculate network parameters for $subnet" return 1 fi - + # Create bridge-specific config printf "subnet %s netmask %s {\n" "${network_info[network]}" "${network_info[netmask]}" > "$DHCP_CONF_DIR/$bridge_name.conf" printf " range %s %s;\n" "${network_info[range_start]}" "${network_info[range_end]}" >> "$DHCP_CONF_DIR/$bridge_name.conf" @@ -693,7 +1108,7 @@ configure_network_bridge() { configure_network() { local bridge_num=$1 local subnet=$2 - + info "Calculating network parameters for $subnet..." if ! calculate_network "$subnet"; then die "Failed to calculate network parameters for $subnet" @@ -746,7 +1161,7 @@ configure_network_bridge() { local default=$2 local validation_func=$3 local value - + while true; do read -rp "$prompt [$default]: " value value=${value:-$default} @@ -762,7 +1177,7 @@ configure_network_bridge() { # Main execution info "Configuring network bridge for macOS in Cloud..." - + # Check root (( EUID == 0 )) || die "This function must be run as root" @@ -804,45 +1219,12 @@ configure_network_bridge() { read -n 1 -s } -# Function to customize OpenCore config.plist -customize_opencore_config() { - local logfile="${LOGDIR}/custom-oc-config.plist.log" - local iso="${ISODIR}/opencore-osx-proxmox-vm.iso" - local loopdev=$(losetup -f --show -P "$iso") || log_and_exit "Failed to set up loop device" "$logfile" - mkdir -p /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to create mount point" "$logfile" - mount "${loopdev}p1" /mnt/opencore >>"$logfile" 2>&1 || log_and_exit "Failed to mount ISO" "$logfile" - local config="/mnt/opencore/EFI/OC/config.plist" - [[ ! -e "$config.backup" ]] && cp "$config" "$config.backup" >>"$logfile" 2>&1 - local prev_lang=$(grep -E '..-..:0' "$config" | sed 's/.*\(..-..\).*/\1/') - local boot_args=$(grep 'boot-args' "$config" -A1 | tail -n1 | sed 's/.*>\(.*\)<.*/\1/') - local timeout=$(grep -A1 '>Timeout<' "$config" | tail -n1 | sed 's/.*>\(.*\)<.*/\1/') - read -rp "Enter language-country code [${prev_lang}]: " NEW_PREV_LANG - sed -i "s/..-..:0/${NEW_PREV_LANG:-$prev_lang}:0/" "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to update language" "$logfile" - read -rp "Enter boot-args [${boot_args}]: " NEW_BOOT_ARGS - sed -i "s|${boot_args}|${NEW_BOOT_ARGS:-$boot_args}|" "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to update boot-args" "$logfile" - read -rp "Remove csr-active-config (unlock SIP)? [Y/N] [N]: " RM_CSR_LOCK - if [[ "${RM_CSR_LOCK:-N}" =~ ^[Yy]$ ]]; then - sed -i '/csr-active-config>/,+1d' "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to remove csr-active-config" "$logfile" - display_and_log "SIP unlocked. Use 'csrutil disable' in Recovery OS" "$logfile" - fi - read -rp "Enter timeout [${timeout}]: " NEW_TIMEOUT - NEW_TIMEOUT=${NEW_TIMEOUT:-$timeout} - if [[ "$NEW_TIMEOUT" != "$timeout" ]]; then - sed -i "/Timeout<\/key>/{n;s/$timeout<\/integer>/$NEW_TIMEOUT<\/integer>/}" "$config" >>"$logfile" 2>&1 || log_and_exit "Failed to update timeout" "$logfile" - fi - diff -u "$config.backup" "$config" || true - 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" - display_and_log "OpenCore config customized" "$logfile" - read -n 1 -sp "Press any key to return to menu..." -} - # Function to configure macOS VM configure_macos_vm() { - local opt=$1 + local macopt=$1 local nextid=$2 - local version_name version board_id model_id iso_size disk_type - IFS='|' read -r version_name version board_id model_id iso_size disk_type <<< "${MACOS_CONFIG[$opt]}" + local version_name version board_id model_id iso_size disk_type opt=$3 + IFS='|' read -r version_name version board_id model_id iso_size disk_type <<< "$macopt" 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" clear @@ -1049,7 +1431,7 @@ main_menu() { [[ -z "$OPT" || "$OPT" -eq 0 ]] && exit if [[ ${MACOS_CONFIG[$OPT]} ]]; then - configure_macos_vm "$OPT" "$NEXTID" + configure_macos_vm "${MACOS_CONFIG[$OPT]}" "$NEXTID" "$OPT" else case $OPT in 200) add_no_subscription_repo ;; @@ -1070,8 +1452,8 @@ init_dirs check_proxmox_version set_isodir # Check if OpenCore ISO exists, and install if not in the ISODIR. -if [ ! -f "${ISODIR}/opencore-osx-proxmox-vm.iso" ]; then - update_opencore_iso +if [ ! -f "${ISODIR}/${OPENCORE_ISO}" ]; then + update_opencore_iso "0" fi sleep 4 OSX_PLATFORM=$(detect_cpu_platform) diff --git a/tools/GenSMBIOS b/tools/GenSMBIOS new file mode 160000 index 0000000..573f5fc --- /dev/null +++ b/tools/GenSMBIOS @@ -0,0 +1 @@ +Subproject commit 573f5fc375cb52688ccac4312de8422ae263dcf2