diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 000000000..8226afb6b --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1 @@ +external-sources=true diff --git a/misc/build.func b/misc/build.func index f6706adaf..d2e2ceb4b 100644 --- a/misc/build.func +++ b/misc/build.func @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Copyright (c) 2021-2026 community-scripts ORG # Author: tteck (tteckster) | MickLesk | michelroegl-brunner +# Co-Author: bandogora # License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE # ============================================================================== @@ -83,20 +84,21 @@ variables() { fi } -# Configurable base URL for development — override with COMMUNITY_SCRIPTS_URL -# See docs/DEV_MODE.md for details -COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}" - -source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/api.func") +# shellcheck source=misc/api.func +source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/api.func) if command -v curl >/dev/null 2>&1; then - source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/core.func") - source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/error_handler.func") + # shellcheck source=misc/core.func + source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func) + # shellcheck source=misc/error_handler.func + source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func) load_functions catch_errors elif command -v wget >/dev/null 2>&1; then - source <(wget -qO- "$COMMUNITY_SCRIPTS_URL/misc/core.func") - source <(wget -qO- "$COMMUNITY_SCRIPTS_URL/misc/error_handler.func") + # shellcheck source=misc/core.func + source <(wget -qO- https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func) + # shellcheck source=misc/error_handler.func + source <(wget -qO- https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func) load_functions catch_errors fi @@ -682,7 +684,7 @@ find_host_ssh_keys() { shopt -s nullglob if [[ -n "$g" ]]; then - for pat in $g; do cand+=($pat); done + for pat in $g; do cand+=("$pat"); done else cand+=(/root/.ssh/authorized_keys /root/.ssh/authorized_keys2) cand+=(/root/.ssh/*.pub) @@ -699,11 +701,11 @@ find_host_ssh_keys() { esac # CRLF safe check for host keys - c=$(tr -d '\r' <"$f" | awk ' - /^[[:space:]]*#/ {next} - /^[[:space:]]*$/ {next} - {print} - ' | grep -E -c '"$re"' || true) + c=$( + tr -d '\r' <"$f" | + awk '/^[[:space:]]*#/ {next} /^[[:space:]]*$/ {next} {print}' | + grep -E -c "$re" || true + ) if ((c > 0)); then files+=("$f") @@ -772,11 +774,13 @@ resolve_ip_from_range() { local ip2="${ip_end%%/*}" local cidr="${ip_start##*/}" - local start_int=$(ip_to_int "$ip1") - local end_int=$(ip_to_int "$ip2") + local start_int end_int + start_int=$(ip_to_int "$ip1") + end_int=$(ip_to_int "$ip2") for ((ip_int = start_int; ip_int <= end_int; ip_int++)); do - local ip=$(int_to_ip $ip_int) + local ip + ip=$(int_to_ip $ip_int) msg_info "Checking IP: $ip" if ! ping -c 1 -W 1 "$ip" >/dev/null 2>&1; then NET_RESOLVED="$ip/$cidr" @@ -1309,7 +1313,7 @@ var_timezone= # Container timezone (e.g. Europe/Berlin, leave empty for var_tags=community-script var_verbose=no -# Security (root PW) – empty => autologin +# Security (root PW) - empty => autologin # var_pw= EOF @@ -1398,7 +1402,7 @@ _is_whitelisted_key() { _sanitize_value() { # Disallow Command-Substitution / Shell-Meta case "$1" in - *'$('* | *'`'* | *';'* | *'&'* | *'<('*) + *\$\(* | *\`* | *\;* | *\&* | *\<\(*) echo "" return 0 ;; @@ -1480,7 +1484,7 @@ _build_vars_diff() { # Build a temporary .vars file from current advanced settings _build_current_app_vars_tmp() { - tmpf="$(mktemp /tmp/${NSAPP:-app}.vars.new.XXXXXX)" + tmpf=$(mktemp "/tmp/${NSAPP:-app}.vars.new.XXXXXX") # NET/GW _net="${NET:-}" @@ -1643,7 +1647,7 @@ maybe_offer_save_app_defaults() { while true; do local sel sel="$(whiptail --backtitle "Proxmox VE Helper Scripts" \ - --title "APP DEFAULTS – ${APP}" \ + --title "APP DEFAULTS - ${APP}" \ --menu "Differences detected. What do you want to do?" 20 78 10 \ "Update Defaults" "Write new values to ${app_vars_file}" \ "Keep Current" "Keep existing defaults (no changes)" \ @@ -1664,7 +1668,7 @@ maybe_offer_save_app_defaults() { ;; "View Diff") whiptail --backtitle "Proxmox VE Helper Scripts" \ - --title "Diff – ${APP}" \ + --title "Diff - ${APP}" \ --scrolltext --textbox "$diff_tmp" 25 100 ;; "Cancel" | *) @@ -1796,14 +1800,17 @@ advanced_settings() { local OLD_IFS=$IFS IFS=$'\n' for iface_filepath in ${IFACE_FILEPATH_LIST}; do - local iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX') + local iface_indexes_tmpfile + iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX') (grep -Pn '^\s*iface' "${iface_filepath}" 2>/dev/null | cut -d':' -f1 && wc -l "${iface_filepath}" 2>/dev/null | cut -d' ' -f1) | awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' >"${iface_indexes_tmpfile}" 2>/dev/null || true if [ -f "${iface_indexes_tmpfile}" ]; then while read -r pair; do - local start=$(echo "${pair}" | cut -d':' -f1) - local end=$(echo "${pair}" | cut -d':' -f2) + local start end + start=$(echo "${pair}" | cut -d':' -f1) + end=$(echo "${pair}" | cut -d':' -f2) if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" 2>/dev/null | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then - local iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') + local iface_name + iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}') BRIDGES="${iface_name}"$'\n'"${BRIDGES}" fi done <"${iface_indexes_tmpfile}" @@ -1818,7 +1825,8 @@ advanced_settings() { if [[ -n "$BRIDGES" ]]; then while IFS= read -r bridge; do if [[ -n "$bridge" ]]; then - local description=$(grep -A 10 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep '^#' | head -n1 | sed 's/^#\s*//') + local description + description=$(grep -A 10 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep '^#' | head -n1 | sed 's/^#\s*//') BRIDGE_MENU_OPTIONS+=("$bridge" "${description:- }") fi done <<<"$BRIDGES" @@ -1830,9 +1838,9 @@ advanced_settings() { while [ $STEP -le $MAX_STEP ]; do case $STEP in - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 1: Container Type - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 1) local default_on="ON" local default_off="OFF" @@ -1855,9 +1863,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 2: Root Password - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 2) if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "ROOT PASSWORD" \ @@ -1909,9 +1917,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 3: Container ID - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 3) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "CONTAINER ID" \ @@ -1943,9 +1951,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 4: Hostname - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 4) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "HOSTNAME" \ @@ -1966,9 +1974,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 5: Disk Size - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 5) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "DISK SIZE" \ @@ -1987,9 +1995,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 6: CPU Cores - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 6) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "CPU CORES" \ @@ -2008,9 +2016,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 7: RAM Size - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 7) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "RAM SIZE" \ @@ -2029,9 +2037,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 8: Network Bridge - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 8) if [[ ${#BRIDGE_MENU_OPTIONS[@]} -eq 0 ]]; then # Validate default bridge exists @@ -2062,9 +2070,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 9: IPv4 Configuration - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 9) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "IPv4 CONFIGURATION" \ @@ -2159,9 +2167,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 10: IPv6 Configuration - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 10) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "IPv6 CONFIGURATION" \ @@ -2234,9 +2242,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 11: MTU Size - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 11) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "MTU SIZE" \ @@ -2254,9 +2262,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 12: DNS Search Domain - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 12) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "DNS SEARCH DOMAIN" \ @@ -2270,9 +2278,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 13: DNS Server - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 13) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "DNS SERVER" \ @@ -2286,9 +2294,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 14: MAC Address - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 14) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "MAC ADDRESS" \ @@ -2306,9 +2314,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 15: VLAN Tag - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 15) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "VLAN TAG" \ @@ -2326,9 +2334,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 16: Tags - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 16) if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ --title "CONTAINER TAGS" \ @@ -2348,18 +2356,18 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 17: SSH Settings - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 17) configure_ssh_settings "Step $STEP/$MAX_STEP" # configure_ssh_settings handles its own flow, always advance ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 18: FUSE Support - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 18) local fuse_default_flag="--defaultno" [[ "$_enable_fuse" == "yes" || "$_enable_fuse" == "1" ]] && fuse_default_flag="" @@ -2381,9 +2389,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 19: TUN/TAP Support - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 19) local tun_default_flag="--defaultno" [[ "$_enable_tun" == "yes" || "$_enable_tun" == "1" ]] && tun_default_flag="" @@ -2405,9 +2413,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 20: Nesting Support - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 20) local nesting_default_flag="" [[ "$_enable_nesting" == "0" || "$_enable_nesting" == "no" ]] && nesting_default_flag="--defaultno" @@ -2429,9 +2437,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 21: GPU Passthrough - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 21) local gpu_default_flag="--defaultno" [[ "$_enable_gpu" == "yes" ]] && gpu_default_flag="" @@ -2453,9 +2461,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 22: Keyctl Support (Docker/systemd) - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 22) local keyctl_default_flag="--defaultno" [[ "$_enable_keyctl" == "1" ]] && keyctl_default_flag="" @@ -2477,9 +2485,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 23: APT Cacher Proxy - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 23) local apt_cacher_default_flag="--defaultno" [[ "$_apt_cacher" == "yes" ]] && apt_cacher_default_flag="" @@ -2509,9 +2517,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 24: Container Timezone - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 24) local tz_hint="$_ct_timezone" [[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)" @@ -2534,9 +2542,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 25: Container Protection - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 25) local protect_default_flag="--defaultno" [[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag="" @@ -2558,9 +2566,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 26: Device Node Creation (mknod) - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 26) local mknod_default_flag="--defaultno" [[ "$_enable_mknod" == "1" ]] && mknod_default_flag="" @@ -2582,9 +2590,9 @@ advanced_settings() { ((STEP++)) ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 27: Mount Filesystems - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 27) local mount_hint="" [[ -n "$_mount_fs" ]] && mount_hint="$_mount_fs" || mount_hint="(none)" @@ -2601,9 +2609,9 @@ advanced_settings() { fi ;; - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # STEP 28: Verbose Mode & Confirmation - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== 28) local verbose_default_flag="--defaultno" [[ "$_verbose" == "yes" ]] && verbose_default_flag="" @@ -2669,9 +2677,9 @@ Advanced: esac done - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== # Apply all collected values to global variables - # ═══════════════════════════════════════════════════════════════════════════ + # =========================================================================== CT_TYPE="$_ct_type" PW="$_pw" CT_ID="$_ct_id" @@ -2797,7 +2805,12 @@ diagnostics_check() { fi if ! [ -f "/usr/local/community-scripts/diagnostics" ]; then - if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "DIAGNOSTICS" --yesno "Send Diagnostics of LXC Installation?\n\n(This only transmits data without user data, just RAM, CPU, LXC name, ...)" 10 58); then + if ( + whiptail --backtitle "Proxmox VE Helper Scripts" \ + --title "DIAGNOSTICS" \ + --yesno "Send Diagnostics of LXC Installation?\n\n(This only transmits data without user data, just RAM, CPU, LXC name, ...)" \ + 10 58 + ); then cat </usr/local/community-scripts/diagnostics DIAGNOSTICS=yes @@ -3484,7 +3497,8 @@ msg_menu() { # - Otherwise: shows update/setting menu and runs update_script with cleanup # ------------------------------------------------------------------------------ start() { - source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/tools.func") + # shellcheck source=misc/tools.func + source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func) if command -v pveversion >/dev/null 2>&1; then install_script || return 0 return 0 @@ -3614,10 +3628,11 @@ build_container() { TEMP_DIR=$(mktemp -d) pushd "$TEMP_DIR" >/dev/null if [ "$var_os" == "alpine" ]; then - export FUNCTIONS_FILE_PATH="$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/alpine-install.func")" + FUNCTIONS_FILE_PATH=$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/alpine-install.func) else - export FUNCTIONS_FILE_PATH="$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/install.func")" + FUNCTIONS_FILE_PATH=$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/install.func) fi + export FUNCTIONS_FILE_PATH # Core exports for install.func export DIAGNOSTICS="$DIAGNOSTICS" @@ -3769,7 +3784,8 @@ $PCT_OPTIONS_STRING" NVIDIA_DEVICES=() # Store PCI info to avoid multiple calls - local pci_vga_info=$(lspci -nn 2>/dev/null | grep -E "VGA|Display|3D") + local pci_vga_info + pci_vga_info=$(lspci -nn 2>/dev/null | grep -E "VGA|Display|3D") # Check for Intel GPU - look for Intel vendor ID [8086] if echo "$pci_vga_info" | grep -q "\[8086:"; then @@ -4039,8 +4055,9 @@ EOF fi # Function to get correct GID inside container get_container_gid() { - local group="$1" - local gid=$(pct exec "$CTID" -- getent group "$group" 2>/dev/null | cut -d: -f3) + local group gid + group="$1" + gid=$(pct exec "$CTID" -- getent group "$group" 2>/dev/null | cut -d: -f3) echo "${gid:-44}" # Default to 44 if not found } @@ -4101,7 +4118,7 @@ EOF' # Create /etc/timezone for backwards compatibility with older scripts pct exec "$CTID" -- bash -c "tz='$tz'; ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime && echo \"\$tz\" >/etc/timezone || true" else - msg_warn "Skipping timezone setup – zone '$tz' not found in container" + msg_warn "Skipping timezone setup - zone '$tz' not found in container" fi pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 jq >/dev/null" || { @@ -4123,7 +4140,7 @@ EOF' set +Eeuo pipefail # Disable ALL error handling temporarily trap - ERR # Remove ERR trap completely - lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/install/${var_install}.sh")" + lxc-attach -n "$CTID" -- bash -c "curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/install/${var_install}.sh" local lxc_exit=$? set -Eeuo pipefail # Re-enable error handling @@ -4215,7 +4232,7 @@ EOF' else msg_dev "Container ${CTID} kept for debugging" fi - exit $install_exit_code + exit "$install_exit_code" fi # Prompt user for cleanup with 60s timeout @@ -4375,11 +4392,12 @@ EOF' source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/install.func") declare -f motd_ssh >/dev/null 2>&1 && motd_ssh || true " >/dev/null 2>&1; then - local ct_ip=$(pct exec "$CTID" ip a s dev eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1) + local ct_ip + ct_ip=$(pct exec "$CTID" ip a s dev eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1) echo -e "${BFR}${CM}${GN}MOTD/SSH ready - SSH into container: ssh root@${ct_ip}${CL}" fi fi - exit $install_exit_code + exit "$install_exit_code" ;; 3) # Retry with verbose mode @@ -4390,7 +4408,8 @@ EOF' echo "" # Get new container ID local old_ctid="$CTID" - export CTID=$(get_valid_container_id "$CTID") + CTID=$(get_valid_container_id "$CTID") + export CTID export VERBOSE="yes" export var_verbose="yes" @@ -4487,9 +4506,10 @@ EOF' local old_ctid="$CTID" local old_ram="$RAM_SIZE" local old_cpu="$CORE_COUNT" - export CTID=$(get_valid_container_id "$CTID") - export RAM_SIZE=$((RAM_SIZE * 2)) - export CORE_COUNT=$((CORE_COUNT * 2)) + CTID=$(get_valid_container_id "$CTID") + export CTID + export RAM_SIZE=$((RAM_SIZE * 3 / 2)) + export CORE_COUNT=$((CORE_COUNT + 1)) export var_ram="$RAM_SIZE" export var_cpu="$CORE_COUNT" export VERBOSE="yes" @@ -4536,13 +4556,13 @@ EOF' if [[ "$handled" == false ]]; then echo -e "\n${TAB}${YW}Invalid option. Container ${CTID} kept.${CL}" - exit $install_exit_code + exit "$install_exit_code" fi ;; - - - - + *) + echo -e "\n${TAB}${YW}Invalid option. Container ${CTID} kept.${CL}" + exit "$install_exit_code" + ;; esac else # Timeout - auto-remove @@ -4554,11 +4574,7 @@ EOF' msg_ok "Container ${CTID} removed" fi - # Force one final status update attempt after cleanup - # This ensures status is updated even if the first attempt failed (e.g., HTTP 400) - post_update_to_api "failed" "$install_exit_code" "force" - - exit $install_exit_code + exit "$install_exit_code" fi # Clean up host-side capture log (not needed on success, already in combined_log on failure) @@ -4649,8 +4665,9 @@ fix_gpu_gids() { msg_info "Detecting and setting correct GPU group IDs" # Get actual GIDs from container - local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") - local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") + local video_gid render_gid + video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") + render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") # Create groups if they don't exist if [[ -z "$video_gid" ]]; then @@ -4746,10 +4763,11 @@ select_storage() { while read -r TAG TYPE _ TOTAL USED FREE _; do [[ -n "$TAG" && -n "$TYPE" ]] || continue - local DISPLAY="${TAG} (${TYPE})" - local USED_FMT=$(numfmt --to=iec --from-unit=1024 --format %.1f <<<"$USED") - local FREE_FMT=$(numfmt --to=iec --from-unit=1024 --format %.1f <<<"$FREE") - local INFO="Free: ${FREE_FMT}B Used: ${USED_FMT}B" + local DISPLAY USED_FMT FREE_FMT INFO + DISPLAY="${TAG} (${TYPE})" + USED_FMT=$(numfmt --to=iec --from-unit=1024 --format %.1f <<<"$USED") + FREE_FMT=$(numfmt --to=iec --from-unit=1024 --format %.1f <<<"$FREE") + INFO="Free: ${FREE_FMT}B Used: ${USED_FMT}B" STORAGE_MAP["$DISPLAY"]="$TAG" MENU+=("$DISPLAY" "$INFO" "OFF") ((${#DISPLAY} > COL_WIDTH)) && COL_WIDTH=${#DISPLAY} @@ -5157,7 +5175,7 @@ create_lxc_container() { fi fi - TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)" + TEMPLATE_PATH=$(pvesm path "$TEMPLATE_STORAGE:vztmpl/$TEMPLATE" 2>/dev/null || true) if [[ -z "$TEMPLATE_PATH" ]]; then TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg) [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE" @@ -5217,7 +5235,7 @@ create_lxc_container() { TEMPLATE_SOURCE="online" fi - TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)" + TEMPLATE_PATH=$(pvesm path "$TEMPLATE_STORAGE:vztmpl/$TEMPLATE" 2>/dev/null || true) if [[ -z "$TEMPLATE_PATH" ]]; then TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg) [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE" @@ -5253,21 +5271,21 @@ create_lxc_container() { NEED_DOWNLOAD=0 if [[ ! -f "$TEMPLATE_PATH" ]]; then - msg_info "Template not present locally – will download." + msg_info "Template not present locally - will download." NEED_DOWNLOAD=1 elif [[ ! -r "$TEMPLATE_PATH" ]]; then - msg_error "Template file exists but is not readable – check permissions." + msg_error "Template file exists but is not readable - check permissions." exit 221 elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then if [[ -n "$ONLINE_TEMPLATE" ]]; then - msg_warn "Template file too small (<1MB) – re-downloading." + msg_warn "Template file too small (<1MB) - re-downloading." NEED_DOWNLOAD=1 else msg_warn "Template looks too small, but no online version exists. Keeping local file." fi elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then if [[ -n "$ONLINE_TEMPLATE" ]]; then - msg_warn "Template appears corrupted – re-downloading." + msg_warn "Template appears corrupted - re-downloading." NEED_DOWNLOAD=1 else msg_warn "Template appears corrupted, but no online version exists. Keeping local file." @@ -5328,7 +5346,7 @@ create_lxc_container() { # PCT_OPTIONS is now a string (exported from build_container) # Add rootfs if not already specified - if [[ ! "$PCT_OPTIONS" =~ "-rootfs" ]]; then + if [[ ! $PCT_OPTIONS =~ "-rootfs" ]]; then PCT_OPTIONS="$PCT_OPTIONS -rootfs $CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}" fi @@ -5369,13 +5387,13 @@ create_lxc_container() { # Validate template before pct create (while holding lock) if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH" 2>/dev/null || echo 0)" -lt 1000000 ]]; then - msg_info "Template file missing or too small – downloading" + msg_info "Template file missing or too small - downloading" rm -f "$TEMPLATE_PATH" pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1 msg_ok "Template downloaded" elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then if [[ -n "$ONLINE_TEMPLATE" ]]; then - msg_info "Template appears corrupted – re-downloading" + msg_info "Template appears corrupted - re-downloading" rm -f "$TEMPLATE_PATH" pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1 msg_ok "Template re-downloaded" @@ -5396,7 +5414,7 @@ create_lxc_container() { # Check if template issue - retry with fresh download if grep -qiE 'unable to open|corrupt|invalid' "$LOGFILE"; then - msg_info "Template may be corrupted – re-downloading" + msg_info "Template may be corrupted - re-downloading" rm -f "$TEMPLATE_PATH" pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1 msg_ok "Template re-downloaded" @@ -5420,7 +5438,7 @@ create_lxc_container() { # Local fallback also failed - check for LXC stack version issue if grep -qiE 'unsupported .* version' "$LOGFILE"; then echo - echo "pct reported 'unsupported ... version' – your LXC stack might be too old for this template." + echo "pct reported 'unsupported ... version' - your LXC stack might be too old for this template." echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically." offer_lxc_stack_upgrade_and_maybe_retry "yes" rc=$? @@ -5452,7 +5470,7 @@ create_lxc_container() { # Already on local storage and still failed - check LXC stack version if grep -qiE 'unsupported .* version' "$LOGFILE"; then echo - echo "pct reported 'unsupported ... version' – your LXC stack might be too old for this template." + echo "pct reported 'unsupported ... version' - your LXC stack might be too old for this template." echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically." offer_lxc_stack_upgrade_and_maybe_retry "yes" rc=$?