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