Skip to main content

Module 5 · Package Management

yum/dnf & rpm

  • Lesson 14/15
  • 30 min
  • Difficulty: Intermediate

This lesson is not available in English yet: you are reading it in Italian.

Objective

Operare sulla famiglia RPM riconoscendo la struttura a due livelli, e dire dove la corrispondenza con i comandi Debian non regge invece di applicare una tabella di traduzione

Prerequisites

Prima di leggere: quattro domande alternate

Nella lezione precedente hai imparato la famiglia Debian. Qui impari l'altra, e non le imparerai una dopo l'altra: le imparerai alternate, perché è l'unico modo di non confonderle. Queste quattro domande non sono un ripasso, sono il modo in cui la lezione è costruita. Rispondi prima di proseguire.

  1. Quale comando ti dice a quale pacchetto appartiene un file, su Debian?
  2. Quale programma scarica e risolve le dipendenze, su Debian?
  3. Quale comando ti dice se un pacchetto è installato, su Debian?
  4. Che cosa fa apt remove e che cosa lascia?

Tieni queste quattro risposte sotto gli occhi. Per ciascuna, nel corso della lezione, troverai la corrispondente dell'altra famiglia, e la domanda che ti farò ogni volta è la stessa: è lo stesso concetto con un nome diverso, oppure è un concetto diverso?

Il problema: due famiglie, e un giorno su una macchina dell'altra

Se hai imparato su Ubuntu, prima o poi finisci su una macchina Red Hat, CentOS, Rocky, Fedora o Amazon Linux, e succede nel momento sbagliato: un incidente, un contenitore di qualcun altro, una pipeline che gira su un'immagine che non hai scelto tu. I concetti sono gli stessi e i comandi sono tutti diversi, e la tentazione è imparare a memoria una tabella di traduzione.

La tabella di traduzione funziona male per un motivo preciso: due coppie di comandi che la tabella presenta come equivalenti non lo sono, e sono proprio quelle su cui si fa danno. Alternare le due famiglie invece di studiarle in blocco serve a questo: a notare dove la corrispondenza regge e dove si rompe.

Tutti gli output di questa lezione vengono da un contenitore Fedora 43 che ho eseguito il 2026-10-30. Il motivo per cui te lo dico è che la mia macchina è Ubuntu, quindi non posso provare dnf su di essa, e un contenitore è il modo onesto di avere output veri invece di output ricordati. È anche il modo con cui puoi rifarli tu.

I due livelli, di nuovo, con altri nomi

La struttura è la stessa della famiglia Debian: uno strumento di basso livello che tratta i pacchetti che hai in mano, e uno di alto livello che conosce i repository e risolve le dipendenze. Qui si chiamano rpm e dnf.

$ grep -E '^(NAME|VERSION_ID)=' /etc/os-release
NAME="Fedora Linux"
VERSION_ID=43
$ dnf --version
dnf5 version 5.2.18.0
$ rpm --version
RPM version 6.0.2

Prima risposta alla prima domanda d'apertura. Su Debian il comando è dpkg -S percorso; qui è rpm -qf percorso, dove -q significa interroga e -f significa «per questo file».

$ rpm -qf /usr/bin/ls
coreutils-9.7-10.fc43.x86_64

Nota la forma del nome: nome-versione-release.architettura, tutto in una stringa. È una differenza di presentazione che diventa sostanziale quando scrivi uno script, perché su Debian nome e versione sono campi separati e qui vanno estratti da una stringa, oppure chiesti con un formato dichiarato.

E nota il contenuto, che risponde a una domanda di una lezione precedente. Qui ls appartiene a coreutils versione 9.7, e ls --version risponde ls (GNU coreutils) 9.7: la riscrittura in Rust che su Ubuntu 26.04 aveva sostituito centootto comandi, su Fedora 43 non c'è. La domanda «quale programma sto eseguendo» ha una risposta diversa su ogni famiglia, e questo è il motivo per cui va fatta.

Seconda e terza domanda. Per sapere se un pacchetto è installato, su Debian usavi dpkg-query; qui è rpm -q. Per i dettagli e per l'elenco dei file, le due opzioni sono -qi e -ql.

$ rpm -qa | wc -l
142
$ rpm -qi coreutils
Name        : coreutils
Version     : 9.7
Release     : 10.fc43
Architecture: x86_64
Install Date: Tue Aug 25 05:47:41 2026
Size        : 5648233
License     : GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later

