[precedente] IPSEC - Copertina - Trucco HW [successivo]

Articoli


Costruire semplici RPM

Introduzione: cosa sono questi RPM?

La distribuzione Redhat, grazie al suo amministratore di pacchetti rpm (il RedHat Package Manager), è certamente una delle distribuzioni di Linux più amate, e non solo dai principianti. A me piace perché quando la installo non mi rompe l'anima con delle improvvise richieste di configurazione: tanto, in ogni caso, io ho i miei script per riportare il sistema nella condizione che ho previsto. Quindi, perché rispondere due volte alle stesse domande?

Come è noto, rpm non è l'unico package manager del mondo Linux e probabilmente l'analogo Debian dpkg fa cose completamente analoghe, o anche di più. Sia ben chiaro: in questo articolo descrivo rpm perché è l'unico che conosco, e non perché va in qualche modo preferito a quello Debian o ad altri.

Disporre di un tool di questo tipo (sia esso RedHat o Debian) significa innanzitutto poter installare (rpm -i), disinstallare (rpm -e) e aggiornare (rpm -U) il software in maniera immediata, ma anche rispondere a domande più specifiche, quali:

Quante di queste domande riceverebbero una risposta in un sistema tipo Window? Ben poche, credo (anzi, ne sono sicuro!). In sistemi come Windows una volta installato qualcosa, non è così facile liberarsene: resta sempre una macchia, come un peccato originale. E così si precipita in quel turbine installatorio che tutti noi abbiamo sperimentato, al termine del quale ci attende - puntuale, come l'arrivo di una stagione non amata - la rimozione directory per directory e la reinstallazione dell'intero sistema operativo.

Ok: stabilito che questi pacchetti ci piacciano e che la filosofia retrostante ci trova completamente consensienti, sorge spontanea la domanda: posso io costuirmi i miei rpm e lanciarli nello spazio vettoriale dei pacchetti, alla pari degli altri?

La risposta è ovviamente alla prima parte della domanda; quanto al fatto che essi siano ``al pari degl'altri'', beh questo dipende ovviamente da quanto di buono ci mettete dentro, no?

Lo scopo di questo piccolo articolo è mostrare, appunto, come il comando rpm possa essere usato anche per costruire i pacchetti, oltre che amministrarli, possibilmente in maniera semplice e piana, usando gli esempi piuttosto che le disquisizioni.

Naturalmente, conoscendo di rpm sì e no il 50% di quanto sarebbe considerato decente, non potrò trattare tutte le questioni col dettaglio che meriterebbero. La lettura di questo articolo va intesa quindi come introduttoria ad un più approfondito studio delle relative pagine di manuale e come un incoraggiamento allo sviluppo di software nuovo.

Com'è fatto un .spec minimale

Tutte le caratteristiche di un pacchetto rpm sono contenute nel relativo file .spec. Si tratta di un file ASCII strutturato in varie sezioni, ognuna delle quali inizia con un identificativo del tipo %string. In aggiunta, in testa al file stesso, devono essere presenti alcuni record di assegnamento, tipo ``Name:'', ``Release'', ecc.

Non tutte le sezioni sono ugualmente importanti e noi ci concentreremo soprattutto su quelle più urgenti e quelle obbligatorie.

Supponiamo ad esempio di voler costruire un pacchetto rpm denominato my, costituito dai seguenti file:

