etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
backup-crashes.sh (3355B)
1 #!/bin/bash 2 # backup-crashes.sh — archive unique syzkaller crashes with deduplication. 3 # 4 # Intended to run as a cron job or in a background loop: 5 # crontab -e 6 # */15 * * * * /path/to/linux-usb-stack/backup-crashes.sh >> /tmp/crash-backup.log 2>&1 7 # 8 # Or in a loop from another terminal: 9 # while sleep 900; do bash backup-crashes.sh; done 10 # 11 # syzkaller stores crashes as directories under workdir-*/crashes/<id>/ 12 # Each crash dir contains: description, log0, report0 (and possibly log1, report1, etc.) 13 # 14 # This script: 15 # 1. Scans workdir-*/crashes/ for crash dirs newer than .last_backup stamp 16 # 2. Deduplicates by sha256 of the report0 file (unique crash signatures) 17 # 3. Compresses unique new crashes into backups/crashes_YYYYMMDD_HHMMSS.tar.gz 18 # 4. Updates .last_backup stamp 19 20 set -euo pipefail 21 22 SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)" 23 cd "${SCRIPT_DIR}" 24 25 BACKUP_DIR="${SCRIPT_DIR}/backups" 26 STAMP_FILE="${SCRIPT_DIR}/.last_backup" 27 SEEN_HASHES="${SCRIPT_DIR}/.seen_crash_hashes" 28 29 log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } 30 31 mkdir -p "${BACKUP_DIR}" 32 touch "${STAMP_FILE}" "${SEEN_HASHES}" 33 34 # ── find new crash directories ──────────────────────────────────────────────── 35 # syzkaller crash dirs contain a 'report0' file with the kernel crash report 36 TMPLIST="$(mktemp)" 37 trap "rm -f ${TMPLIST}" EXIT 38 39 find workdir-*/crashes/ -maxdepth 2 -name "report0" -newer "${STAMP_FILE}" \ 40 2>/dev/null > "${TMPLIST}" || true 41 42 TOTAL=$(wc -l < "${TMPLIST}") 43 if [[ "${TOTAL}" -eq 0 ]]; then 44 log "No new crashes since last backup." 45 exit 0 46 fi 47 48 log "Found ${TOTAL} new crash report(s) since last backup." 49 50 # ── deduplicate by sha256 of report0 ───────────────────────────────────────── 51 TMPSTAGE="$(mktemp -d)" 52 trap "rm -rf ${TMPSTAGE} ${TMPLIST}" EXIT 53 54 NEW=0 55 while IFS= read -r report; do 56 hash="$(sha256sum "${report}" | cut -d' ' -f1)" 57 if ! grep -qF "${hash}" "${SEEN_HASHES}" 2>/dev/null; then 58 # Archive the entire crash directory (includes description, logs, reports) 59 crash_dir="$(dirname "${report}")" 60 crash_name="$(basename "${crash_dir}")" 61 cp -r "${crash_dir}" "${TMPSTAGE}/${crash_name}" 62 echo "${hash}" >> "${SEEN_HASHES}" 63 NEW=$((NEW + 1)) 64 fi 65 done < "${TMPLIST}" 66 67 if [[ "${NEW}" -eq 0 ]]; then 68 log "All ${TOTAL} new reports were duplicates. Nothing to archive." 69 touch "${STAMP_FILE}" 70 exit 0 71 fi 72 73 # ── create archive ──────────────────────────────────────────────────────────── 74 ARCHIVE="${BACKUP_DIR}/crashes_$(date +%Y%m%d_%H%M%S).tar.gz" 75 tar -czf "${ARCHIVE}" -C "${TMPSTAGE}" . 76 77 SIZE="$(du -sh "${ARCHIVE}" | cut -f1)" 78 log "Archived ${NEW} unique crash(es) → ${ARCHIVE} (${SIZE})" 79 80 touch "${STAMP_FILE}" 81 82 # ── prune old backups (keep last 50) ───────────────────────────────────────── 83 ls -t "${BACKUP_DIR}"/crashes_*.tar.gz 2>/dev/null | tail -n +51 | while read old; do 84 rm -f "${old}" 85 log "Pruned old backup: $(basename "${old}")" 86 done 87 88 exit 0