DPKG: Panoramica ed opzioni particolari

debian

Sulla scia del precedente articolo di Raoul Scarazzini “RPM: Panoramica ed opzioni particolari”, ho deciso di ampliare il discorso e proporre qui una panoramica di DPKG, il package manager nato e progettato per Debian e usato da tutte le sue derivate (Ubuntu, Mepis, Knoppix e tante altre).

Stati dei pacchetti

Prima di addentrarci nella spiegazione delle numerose opzioni di dpkg, è necessario introdurre il concetto di “stato” di un pacchetto.

Su Debian, non ci si limita ad avere i classici due stati per un pacchetto “non installato” ed “installato”, sarebbe troppo semplice e semplicistico!

La necessità di avere diversi stati è data dal fatto che l’installazione di un pacchetto non può essere un’operazione atomica (cioè che viene eseguita tutta), ma si compone di varie fasi, dalla decompressione del pacchetto deb (che è un file compresso in formato ‘ar’) fino al lancio degli script contenuti nel pacchetto necessari alla corretta installazione.

Di seguito l’elenco dei possibili stati con una loro spiegazione sommaria:

  • not-installed: il più semplice, lo stato di un pacchetto che non è ancora stato installato…
  • half-installed: l’installazione del pacchetto è iniziata ma per qualche motivo non è stata completata (errori vari oppure interruzione del processo da parte dell’utente)
  • unpacked: il pacchetto è stato correttamente decompresso e i suoi file sono stati posizionati nelle varie directory di destinazione, ma la configurazione del pacchetto non è ancora avvenuta
  • half-configured: il pacchetto ha già raggiunto lo stato di “unpacked”, ed è iniziata la fase di configurazione che non è giunta a termine (anche in questo caso per colpa di errori vari o a causa dell’interruzione da parte dell’utente)
  • triggers-awaited: il pacchetto è installato e configurato, ma sta attendendo l’esecuzione dei ‘trigger’ di un altro pacchetto. I ‘Trigger’ di dpkg sono un modo per posticipare l’esecuzione di alcune operazioni comuni, pensate ad esempio al lancio del comando ‘ldconfig’, che deve essere lanciato dopo l’installazione di un pacchetto che contiene librerie… Un trigger su ldconfig è utile, nel caso di installazione di molti pacchetti, per eseguire l’operazione solo una volta al termine dell’installazione di tutti i pacchetti, anzichè lanciare ldconfig al termine dell’installazione di ogni pacchetto… il risparmio di tempo e di risorse è notevole!
  • trigger-pending: i trigger del pacchetto sono in fase di esecuzione
  • installed: il pacchetto è stato decompresso, configurato e ‘triggerato’, è finalmente disponibile per il sistema.

Oltre agli stati dei pacchetti bisogna distinguere anche lo ‘Stato di selezione dei pacchetti’ e le ‘Flag dei pacchetti’;

Stato di Selezione Dei Pacchetti

Dpkg lavora su collezioni di pacchetti, e ne processa uno alla volta, lo ‘seleziona’ appunto. Ogni pacchetto che deve venire processato ha uno stato target, al termine del lavoro di dpkg si spera che il pacchetto possa essere lasciato nello stato desiderato. Gli stati di selezione dei pacchetti sono tre:

  • install: il pacchetto è stato selezionato per essere installato, al termine dell’operazione il suo stato sarà “installed”
  • deinstall: il pacchetto è stato selezionato per essere rimosso dal sistema, verranno rimossi tutti i suoi files tranne i file di configurazione posti in /etc
  • purge: il pacchetto è stato selezionato per la rimozione completa dal sistema, verranno rimossi anche i file di configurazione posti in /etc

Flag dei pacchetti

Una volta che un pacchetto risulta in stato ‘installed‘può avere due flags, che contraddistinguono in maniera più particolare ciò che dpkg deve fare con lui:

  • hold: il pacchetto è installato, ma non viene più gestito da dpkg, deve rimanere così com’è. L’unica maniera per far eseguire a dpkg operazioni su quel pacchetto è usare l’opzione –force-hold
  • reinst-required: il pacchetto è rovinato (sono stati cancellati dei file oppure la rimozione non è andata a buon fine) e deve per tanto essere reinstallato. I pacchetti con questa flag non possono essere rimossi senza specificare l’opzione –force-remove-reinstreq

Operazioni comuni con i pacchetti DEB

E siamo finalmente arrivati alle operazioni più comuni che si fanno con dpkg…

Interrogazioni sul database di DPKG

Per ottenere la lista di tutti i pacchetti (in qualsiasi stato) presenti sul sistema è sufficiente lanciare dpkg passando l’opzione ‘-l’, che produrrà un output simile al seguente

