back to scripts

cyber-av-scan.sh

bash 83 lines secrets redacted

Scoped ClamAV malware scans (quick / docker-config / nas-media / home) with single-instance locking.

Note Live script from my home-lab server. Tokens, IDs, phone numbers and other secrets have been replaced with placeholders like <WHATSAPP_GROUP_ID> — everything else is the real, running code.
#!/usr/bin/env bash
set -euo pipefail

REPORT_DIR=/home/lanky/reports
LOCK_FILE=/home/lanky/reports/cyber-av-scan.lock
GROUP_ID=<WHATSAPP_GROUP_ID>
mkdir -p "$REPORT_DIR"
stamp=$(date +%Y%m%d-%H%M%S)
report="$REPORT_DIR/cyber-av-scan-$stamp.txt"
latest="$REPORT_DIR/cyber-av-scan-latest.txt"
scope=${1:-quick}

exec 9>"$LOCK_FILE"
if ! flock -n 9; then
  echo "A Cyber Analyst AV scan is already running."
  exit 0
fi

case "$scope" in
  quick)
    paths=(/home/lanky/Downloads /home/lanky/scripts /tmp)
    ;;
  docker-config)
    paths=(/home/lanky/docker)
    ;;
  nas-media)
    paths=(/mnt/jelly /mnt/nas)
    ;;
  home)
    paths=(/home/lanky)
    ;;
  *)
    echo "Usage: cyber-av-scan.sh [quick|docker-config|nas-media|home]" >&2
    exit 2
    ;;
esac

existing=()
for p in "${paths[@]}"; do
  [ -e "$p" ] && existing+=("$p")
done
if [ "${#existing[@]}" -eq 0 ]; then
  echo "No scan paths exist for scope: $scope" >&2
  exit 2
fi

{
  echo "Cyber Analyst AV scan"
  echo "Generated: $(date -Is)"
  echo "Scanner: $(clamscan --version)"
  echo "Scope: $scope"
  echo "Mode: report-only; no files are deleted, moved, or quarantined."
  echo
  echo "Paths:"
  printf -- '- %s\n' "${existing[@]}"
  echo
  clamscan \
    --recursive=yes \
    --infected \
    --suppress-ok-results \
    --cross-fs=no \
    --exclude-dir='^/tmp/systemd-private-' \
    --exclude-dir='^/tmp/snap-private-tmp' \
    --exclude-dir='@Recycle' \
    --exclude-dir='#recycle' \
    --exclude-dir='\.Trash' \
    "${existing[@]}"
} > "$report" 2>&1 || scan_status=$?
scan_status=${scan_status:-0}

rm -f "$latest"
cp "$report" "$latest"
chown lanky:lanky "$report" "$latest" 2>/dev/null || true
summary=$(/home/lanky/scripts/person-friendly-report.sh av "$report")
if [ -z "${SERVICE_DESK_JOB_ID:-}" ]; then
  sudo -u lanky openclaw message send --channel whatsapp --account default --target "$GROUP_ID" --message "$summary" --media "$report" --force-document >/dev/null 2>&1 || true
fi

# ClamAV returns 1 when infections are found. Treat that as a successful scan with findings.
if [ "$scan_status" -eq 1 ]; then
  exit 0
fi
exit "$scan_status"

back to scripts