Gentoo Linux 1.0 Init System

Contenuti:

1.Introduzione

Gentoo Linux usa un sistema di inizializzazione (init system) che è controllato attraverso dipendenze. Dovrebbe essere semplice da mantenere oltre che abbastanza potente e flessibile per ogni tipo di setup. Questa guida non deve essere considerata una introduzione su come funziona il sistema internamente, ma come una rapida guida su come I più curiosi sono invitati a leggersi i sorgenti.

2.Runlevel

A differenza di altri init system, Gentoo non ha rigidi nomi o numeri per definire i runlevel, ma piuttosto nomi comuni mappati nello standard runlevel di init.

Nota: Per default ci sono tre runlevel, chiamati "boot", "default" e "nonetwork".

Il runlevel "boot" dovrebbe essere lo standard per molti setup e, come denota il nome, è il primo runlevel ad essere eseguito dopo il boot time. Quindi c'è il "default" che, come indica il nome, è il principale runlevel ad essere eseguito dopo il boot. L'ultimo è "nonetwork" che serve puramente come esempio.

I runlevel sono collocati in /etc/runlevels, in sottodirectory chiamate con i nomi dei runlevel dentro le quali si trovano dei link ai servizi che sono propri del runlevel corrispondente.

Nota: Il modo migliore per aggiungere o rimuovere servizi sarà discusso nella sezione "L'utilità rc-update".

Come abbiamo già detto, il nome avrebbe potuto essere cambiato a seconda delle necessità dell'utente, e come regola dovrebbe essere cambiato anche il file /etc/inittab per riflettere il nuovo nome del runlevel di default.

Importante: Un eccezione alla regola riguarda il runlevel "boot"

Attenzione: NON cambiate il nome del runlevel "boot" perché potrebbe non funzionare più niente.

Tutto il lavoro è svolto dallo script /sbin/rc che può anche essere usato per cambiare il runlevel al volo.

Runlevel virtuali 

Dato che i runlevel non sono staticamente mappati a quelli di init, ci possono essere più livelli rispetto a quelli supportati da init. Questo permette all'utente di creare profili o runlevel virtuali a seconda del bisogno.

Per esempio, su un lapotop possiamo avere due runlevel di default, chiamati "online" e "offline". Questo ci permetterebbe di avere un runlevel quando la scheda di rete PCMCIA è attiva ed uno quando non lo è. Lo scripts PCMCIA potrebbe essere configurato in modo da chiamare "/sbin/rc online" o "/sbin/rc offline" in modo da far partire o fermare i corretti servizi a seconda dello stato della scheda di rete PCMCIA.

Runlevel e XFree86 

In Gentoo non abbiamo un runlevel dedicato a X, ma piuttosto uno script di startup il quale è chiamato "xdm" e può essere aggiunto a qualsiasi runlevel che vogliamo.

Nota: In effetti dovrebbe essere messo nel runlevel principale che desiderate.

Attenzione: Aggiungendolo al runlevel di boot i risultati possono essere imprevedibili.

Di default se avete fatto partire xdm, gdm o kdm dopo la partenza delle getty, X probabilmente partirà nella prossima console disponibile. Su macchine lente non è un problema se il Desktop Manager parte verso la fine dei processi iniziali del runlevel. Le getty partiranno prima di X che partirà nella console 7 come dovrebbe. Su macchine veloci comunque questo non è così. X parte prima delle getty e quindi nella console 2, Quando getty parte prende il controllo della tastiera e il Desktop Manager perde il supporto della tastiera.

Per ovviare a questo problema lo script di startup del Desktop Manager viene posto in un'extra init runlevel chiamato runlevel 'a'. Quest'ultimo non è un runlevel reale, il nostro script "xdm" richiamerà "telinit a" che rischedulerà tutti i servizi in runlevel 'a' perché siano eseguiti dopo il runlevel corrente, dopo cioè che getty è partito.

Nota: Maggiori informazioni circa il runlevel 'a' possono essere acquisite leggendo le man pages di init.

3.rc-script

Gli rc-script sono script che definiscono le funzioni di base per ogni servizio, così come le sue dipendenze, per la partenza. La directory di riferimento è /etc/init.d/.

Come si presenta un rc-script di base 

Esempio 1: rc-script layout

#!/sbin/runscript
 
depend() {
    need bar
}
 
start() {
    ebegin "Starting foo"
    /sbin/foo
    eend $? "Failed to start foo"
}
 
stop() {
    ebegin "Stopping foo"
    kill $(cat /var/run/foo.pid)
    eend $? "Failed to stop foo"
}

Nota: L'interprete è "/sbin/runscript".

Nota: La funzione "depend" è opzionale.

Nota: Ogni rc-script ha bisogno almeno della funzione "start".

Controllare l'avvio dei servizi 

In genere l'ordine di avvio dei servizi è alfabetico. Questo è causato dall'output generato da /bin/ls.

