diff --git a/[core]:-error_handler.func.md b/[core]:-error_handler.func.md new file mode 100644 index 0000000..f8b2aec --- /dev/null +++ b/[core]:-error_handler.func.md @@ -0,0 +1,598 @@ +# Error-Handler.func Wiki + +Comprehensive error handling and signal management module providing exit code explanations, error handlers with logging, and signal trap configuration for all Community-Scripts projects. + +--- + +## 📋 Table of Contents + +- [Overview](#overview) +- [Exit Code Reference](#exit-code-reference) +- [Error Handler Functions](#error-handler-functions) +- [Signal Traps](#signal-traps) +- [Initialization & Setup](#initialization--setup) +- [Error Logging](#error-logging) +- [Best Practices](#best-practices) +- [Debugging](#debugging) +- [Contributing](#contributing) + +--- + +## Overview + +The error_handler.func module provides robust error handling infrastructure: + +- ✅ Comprehensive exit code mapping (1-255+ codes documented) +- ✅ Detailed error messages with line numbers and commands +- ✅ Signal trap configuration (ERR, EXIT, INT, TERM, RETURN) +- ✅ Error logging to persistent files +- ✅ Graceful cleanup on signal termination +- ✅ Stack trace display for debugging +- ✅ Integration with core.func message functions +- ✅ Container-agnostic (works in Proxmox + LXC) + +### Error Handling Flow + +``` +Command Execution + ↓ + ERROR (non-zero exit) + ↓ + ERR Trap Triggered + ↓ +error_handler() called + ↓ +explain_exit_code() lookup + ↓ +Display error with line/command + ↓ +Check for log file + ↓ +Exit with original code +``` + +--- + +## Exit Code Reference + +Exit codes are categorized by source system. See `api.func.md` for comprehensive mapping documentation. + +### Quick Reference Table + +| Range | Category | Examples | +|-------|----------|----------| +| 0 | Success | (no error) | +| 1-2 | Shell errors | Syntax error, operation not permitted | +| 100-101 | APT errors | Package manager errors | +| 126-139 | System errors | Command not found, segfault, OOM | +| 200-231 | Proxmox custom | Container creation errors | +| 210-234 | Database errors | PostgreSQL, MySQL connection issues | +| 243-254 | Runtime errors | Node.js, Python, npm errors | +| 255 | DPKG fatal | Package system fatal error | + +--- + +## Error Handler Functions + +### `explain_exit_code()` + +**Purpose**: Maps numeric exit codes to human-readable descriptions. Shared with api.func for consistency. + +**Signature**: +```bash +explain_exit_code() +``` + +**Parameters**: +- `$1` - Exit code (0-255+) + +**Returns**: Human-readable explanation string + +**Categories Handled**: +- Generic shell errors (1, 2, 126-128, 130, 137, 139, 143) +- Package managers (100-101, 255) +- Python (210-212) +- Databases (PostgreSQL 231-234, MySQL 241-244, MongoDB 251-254) +- Node.js/npm (243-249, 254) +- Proxmox custom (200-231) +- Default: "Unknown error" + +**Usage Examples**: + +```bash +# Example 1: Look up error code +explain_exit_code 127 +# Output: "Command not found" + +# Example 2: In error logging +error_desc=$(explain_exit_code "$exit_code") +echo "Error: $error_desc" >> /tmp/error.log + +# Example 3: Unknown code +explain_exit_code 999 +# Output: "Unknown error" +``` + +--- + +### `error_handler()` + +**Purpose**: Main error handler triggered by ERR trap. Displays detailed error information and exits. + +**Signature**: +```bash +error_handler() +``` + +**Parameters**: +- `$1` (optional) - Exit code (default: current $?) +- `$2` (optional) - Command that failed (default: $BASH_COMMAND) +- `$3` (optional) - Line number (default: ${BASH_LINENO[0]}) + +**Returns**: Exits with original exit code (does not return) + +**Output Format**: +``` +[ERROR] in line 42: exit code 1 (General error): while executing command curl https://api.example.com + +--- Last 10 lines of log file --- +[log content] +------------------------------------ +``` + +**Implementation Pattern**: +```bash +error_handler() { + local exit_code=${1:-$?} + local command=${2:-${BASH_COMMAND:-unknown}} + local line_number=${BASH_LINENO[0]:-unknown} + + # If successful, return silently + if [[ "$exit_code" -eq 0 ]]; then + return 0 + fi + + # Get human-readable error description + local explanation=$(explain_exit_code "$exit_code") + + # Show cursor (might be hidden by spinner) + printf "\e[?25h" + + # Display error using color messages + if declare -f msg_error >/dev/null 2>&1; then + msg_error "in line ${line_number}: exit code ${exit_code} (${explanation}): while executing command ${command}" + else + echo -e "\n${RD}[ERROR]${CL} in line ${line_number}: exit code ${exit_code}: ${command}\n" + fi + + # Log error details if log file configured + if [[ -n "${DEBUG_LOGFILE:-}" ]]; then + { + echo "------ ERROR ------" + echo "Timestamp : $(date '+%Y-%m-%d %H:%M:%S')" + echo "Exit Code : $exit_code ($explanation)" + echo "Line : $line_number" + echo "Command : $command" + echo "-------------------" + } >> "$DEBUG_LOGFILE" + fi + + # Show last lines of log if available + local active_log="$(get_active_logfile)" + if [[ -s "$active_log" ]]; then + local log_lines=$(wc -l < "$active_log") + echo "--- Last 10 lines of log ---" + tail -n 10 "$active_log" + echo "----------------------------" + fi + + exit "$exit_code" +} +``` + +**Usage Examples**: + +```bash +# Example 1: Automatic trap (recommended) +trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR +# Error automatically caught and handled + +# Example 2: Manual invocation (testing) +error_handler 1 "curl https://api.example.com" 42 +# Output: Detailed error with line number + +# Example 3: In conditional +if ! some_command; then + error_handler $? "some_command" $LINENO +fi +``` + +--- + +## Signal Traps + +### `on_exit()` + +**Purpose**: Cleanup handler called on normal script exit or error. + +**Signature**: +```bash +on_exit() +``` + +**Parameters**: None + +**Returns**: Exits with captured exit code + +**Behavior**: +- Captures current exit code +- Removes lock files if present +- Exits with original exit code + +**Implementation Pattern**: +```bash +on_exit() { + local exit_code="$?" + + # Cleanup lock files + [[ -n "${lockfile:-}" && -e "$lockfile" ]] && rm -f "$lockfile" + + # Preserve exit code + exit "$exit_code" +} +``` + +**Trap Configuration**: +```bash +trap on_exit EXIT # Always called on exit +``` + +--- + +### `on_interrupt()` + +**Purpose**: Handler for Ctrl+C (SIGINT) signal. Allows graceful shutdown. + +**Signature**: +```bash +on_interrupt() +``` + +**Parameters**: None + +**Returns**: Exits with code 130 (standard SIGINT exit code) + +**Output**: Displays "Interrupted by user (SIGINT)" message + +**Implementation Pattern**: +```bash +on_interrupt() { + echo -e "\n${RD}Interrupted by user (SIGINT)${CL}" + exit 130 +} +``` + +**Trap Configuration**: +```bash +trap on_interrupt INT # Called on Ctrl+C +``` + +**Usage Example**: +```bash +# Script interrupted by user: +# Ctrl+C pressed +# → on_interrupt() triggers +# → "Interrupted by user (SIGINT)" displayed +# → Exit with code 130 +``` + +--- + +### `on_terminate()` + +**Purpose**: Handler for SIGTERM signal. Allows graceful shutdown on termination. + +**Signature**: +```bash +on_terminate() +``` + +**Parameters**: None + +**Returns**: Exits with code 143 (standard SIGTERM exit code) + +**Output**: Displays "Terminated by signal (SIGTERM)" message + +**Implementation Pattern**: +```bash +on_terminate() { + echo -e "\n${RD}Terminated by signal (SIGTERM)${CL}" + exit 143 +} +``` + +**Trap Configuration**: +```bash +trap on_terminate TERM # Called on SIGTERM +``` + +**Usage Example**: +```bash +# System sends SIGTERM: +# kill -TERM $PID executed +# → on_terminate() triggers +# → "Terminated by signal (SIGTERM)" displayed +# → Exit with code 143 +``` + +--- + +## Initialization & Setup + +### `catch_errors()` + +**Purpose**: Sets up all error traps and signal handlers. Called once at script start. + +**Signature**: +```bash +catch_errors() +``` + +**Parameters**: None + +**Returns**: No explicit return value (configures traps) + +**Traps Configured**: +1. `ERR` → `error_handler()` - Catches command failures +2. `EXIT` → `on_exit()` - Cleanup on any exit +3. `INT` → `on_interrupt()` - Handle Ctrl+C +4. `TERM` → `on_terminate()` - Handle SIGTERM +5. `RETURN` → `error_handler()` - Catch function errors + +**Implementation Pattern**: +```bash +catch_errors() { + # Set strict mode + set -Eeuo pipefail + + # Configure traps + trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR + trap on_exit EXIT + trap on_interrupt INT + trap on_terminate TERM + trap 'error_handler $? "$BASH_COMMAND" $LINENO' RETURN +} +``` + +**Usage Examples**: + +```bash +# Example 1: Alpine container script +#!/bin/sh +source <(curl -fsSL .../core.func) +source <(curl -fsSL .../error_handler.func) +load_functions +catch_errors + +# Now all signals handled automatically +update_os + +# Example 2: Proxmox host script +#!/bin/bash +source <(curl -fsSL .../core.func) +source <(curl -fsSL .../error_handler.func) +load_functions +catch_errors + +# Safe to proceed with error handling +create_container +``` + +--- + +## Error Logging + +### Log File Configuration + +**Active Log Detection**: +```bash +# In build.func/install.func: +BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" +INSTALL_LOG="/root/install-${SESSION_ID}.log" +SILENT_LOGFILE="$(get_active_logfile)" # Points to appropriate log +``` + +### Log Output Behavior + +When command fails in `silent()`: + +1. Last 10 lines of log file are displayed +2. Full log path shown if more than 10 lines +3. Error message includes line number where failure occurred +4. Command that failed is displayed + +### Accessing Error Logs + +From Proxmox host: +```bash +# Host-side container creation log +/tmp/create-lxc-.log + +# View error details +tail -50 /tmp/create-lxc-550e8400.log +grep ERROR /tmp/create-lxc-*.log + +# Development mode persistent logs +/var/log/community-scripts/create-lxc--.log +``` + +From inside LXC container: +```bash +# Container installation log +/root/install-.log + +# View recent errors +tail -20 /root/install-550e8400.log +``` + +--- + +## Best Practices + +### 1. **Always Setup Traps Early** + +```bash +#!/bin/bash +set -Eeuo pipefail + +source <(curl -fsSL .../core.func) +source <(curl -fsSL .../error_handler.func) +load_functions +catch_errors # MUST be called before any real work + +# Now safe - all signals handled +``` + +### 2. **Use Meaningful Error Exit Codes** + +```bash +# Use Proxmox custom codes for container-specific errors +if [[ "$CTID" -lt 100 ]]; then + msg_error "Container ID must be >= 100" + exit 205 # Proxmox custom code +fi + +# Use standard codes for common errors +if ! command -v curl &>/dev/null; then + msg_error "curl not installed" + exit 127 # Command not found +fi +``` + +### 3. **Log Context Information** + +```bash +# In error_handler, DEBUG_LOGFILE receives: +DEBUG_LOGFILE="/tmp/debug.log" + +# All errors logged with timestamp and details +{ + echo "Error at $(date)" + echo "Exit code: $exit_code" + echo "Command: $command" +} >> "$DEBUG_LOGFILE" +``` + +### 4. **Graceful Signal Handling** + +```bash +# Setup signal handlers for cleanup +cleanup() { + [[ -f "$temp_file" ]] && rm -f "$temp_file" + [[ -d "$temp_dir" ]] && rm -rf "$temp_dir" +} +trap cleanup EXIT + +# Now temporary files always cleaned up +``` + +### 5. **Test Error Paths** + +```bash +# Force error for testing +false # Triggers error_handler +# or +exit 1 # Custom error + +# Verify error handling works correctly +# Check log files and messages +``` + +--- + +## Debugging + +### Enable Stack Trace + +```bash +# Via environment variable +DEV_MODE_TRACE=true bash script.sh + +# Or in script +set -x # Show all commands +trap 'error_handler $? "$BASH_COMMAND" $LINENO' ERR +``` + +### View Full Error Context + +```bash +# Show full log file instead of last 10 lines +DEBUG_LOGFILE="/tmp/full-debug.log" + +# After error, review complete context +less /tmp/full-debug.log +``` + +### Test Error Handler + +```bash +# Manually trigger error handler +bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; exit 42' + +# Should display: +# [ERROR] in line N: exit code 42 (Unknown error): ... +``` + +--- + +## Contributing + +### Adding New Error Codes + +1. Assign code in appropriate range (see Exit Code Reference) +2. Add description to `explain_exit_code()` in both: + - error_handler.func + - api.func (for consistency) +3. Document in exit code table +4. Update error mapping documentation + +### Improving Error Messages + +Example: Make error message more helpful: + +```bash +# Before: +"Container ID must be >= 100" + +# After: +"Invalid CTID: $CTID. Container IDs must be >= 100. Current range: 100-999" +``` + +### Testing Signal Handlers + +```bash +# Test INT signal (Ctrl+C) +bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' & +PID=$! +sleep 1 +kill -INT $PID +wait + +# Test TERM signal +bash -c 'source <(curl -fsSL .../error_handler.func); catch_errors; sleep 30' & +PID=$! +sleep 1 +kill -TERM $PID +wait +``` + +--- + +## Notes + +- Error handler is **required** for all scripts (ensures safe cleanup) +- Exit codes are **standardized** (0 = success, 1-255 = specific errors) +- Signals are **trapped** to allow graceful shutdown +- Lock files are **automatically cleaned** on exit +- Log files contain **full error context** for debugging +