Riparare apt e dpkg interrotti a metà upgrade senza reinstallare

Riparare apt e dpkg interrotti a metà upgrade senza reinstallare

C'è un messaggio che prima o poi ogni amministratore di sistemi Debian incontra: E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem. Arriva dopo che qualcosa ha ucciso un upgrade a metà: la sessione SSH caduta senza screen, l'OOM killer che ha scelto proprio apt come vittima, un riavvio impaziente, il disco esaurito al momento sbagliato. Da lì in avanti la macchina è in uno stato curioso: i servizi girano, il sito risponde, tutto sembra normale, ma il sistema di gestione dei pacchetti è congelato, e con lui gli aggiornamenti di sicurezza. In un subentro di qualche tempo fa ho trovato un VPS che viveva così da undici mesi: l'upgrade interrotto era diventato un tabù, nessuno osava toccare apt, e nel frattempo la macchina aveva saltato quasi un anno di patch. La riparazione ha richiesto venti minuti. Questo articolo è la scala di riparazione completa che applico in questi casi, dal gradino banale a quello raro, con un principio in testa che vale come rassicurazione e come metodo: un sistema Debian interrotto a metà upgrade è quasi sempre riparabile senza reinstallare, perché dpkg è costruito esattamente per sopravvivere alle proprie interruzioni. Bisogna solo assecondarlo nell'ordine giusto invece di combatterlo con comandi a caso.

