Files
felhom.eu/documentation/audits/os-updates-spike-2026-10-04/scripts/os-survey.sh
T

39 lines
3.2 KiB
Bash
Executable File

#!/bin/bash
# os-survey.sh — READ-ONLY survey for the OS-updates spike (2026-10-04). Changes no package, no source,
# no system apt list: apt indexes go to a throwaway dir under /tmp and are removed at the end.
# Usage: os-survey.sh <label>
export LC_ALL=C DEBIAN_FRONTEND=noninteractive
L=${1:-unknown}
T=$(mktemp -d /tmp/os-survey.XXXXXX)
mkdir -p "$T/lists/partial" "$T/cache/archives/partial"
A=(-o "Dir::State::Lists=$T/lists" -o "Dir::Cache=$T/cache" -o "Debug::NoLocking=1")
echo "### label: $L host: $(hostname) date: $(date -u +%FT%TZ)"
echo "### os"; grep -E '^(PRETTY_NAME|VERSION_ID|VERSION_CODENAME)=' /etc/os-release; echo "debian_version: $(cat /etc/debian_version)"; uname -r
echo "### packages installed: $(dpkg-query -W -f='${db:Status-Abbrev}\n' | grep -c '^ii')"
echo "### apt sources (URIs and suites only)"
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do [ -f "$f" ] || continue
echo "-- $f"; grep -hE '^(deb |URIs:|Suites:|Components:|Enabled:)' "$f" 2>/dev/null; done
echo "### system apt lists age (newest *_InRelease mtime)"; ls -t --time-style=+%FT%T /var/lib/apt/lists/*InRelease 2>/dev/null | head -1 | xargs -r stat -c '%y %n'
echo "### apt-get update into a throwaway dir"
s=$(date +%s.%N); apt-get "${A[@]}" -q update >"$T/update.log" 2>&1; echo "update_rc=$? seconds=$(awk -v a="$s" -v b="$(date +%s.%N)" "BEGIN{printf \"%.1f\", b-a}")"
grep -E '^(Err|W:|E:)' "$T/update.log" | head -5
for mode in upgrade dist-upgrade; do
apt-get "${A[@]}" -s -q "$mode" >"$T/sim-$mode.txt" 2>&1
echo "### simulate $mode: rc=$? Inst=$(grep -c '^Inst ' "$T/sim-$mode.txt") Remv=$(grep -c '^Remv ' "$T/sim-$mode.txt")"
grep -E 'kept back|^The following packages have been kept back' -A3 "$T/sim-$mode.txt" | head -4
done
echo "### pending (dist-upgrade) by origin"
grep '^Inst ' "$T/sim-dist-upgrade.txt" | sed -E 's/^Inst ([^ ]+) (\[[^]]*\] )?\(([^ ]+) ([^)]*)\).*/\4/' | sed -E 's/ \[[^]]*\]$//' | sort | uniq -c | sort -rn
echo "### pending list (pkg old -> new origin)"
grep '^Inst ' "$T/sim-dist-upgrade.txt" | sed -E 's/^Inst ([^ ]+) \[([^]]*)\] \(([^ ]+) ([^)]*)\).*/\1 \2 -> \3 [\4]/; s/^Inst ([^ ]+) \(([^ ]+) ([^)]*)\).*/\1 (new) -> \2 [\3]/'
echo "### new packages pulled (not installed now)"; grep '^Inst ' "$T/sim-dist-upgrade.txt" | grep -v '^Inst [^ ]* \[' | awk '{print $2}'
echo "### kernel / proxmox / docker packages installed"
dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\n' | awk '$1=="ii"{print $2, $3}' | grep -E '^(proxmox-kernel|proxmox-default-kernel|pve-manager|proxmox-ve|pve-|proxmox-|lxc-pve|qemu-server|docker-ce|docker-ce-cli|containerd.io|docker-compose-plugin|docker-buildx-plugin|cloudflared|linux-image)' | head -80
echo "### unattended-upgrades / needrestart"; for p in unattended-upgrades needrestart apt-listchanges; do dpkg-query -W -f='${Package} ${Version} ${db:Status-Abbrev}\n' $p 2>/dev/null || echo "$p not installed"; done
systemctl is-enabled unattended-upgrades 2>/dev/null | sed 's/^/unattended-upgrades.service enabled: /'
echo "### timers"; systemctl list-timers --all --no-pager 2>/dev/null | head -40
echo "### cron"; ls /etc/cron.d 2>/dev/null; crontab -l 2>/dev/null | grep -v '^#' | head
echo "### apt periodic config"; apt-config dump 2>/dev/null | grep -E 'APT::Periodic' | head
rm -rf "$T"
echo "### end"