Il metodo primario per deviare dalla sequenza di avvio di default, sono le dipendenze. Alternativamente se non c'è relazione tra i servizi, può essere usata la sequenza tipo.

4.Tipi di dipendenze

Molti servizi hanno relazione o sono dipendenti da altri.

Postfix, per esempio, ha bisogno che la rete sia funzionante, così come il sistema di log.

Samba ha bisogno di una rete funzionante. Se CUPS viene usato per stampare, cupsd dovrebbe partire prima di samba. Cups non è comunque strettamente necessario a samba.

Abbiamo così due modi per esprimere le dipendenze che relazionano differenti servizi. Queste dipendenze sono sempre valide, sia che il runlevel sia cambiato per intero, sia che il servizio sia fatto partire o sia fermato manualmente dopo l'avvio della macchina.

Quando initscript multipli forniscono una certa virtualità ( come se avessimo script net.eth* multipli che provvedono tutti la dipendenza "net"), solo uno di loro sarà usato per fornire tale dipendenza. Così se abbiamo uno script che necessita della dipendenza net (need net), userà uno solo degli script net.eth* disponibile e non tutti.

La dipendenza di tipo NEED 

La dipendenza di tipo NEED è usata se un servizio è indispensabile per la corretta partenza del servizio corrente.

Esempio 2: aggiungiamo logger e net come dipendenze di tipo NEED

depend() {
    need net logger
}

Nota: I servizi menzionati dopo NEED sono critici per la partenza del servizio corrente la cui partenza fallirà se una delle dipendenze non parte.

Importante: Ogni servizio nella linea NEED sarà fatto partire anche se NON è incluso nel corrente runlevel o in quello di "boot".

NEED crea così una dipendenza molto "forte".

La dipendenza di tipo USE 

La dipendenza di tipo USE è usata per quei servizi che non sono critici per la partenza del servizio corrente, ma che dovrebbero partire prima di tale servizio se è usato.

Esempio 3: aggiungiamo portmap come dipendenza di tipo USE a netmount

depend() {
    use portmap
}

Netmount può usare mount di tipo NFS, ma questo dipende se il portmap è aggiunto al runlevel corrente o di boot. Ogni utente con mount NFS dovrebbe per default aggiungere portmap al runlevel di default, in modo tale che netmount veda portmap come una dipendenza USE e lo faccia partire prima di se stesso.

Importante: Ogni servizio nella linea USE *deve* essere aggiunto al runlevel corrente o a quello di boot per essere considerato una dipendenza valida USE.

USE è così una dipendenza "debole".

Nota: Se ogni servizio in una linea USE non parte, il servizio corrente partirà lo stesso, come se i servizi nella linea USE non fossero critici per l'avvio del servizio corrente.

5.Controllare la sequenza di avvio senza dipendenze

Se non esistono relazioni di dipendenza tra due servizi, ma è necessario o si desidera far partire esplicitamente un servizio dopo un altro, possono essere usate le relazioni AFTER e BEFORE.

Nota: Questi due tipi sono validi solo durante un cambio di runlevel.

Opzionalmente è supportato il carattere "*" per includere altri servizi:

Esempio 4: un esempio di AFTER col carattere *

depend() {
    after *
}

Questo causerà la partenza del servizio corrente *dopo* tutti gli altri servizi.

La relazione di tipo BEFORE 

Il servizio corrente partirà *prima* di tutti quelli elencati nella linea BEFORE.

Esempio 5: il corrente servizio parte prima di bar

depend() {
   before bar
}

La relazione di tipo AFTER 

Il servizio corrente parte *dopo* tutti quelli elencati nella linea AFTER.

Esempio 6: il corrente servizio parte dopo foo

depend() {
    after foo
}

6.Servizi virtuali

I servizi, come molte cose nell'odierno mondo unix, sono di molti tipi e generi. Di solito è la scelta dell'utente/amministratore a determinare quelli che saranno usati.

I sistemi di log ne sono un esempio. Al momento della scrittura di questo manuale, Gentoo Linux permette di scegliere fra quattro differenti sistemi di log. Tutti i servizi che necessitano che un sistema di log sia in uso prima di partire, non possono aver bisogno di tutti e quattro, attraverso l'uso di NEED. D'altra parte includerli in USE è controindicato data la dipendenza "debole".

E' qui dove i servizi virtuali e la dipendenza PROVIDE entrano in gioco.

La relazione di tipo PROVIDE 

La relazione di tipo PROVIDE definisce servizi virtuali di cui altri servizi necessitano. (Servizi che possono essere in relazioni di tipo NEED o USE).

Esempio 7: sysklogd provvede servizi di log

depend() {
    provide logger
}

Il servizio virtuale LOGGER 

LOGGER è un servizio virtuale predefinito che è fornito da tutti i sistemi di log e può essere usato sia con relazioni di tipo NEED che con quelle di tipo USE.

Il servizio virtuale NET 

Il servizio NET è un altro servizio virutale, ma a differenza di LOGGER, non provvede (PROVIDE) esplicitamente un servizio.

