#!/bin/sh
# Ruota dns.log, flows.log ed eventi.log quando superano il tetto: copia in .1
# (le copie più vecchie scalano) e svuota sul posto, perché chi scrive tiene il
# file aperto in append (dnsmasq, conntrack -E, velmod). connessioni.log lo
# ruota il guardiano da sé (-registro-kb). Un giro ogni dieci secondi: con un
# giro al minuto, il 17 settembre 2026 dns.log è arrivato a 3 MB con un tetto di
# 2, nei minuti in cui il DNS ripartiva a ogni modifica della lista. Un giro
# costa tre «wc -c».

giro() {
	. /var/run/velmo/dati || return
	. /etc/velmo/router.conf
	ruota "$VELMO_DATI/dns.log" "$DNS_KB" "$DNS_COPIE"
	ruota "$VELMO_DATI/flows/flows.log" "$FLUSSI_KB" "$FLUSSI_COPIE"
	ruota "$VELMO_DATI/eventi.log" "$EVENTI_KB" "$EVENTI_COPIE"
	libera
}

# libera cancella le copie più vecchie solo quando il disco si avvicina alla
# soglia, e nient'altro.
#
# Prima le copie si buttavano a numero fisso, e il numero era piccolo perché il
# disco è piccolo: la storia durava quattro ore, e il traffico di una notte non
# si poteva più bloccare la mattina dopo. Ma una notte a televisore spento
# occupa pochi kilobyte, e tenerli non costa niente finché lo spazio c'è
# (committente, 19 settembre 2026: «se la notte a tv spento c'è traffico tra le
# 2 e le 4 e poi niente per 12 ore vuol dire che non viene occupato più spazio e
# quello può rimanere disponibile fino a che la soglia di sicurezza della
# memoria non deve recuperare spazio, solo a quel punto cancelliamo partendo
# dalle voci più vecchie»).
#
# Si libera a VELMO_SOGLIA_RECUPERO, sotto la soglia d'allarme della guardia
# (VELMO_SOGLIA_DISCO): quando la guardia si accorge del disco pieno il danno è
# già fatto - il 17 settembre il guardiano aveva smesso di scrivere - mentre qui
# si fa spazio prima, e in silenzio.
libera() {
	soglia=${VELMO_SOGLIA_RECUPERO:-70}
	while [ "$(pieno)" -ge "$soglia" ]; do
		vecchia=$(piu_vecchia) || return
		[ -n "$vecchia" ] || return
		rm -f "$vecchia"
		logger -t velmo-ruota "disco al $(pieno)%: cancellata $vecchia, la copia più vecchia"
	done
}

pieno() {
	df "$VELMO_DATI" 2>/dev/null | awk 'NR == 2 {gsub("%", "", $5); print $5 + 0}'
}

# piu_vecchia è la copia ruotata più vecchia fra tutti i registri, per data di
# modifica. Il file vivo e la .1 non si toccano mai: la .1 è ciò che si legge per
# l'intervallo appena passato.
#
# Per data e non per indice: l'indice sembrava più diretto - più alto, più
# vecchio - ma «sort -t. -k3 -rn» sul percorso intero, con BusyBox, ha cancellato
# dns.log.9 tenendo dns.log.12 (prova sul router, 19 settembre 2026). La data la
# mette la rotazione stessa con «cp -p», e non dipende da come si legge un nome.
piu_vecchia() {
	for f in "$VELMO_DATI"/dns.log.*.gz "$VELMO_DATI"/flows/flows.log.*.gz \
		"$VELMO_DATI"/eventi.log.*.gz "$VELMO_DATI"/guardiano/connessioni.log.*.gz; do
		[ -f "$f" ] && echo "$f"
	done | xargs -r ls -1t 2>/dev/null | tail -1
}

# Le copie si comprimono dalla seconda in poi, come logrotate con delaycompress
# su main: la .1 resta in chiaro (la si legge di continuo), le altre no. Il testo
# di questi registri comprime sedici volte (dns.log del router, misurato il 18
# settembre 2026), quindi lo stesso spazio tiene ore di storia invece di minuti.
#
# Serve a una cosa sola, e concreta: bloccare il traffico di una notte la mattina
# dopo. Con quattro ore di storia, alle undici le righe della notte non c'erano
# più e il gesto non aveva più niente su cui lavorare (committente, 18 settembre
# 2026). Chi legge i .gz lo sa già fare: esporta/registri.go e raccolta li aprono
# al volo, come sul Raspberry.
ruota() {
	f=$1; kb=$2; copie=$3
	[ -f "$f" ] || return
	dim=$(wc -c < "$f")
	[ "$dim" -gt $((kb * 1024)) ] || return
	# Il tetto del numero di copie resta come limite massimo, non come politica:
	# a decidere quando si butta è «libera», sul disco vero. Qui si scarta solo
	# ciò che sfonda il limite.
	i=$copie
	rm -f "$f.$i" "$f.$i.gz"
	while [ "$i" -gt 1 ]; do
		p=$((i - 1))
		[ -f "$f.$p.gz" ] && mv "$f.$p.gz" "$f.$i.gz"
		# La .1 è in chiaro: diventando .2 si comprime.
		[ -f "$f.$p" ] && { gzip -c "$f.$p" > "$f.$i.gz.parziale" \
			&& mv "$f.$i.gz.parziale" "$f.$i.gz" && rm -f "$f.$p"; }
		rm -f "$f.$i.gz.parziale"
		i=$p
	done
	cp -p "$f" "$f.1" && : > "$f"
	logger -t velmo-ruota "$f ruotato a $dim byte"
}

while :; do
	giro
	sleep 10
done