/etc/my.conf
/usr/local/man/man1/my.1
/usr/local/bin/my
/usr/local/lib/my/*.sample

e che questi file si trovino già al loro posto. Ecco il file my.spec che potrebbe fare al nostro scopo:

# my.spec
Name: my 
Summary: Controllo periodo Conti Svizzeri 
Version: 1.0 
Release: 1
Copyright: SANVITTORE 
Group: Application/CashControl
Packager: craxi@sanvittore.it 

%description
Programma per l'amministrazione periodica
e programmata dei conti bancari.
%files
/etc/my.conf
/usr/local/man/man1/my.1
/usr/local/bin/my
/usr/local/lib/my/larini
/usr/local/lib/my/intini

Col comando rpm -bb my.spec verrà creato il file my-1.0-1.i386.rpm nella directory /usr/src/redhat/RPMS, che è il posto normale dove vengono depositate cose come queste.

Si può però fare di più, identificando anche il tipo di file, separando quelli di tipo documentativo e quelli di configurazione, in questo modo:

%files
/usr/local/lib/my/larini
/usr/local/lib/my/intini
/usr/local/bin/my
%config /etc/my.conf
%doc /usr/local/man/man1/my.1

Disinstallando il pacchetto, accade però una cosa spiacevole: la directory /usr/local/lib/my non viene rimossa: il comando rpm -e e molto sospettoso e vuole essere certo che la directory non appartenga a qualche altro pacchetto.

Se io volessi che questa directory facesse parte del mio pacchetto dovrei soltanto aggiungere la direttiva %dir /usr/local/lib/my. Ben diverso sarebbe il risultato se aggiungessi %dir /etc: con rpm -e my, il comando rpm tenterebbe di eliminare anche la directory /etc e si arrabbierebbe, trovandola non vuota (o la vostra è vuota?).

Direttive eseguibili di contorno

All'atto dell'installazione e della disinstallazione di un pacchetto è possibile attivare delle procedure predefinite, descritte con speciali direttive, le direttive %post, %preun e %pre. La prima viene attivata subito dopo l'installazione; la seconda subito prima della disinstallazione e la terza prima dell'installazione.

Ecco un esempio, assai poco utile ma esplicativo:

%pre
echo "Sto per installare il tuo pacchetto..."
%post 
echo "Installazione completata."
%preun	
echo "Ok, ma attenzione! Ti stai privando "
echo "di un software vitale!"

Esercizio per casa: cosa succederebbe se nel mio my.spec aggiungessi una cosa del genere?

%post
rpm -e my*rpm
%preun
rpm --force -U my*rpm

Ci si potrebbe attendere l'avvio di un fantastico processo ricorsivo, se non fosse che rpm blocca preventivamente l'accesso multiplo al suo db interno. Tutto quello che otterremmo è solo un malinconico messaggio di errore, nient'altro.

I .spec, quelli buoni

Nella precedente sezione abbiamo visto come si può prepare un pacchetto rpm a partire da materiale già installato nel nostro sistema. Meditando sulla locuzione già installato non faticherete a capire che questa non può essere la via normale con cui funzionano i .spec che scarichiamo dalla rete. Nessuno di questi .spec può presupporre di trovare già installato quello che l'utente ha appena detto di voler installare, no?

La procedura ivi descritta può andare bene giusto quando vogliamo preparare un semplice pacchetto binario RPMS per il nostro uso interno o se vogliamo, per qualche inconfessabile motivo, distribuire solo il binario. Normalmente però i pacchetti rpm viaggiano a coppie: l'RPMS (estensione .i386.rpm), contenente solo l'insieme dei file necessari al funzionamento del software in quanto tale e l'SRPMS (estensione .src.rpm), contenente l'originale pacchetto tgz, il file .spec più varie cose, quali le patch da applicare al tgz, ecc.

La creazione di un tale tipo di .spec procede in maniera analoga a quanto visto, ma dobbiamo ora aggiungere delle nuove direttive eseguibili, capaci di spacchettare il tgz da qualche parte e di installarlo nel sistema (nel modo esatto che l'autore aveva previsto), prima ancora di raccattare in giro i vari file (comprese le pagine di manuale) e riunirli in un binario .rpm nuovo di zecca.

Queste nuove direttive sono: %prep, %build e %install e sono singolarmente accedibili con delle switch del tipo rpm -bp o rpm -bb e rpm -bi. Il loro scopo è organizzare in maniera pulita i vari processi di spacchettamento e di installazione ma potrebbero essere, in buona sostanza, condensate in una sola ma più corposa.

Esse fanno proprio ciò che il loro nome promette: %prep spacchetta il tgz e applica le patch, %build compila e %install installa. Nel linguaggio del mondo tgz esse equivarrebbero nell'ordine a

tar -zxf 	# %prep
make		# %build
make install	# %install

I pacchetti tgz vengono scompattati generalmente nella directory /usr/src/redhat/BUILD, ma volendo si può scegliere un altro posto. È possibile parametrizzare il tutto usando le variabili predefinite $RPM_BUILD_DIR e $RPM_SOURCE_DIR, per indirizzare rispettivamente la directory di compilazione e quella dei tgz.

Supponendo quindi di aver gzippato la mia appplicazione nel file my-1.0.tgz, di aver copiato questo file sotto /usr/src/redhat/SOURCES e di aver informato my.spec della sua presenza con la direttiva di testa Source0: my-1.0, ecco le rimanenti cosette che dovrei aggiungere al my.spec:

%prep
/bin/gzip -dc $RPM_SOURCE_DIR/my-1.0.tgz | tar -xvvf -
%build
make all 
%install
make install

Ovviamente, si presuppone che il pacchetto sia dotato di un Makefile capace di compilare con make all e di installare binari, documentazione etc. con make install.

Se così non fosse, si può sempre aggiungere il comando gcc nella sezione %build e vari comandi cp nella sezione %install.

La directory in cui tutto ciò viene svolto è, come già detto, /usr/src/redhat/BUILD. Se ciò non piace si può all'inizio della sezione %prep creare una sottodirectory opportuna:

mkdir my-1.0

e nelle altre immettere il cd giusto (sì, è vero: sotto questo aspetto il comando rpm è un po' pigro)

Conclusioni

A mio giudizio rpm è un buon software e ci si potrebbero fare molte cose carine che non solo e soltanto pacchetti redhat. Mi riferisco innanzitutto alle sezioni esequibili (quali %post, %preun, ecc.). Chi ci impedisce, infatti, di pensare a queste sezioni come a segmenti di shell richiamabili selettivamente con le switch di rpm?

Non potrei ad esempio costruirmi un ppp.rpm fantasma che con rpm -i ppp.rpm inizia la connessione PPP, con rpm -e ppp.rpm la termina e con rpm -q ppp.rpm controlla se è stata iniziata?

Lo so: è un esempio forse un po' esotico. Dicevo così per dire!

di Michele Andreoli


[precedente] IPSEC - Copertina - Trucco HW [successivo]