Importante: Per fornire un servizio virtuale NET, un servizio deve:

  • essere aggiunto al runlevel corrente o di boot.
  • avere un "net." seguito dall'attuale interfaccia di rete (per esempio net.eth0 o net.ppp1).

Per ogni servizio valido net.*, $IFACE sarà impostata col nome dell'interfaccia di rete. ("eth0" per net.eth0).

7.Opzioni predefinite per la linea di comando

Ogni servizio può essere chiamato con le opzioni predefinite. Tutte quelle menzionate sono già predefinite, eccetto che per START e STOP che l'utente dovrebbe definire come funzioni del proprio rc-script.

Importante: La funzione start() deve essere definita.

Nota: La funzione stop() è meno importante e può essere omessa.

Nota: In generale, l'utente dovrà solo definire start(), stop() e restart(). Il resto è interno e dovrebbe essere lasciato invariato.

Esempio 8: far partire il servizio httpd

# /etc/init.d/httpd start

Nota: Le opzioni sulla linea di comando possono anche essere scritte una dopo l'altra.

Esempio 9: pause/start net.eth0

# /etc/init.d/net.eth0 pause start

Le opzioni START/STOP 

START fa partire il servizio e quelli dai quali dipende.

STOP ferma il servizio incluso ogni servizio che dipende da lui.

L'opzione RESTART 

Il servizio deve essere già attivo perché RESTART funzioni. RESTART farà ripartire il servizio e quelli che dipendono da lui.

Importante: Se è definita una funzione restart(), l'utente dovrebbe usare "svc_start()" e "svc_stop()" per far partire e fermare il servizio.

Nota: Questo per gestire correttamente tutti i servizi dipendenti.

L'opzione PAUSE 

Questa opzione fermerà il servizio, ma a differenza di STOP, non verrà fermato nessun servizio dipendente.

L'opzione ZAP 

Inizializza lo stato del servizio che deve essere fermato.

Nota: Notate che nessuno dei comandi nella funzione stop() sarà eseguito. L'utente dovrebbe fare ogni azione necessaria.

Le opzioni INEED/NEEDSME 

INEED lista i servizi NEED per il corrente servizio.

NEEDSME lista i servizi per i quali questo servizio è necessario (NEED).

Le opzioni IUSE/USESME 

IUSE lista i servizi USE per il corrente servizio.

USESME lista i servizi che usano (USE) questo servizio.

L'opzione BROKEN 

BROKEN lista i servizi omessi (se ce ne sono) dei quali il corrente servizio ha bisogno (NEED).

8.Aggiungere nuove opzioni per la linea di comando

E' relativamente facile aggiungere nuove opzioni per la linea di comando. Una funzione con una opzione ha bisogno di essere definita nell' rc-script e aggiunta alla variabile $opts, come mostrato di eguito:

Esempio 10: foo come una nuova opzione

opts="${opts} foo"
 
foo() {
    ............
}

9.Configurazione

Le configurazioni dovrebbero generalmente essere sempre definite attraverso variabili ambiente. Queste, comunque, non dovrebbero essere definite nell' rc-script, ma in uno dei tre possibili file di configurazione.

Uno è specifico per gli rc-script, gli altri due sono file di configurazione globali:

Esempio 11: file di configurazione per gli rc-script

/etc/conf.d/<nome dell' rc-script>
/etc/conf.d/basic
/etc/rc.conf

Nota: Questi tre file di configurazione vengono letti automaticamente nell'ordine che abbiamo dato.

Importante: Tutti i servizi NET hanno il loro punto di partenza in /etc/conf.d/net

10.Utilità per gli rc-script

L'utilità rc-update 

Lo strumento primario per aggiungere e rimuovere servizi in e da un runlevel è rc-update. Attraverso rc-update verrà eseguito "depscan.sh" per aggiornare la cache delle dipendenze.

Esempio 12: aggiungere metalog al runlevel di default

# rc-update add metalog default

Esempio 13: rimuovere metalog dal runlevel di default

# rc-update del metalog default

Nota: L'esecuzione del comando rc-update senza argomenti dovrebbe visualizzare maggiori informazioni.

Lo script depscan.sh 

Per completezza, depscan.sh è menzionato qui. E' usato per creare una cache di dipendenze che basilarmente è una mappa delle dipendenze tra i servizi.

Dovrebbe essere eseguito ogni volta che un nuovo rc-script è aggiunto a /etc/init.d, ma dato che viene automaticamente eseguito da rc-update, non è necessario eseguirlo nuovamente.



Ultimo aggiorn.:
5 Dicembre 2003
Martin Schlemmer
Autore Originale

Seemant Kulleen
Correttore di bozza

Enrico Morelli
Traduttore

Team Italiano
Traduttore

Sommario:  Questa guida è una introduzione all'init system di Gentoo Linux e spiega in dettaglio come scrivere rc-script.
- 2002 Gentoo.it - Domande, commenti e/o correzioni? Email gentoo-dev@gentoo.it.