From 9bedb4f31176abdbbdf8b173b438102b32ad9140 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Thu, 11 Jun 2026 23:49:13 +0200 Subject: [PATCH] update 1.2.2.2 beta --- scripts/backup_restore/backup_host.sh | 40 +++++++++++++++---- scripts/gpu_tpu/nvidia_installer.sh | 56 ++++++++++++++++++++------- 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/scripts/backup_restore/backup_host.sh b/scripts/backup_restore/backup_host.sh index 8fd55fc9..99a7bd87 100644 --- a/scripts/backup_restore/backup_host.sh +++ b/scripts/backup_restore/backup_host.sh @@ -1793,6 +1793,21 @@ _rs_run_complete_guided() { plan_body="\Zb$(translate "Smart restore plan — hardware compatibility check")\ZB"$'\n\n' plan_body+="$(translate "The backup metadata was compared against this host. The following items will be SKIPPED to keep the boot safe:")"$'\n\n' + # Identifier-based skips (ZFS pool GUID, boot EFI UUID, fstab + # UUID) ALWAYS fire on a cross-host restore — those identifiers + # are unique per disk/pool. Showing them in the dialog is noise + # the operator can't act on. We still apply the skips (that's + # what protects against, e.g., restoring zpool.cache pointing at + # a ghost pool), just without the dialog when only this noise + # would be shown. The signal-bearing skips (component drift — + # NVIDIA in backup, no NVIDIA card here) still trigger the dialog + # so the operator can decide. + local -A _IDENTIFIER_PATHS=( + ["/etc/zfs/zpool.cache"]=1 + ["/etc/kernel/proxmox-boot-uuids"]=1 + ["/etc/fstab"]=1 + ) + local dialog_signal=0 local line key action reason for line in "${drift_lines[@]}"; do IFS=$'\t' read -r key action reason <<<"$line" @@ -1802,20 +1817,32 @@ _rs_run_complete_guided() { skip_components+="${cname} " plan_body+=" \Z1•\Zn $(translate "Component:") \Zb${cname}\ZB"$'\n' plan_body+=" ${reason}"$'\n\n' + dialog_signal=1 else skip_paths+="${key}"$'\n' + # Identifier-based paths on cross-host: skip silently + # (the path goes into RS_SKIP_PATHS but stays out of + # the dialog body, and dialog_signal stays 0 if every + # skip is of this kind). + if [[ "${HB_COMPAT_SAME_HOST:-1}" == "0" ]] \ + && [[ -n "${_IDENTIFIER_PATHS[$key]:-}" ]]; then + continue + fi plan_body+=" \Z1•\Zn $(translate "Path:") \Zb${key}\ZB"$'\n' plan_body+=" ${reason}"$'\n\n' + dialog_signal=1 fi done - plan_body+="$(translate "PVE will regenerate these files automatically for the current hardware. The rest of the backup will be applied normally.")"$'\n\n' - plan_body+="\Zb$(translate "Continue with safe restore?")\ZB" + if (( dialog_signal == 1 )); then + plan_body+="$(translate "PVE will regenerate these files automatically for the current hardware. The rest of the backup will be applied normally.")"$'\n\n' + plan_body+="\Zb$(translate "Continue with safe restore?")\ZB" - if ! dialog --backtitle "ProxMenux" --colors \ - --title "$(translate "Restore plan — compatibility check")" \ - --yesno "$plan_body" 24 90; then - return 1 + if ! dialog --backtitle "ProxMenux" --colors \ + --title "$(translate "Restore plan — compatibility check")" \ + --yesno "$plan_body" 24 90; then + return 1 + fi fi # Persist for _rs_apply / _rs_collect_pending_paths to honor. @@ -2286,7 +2313,6 @@ _rs_run_complete_extras() { fi if (( ${#unknown[@]} > 0 )); then msg_warn "$(translate "Skipped, not in apt cache:") ${unknown[*]:0:6}$([[ ${#unknown[@]} -gt 6 ]] && echo " … (+ $((${#unknown[@]} - 6)) more)")" - echo -e "${TAB}${BL}$(translate "These were marked manual on the source host but apt-cache cannot resolve them now (typo, removed pkg, third-party repo not configured yet).")${CL}" fi fi fi diff --git a/scripts/gpu_tpu/nvidia_installer.sh b/scripts/gpu_tpu/nvidia_installer.sh index d1a5ae86..f0e77df9 100644 --- a/scripts/gpu_tpu/nvidia_installer.sh +++ b/scripts/gpu_tpu/nvidia_installer.sh @@ -1150,12 +1150,28 @@ EOF } apply_nvidia_patch_if_needed() { - if ! hybrid_whiptail_yesno "$(translate 'NVIDIA Patch')" \ - "\n$(translate 'Do you want to apply the optional NVIDIA patch to remove some GPU limitations?')"; then - msg_info2 "$(translate 'NVIDIA patch not applied.')" - update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}' - return 0 - fi + # NVIDIA_PATCH_AUTO lets non-interactive callers (the post-restore + # auto-reinstall path in particular) skip the yes/no: + # yes → apply the patch silently (the operator decided "true" was + # the recorded state in the backup we just restored from) + # no → don't apply, mark as not patched (recorded state was false) + # unset → ask, as before (interactive use from the menu) + case "${NVIDIA_PATCH_AUTO:-}" in + yes) : ;; + no) + msg_info2 "$(translate 'NVIDIA patch not applied.')" + update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}' + return 0 + ;; + *) + if ! hybrid_whiptail_yesno "$(translate 'NVIDIA Patch')" \ + "\n$(translate 'Do you want to apply the optional NVIDIA patch to remove some GPU limitations?')"; then + msg_info2 "$(translate 'NVIDIA patch not applied.')" + update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}' + return 0 + fi + ;; + esac msg_info "$(translate 'Cloning and applying NVIDIA patch (keylase/nvidia-patch)...')" ensure_workdir @@ -1593,9 +1609,10 @@ auto_reinstall_from_state() { return 1 fi - local recorded_status recorded_version - recorded_status=$(jq -r '.nvidia_driver.status // ""' "$COMPONENTS_STATUS_FILE" 2>/dev/null) - recorded_version=$(jq -r '.nvidia_driver.version // ""' "$COMPONENTS_STATUS_FILE" 2>/dev/null) + local recorded_status recorded_version recorded_patched + recorded_status=$(jq -r '.nvidia_driver.status // ""' "$COMPONENTS_STATUS_FILE" 2>/dev/null) + recorded_version=$(jq -r '.nvidia_driver.version // ""' "$COMPONENTS_STATUS_FILE" 2>/dev/null) + recorded_patched=$(jq -r '.nvidia_driver.patched // false' "$COMPONENTS_STATUS_FILE" 2>/dev/null) if [[ "$recorded_status" != "installed" ]]; then echo "nvidia_driver not marked installed in state ($recorded_status) — nothing to do" | tee -a "$LOG_FILE" @@ -1605,7 +1622,7 @@ auto_reinstall_from_state() { echo "nvidia_driver marked installed but no version recorded — aborting" | tee -a "$LOG_FILE" return 1 fi - echo "Recorded driver: $recorded_version" >>"$LOG_FILE" + echo "Recorded driver: $recorded_version (patched=$recorded_patched)" >>"$LOG_FILE" detect_nvidia_gpus if ! $NVIDIA_GPU_PRESENT; then @@ -1646,10 +1663,21 @@ auto_reinstall_from_state() { fi install_udev_rules_and_persistenced >>"$LOG_FILE" 2>&1 - # Record success — overwrites whatever the restore put there - # (same version key, fresh timestamp). - if declare -F update_component_status >/dev/null 2>&1; then - update_component_status "nvidia_driver" "installed" "$DRIVER_VERSION" "gpu" '{"patched":false}' >>"$LOG_FILE" 2>&1 + # If the backup said the driver was patched, re-apply the keylase + # patch in non-interactive mode (NVIDIA_PATCH_AUTO=yes bypasses the + # yes/no prompt and goes straight to clone+apply). The patch helper + # writes its own update_component_status with {"patched":true} on + # success, so we don't overwrite it below. If the backup said the + # driver was NOT patched, write {"patched":false} explicitly so the + # operator's recorded preference doesn't silently flip. + CURRENT_DRIVER_VERSION="$DRIVER_VERSION" + if [[ "$recorded_patched" == "true" ]]; then + echo "Recorded state had patched=true — re-applying NVIDIA patch..." | tee -a "$LOG_FILE" + NVIDIA_PATCH_AUTO=yes apply_nvidia_patch_if_needed >>"$LOG_FILE" 2>&1 || true + else + if declare -F update_component_status >/dev/null 2>&1; then + update_component_status "nvidia_driver" "installed" "$DRIVER_VERSION" "gpu" '{"patched":false}' >>"$LOG_FILE" 2>&1 + fi fi echo "✓ NVIDIA driver $DRIVER_VERSION reinstalled" | tee -a "$LOG_FILE"