TL;DR

  • Primo gradino (risolve l'80% dei casi): dpkg --configure -a, poi apt -f install, poi un normale apt upgrade.
  • Lock occupato: scopri CHI lo tiene con fuser -v /var/lib/dpkg/lock-frontend; il lock si rimuove a mano solo se nessun processo lo detiene.
  • Errore su un pacchetto specifico: leggi il vero errore (è lo script postinst), risolvi la causa (spazio, servizio, config), non aggirare con i force.
  • Spazio esaurito: prima si libera (/boot, /var), poi si riprende la configurazione: mai il contrario.
  • Database di dpkg corrotto: si recupera dai backup automatici in /var/backups/dpkg.status.*.
  • Mai: --force-all d'istinto, rimozione dei lock alla cieca, riavvio "per sbloccare".

Perché il sistema funziona ma non si aggiorna più?

Per orientarsi serve avere chiara la divisione dei ruoli, perché i due nomi che compaiono negli errori non sono sinonimi. apt è lo stratega: risolve le dipendenze, decide cosa installare e in che ordine, scarica gli archivi. dpkg è l'esecutore: spacchetta i file sul disco ed esegue gli script di configurazione dei pacchetti. Un'interruzione durante la fase di download lascia solo archivi parziali nella cache, e non fa alcun danno; un'interruzione durante la fase di esecuzione lascia dpkg a metà del lavoro, ed è il nostro caso. È per questo che la riparazione parte sempre dal livello dpkg, e solo dopo risale ad apt.

La resilienza sta nel modo in cui dpkg lavora: ogni pacchetto attraversa stati espliciti, scaricato, spacchettato, configurato, e ogni transizione viene registrata nel database sotto /var/lib/dpkg prima di procedere. Quando un upgrade muore a metà, i pacchetti restano fotografati nello stato esatto in cui erano: alcuni già configurati, altri solo spacchettati (unpacked), altri a metà della configurazione (half-configured). I file nuovi sono spesso già al loro posto, ed è per questo che i servizi continuano a girare; ma dpkg sa che il lavoro non è finito, e finché non lo finisce rifiuta di iniziarne altro. Non è testardaggine: è l'unica scelta sana, perché operare sopra uno stato incoerente moltiplicherebbe i danni. Il messaggio d'errore, letto bene, non è un allarme: è un'istruzione di riparazione, e insolitamente onesta.

La fotografia dello stato si ottiene in due comandi, da fare prima di qualunque intervento:

dpkg --audit
# elenca i pacchetti in stato anomalo, divisi per categoria

dpkg -l | grep -v '^ii' | head -20
# tutto ciò che non è in stato "installato e configurato"

Se dpkg --audit elenca pacchetti "half-configured" o "unpacked", sei nel caso standard e il primo gradino della scala quasi certamente basta. Vale anche la pena, su una macchina remota, ricordare la regola di contesto: la riparazione è un'operazione lunga quanto un upgrade, e merita le stesse protezioni, screen e console del provider verificata, come nella sequenza per lavorare via SSH senza restare chiusi fuori. Questo genere di recuperi ordinati è pane quotidiano nei subentri che seguo per le PMI: nel mio profilo professionale trovi come lavoro sulle macchine ereditate in condizioni incerte.

Il primo gradino: lasciare che dpkg finisca il suo lavoro

Il comando che il messaggio d'errore suggerisce fa esattamente ciò che dice: riprende la configurazione di tutti i pacchetti rimasti a metà, nell'ordine corretto delle dipendenze.

dpkg --configure -a
apt -f install
apt update && apt upgrade

Il primo comando può lavorare a lungo e produrre molto output: lascialo finire, anche se sembra fermo su un pacchetto (alcuni postinst, pensa a un aggiornamento di initramfs, impiegano minuti). Su sistemi molto arretrati conviene catturare tutto con dpkg --configure -a 2>&1 | tee /root/riparazione.log, perché se qualcosa fallisce il vero errore sarà sepolto in mezzo a centinaia di righe, e cercarlo in un file è molto più sano che ricostruirlo dallo scrollback del terminale. Il secondo, apt -f install, chiede ad apt di riparare le dipendenze rotte residue, scaricando o rimuovendo il minimo necessario: se propone modifiche, leggile davvero prima di confermare, perché è qui che un sistema molto incoerente può proporre rimozioni che non vuoi. Il terzo verifica che il ciclo sia tornato normale. Nell'ottanta per cento dei casi la storia finisce qui, e l'unico errore possibile era non provarci per undici mesi.

La paura di toccare un sistema "delicato" è quasi sempre più dannosa del guasto: un dpkg interrotto è uno stato progettato e documentato, non una terra incognita. Il vero rischio non è la riparazione: è il tempo passato senza patch mentre nessuno osava ripararlo.

I lock: capire chi li tiene prima di toccarli

Variante frequente: E: Could not get lock /var/lib/dpkg/lock-frontend. Qui l'istinto da forum, rimuovere il file di lock, è la mossa giusta solo nell'ultimo scenario e quella sbagliata in tutti gli altri. Il lock esiste per impedire che due processi modifichino il database insieme, e spesso qualcuno lo sta legittimamente tenendo: un unattended-upgrades partito in background, un altro amministratore, un pannello di gestione, o il tuo stesso upgrade in un'altra sessione screen dimenticata. La diagnosi:

fuser -v /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock 2>&1
ps aux | grep -E 'apt|dpkg' | grep -v grep

C'è un caso ricorrente che vale la pena conoscere per nome: il lock occupato pochi minuti dopo un riavvio. Non è un fantasma del guasto, è apt-daily: i timer di sistema che aggiornano gli indici e lanciano unattended-upgrades partono spesso poco dopo il boot, e su una macchina appena riavviata per la riparazione ti trovi in coda dietro al sistema stesso. systemctl list-timers 'apt-daily*' te lo mostra; la pazienza di qualche minuto, o un systemctl stop temporaneo dei timer durante la finestra di riparazione, è tutta la contromisura che serve.

Se un processo c'è, la scelta è aspettare che finisca o, se è davvero bloccato (un apt in D state da ore, un processo zombie), terminarlo con garbo prima e con decisione poi. Solo quando fuser non mostra nessun detentore, e i processi apt e dpkg non esistono più, il lock residuo di un processo morto si può rimuovere a mano; subito dopo, di nuovo dpkg --configure -a, perché il processo ucciso ha quasi certamente lasciato pacchetti a metà.

Quando un pacchetto specifico si mette di traverso

Il caso più istruttivo: dpkg --configure -a procede e poi inciampa sempre sullo stesso pacchetto, con errors were encountered while processing. Qui la tentazione è la scorciatoia con i flag --force-*, e la regola è resistere finché non hai letto il vero errore, che sta qualche riga sopra il riassunto finale. La configurazione di un pacchetto è l'esecuzione del suo script postinst, e quello script fallisce per ragioni concrete e quasi sempre leggibili: un servizio che non riparte perché la sua configurazione ha un errore di sintassi, spazio esaurito su una partizione (il classico è /boot, di cui ho scritto nella diagnosi del /boot pieno durante l'upgrade), una migrazione di database che si aspetta un demone acceso, un file di configurazione locale che confligge. La riparazione giusta è risolvere quella causa, poi rilanciare la configurazione del solo pacchetto con dpkg --configure nomepacchetto per verificare, e infine il giro completo. I force esistono e hanno usi legittimi, --force-confnew o --force-confold per i conflitti di configurazione, per esempio, ma vanno usati come un bisturi su un pacchetto identificato, mai come --force-all a tappeto: quel flag non ripara, seppellisce, e trasforma un problema leggibile in uno stato che nemmeno dpkg sa più raccontare. La manpage di dpkg documenta ogni force con la sua avvertenza, ed è una lettura che ridimensiona l'entusiasmo.

