#!/usr/bin/env bash set -Eeuo pipefail umask 022 # STEP026 - SERVER ATTESO: 215.6 / ax-accessi # # Audit esclusivo di: # /var/www/html/presenze.distribuite # # Confronta la struttura con Silvelox in sola lettura e individua: # - directory/file che occupano più spazio; # - elementi presenti solo nel target; # - cache, log, tmp, backup, archivi e dump candidati alla pulizia; # - file più grandi; # - estensioni che consumano più spazio. # # Non segue bower_components/node_modules. # Non modifica nulla. # Non tocca altri portali custom. START_DIR="$PWD" STAMP="$(date '+%Y%m%d_%H%M%S')" BASE="STEP026_2156_DISTRIBUITE_REMAINING_352M_REDUCTION_AUDIT_ONLY_${STAMP}" WORKDIR="${START_DIR}/.${BASE}_work_$$" OUTZIP="${START_DIR}/${BASE}.zip" LOGFILE="${WORKDIR}/run.log" REPORT="${WORKDIR}/report.txt" PACKAGED=0 FAILURES=0 WARNINGS=0 EXPECTED_HOST="${STEP_EXPECTED_HOST:-ax-accessi}" EXPECTED_IP="${STEP_EXPECTED_IP:-192.168.215.6}" SKIP_SERVER_CHECK="${STEP_SKIP_SERVER_CHECK:-0}" TARGET_DIR="${STEP_TARGET_DIR:-/var/www/html/presenze.distribuite}" SOURCE_DIR="${STEP_SOURCE_DIR:-/var/www/html/presenze.silvelox}" mkdir -p "$WORKDIR" : >"$LOGFILE" : >"$REPORT" log() { printf '%s\n' "$*" | tee -a "$LOGFILE"; } report() { printf '%s\n' "$*" >>"$REPORT"; } fail() { FAILURES=$((FAILURES + 1)); log "ERRORE: $*"; report "ERRORE: $*"; } warn() { WARNINGS=$((WARNINGS + 1)); log "ATTENZIONE: $*"; report "ATTENZIONE: $*"; } package_results() { local rc="${1:-0}" local zip_rc=0 [[ "$PACKAGED" -eq 1 ]] && return 0 PACKAGED=1 report "" report "Esito finale: errori=${FAILURES}, avvisi=${WARNINGS}, exit_code=${rc}" rm -f -- "$OUTZIP" if ! command -v zip >/dev/null 2>&1; then rm -rf -- "$WORKDIR" printf '%s\n' "ERRORE: comando zip non disponibile" >&2 return 127 fi (cd "$WORKDIR" && zip -qr "$OUTZIP" .) || zip_rc=$? if [[ "$zip_rc" -eq 0 ]]; then zip -T "$OUTZIP" >>"$LOGFILE" 2>&1 || zip_rc=$? fi rm -rf -- "$WORKDIR" if [[ "$zip_rc" -ne 0 ]]; then rm -f -- "$OUTZIP" printf '%s\n' "ERRORE: creazione/verifica ZIP fallita (rc=${zip_rc})" >&2 return "$zip_rc" fi printf '%s\n' "ZIP CREATO E VERIFICATO: $OUTZIP" } on_exit() { local rc=$? trap - EXIT INT TERM HUP package_results "$rc" || rc=$? exit "$rc" } trap on_exit EXIT trap 'exit 130' INT trap 'exit 143' TERM HUP log "$BASE" log "SERVER ATTESO: 215.6 / ax-accessi" log "TARGET ESCLUSIVO: $TARGET_DIR" log "RIFERIMENTO SOLA LETTURA: $SOURCE_DIR" log "ALTRI PORTALI CUSTOM: NON TOCCATI" log "MODALITA': AUDIT ONLY - NESSUNA MODIFICA" log "Avvio: $(date --iso-8601=seconds)" ACTUAL_HOST="$(hostname -s 2>/dev/null || hostname)" ACTUAL_IPS="$(hostname -I 2>/dev/null | xargs || true)" { echo "STEP: $BASE" echo "Server atteso: 215.6 / ax-accessi" echo "Target esclusivo: $TARGET_DIR" echo "Riferimento sola lettura: $SOURCE_DIR" echo "Altri portali custom: NON TOCCATI" echo "Modalita': AUDIT ONLY" echo "Data: $(date --iso-8601=seconds)" echo "Hostname: $ACTUAL_HOST" echo "IP: $ACTUAL_IPS" echo } >>"$REPORT" for cmd in grep awk wc sort zip hostname xargs tr find du numfmt basename dirname stat readlink cut sed; do command -v "$cmd" >/dev/null 2>&1 || fail "comando richiesto non disponibile: $cmd" done [[ "$FAILURES" -eq 0 ]] || exit 20 if [[ "$SKIP_SERVER_CHECK" != "1" ]]; then [[ "$ACTUAL_HOST" == "$EXPECTED_HOST" ]] \ || fail "hostname ${ACTUAL_HOST}; previsto ${EXPECTED_HOST}" if [[ -n "$EXPECTED_IP" ]] && ! grep -qw -- "$EXPECTED_IP" <<<"$ACTUAL_IPS"; then fail "IP ${EXPECTED_IP} non presente tra: ${ACTUAL_IPS}" fi fi [[ "$TARGET_DIR" == "/var/www/html/presenze.distribuite" ]] \ || fail "target inatteso: $TARGET_DIR" [[ "$SOURCE_DIR" == "/var/www/html/presenze.silvelox" ]] \ || fail "sorgente inattesa: $SOURCE_DIR" [[ -d "$TARGET_DIR" ]] || fail "target assente: $TARGET_DIR" [[ -d "$SOURCE_DIR" ]] || fail "sorgente assente: $SOURCE_DIR" [[ ! -L "$TARGET_DIR" ]] || fail "target root non deve essere symlink" [[ ! -L "$SOURCE_DIR" ]] || fail "sorgente root non deve essere symlink" [[ "$FAILURES" -eq 0 ]] || exit 21 log "[1/7] Dimensione reale complessiva" TARGET_BYTES="$(du -sbx -- "$TARGET_DIR" 2>/dev/null | awk '{print $1}' || printf '0')" TARGET_HUMAN="$(numfmt --to=iec-i --suffix=B "$TARGET_BYTES" 2>/dev/null || printf '%sB' "$TARGET_BYTES")" SOURCE_BYTES="$(du -sbx -- "$SOURCE_DIR" 2>/dev/null | awk '{print $1}' || printf '0')" SOURCE_HUMAN="$(numfmt --to=iec-i --suffix=B "$SOURCE_BYTES" 2>/dev/null || printf '%sB' "$SOURCE_BYTES")" { printf 'voce\tbyte\tspazio\n' printf 'presenze.distribuite\t%s\t%s\n' "$TARGET_BYTES" "$TARGET_HUMAN" printf 'presenze.silvelox\t%s\t%s\n' "$SOURCE_BYTES" "$SOURCE_HUMAN" } >"${WORKDIR}/01_TOTAL_SIZE.tsv" log "[2/7] Dimensioni primo livello del target" TOP_RAW="${WORKDIR}/.top_level_raw.tsv" : >"$TOP_RAW" while IFS= read -r -d '' item; do name="$(basename "$item")" if [[ -L "$item" ]]; then type="symlink" bytes="$(stat -c '%s' "$item" 2>/dev/null || printf '0')" human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" destination="$(readlink -f "$item" 2>/dev/null || true)" elif [[ -d "$item" ]]; then type="directory" bytes="$(du -sbx -- "$item" 2>/dev/null | awk '{print $1}' || printf '0')" human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" destination="" elif [[ -f "$item" ]]; then type="file" bytes="$(stat -c '%s' "$item" 2>/dev/null || printf '0')" human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" destination="" else continue fi printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ "$bytes" "$human" "$type" "$name" "$item" "$destination" \ >>"$TOP_RAW" done < <( find "$TARGET_DIR" \ -xdev \ -mindepth 1 \ -maxdepth 1 \ \( -type f -o -type d -o -type l \) \ -print0 2>>"$LOGFILE" ) { printf 'byte\tspazio\ttipo\tnome\tpercorso\tdestinazione_symlink\n' sort -t $'\t' -rn -k1,1 "$TOP_RAW" } >"${WORKDIR}/02_TARGET_TOP_LEVEL.tsv" log "[3/7] Confronto primo livello con Silvelox" printf 'nome\ttipo_target\tspazio_target\ttipo_silvelox\tspazio_silvelox\tstato\n' \ >"${WORKDIR}/03_TOP_LEVEL_COMPARE_SILVELOX.tsv" while IFS=$'\t' read -r bytes human type name path destination; do [[ "$bytes" == "byte" ]] && continue source_item="${SOURCE_DIR}/${name}" source_type="assente" source_human="0B" status="TARGET_ONLY" if [[ -L "$source_item" ]]; then source_type="symlink" source_bytes="$(stat -c '%s' "$source_item" 2>/dev/null || printf '0')" source_human="$(numfmt --to=iec-i --suffix=B "$source_bytes" 2>/dev/null || printf '%sB' "$source_bytes")" status="PRESENTE_ENTRAMBI" elif [[ -d "$source_item" ]]; then source_type="directory" source_bytes="$(du -sbx -- "$source_item" 2>/dev/null | awk '{print $1}' || printf '0')" source_human="$(numfmt --to=iec-i --suffix=B "$source_bytes" 2>/dev/null || printf '%sB' "$source_bytes")" status="PRESENTE_ENTRAMBI" elif [[ -f "$source_item" ]]; then source_type="file" source_bytes="$(stat -c '%s' "$source_item" 2>/dev/null || printf '0')" source_human="$(numfmt --to=iec-i --suffix=B "$source_bytes" 2>/dev/null || printf '%sB' "$source_bytes")" status="PRESENTE_ENTRAMBI" fi if [[ "$type" == "symlink" && "$name" =~ ^(bower_components|node_modules)$ ]]; then status="SHARED_SYMLINK_OK" fi printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ "$name" "$type" "$human" "$source_type" "$source_human" "$status" \ >>"${WORKDIR}/03_TOP_LEVEL_COMPARE_SILVELOX.tsv" done <"${WORKDIR}/02_TARGET_TOP_LEVEL.tsv" log "[4/7] Cache, log, tmp, backup, archivi e dump" CANDIDATE_RAW="${WORKDIR}/.cleanup_candidates_raw.tsv" : >"$CANDIDATE_RAW" while IFS= read -r -d '' item; do [[ "$item" == "${TARGET_DIR}/"* ]] || continue if [[ -L "$item" ]]; then continue elif [[ -d "$item" ]]; then type="directory" bytes="$(du -sbx -- "$item" 2>/dev/null | awk '{print $1}' || printf '0')" elif [[ -f "$item" ]]; then type="file" bytes="$(stat -c '%s' "$item" 2>/dev/null || printf '0')" else continue fi human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" name="$(basename "$item")" parent="$(dirname "$item")" case "${name,,}" in cache|caches|tmp|temp|logs|log|backup|backups|archive|archives|templates_c) category="RUNTIME_O_ARCHIVIO" ;; *.zip|*.tar|*.tar.gz|*.tgz|*.gz|*.bz2|*.xz|*.7z|*.rar) category="ARCHIVIO_COMPRESSO" ;; *.bak|*.backup|*.save|*.orig|*~) category="BACKUP_FILE" ;; *.log|*.tmp|*.temp) category="LOG_O_TEMP" ;; *.sql|*.dump) category="DUMP_DATABASE" ;; *) continue ;; esac printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ "$bytes" "$human" "$category" "$type" "$item" "$parent" \ >>"$CANDIDATE_RAW" done < <( find "$TARGET_DIR" \ -xdev \ \( \ -path "${TARGET_DIR}/bower_components" \ -o -path "${TARGET_DIR}/node_modules" \ -o -path "${TARGET_DIR}/libs/stimulsoft_legacy" \ \) -prune \ -o -mindepth 1 \ \( -type f -o -type d \) \ -print0 2>>"$LOGFILE" ) { printf 'byte\tspazio\tcategoria\ttipo\tpercorso\tparent\n' sort -t $'\t' -rn -k1,1 "$CANDIDATE_RAW" } >"${WORKDIR}/04_CLEANUP_CANDIDATES.tsv" CANDIDATE_COUNT="$(wc -l <"$CANDIDATE_RAW" | tr -d ' ')" log "[5/7] File più grandi" LARGEST_RAW="${WORKDIR}/.largest_raw.tsv" : >"$LARGEST_RAW" find "$TARGET_DIR" \ -xdev \ \( \ -path "${TARGET_DIR}/bower_components" \ -o -path "${TARGET_DIR}/node_modules" \ \) -prune \ -o -type f \ -printf '%s\t%p\n' 2>>"$LOGFILE" \ | sort -t $'\t' -rn -k1,1 >"$LARGEST_RAW" { printf 'byte\tspazio\tpercorso\n' awk -F '\t' 'NR<=200 {print}' "$LARGEST_RAW" \ | while IFS=$'\t' read -r bytes path; do human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" printf '%s\t%s\t%s\n' "$bytes" "$human" "$path" done } >"${WORKDIR}/05_LARGEST_FILES.tsv" FILES_OVER_10M="$(awk -F '\t' '$1 > 10485760 {n++} END {print n+0}' "$LARGEST_RAW")" FILES_OVER_50M="$(awk -F '\t' '$1 > 52428800 {n++} END {print n+0}' "$LARGEST_RAW")" log "[6/7] Riepilogo spazio per estensione" EXT_RAW="${WORKDIR}/.extensions_raw.tsv" : >"$EXT_RAW" find "$TARGET_DIR" \ -xdev \ \( \ -path "${TARGET_DIR}/bower_components" \ -o -path "${TARGET_DIR}/node_modules" \ \) -prune \ -o -type f \ -printf '%s\t%f\n' 2>>"$LOGFILE" \ | awk -F '\t' ' { bytes=$1; name=$2; ext="[senza_estensione]"; if (name ~ /\./) { n=split(name, parts, "."); ext=tolower(parts[n]); if (ext=="") ext="[senza_estensione]"; } total[ext]+=bytes; count[ext]++; } END { for (ext in total) { printf "%d\t%d\t%s\n", total[ext], count[ext], ext; } } ' \ | sort -t $'\t' -rn -k1,1 >"$EXT_RAW" { printf 'byte\tspazio\tfile\testensione\n' while IFS=$'\t' read -r bytes count ext; do human="$(numfmt --to=iec-i --suffix=B "$bytes" 2>/dev/null || printf '%sB' "$bytes")" printf '%s\t%s\t%s\t%s\n' "$bytes" "$human" "$count" "$ext" done <"$EXT_RAW" } >"${WORKDIR}/06_EXTENSION_SUMMARY.tsv" log "[7/7] Esito" TOP1="$(awk -F '\t' 'NR==2 {print $4 " (" $2 ")"}' "${WORKDIR}/02_TARGET_TOP_LEVEL.tsv")" TOP2="$(awk -F '\t' 'NR==3 {print $4 " (" $2 ")"}' "${WORKDIR}/02_TARGET_TOP_LEVEL.tsv")" TOP3="$(awk -F '\t' 'NR==4 {print $4 " (" $2 ")"}' "${WORKDIR}/02_TARGET_TOP_LEVEL.tsv")" TARGET_ONLY_COUNT="$(awk -F '\t' 'NR>1 && $6=="TARGET_ONLY" {n++} END {print n+0}' "${WORKDIR}/03_TOP_LEVEL_COMPARE_SILVELOX.tsv")" { printf 'voce\tvalore\n' printf 'target_spazio\t%s\n' "$TARGET_HUMAN" printf 'silvelox_spazio\t%s\n' "$SOURCE_HUMAN" printf 'primo_elemento\t%s\n' "$TOP1" printf 'secondo_elemento\t%s\n' "$TOP2" printf 'terzo_elemento\t%s\n' "$TOP3" printf 'elementi_primo_livello_solo_target\t%s\n' "$TARGET_ONLY_COUNT" printf 'candidati_cache_log_backup_archivi\t%s\n' "$CANDIDATE_COUNT" printf 'file_oltre_10MiB\t%s\n' "$FILES_OVER_10M" printf 'file_oltre_50MiB\t%s\n' "$FILES_OVER_50M" } >"${WORKDIR}/07_SUMMARY.tsv" { echo "AUDIT COMPLETATO" echo "Server: 215.6 / ax-accessi" echo "Target esclusivo: $TARGET_DIR" echo "Spazio reale target: $TARGET_HUMAN" echo "Spazio reale Silvelox: $SOURCE_HUMAN" echo "Elementi più grandi:" echo "1. $TOP1" echo "2. $TOP2" echo "3. $TOP3" echo "Elementi primo livello presenti solo nel target: $TARGET_ONLY_COUNT" echo "Candidati cache/log/tmp/backup/archivi/dump: $CANDIDATE_COUNT" echo "File oltre 10 MiB: $FILES_OVER_10M" echo "File oltre 50 MiB: $FILES_OVER_50M" echo "bower_components/node_modules: esclusi perché symlink condivisi" echo "stimulsoft_legacy: preservato e non classificato come candidato" echo "Silvelox modificato: NO" echo "Altri portali custom toccati: NO" echo "Nessuna modifica eseguita." } >"${WORKDIR}/99_SUMMARY.txt" report "Spazio reale target: $TARGET_HUMAN." report "Primi tre elementi: $TOP1; $TOP2; $TOP3." report "Candidati pulizia: $CANDIDATE_COUNT." report "Silvelox e altri portali non modificati." log "AUDIT COMPLETATO: errori=${FAILURES}, avvisi=${WARNINGS}"