Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
@@ -0,0 +1,442 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#########################################################################################
|
||||
#### backup-verify.sh — Verify backup files exist, are recent, and aren't zero-size ####
|
||||
#### Checks file existence, size, and modification time against thresholds ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 1.00 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### ./backup-verify.sh /var/backups/*.tar.gz ####
|
||||
#### ./backup-verify.sh --config backup-paths.conf ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#########################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
BACKUP_MAX_AGE="${BACKUP_MAX_AGE:-24h}"
|
||||
BACKUP_MIN_SIZE="${BACKUP_MIN_SIZE:-1}"
|
||||
VERBOSE="${VERBOSE:-false}"
|
||||
COLOR="${COLOR:-auto}"
|
||||
CONFIG_FILE=""
|
||||
PATH_FILE=""
|
||||
|
||||
# ── State ─────────────────────────────────────────────────────────────
|
||||
SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_NAME
|
||||
ENTRIES=()
|
||||
COUNT_TOTAL=0
|
||||
COUNT_OK=0
|
||||
COUNT_WARNING=0
|
||||
COUNT_CRITICAL=0
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
setup_colors() {
|
||||
if [[ "$COLOR" == "never" ]]; then
|
||||
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
|
||||
return
|
||||
fi
|
||||
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
RESET='\033[0m'
|
||||
else
|
||||
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────
|
||||
log() { echo -e "${CYAN}[INFO]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────
|
||||
section_header() {
|
||||
echo ""
|
||||
echo -e " ${BOLD}${CYAN}── $1 ──${RESET}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
field() {
|
||||
printf " ${BOLD}%-22s${RESET} %s\n" "$1" "$2"
|
||||
}
|
||||
|
||||
field_color() {
|
||||
printf " ${BOLD}%-22s${RESET} %b\n" "$1" "$2"
|
||||
}
|
||||
|
||||
human_bytes() {
|
||||
local bytes="$1"
|
||||
if [[ "$bytes" -ge 1073741824 ]]; then
|
||||
awk "BEGIN { printf \"%.1f GiB\", $bytes / 1073741824 }"
|
||||
elif [[ "$bytes" -ge 1048576 ]]; then
|
||||
awk "BEGIN { printf \"%.1f MiB\", $bytes / 1048576 }"
|
||||
elif [[ "$bytes" -ge 1024 ]]; then
|
||||
awk "BEGIN { printf \"%.1f KiB\", $bytes / 1024 }"
|
||||
else
|
||||
echo "${bytes} B"
|
||||
fi
|
||||
}
|
||||
|
||||
human_age() {
|
||||
local seconds="$1"
|
||||
local days=$((seconds / 86400))
|
||||
local hours=$(( (seconds % 86400) / 3600 ))
|
||||
local mins=$(( (seconds % 3600) / 60 ))
|
||||
|
||||
if [[ "$days" -gt 0 ]]; then
|
||||
echo "${days}d ${hours}h"
|
||||
elif [[ "$hours" -gt 0 ]]; then
|
||||
echo "${hours}h ${mins}m"
|
||||
else
|
||||
echo "${mins}m"
|
||||
fi
|
||||
}
|
||||
|
||||
# Convert age string (24h, 7d, 2w) to seconds
|
||||
parse_age_to_seconds() {
|
||||
local age="$1"
|
||||
local num="${age%[hdw]*}"
|
||||
local unit="${age##*[0-9]}"
|
||||
|
||||
case "$unit" in
|
||||
h) echo $((num * 3600)) ;;
|
||||
d) echo $((num * 86400)) ;;
|
||||
w) echo $((num * 604800)) ;;
|
||||
*) echo $((num * 3600)) ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Convert size string (1, 1K, 1M, 1G) to bytes
|
||||
parse_size_to_bytes() {
|
||||
local size="$1"
|
||||
|
||||
# Pure number
|
||||
if [[ "$size" =~ ^[0-9]+$ ]]; then
|
||||
echo "$size"
|
||||
return
|
||||
fi
|
||||
|
||||
local num="${size%[KkMmGg]*}"
|
||||
local unit="${size##*[0-9]}"
|
||||
|
||||
case "${unit^^}" in
|
||||
K) echo $((num * 1024)) ;;
|
||||
M) echo $((num * 1048576)) ;;
|
||||
G) echo $((num * 1073741824)) ;;
|
||||
*) echo "$num" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# VERIFICATION
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
verify_file() {
|
||||
local file="$1"
|
||||
local max_age_str="$2"
|
||||
local min_size_str="$3"
|
||||
|
||||
local max_age_secs min_size_bytes
|
||||
max_age_secs=$(parse_age_to_seconds "$max_age_str")
|
||||
min_size_bytes=$(parse_size_to_bytes "$min_size_str")
|
||||
|
||||
COUNT_TOTAL=$((COUNT_TOTAL + 1))
|
||||
verbose "Checking: ${file} (max-age=${max_age_str}, min-size=${min_size_str})"
|
||||
|
||||
# Check existence
|
||||
if [[ ! -e "$file" ]]; then
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$RED" "$file" "--" "--" "MISSING" "$RESET"
|
||||
COUNT_CRITICAL=$((COUNT_CRITICAL + 1))
|
||||
return
|
||||
fi
|
||||
|
||||
# Get file info
|
||||
local file_size file_mtime now_epoch age_secs
|
||||
file_size=$(stat -c%s "$file" 2>/dev/null || echo "0")
|
||||
file_mtime=$(stat -c%Y "$file" 2>/dev/null || echo "0")
|
||||
now_epoch=$(date +%s)
|
||||
age_secs=$((now_epoch - file_mtime))
|
||||
|
||||
local size_str age_str
|
||||
size_str=$(human_bytes "$file_size")
|
||||
age_str=$(human_age "$age_secs")
|
||||
|
||||
# Check zero-size
|
||||
if [[ "$file_size" -eq 0 ]]; then
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$RED" "$file" "$size_str" "$age_str" "EMPTY" "$RESET"
|
||||
COUNT_CRITICAL=$((COUNT_CRITICAL + 1))
|
||||
return
|
||||
fi
|
||||
|
||||
# Check minimum size
|
||||
if [[ "$file_size" -lt "$min_size_bytes" ]]; then
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$YELLOW" "$file" "$size_str" "$age_str" "SMALL" "$RESET"
|
||||
COUNT_WARNING=$((COUNT_WARNING + 1))
|
||||
return
|
||||
fi
|
||||
|
||||
# Check age
|
||||
if [[ "$age_secs" -gt "$max_age_secs" ]]; then
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$YELLOW" "$file" "$size_str" "$age_str" "STALE" "$RESET"
|
||||
COUNT_WARNING=$((COUNT_WARNING + 1))
|
||||
return
|
||||
fi
|
||||
|
||||
# All good
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$GREEN" "$file" "$size_str" "$age_str" "OK" "$RESET"
|
||||
COUNT_OK=$((COUNT_OK + 1))
|
||||
}
|
||||
|
||||
verify_glob() {
|
||||
local pattern="$1"
|
||||
local max_age_str="$2"
|
||||
local min_size_str="$3"
|
||||
|
||||
local found=false
|
||||
# Use compgen to safely expand globs
|
||||
local files
|
||||
files=$(compgen -G "$pattern" 2>/dev/null || true)
|
||||
|
||||
if [[ -z "$files" ]]; then
|
||||
COUNT_TOTAL=$((COUNT_TOTAL + 1))
|
||||
COUNT_CRITICAL=$((COUNT_CRITICAL + 1))
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$RED" "$pattern" "--" "--" "MISSING" "$RESET"
|
||||
return
|
||||
fi
|
||||
|
||||
while IFS= read -r file; do
|
||||
found=true
|
||||
verify_file "$file" "$max_age_str" "$min_size_str"
|
||||
done <<< "$files"
|
||||
|
||||
if [[ "$found" == "false" ]]; then
|
||||
COUNT_TOTAL=$((COUNT_TOTAL + 1))
|
||||
COUNT_CRITICAL=$((COUNT_CRITICAL + 1))
|
||||
printf " %b%-50s %10s %10s %s%b\n" "$RED" "$pattern" "--" "--" "MISSING" "$RESET"
|
||||
fi
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# INPUT PARSING
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
add_entry() {
|
||||
local path="$1"
|
||||
local max_age="${2:-$BACKUP_MAX_AGE}"
|
||||
local min_size="${3:-$BACKUP_MIN_SIZE}"
|
||||
ENTRIES+=("${path}|${max_age}|${min_size}")
|
||||
}
|
||||
|
||||
load_config_file() {
|
||||
local file="$1"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
err "Config file not found: $file"
|
||||
exit 1
|
||||
fi
|
||||
while IFS= read -r line; do
|
||||
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
[[ -z "$line" || "$line" == \#* ]] && continue
|
||||
|
||||
local path max_age
|
||||
path=$(echo "$line" | awk '{print $1}')
|
||||
max_age=$(echo "$line" | awk '{print $2}')
|
||||
if [[ -z "$max_age" ]]; then
|
||||
max_age="$BACKUP_MAX_AGE"
|
||||
fi
|
||||
add_entry "$path" "$max_age"
|
||||
done < "$file"
|
||||
}
|
||||
|
||||
load_paths_from_file() {
|
||||
local file="$1"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
err "File not found: $file"
|
||||
exit 1
|
||||
fi
|
||||
while IFS= read -r line; do
|
||||
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
[[ -z "$line" || "$line" == \#* ]] && continue
|
||||
add_entry "$line"
|
||||
done < "$file"
|
||||
}
|
||||
|
||||
load_paths_from_stdin() {
|
||||
while IFS= read -r line; do
|
||||
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
[[ -z "$line" || "$line" == \#* ]] && continue
|
||||
add_entry "$line"
|
||||
done
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# USAGE
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
${SCRIPT_NAME} — Verify backup files exist, are recent, and aren't zero-size
|
||||
|
||||
USAGE:
|
||||
${SCRIPT_NAME} [OPTIONS] [PATH/GLOB ...]
|
||||
${SCRIPT_NAME} --config backup-paths.conf
|
||||
${SCRIPT_NAME} --file paths.txt
|
||||
|
||||
OPTIONS:
|
||||
--config FILE Config file with paths and optional max-age per line
|
||||
Format: /path/to/backup/*.tar.gz 24h
|
||||
--file FILE Read paths from file (one per line)
|
||||
--max-age AGE Maximum file age (default: 24h)
|
||||
Accepts: h (hours), d (days), w (weeks)
|
||||
--min-size SIZE Minimum expected file size (default: 1)
|
||||
Accepts: K, M, G suffixes
|
||||
--verbose Enable debug output
|
||||
--no-color Disable colored output
|
||||
--help Show this help
|
||||
|
||||
ENVIRONMENT VARIABLES:
|
||||
BACKUP_MAX_AGE Maximum file age (default: 24h)
|
||||
BACKUP_MIN_SIZE Minimum file size (default: 1)
|
||||
|
||||
CONFIG FILE FORMAT:
|
||||
# One path/glob per line, optional max-age
|
||||
/var/backups/db/*.sql.gz 12h
|
||||
/var/backups/files/*.tar.gz 24h
|
||||
/opt/backups/weekly/*.tar 7d
|
||||
|
||||
EXAMPLES:
|
||||
# Check specific backup files
|
||||
./backup-verify.sh /var/backups/db-latest.sql.gz
|
||||
|
||||
# Check with glob patterns
|
||||
./backup-verify.sh /var/backups/*.tar.gz
|
||||
|
||||
# Use config file with per-path thresholds
|
||||
./backup-verify.sh --config /etc/backup-verify.conf
|
||||
|
||||
# Custom thresholds
|
||||
./backup-verify.sh --max-age 48h --min-size 1M /var/backups/*.tar.gz
|
||||
EOF
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# ARGUMENT PARSING
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--config)
|
||||
CONFIG_FILE="$2"; shift 2 ;;
|
||||
--file)
|
||||
PATH_FILE="$2"; shift 2 ;;
|
||||
--max-age)
|
||||
BACKUP_MAX_AGE="$2"; shift 2 ;;
|
||||
--min-size)
|
||||
BACKUP_MIN_SIZE="$2"; shift 2 ;;
|
||||
--verbose)
|
||||
VERBOSE="true"; shift ;;
|
||||
--no-color)
|
||||
COLOR="never"; shift ;;
|
||||
--help|-h)
|
||||
setup_colors
|
||||
usage
|
||||
exit 0 ;;
|
||||
-*)
|
||||
err "Unknown option: $1"
|
||||
echo "Run ${SCRIPT_NAME} --help for usage" >&2
|
||||
exit 1 ;;
|
||||
*)
|
||||
add_entry "$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
main() {
|
||||
parse_args "$@"
|
||||
setup_colors
|
||||
|
||||
# Load from config file
|
||||
if [[ -n "$CONFIG_FILE" ]]; then
|
||||
load_config_file "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# Load from path file
|
||||
if [[ -n "$PATH_FILE" ]]; then
|
||||
load_paths_from_file "$PATH_FILE"
|
||||
fi
|
||||
|
||||
# Load from stdin if no entries yet and stdin is not a terminal
|
||||
if [[ ${#ENTRIES[@]} -eq 0 ]] && ! [[ -t 0 ]]; then
|
||||
load_paths_from_stdin
|
||||
fi
|
||||
|
||||
if [[ ${#ENTRIES[@]} -eq 0 ]]; then
|
||||
err "No backup paths specified"
|
||||
echo "Run ${SCRIPT_NAME} --help for usage" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}Backup Verification — $(hostname -f 2>/dev/null || hostname)${RESET}"
|
||||
echo -e "${DIM}$(date '+%Y-%m-%d %H:%M:%S %Z')${RESET}"
|
||||
echo -e "${DIM}Defaults: max-age=${BACKUP_MAX_AGE}, min-size=${BACKUP_MIN_SIZE}${RESET}"
|
||||
|
||||
section_header "Backup Status"
|
||||
|
||||
printf " ${BOLD}%-50s %10s %10s %s${RESET}\n" "FILE" "SIZE" "AGE" "STATUS"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..85})"
|
||||
|
||||
for entry in "${ENTRIES[@]}"; do
|
||||
local path max_age min_size
|
||||
path=$(echo "$entry" | cut -d'|' -f1)
|
||||
max_age=$(echo "$entry" | cut -d'|' -f2)
|
||||
min_size=$(echo "$entry" | cut -d'|' -f3)
|
||||
|
||||
# Check if path contains glob characters
|
||||
if [[ "$path" == *\** || "$path" == *\?* || "$path" == *\[* ]]; then
|
||||
verify_glob "$path" "$max_age" "$min_size"
|
||||
else
|
||||
verify_file "$path" "$max_age" "$min_size"
|
||||
fi
|
||||
done
|
||||
|
||||
section_header "Summary"
|
||||
field "Total checked:" "$COUNT_TOTAL"
|
||||
field_color "OK:" "${GREEN}${COUNT_OK}${RESET}"
|
||||
if [[ "$COUNT_WARNING" -gt 0 ]]; then
|
||||
field_color "Warnings:" "${YELLOW}${COUNT_WARNING}${RESET}"
|
||||
else
|
||||
field "Warnings:" "$COUNT_WARNING"
|
||||
fi
|
||||
if [[ "$COUNT_CRITICAL" -gt 0 ]]; then
|
||||
field_color "Critical:" "${RED}${COUNT_CRITICAL}${RESET}"
|
||||
else
|
||||
field "Critical:" "$COUNT_CRITICAL"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Exit with error code if any critical issues
|
||||
if [[ "$COUNT_CRITICAL" -gt 0 ]]; then
|
||||
return 2
|
||||
elif [[ "$COUNT_WARNING" -gt 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user