$ dpkg -l
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Name           Version        Description
+++-==============-==============-============================================
ii  adduser        3.110          add and remove users and groups
ii  aircrack-ng    1:1.0~rc1-2    wireless WEP/WPA cracking utilities
ii  akregator      4:3.5.9-5      RSS feed aggregator for KDE
ii  alsa-base      1.0.17.dfsg-4  ALSA driver configuration files
ii  alsa-tools     1.0.16-2       Console based ALSA utilities for specific ha
ii  alsa-utils     1.0.16-2       ALSA utilities
...
ii  zlib1g         1:1.2.3.3.dfsg compression library - runtime
ii  zlib1g-dev     1:1.2.3.3.dfsg compression library - development
ii  zsh            4.3.9-1        A shell with lots of features

A parte l’intestazione iniziale che serve giusto a ricordare gli stati possibili per i pacchetti, la parte interessante è l’elenco, andiamo ad analizzare la struttura dell’output:

La prima colonna mostra appunto lo stato dei pacchetti, ‘ii’ identifica appunto i pacchetti installati, è lo stato più comune nell’output di dpkg.

Un altro stato che è facile incontrare è lo stato ‘rc’, che identifica i pacchetti che sono stati disinstallati, tali pacchetti non sono più presenti sul sistema, ma vengono mantenuti tutti i file di configurazione.

Quello che identifichiamo come ‘prima colonna’ identifica in realtà due dati, il primo è lo stato desiderato, cioè cosa è stato chiesto dall’utente ed è il primo carattere, il secondo è lo stato effettivo del pacchetto sul sistema.

Ad esempio quando un pacchetto è marcato come ‘ii‘, significa che l’installazione è stata richiesta dall’utente e che esso è effettivamente installato, mentre un pacchetto ‘rc‘ è stato rimosso, ma sono rimasti i file di configurazione (cioè non è stata richiesta un’operazione di ‘purge’).

La seconda colonna invece indica il nome del pacchetto, la terza la versione di tale pacchetto e l’ultima la descrizione breve associata ad ogni pacchetto.

Per ottenere invece, la lista dei pacchetti installati possiamo usare il seguente comando:

$ dpkg --get-selections | awk '/tinstall$/

La lista generata dall’opzione –get-selections è comoda anche per replicare un sistema su un’altro, l’operazione è abbastanza semplice:

Sul sistema sorgente:

$ dpkg --get-selections > package_list
scp package_list user@target:

Sul sistema di destinazione:

$ dpkg --set-selection< package_list
apt-get dselect-upgrade

In questo modo, apt (il principale frontend a dpkg, che si occupa di scaricare e risolvere le dipendenze dei vari pacchetti) andrà a cercare la lista di pacchetti da scaricare non sullo standard input ma direttamente sul database di dpkg.

Per ottenere informazioni su un pacchetto installato è disponibile l’opzione -p:

$ dpkg -p coreutils
Package: coreutils
Essential: yes
Priority: required
Section: utils
Installed-Size: 10368
Maintainer: Michael Stone <mstone@debian.org>
Architecture: powerpc
Version: 6.10-6
Replaces: debianutils (<= 2.3.1), dpkg (<< 1.13.2), fileutils, shellutils, stat, textutils
Provides: fileutils, shellutils, textutils
Pre-Depends: libacl1 (>= 2.2.11-1), libc6 (>= 2.7-1), libselinux1 (>= 2.0.59)
Conflicts: stat
Size: 3649670
Description: The GNU core utilities
 This package contains the essential basic system utilities.
 .
 Specifically, this package includes:
 basename cat chgrp chmod chown chroot cksum comm cp csplit cut date dd df dir
 dircolors dirname du echo env expand expr factor false fmt fold groups head
 hostid id install join link ln logname ls md5sum mkdir mkfifo mknod mv nice nl
 nohup od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir
 sha1sum seq shred sleep sort split stat stty sum sync tac tail tee test touch
 tr true tsort tty uname unexpand uniq unlink users vdir wc who whoami yes

Per ottenere invece la lista dei files contenuti all’interno di un pacchetto installato è possibile usare l’opzione -L:

$ dpkg -L coreutils
/.
/bin
/bin/cat
/bin/chgrp
/bin/chmod
/bin/chown
/bin/cp
/bin/date
...
/usr/share/locale/vi/LC_TIME/coreutils.mo
/usr/share/locale/zh_CN/LC_TIME/coreutils.mo
/usr/share/locale/zh_TW/LC_TIME/coreutils.mo
/usr/bin/touch
/usr/bin/md5sum.textutils

Nel caso invece si disponga di un pacchetto deb non installato è possibile usare l’opzione -c:

