diff --git a/misc/api.func b/misc/api.func index 6d02b29f1..da5a51ed0 100644 --- a/misc/api.func +++ b/misc/api.func @@ -135,19 +135,44 @@ explain_exit_code() { # --- Generic / Shell --- 1) echo "General error / Operation not permitted" ;; 2) echo "Misuse of shell builtins (e.g. syntax error)" ;; + 10) echo "Docker / privileged mode required (unsupported environment)" ;; # --- curl / wget errors (commonly seen in downloads) --- + 4) echo "curl: Feature not supported or protocol error" ;; + 5) echo "curl: Could not resolve proxy" ;; 6) echo "curl: DNS resolution failed (could not resolve host)" ;; 7) echo "curl: Failed to connect (network unreachable / host down)" ;; + 8) echo "curl: FTP server reply error" ;; 22) echo "curl: HTTP error returned (404, 429, 500+)" ;; + 23) echo "curl: Write error (disk full or permissions)" ;; + 25) echo "curl: Upload failed" ;; 28) echo "curl: Operation timeout (network slow or server not responding)" ;; + 30) echo "curl: FTP port command failed" ;; 35) echo "curl: SSL/TLS handshake failed (certificate error)" ;; + 56) echo "curl: Receive error (connection reset by peer)" ;; + 75) echo "Temporary failure (retry later)" ;; + 78) echo "curl: Remote file not found (404 on FTP/file)" ;; # --- Package manager / APT / DPKG --- 100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; + # --- BSD sysexits.h (64-78) --- + 64) echo "Usage error (wrong arguments)" ;; + 65) echo "Data format error (bad input data)" ;; + 66) echo "Input file not found (cannot open input)" ;; + 67) echo "User not found (addressee unknown)" ;; + 68) echo "Host not found (hostname unknown)" ;; + 69) echo "Service unavailable" ;; + 70) echo "Internal software error" ;; + 71) echo "System error (OS-level failure)" ;; + 72) echo "Critical OS file missing" ;; + 73) echo "Cannot create output file" ;; + 74) echo "I/O error" ;; + 76) echo "Remote protocol error" ;; + 77) echo "Permission denied" ;; + # --- Common shell/system errors --- 124) echo "Command timed out (timeout command)" ;; 126) echo "Command invoked cannot execute (permission problem?)" ;; @@ -624,6 +649,8 @@ EOF curl -fsS -m "${TELEMETRY_TIMEOUT}" -X POST "${TELEMETRY_URL}" \ -H "Content-Type: application/json" \ -d "$JSON_PAYLOAD" &>/dev/null || true + + POST_TO_API_DONE=true } # ------------------------------------------------------------------------------ diff --git a/misc/build.func b/misc/build.func index bae2c95b9..215fbb0e5 100644 --- a/misc/build.func +++ b/misc/build.func @@ -5253,14 +5253,20 @@ ensure_log_on_host() { # - Exit trap handler for reporting to API telemetry # - Captures exit code and reports to PocketBase using centralized error descriptions # - Uses explain_exit_code() from api.func for consistent error messages -# - Posts failure status with exit code to API (error description resolved automatically) -# - Only executes on non-zero exit codes +# - For non-zero exit codes: posts "failed" status +# - For zero exit codes where post_update_to_api was never called: +# catches orphaned "installing" records (e.g., script exited cleanly +# but description() was never reached) # ------------------------------------------------------------------------------ api_exit_script() { - exit_code=$? + local exit_code=$? if [ $exit_code -ne 0 ]; then ensure_log_on_host post_update_to_api "failed" "$exit_code" + elif [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + # Script exited with 0 but never sent a completion status + # This catches edge cases like early returns after post_to_api() + post_update_to_api "failed" "1" fi } diff --git a/misc/error_handler.func b/misc/error_handler.func index 2f0fc2438..f46ba5f8d 100644 --- a/misc/error_handler.func +++ b/misc/error_handler.func @@ -37,11 +37,34 @@ if ! declare -f explain_exit_code &>/dev/null; then case "$code" in 1) echo "General error / Operation not permitted" ;; 2) echo "Misuse of shell builtins (e.g. syntax error)" ;; + 10) echo "Docker / privileged mode required (unsupported environment)" ;; + 4) echo "curl: Feature not supported or protocol error" ;; + 5) echo "curl: Could not resolve proxy" ;; 6) echo "curl: DNS resolution failed (could not resolve host)" ;; 7) echo "curl: Failed to connect (network unreachable / host down)" ;; + 8) echo "curl: FTP server reply error" ;; 22) echo "curl: HTTP error returned (404, 429, 500+)" ;; + 23) echo "curl: Write error (disk full or permissions)" ;; + 25) echo "curl: Upload failed" ;; 28) echo "curl: Operation timeout (network slow or server not responding)" ;; + 30) echo "curl: FTP port command failed" ;; 35) echo "curl: SSL/TLS handshake failed (certificate error)" ;; + 56) echo "curl: Receive error (connection reset by peer)" ;; + 75) echo "Temporary failure (retry later)" ;; + 78) echo "curl: Remote file not found (404 on FTP/file)" ;; + 64) echo "Usage error (wrong arguments)" ;; + 65) echo "Data format error (bad input data)" ;; + 66) echo "Input file not found (cannot open input)" ;; + 67) echo "User not found (addressee unknown)" ;; + 68) echo "Host not found (hostname unknown)" ;; + 69) echo "Service unavailable" ;; + 70) echo "Internal software error" ;; + 71) echo "System error (OS-level failure)" ;; + 72) echo "Critical OS file missing" ;; + 73) echo "Cannot create output file" ;; + 74) echo "I/O error" ;; + 76) echo "Remote protocol error" ;; + 77) echo "Permission denied" ;; 100) echo "APT: Package manager error (broken packages / dependency problems)" ;; 101) echo "APT: Configuration error (bad sources.list, malformed config)" ;; 102) echo "APT: Lock held by another process (dpkg/apt still running)" ;; diff --git a/misc/vm-core.func b/misc/vm-core.func index 557b99a46..66949fa69 100644 --- a/misc/vm-core.func +++ b/misc/vm-core.func @@ -529,9 +529,21 @@ cleanup_vmid() { } cleanup() { + local exit_code=$? if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then popd >/dev/null || true fi + # Report final telemetry status if post_to_api_vm was called but no update was sent + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if declare -f post_update_to_api >/dev/null 2>&1; then + if [[ $exit_code -ne 0 ]]; then + post_update_to_api "failed" "$exit_code" + else + # Exited cleanly but description()/success was never called — shouldn't happen + post_update_to_api "failed" "1" + fi + fi + fi } check_root() { diff --git a/vm/archlinux-vm.sh b/vm/archlinux-vm.sh index 14aa5ba0b..8eb0e15ab 100644 --- a/vm/archlinux-vm.sh +++ b/vm/archlinux-vm.sh @@ -100,8 +100,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/debian-13-vm.sh b/vm/debian-13-vm.sh index fcf0f7978..7be0c8cce 100644 --- a/vm/debian-13-vm.sh +++ b/vm/debian-13-vm.sh @@ -100,8 +100,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/debian-vm.sh b/vm/debian-vm.sh index 1af726b3d..3fbac27ce 100644 --- a/vm/debian-vm.sh +++ b/vm/debian-vm.sh @@ -100,8 +100,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/haos-vm.sh b/vm/haos-vm.sh index ab490b002..f4d2239c2 100644 --- a/vm/haos-vm.sh +++ b/vm/haos-vm.sh @@ -104,8 +104,16 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + # Only send telemetry if post_to_api_vm was called (installing status was sent) + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/mikrotik-routeros.sh b/vm/mikrotik-routeros.sh index 6ea0c868b..efaff65f9 100644 --- a/vm/mikrotik-routeros.sh +++ b/vm/mikrotik-routeros.sh @@ -101,8 +101,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/nextcloud-vm.sh b/vm/nextcloud-vm.sh index 960322d5d..7e4f1329d 100644 --- a/vm/nextcloud-vm.sh +++ b/vm/nextcloud-vm.sh @@ -100,8 +100,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/openwrt-vm.sh b/vm/openwrt-vm.sh index f14708f86..b68dd5845 100644 --- a/vm/openwrt-vm.sh +++ b/vm/openwrt-vm.sh @@ -105,7 +105,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/opnsense-vm.sh b/vm/opnsense-vm.sh index 9d7eac26a..82dceb44e 100644 --- a/vm/opnsense-vm.sh +++ b/vm/opnsense-vm.sh @@ -79,8 +79,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/owncloud-vm.sh b/vm/owncloud-vm.sh index 8cfd668f8..07cfddd15 100644 --- a/vm/owncloud-vm.sh +++ b/vm/owncloud-vm.sh @@ -101,8 +101,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/pimox-haos-vm.sh b/vm/pimox-haos-vm.sh index e234ecc96..9d61ae08c 100644 --- a/vm/pimox-haos-vm.sh +++ b/vm/pimox-haos-vm.sh @@ -109,8 +109,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/ubuntu2204-vm.sh b/vm/ubuntu2204-vm.sh index 910691104..dd9b2872a 100644 --- a/vm/ubuntu2204-vm.sh +++ b/vm/ubuntu2204-vm.sh @@ -97,7 +97,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/ubuntu2404-vm.sh b/vm/ubuntu2404-vm.sh index d2c503458..67f7a3bd2 100644 --- a/vm/ubuntu2404-vm.sh +++ b/vm/ubuntu2404-vm.sh @@ -100,7 +100,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/ubuntu2504-vm.sh b/vm/ubuntu2504-vm.sh index 7ba4da312..a285f7218 100644 --- a/vm/ubuntu2504-vm.sh +++ b/vm/ubuntu2504-vm.sh @@ -99,7 +99,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR } diff --git a/vm/umbrel-os-vm.sh b/vm/umbrel-os-vm.sh index 25ef06ed2..4d71d0732 100644 --- a/vm/umbrel-os-vm.sh +++ b/vm/umbrel-os-vm.sh @@ -99,8 +99,15 @@ function cleanup_vmid() { } function cleanup() { + local exit_code=$? popd >/dev/null - post_update_to_api "done" "none" + if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then + if [[ $exit_code -eq 0 ]]; then + post_update_to_api "done" "none" + else + post_update_to_api "failed" "$exit_code" + fi + fi rm -rf $TEMP_DIR }