$ rpm -ql coreutils | grep "^/usr/bin/" | head -6
/usr/bin/[
/usr/bin/arch
/usr/bin/b2sum
/usr/bin/base32
/usr/bin/base64
/usr/bin/basename

Centoquarantadue pacchetti in questo contenitore, contro i duemilaottocentosedici della mia macchina completa: il confronto dice qualcosa sul contenitore, non sulla distribuzione, ed è utile averlo in mente quando diagnostichi un'immagine minimale in cui metà degli strumenti non c'è.

Dove la traduzione si rompe, prima volta

Quarta domanda d'apertura: che cosa lascia apt remove. La risposta era «i file di configurazione», in stato rc, e per toglierli serviva purge. Qui la corrispondenza non regge, e la differenza è strutturale.

Il formato RPM non ha il concetto di «pacchetto rimosso con configurazione residua»: un pacchetto è installato oppure non c'è, e rpm -qa non elenca stati intermedi. I file di configurazione vengono trattati in modo diverso: quando un pacchetto viene rimosso, un file di configurazione che hai modificato viene rinominato con un suffisso e lasciato, invece di restare registrato come residuo del pacchetto. Quindi la domanda «quali pacchetti hanno lasciato configurazione» che su Debian ha una risposta esatta, qui non ha un comando: si cercano i file con quel suffisso.

L'errore di classificazione plausibile, e vale la pena nominarlo perché l'ho visto in una tabella di traduzione pubblicata, è scrivere che dnf remove corrisponde ad apt purge. Non corrisponde a nessuno dei due in modo esatto: il meccanismo dei residui è diverso, quindi la domanda da farsi su una macchina RPM non è «ho fatto purge» ma «ci sono file con il suffisso dei file di configurazione salvati».

La seconda coppia che non si traduce riguarda i repository. Su Debian le fonti stanno in file di elenco e le priorità si leggono con apt-cache policy; qui le fonti stanno in file sotto /etc/yum.repos.d/, ciascuno con un proprio identificativo, e il meccanismo di priorità di base non esiste nella stessa forma: i conflitti si risolvono per versione, e la precedenza fra repository richiede un modulo aggiuntivo. Concludere che «la policy di apt corrisponde a qualcosa in dnf» porta a cercare un comando che non c'è.

Esempio svolto: la differenza fra i due livelli, provata

Il problema: hai un file di pacchetto scaricato e lo devi installare. Esistono due comandi che lo fanno, e vuoi sapere perché ne esistono due.

L'informazione disponibile: rpm non conosce i repository e dnf sì. Il ragionamento: se un pacchetto ha dipendenze non soddisfatte, lo strumento di basso livello non può procurarsele, quindi deve rifiutare; quello di alto livello può. La prova si fa su un pacchetto con dipendenze vere, e httpd ne ha.

$ dnf download httpd
 httpd-0:2.4.69-1.fc43.x86_64           100% | 235.2 KiB/s |  46.3 KiB |  00m00s

$ rpm -i ./httpd-2.4.69-1.fc43.x86_64.rpm
error: Failed dependencies:
	httpd-core = 0:2.4.69-1.fc43 is needed by httpd-2.4.69-1.fc43.x86_64
	system-logos(httpd-logo-ng) is needed by httpd-2.4.69-1.fc43.x86_64
	systemd is needed by httpd-2.4.69-1.fc43.x86_64
$ echo $?
1
$ dnf -y install ./httpd-2.4.69-1.fc43.x86_64.rpm
 httpd                       x86_64 2.4.69-1.fc43   @commandline      56.6 KiB
 apr                         x86_64 1.7.6-3.fc43    fedora           299.6 KiB
 apr-util                    x86_64 1.6.5-1.fc43    updates          219.7 KiB
 httpd-core                  x86_64 2.4.69-1.fc43   updates            4.5 MiB
 httpd-tools                 x86_64 2.4.69-1.fc43   updates          198.1 KiB
 mod_http2                   x86_64 2.0.39-1.fc43   updates          431.5 KiB
 Installing:        45 packages

Lo stesso file, due esiti. rpm -i elenca le tre dipendenze che gli mancano e si ferma con codice uno. dnf install sullo stesso file risolve e installa quarantacinque pacchetti: uno è quello che gli ho dato, marcato @commandline perché viene dalla riga di comando e non da un repository, e quarantaquattro li ha trovati lui.

La decisione che prendo: rpm -i non lo uso quasi mai, e quando lo uso è perché voglio esattamente quel comportamento, cioè il rifiuto in assenza di dipendenze. L'alternativa che ho visto praticare e che va evitata è aggiungere l'opzione che salta il controllo delle dipendenze: il pacchetto si installa, il programma non parte, e il sistema resta in uno stato che il gestore considera coerente mentre non lo è. È il modo più rapido di rendere una macchina difficile da riparare.

La verifica, e qui c'è un richiamo a una lezione precedente che vale la pena fare. La prima volta che ho eseguito quel comando avevo scritto rpm -i *.rpm | head -12 per abbreviare l'output, e il codice di uscita stampato era zero. Rieseguito senza la barra verticale, rpm lascia uno:

$ rpm -i ./httpd-*.rpm > /tmp/out.txt 2>&1; echo "rpm exit=$?"
rpm exit=1
$ rpm -i ./httpd-*.rpm 2>&1 | head -1 > /dev/null; echo "PIPESTATUS=${PIPESTATUS[*]}"
PIPESTATUS=1 0

È esattamente il difetto della lezione sui comandi fondamentali: in una catena il codice che resta è quello dell'ultimo comando. L'errore che avrei potuto commettere, e che per un momento ho commesso, è concludere che rpm fallisce silenziosamente con codice zero. Falliva con uno; era head a riuscire.

Esercizio 1, intercalato: completa la tabella in entrambe le direzioni

Per ciascuna delle righe seguenti, scrivi il comando mancante e dichiara se la corrispondenza è esatta oppure approssimata. Per le approssimate, scrivi in che cosa differiscono. Due righe sono già fatte come modello, e nota che nelle prime due il senso della traduzione è invertito di proposito.

  1. Debian dpkg -S percorso → RPM rpm -qf percorso. Esatta.
  2. RPM rpm -ql pacchetto → Debian dpkg -L pacchetto. Esatta.
  3. Debian apt-cache policy pacchetto → RPM ?
  4. RPM dnf remove pacchetto → Debian ?
  5. Debian apt-mark showmanual → RPM ?
  6. RPM rpm -V pacchetto → Debian ?

Esercizio 2, autonomo: la stessa domanda su due macchine

Avvia un contenitore di una distribuzione della famiglia RPM e rispondi, su quella macchina, alle tre domande quantitative della lezione precedente: quanti pacchetti installati, quanti richiesti esplicitamente, quanti con residui di configurazione. Poi confronta con i numeri della tua macchina. Criterio di successo: per ciascuna delle tre domande hai il comando della famiglia RPM, e per almeno una sai dire che la domanda non ha un equivalente diretto e perché.

Soluzioni commentate

Riga 3. La risposta più vicina è dnf repoquery --info pacchetto, e la corrispondenza è approssimata. Il comando dice la versione disponibile e il repository di provenienza, che è gran parte di quello che dava apt-cache policy, e non dice le priorità, perché come hai letto sopra quel meccanismo di base non c'è. Chi cerca la colonna dei numeri di priorità in questa famiglia la cerca a lungo.

Riga 4. La risposta è che corrisponde a nessuno dei due, ed è la riga che l'esercizio esiste per fare sbagliare. dnf remove non è apt remove perché non lascia un pacchetto in stato residuo, e non è apt purge perché i file di configurazione modificati vengono comunque conservati, con un altro nome. Chi scrive «equivale a purge» produce una tabella che fa prendere decisioni sbagliate su una macchina di produzione.

Riga 5. La risposta è dnf repoquery --userinstalled, e la corrispondenza è approssimata per un motivo che vale la pena capire: le due famiglie registrano questa informazione in momenti diversi della storia della macchina. Un pacchetto installato prima che quel registro esistesse, o installato con lo strumento di basso livello, non compare. Quindi il numero che ottieni è una risposta utile e non è un inventario completo, e questo vale anche per apt-mark showmanual.

Riga 6. La risposta è dpkg --verify, cioè lo strumento dell'esercizio autonomo della lezione precedente, e qui la corrispondenza è esatta nel concetto: entrambi confrontano i file installati con le somme di controllo registrate. Vale però la stessa avvertenza: un file di configurazione modificato da te compare come differente, e «differente» non significa «compromesso».

Esercizio 2. La terza domanda è quella che non ha equivalente, ed è il punto. Le prime due si rispondono con rpm -qa | wc -l e dnf repoquery --userinstalled | wc -l. Per la terza non esiste un comando che elenchi i pacchetti con residui di configurazione, perché in questa famiglia quello stato non esiste: la domanda equivalente è «esistono file di configurazione salvati da una rimozione», e si risponde cercando i file con il suffisso corrispondente sotto /etc.

Perché sui numeri non vale la pena confrontare i miei con i tuoi. In un contenitore Fedora 43 ho contato centoquarantadue pacchetti, contro i duemilaottocentosedici della mia installazione completa di Ubuntu: la differenza misura la differenza fra un contenitore e un sistema desktop, non fra due distribuzioni. Un confronto onesto fra le due famiglie richiederebbe due installazioni comparabili, e non ce l'ho: quindi il numero resta un dato sul mio contenitore e non diventa un'affermazione sulle distribuzioni.

Che cosa adesso sai fare

Sai operare sulla famiglia RPM conoscendo la struttura a due livelli invece di una tabella di comandi: sai che rpm interroga e tratta i file che hai, e che dnf conosce i repository e risolve. Lo hai provato sullo stesso file di pacchetto, ottenendo tre dipendenze mancanti dal primo e quarantacinque pacchetti installati dal secondo.

Sai anche dove la traduzione fra le due famiglie si rompe, e sono due punti precisi: i residui di configurazione dopo una rimozione, e le priorità fra repository. Sapere dove una corrispondenza non regge vale più che ricordarne dieci che reggono. La verifica concreta: avvia un contenitore di una distribuzione RPM e risali al pacchetto che possiede /usr/bin/ls, poi confronta la sua versione con quella della tua macchina.