Un'altra causa che merita il suo paragrafo, perché sui VPS piccoli è la più frequente di tutte, è l'OOM killer. Lo spacchettamento di pacchetti grandi e l'esecuzione dei loro script hanno picchi di memoria non banali, e su una macchina da 1-2 GB senza swap, magari con MySQL e PHP-FPM già affamati, il kernel a corto di memoria sceglie una vittima, e apt è un candidato perfetto: grosso e non essenziale ai suoi occhi. La verifica è dmesg -T | grep -i -A3 'killed process': se trovi apt o dpkg fra le vittime, riparare e riprovare identico produrrà lo stesso esito. Prima si dà respiro alla macchina, fermando temporaneamente un servizio ingordo durante la finestra di upgrade o, meglio, aggiungendo la swap che a quella taglia di VPS serve comunque, come ho descritto nella guida al file di swap su Debian e Ubuntu; poi si riprende la scala dal primo gradino.

Un sottocaso merita menzione perché spaventa più di tutti: l'interruzione durante un aggiornamento del kernel o di initramfs. La regola qui è una sola, non riavviare finché la catena non è ricomposta: dpkg --configure -a per completare, poi verifica esplicita che initrd e immagine del kernel esistano appaiati per la versione che il bootloader caricherà. Il sistema in esecuzione è al sicuro per definizione, sta già girando; è il prossimo avvio che va garantito prima di concederselo.

L'ultimo gradino: il database di dpkg corrotto

Rarissimo ma documentato: l'interruzione avviene mentre dpkg sta riscrivendo il proprio database, tipicamente per un disco pieno o un guasto I/O, e /var/lib/dpkg/status risulta troncato o illeggibile ("dpkg: unrecoverable fatal error"). Anche qui la reinstallazione non è la risposta, perché Debian tiene i backup del database in due posti: /var/lib/dpkg/status-old, la versione immediatamente precedente, e la serie giornaliera in /var/backups/dpkg.status.*, che copre l'ultima settimana. Il recupero è la copia del backup più recente e coerente al posto del file rotto, seguita dal solito dpkg --configure -a e da un apt update: nel peggiore dei casi il database recuperato è indietro di qualche giorno rispetto alla realtà del disco, e un apt -f install riallinea le differenze. È un intervento che nella mia carriera ho fatto una manciata di volte, sempre con successo, e che ogni volta mi ricorda perché questa famiglia di distribuzioni invecchia così bene: i meccanismi di recupero sono parte del progetto, non un ripiego.

Chiudo con la prevenzione, che per questo guasto specifico è quasi tutta igiene operativa già raccontata su queste pagine: gli upgrade dentro screen con le vie di fuga pronte, lo spazio verificato prima di partire, e una regola sul Ctrl-C che vale la pena esplicitare perché l'ho visto usare nel momento sbagliato: interrompere apt durante la fase di download è innocuo, gli archivi parziali si riprendono; interromperlo mentre dpkg sta spacchettando o configurando è esattamente il modo in cui si produce lo stato che questo articolo insegna a riparare. Se l'upgrade sembra bloccato in quella fase, la risposta è indagare da un'altra sessione, mai il colpo di forbici sulla prima. A questo si aggiunge e la checklist di emergenza per VPS unmanaged a portata di mano per quando qualcosa va storto comunque. E una nota culturale che vale quanto la tecnica: se erediti una macchina con apt bloccato da mesi, quella non è una stranezza da aggirare, è il sintomo numero uno che nessuno la stava amministrando davvero, e merita un censimento completo, non solo lo sblocco. Se hai in casa una macchina così, congelata a metà di un upgrade di chissà quando, e preferisci che la riparazione e il censimento li faccia qualcuno che questa scala l'ha percorsa molte volte, contattami per una consulenza: il recupero in sé raramente supera l'ora di lavoro, ed è il resto della verifica, patch arretrate, backup, monitoraggio, a trasformare una macchina sbloccata in una macchina di cui fidarsi di nuovo.

Ultima modifica: