#!/usr/bin/env bash
#
# syskiller.sh
# diagnostica rapida linux
# by Lomazzi Federico 2/7/2025
#
# uso:
# ./syskiller.sh
# mostra il report a video
#
# ./syskiller.sh -o
# salva anche il report in /tmp
#
# ./syskiller.sh -f
# analisi filesystem più approfondita
#
# ./syskiller.sh -o -f
# report completo salvato su file
#
# eseguirlo come root per ottenere tutte le informazioni disponibili
set -u
SAVE=0
FULL=0
for ARG in "$@"; do
case "$ARG" in
-o) SAVE=1 ;;
-f) FULL=1 ;;
-h|--help)
head -n 20 "$0"
exit 0
;;
esac
done
HOST="$(hostname 2>/dev/null || echo unknown)"
DATE="$(date '+%Y-%m-%d_%H-%M-%S')"
REPORT="/tmp/syskiller_${HOST}_${DATE}.log"
if [ "$SAVE" -eq 1 ]; then
exec > >(tee "$REPORT") 2>&1
fi
section()
{
echo
echo "======================================================================"
echo "$1"
echo "======================================================================"
}
command_exists()
{
command -v "$1" >/dev/null 2>&1
}
section "SYSTEM"
echo "host: $HOST"
echo "date: $(date)"
echo "kernel: $(uname -r)"
echo "architecture: $(uname -m)"
echo "uptime: $(uptime -p 2>/dev/null || uptime)"
if [ -r /etc/os-release ]; then
. /etc/os-release
echo "os: ${PRETTY_NAME:-unknown}"
fi
section "LOAD"
uptime
if [ -r /proc/loadavg ]; then
echo
echo "loadavg:"
cat /proc/loadavg
fi
CPU_COUNT="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)"
LOAD1="$(awk '{print $1}' /proc/loadavg 2>/dev/null)"
echo
echo "cpu disponibili: $CPU_COUNT"
if command_exists awk && [ -n "${LOAD1:-}" ]; then
awk -v load="$LOAD1" -v cpu="$CPU_COUNT" '
BEGIN {
ratio = load / cpu
if (ratio >= 2)
print "attenzione: load estremamente elevato"
else if (ratio >= 1)
print "attenzione: load superiore alla capacità nominale"
else
print "load compatibile con il numero di cpu"
}
'
fi
section "MEMORY"
free -h 2>/dev/null || cat /proc/meminfo
echo
echo "swap:"
swapon --show 2>/dev/null || true
section "DISK"
df -hT 2>/dev/null
echo
echo "filesystem oltre 85%:"
df -P 2>/dev/null |
awk '
NR > 1 {
gsub("%","",$5)
if ($5 >= 85)
print "WARNING:", $6, $5 "%"
}
'
section "INODES"
df -ih 2>/dev/null
echo
echo "inode oltre 85%:"
df -Pi 2>/dev/null |
awk '
NR > 1 && $5 != "-" {
gsub("%","",$5)
if ($5 >= 85)
print "WARNING:", $6, $5 "%"
}
'
section "TOP CPU"
ps -eo pid,ppid,user,%cpu,%mem,etime,comm --sort=-%cpu 2>/dev/null |
head -n 16
section "TOP MEMORY"
ps -eo pid,ppid,user,%cpu,%mem,rss,etime,comm --sort=-%mem 2>/dev/null |
head -n 16
section "PROCESSI ZOMBIE"
ZOMBIES="$(
ps -eo stat,pid,ppid,user,comm 2>/dev/null |
awk '$1 ~ /^Z/ {print}'
)"
if [ -n "$ZOMBIES" ]; then
echo "$ZOMBIES"
else
echo "nessun processo zombie"
fi
section "NETWORK"
if command_exists ss; then
echo "porte in ascolto:"
ss -lntup 2>/dev/null
echo
echo "stato connessioni tcp:"
ss -tan 2>/dev/null |
awk '
NR > 1 {
state[$1]++
}
END {
for (s in state)
printf "%-15s %d\n", s, state[s]
}
' | sort
elif command_exists netstat; then
netstat -lntup 2>/dev/null
else
echo "ss/netstat non disponibili"
fi
section "FAILED SERVICES"
if command_exists systemctl; then
FAILED="$(systemctl --failed --no-legend 2>/dev/null)"
if [ -n "$FAILED" ]; then
echo "$FAILED"
else
echo "nessun servizio systemd fallito"
fi
else
echo "systemd non disponibile"
fi
section "KERNEL ERRORS"
if command_exists journalctl; then
journalctl -k -p err..alert -n 40 --no-pager 2>/dev/null
else
dmesg 2>/dev/null |
grep -Ei 'error|fail|critical|panic' |
tail -n 40
fi
section "OOM KILLER"
if command_exists journalctl; then
OOM="$(
journalctl -k --no-pager 2>/dev/null |
grep -Ei 'out of memory|oom-killer|killed process' |
tail -n 30
)"
else
OOM="$(
dmesg 2>/dev/null |
grep -Ei 'out of memory|oom-killer|killed process' |
tail -n 30
)"
fi
if [ -n "$OOM" ]; then
echo "$OOM"
else
echo "nessun intervento oom rilevato"
fi
section "RECENT LOGIN"
last -n 15 2>/dev/null || true
section "LAST REBOOT"
last reboot -n 10 2>/dev/null || true
section "FAILED LOGIN"
if command_exists journalctl; then
journalctl --since "24 hours ago" --no-pager 2>/dev/null |
grep -Ei \
'failed password|authentication failure|invalid user' |
tail -n 30
elif [ -r /var/log/auth.log ]; then
grep -Ei \
'failed password|authentication failure|invalid user' \
/var/log/auth.log |
tail -n 30
else
echo "log autenticazione non disponibile"
fi
section "RECENT ERRORS"
if command_exists journalctl; then
journalctl -p err..alert --since "2 hours ago" \
--no-pager 2>/dev/null |
tail -n 80
else
echo "journalctl non disponibile"
fi
section "LARGE FILES"
# cerca soltanto nei punti dove normalmente nasce il disastro
for DIR in /var /tmp /home; do
[ -d "$DIR" ] || continue
find "$DIR" \
-xdev \
-type f \
-size +500M \
-printf '%s %p\n' 2>/dev/null
done |
sort -nr |
head -n 20 |
awk '
{
size=$1
$1=""
printf "%.2f GB%s\n", size/1073741824, $0
}
'
if [ "$FULL" -eq 1 ]; then
section "BIG DIRECTORIES"
# modalità più lenta: individua chi si sta mangiando il filesystem
for DIR in /var /home /opt /srv; do
[ -d "$DIR" ] || continue
du -x -B1 -d 2 "$DIR" 2>/dev/null
done |
sort -nr |
head -n 30 |
awk '
{
size=$1
$1=""
printf "%8.2f GB%s\n", size/1073741824, $0
}
'
fi
section "DELETED BUT OPEN FILES"
if command_exists lsof; then
DELETED="$(
lsof +L1 2>/dev/null |
head -n 30
)"
if [ -n "$DELETED" ]; then
echo "$DELETED"
else
echo "nessun file cancellato ancora mantenuto aperto"
fi
else
echo "lsof non disponibile, controllo saltato"
fi
section "SUMMARY"
WARNINGS=0
ROOT_USAGE="$(
df -P / 2>/dev/null |
awk 'NR == 2 {gsub("%","",$5); print $5}'
)"
if [ "${ROOT_USAGE:-0}" -ge 90 ] 2>/dev/null; then
echo "WARNING: filesystem root quasi pieno: ${ROOT_USAGE}%"
WARNINGS=$((WARNINGS + 1))
fi
MEM_AVAIL="$(
awk '/MemAvailable:/ {print $2}' /proc/meminfo 2>/dev/null
)"
MEM_TOTAL="$(
awk '/MemTotal:/ {print $2}' /proc/meminfo 2>/dev/null
)"
if [ -n "${MEM_AVAIL:-}" ] && [ -n "${MEM_TOTAL:-}" ]; then
MEM_PERCENT=$((MEM_AVAIL * 100 / MEM_TOTAL))
if [ "$MEM_PERCENT" -lt 10 ]; then
echo "WARNING: memoria disponibile inferiore al 10%"
WARNINGS=$((WARNINGS + 1))
fi
fi
if [ "$WARNINGS" -eq 0 ]; then
echo "nessuna anomalia macroscopica rilevata"
else
echo "anomalie immediate rilevate: $WARNINGS"
fi
if [ "$SAVE" -eq 1 ]; then
echo
echo "report salvato in: $REPORT"
fi
exit 0
Commenti
Nessun commento, per ora.
Per commentare serve un accesso. Qui siamo tutti tecnici e colleghi!
Accedi per commentare