$ dpkg -c /var/cache/apt/archive/coreutils_6.10-6_powerpc.deb
drwxr-xr-x root/root         0 2008-04-04 17:08 ./
drwxr-xr-x root/root         0 2008-04-04 17:08 ./bin/
-rwxr-xr-x root/root     20780 2008-04-04 17:08 ./bin/cat
-rwxr-xr-x root/root     44992 2008-04-04 17:08 ./bin/chgrp
-rwxr-xr-x root/root     40596 2008-04-04 17:08 ./bin/chmod
-rwxr-xr-x root/root     47060 2008-04-04 17:08 ./bin/chown
...
lrwxr-xr-x root/root         0 2008-04-04 17:08 ./usr/share/locale/vi/LC_TIME/coreutils.mo -> ../LC_MESSAGES/coreutils.mo
lrwxr-xr-x root/root         0 2008-04-04 17:08 ./usr/share/locale/zh_CN/LC_TIME/coreutils.mo -> ../LC_MESSAGES/coreutils.mo
lrwxr-xr-x root/root         0 2008-04-04 17:08 ./usr/share/locale/zh_TW/LC_TIME/coreutils.mo -> ../LC_MESSAGES/coreutils.mo
lrwxr-xr-x root/root         0 2008-04-04 17:08 ./usr/bin/touch -> /bin/touch
lrwxr-xr-x root/root         0 2008-04-04 17:08 ./usr/bin/md5sum.textutils -> md5sum

Installazione e aggiornamento di un pacchetto

Per l’installazione di un pacchetto scaricato localmente è possibile utilizzare l’opzione -i (o –install):

$ dpkg -i /var/cache/apt/archives/coreutils_6.10-6_powerpc.deb
(Reading database ... 259576 files and directories currently installed.)
Preparing to replace coreutils 6.10-6 (using .../coreutils_6.10-6_powerpc.deb) ...
Unpacking replacement coreutils ...
Setting up coreutils (6.10-6) ...
Processing triggers for man-db ...

Nel caso di aggiornamento di un pacchetto precedentemente installato, dpkg si occuperà da solo di rimuovere la versione più vecchia e sovrascriverla con la nuova versione (o con la stessa versione nel caso di una reinstallazione, come nel caso precedente).

Nel caso si vogliano installare ricorsivamente i pacchetti contenuti in una struttura di directory è possibile usare l’opzione -R ( o –recursive) passando come parametro il path di tale directory, in questo modo dpkg eseguirà l’operazione ricorsivamente su tutti i file contenuti all’interno della dir:

dpkg -Ri /var/cache/apt/archives

Rimozione di un pacchetto

Dpkg mette a disposizione due metodi per rimuovere i pacchetti: la semplice rimozione che rimuove tutti i file del pacchetto tranne che la configurazione nelle directory di sistema (quindi in /etc) e il ‘purge‘ del pacchetto, che elimina qualsiasi traccia del pacchetto, compresi i file di configurazione globali. Ovviamente tutti i file creati dalle varie applicazioni nelle home directory di utenti non verranno toccati.

Per rimuovere semplicemente un pacchetto bisogna usare l’opzione -r (o –remove):

dpkg -r alsa-utils

Per purgare un pacchetto invece si utilizza l’opzione -P (o –purge):

dpkg -P alsa-utils

Risoluzione delle dipendenze

Dpkg non è mai stato progettato per risolvere in autonomia le dipendenze, l’unica cosa che è in grado di fare è verificare se esse sono soddisfatte, mentre la risoluzione è affidata a tool di più alto livello come Apt o Aptitude. Questi tool oltre a risolvere le dipendenze si occupano anche di scaricare i file dai repository ufficiali di Debian (o della distribuzione derivata, come Ubuntu).

Apt fornisce un wrapper per quasi tutte le opzioni di dpkg, le più comuni sono comunque quelle di ricerca, installazione e rimozione:

$ apt-get install coreutils  #installa il pacchetto specificato
$ apt-get instal --reinstall coreutils  #reinstalla il pacchetto specificato
 
$ apt-get remove coreutils  #rimuove il pacchetto specificato
$ apt-get remove --purge coreutils  #rimuove il pacchetto specificato e ne effettua il purge
 
$ apt-cache search coreuti  #cerca tutti i pacchetti il cui nome è simile a 'coreuti'
$ apt-cache show coreutils  #mostra le informazioni relative al pacchetto coreutils

Estrazione di un pacchetto

Con dpkg è anche possibile estrarre un pacchetto senza installarlo, giusto a scopo di analisi, si deve usare l’opzione -x (o –extract):

$ dpkg -x /var/cache/apt/archives/coreutils_6.10-6_powerpc.deb directory_target

All’interno di ‘directory_target’ sarà presente tutta la struttura del pacchetto deb.

È anche possibile estrarre un singolo file dal pacchetto utilizzando l’opzione –fsys-tarfile, che fa produrre a dpkg l’output sotto forma di tarfile, una volta ottenuto quel file è possibile estrarre tutto grazie al comando tar:

$ dpkg --fsys-tarfile /var/cache/apt/archives/coreutils_6.10-6_powerpc.deb | tar -tvf -

Conclusioni

Ciò che è stato illustrato in questa panoramica corrisponde solo alla punta dell’iceberg delle potenzialità di dpkg, che tra le varie cose è anche in grado di creare da solo pacchetti .deb (a differenza di rpm che si appoggia a tool come rpmbuild). Per una lista completa ed esauriente di tutte le opzioni e le possibilità offerte da dpkg consiglio la lettura del fine manual di dpkg.

Tags: , , ,