[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
4. Initscripts
Indice:
4.a. Runlevel
Avviare il sistema
All'avvio del sistema, ci sono molte scritte che scorrono e il testo è il
medesimo ad ogni avvio. La sequenza di tutte queste azioni viene chiamata
sequenza di boot ed è (più o meno) definita staticamente.
Per prima cosa, il boot loader carica l'imagine del kernel, definita nella
configurazione in memoria, dopo di che dice alla CPU di eseguire il kernel.
Quando il kernel è caricato e in esecuzione, inizializza tutte le strutture e i
lavori specifici del kernel ed avvia il processo init.
Questo processo si assicura che tutti i filesystem (definiti in
/etc/fstab) siano montati e pronti per l'uso. Poi esegue alcuni
script situati in /etc/init.d, che avviano i servizi necessari per
un corretto avvio del sistema.
Alla fine, quando tutti gli script sono eseguiti, init attiva i terminali
(nella maggior parte dei casi solo le console virtuali che sono nascoste in
Alt-F1, Alt-F2, ecc.) attaccandogli un processo chiamato
agetty. Questo processo per prima cosa si assicura che sia possibile
eseguire il login su questi terminali eseguendo login.
Init Script
Ora init non esegue gli script in /etc/init.d casualmente.
Inoltre, non lancia tutti gli script in /etc/init.d, ma solo quelli
che gli è stato detto di eseguire. Decide che script eseguire guardando in
/etc/runlevels.
Prima, init esegue tutti gli script da /etc/init.d che hanno
un link simbolico in /etc/runlevels/boot. Solitamente, esegue gli
script in ordine alfabetico, ma alcuni di essi hanno delle informazioni di
dipendenze all'interno, che dicono al sistema che un altro script deve essere
avviato prima che possa essere avviati loro stessi.
Quando tutti gli script refenziati in /etc/runlevels/boot sono
stati eseguiti, init continua eseguendo gli script che hanno un
collegamento simbolico in /etc/runlevels/default. Ancora, usa
l'ordine alfabetico per decidere che script avviare prima, a meno che lo script
non abbia dipendenze, nel qual caso l'ordine viene cambiato per fornire una
valida sequenza di boot.
Come lavora init
Certamente init non decide tutto da solo. Ha bisogno di un file di
configurazione che specifica quali azioni debba eseguire. Questo file di
configurazione è /etc/inittab.
La prima azione di init è di montare tutti i filesystem. Questo è
definito nella seguente linea di /etc/inittab:
Codice 1.1: La linea di inizializzazione del sistema in /etc/inittab |
si::sysinit:/sbin/rc sysinit
|
Questa linea dice a initche deve eseguire /sbin/rc sysinit per
inizializzare il sistema. Lo script /sbin/rc si occupa
dell'inizializzazione, init infatti non fa molto: esso delega altri
compiti, come l'inizializzazione del sistema, ad un'altro processo.
In secondo luogo init esegue gli script che hanno un collegamento in
/etc/runlevels/boot. Questo è definito dalla seguente linea:
Codice 1.2: Inizializzazione del sistema, continua |
rc::bootwait:/sbin/rc boot
|
Ancora lo script rc provvede ai compiti necessari. Notare che l'opzione
passata a rc (boot) è la stessa della sottodirectory
/etc/runlevels.
Ora init controlla il suo file di configurazione per vedere quale
runlevel deve eseguire. Per deciderlo, legge la seguente linea da
/etc/inittab:
Codice 1.3: La linea initdefault |
id:3:initdefault:
|
In questo caso (che la maggioranza di utenti Gentoo usa), l'id del
runlevel è 3. Usando questa informazione, init vede che deve
avviare il runlevel 3:
Codice 1.4: La definizione del runlevel |
l0:0:wait:/sbin/rc shutdown
l1:S1:wait:/sbin/rc single
l2:2:wait:/sbin/rc nonetwork
l3:3:wait:/sbin/rc default
l4:4:wait:/sbin/rc default
l5:5:wait:/sbin/rc default
l6:6:wait:/sbin/rc reboot
|
La linea che definisce il livello 3, ancora, usa lo script rc per avviare
il servizio (ora con argomento default). L'argomento di rc è
ancora lo stesso della sottodirectory in /etc/runlevels.
Quando rc ha finito, init decide quale console virtuale attivare
e quali comandi devono essere eseguiti su ciascuna console:
Codice 1.5: Definizione delle console virtuali |
c1:12345:respawn:/sbin/agetty 38400 tty1 linux
c2:12345:respawn:/sbin/agetty 38400 tty2 linux
c3:12345:respawn:/sbin/agetty 38400 tty3 linux
c4:12345:respawn:/sbin/agetty 38400 tty4 linux
c5:12345:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux
|
Cos'è un runlevel?
Init usa uno schema numerico per decidere quale runlevel attivare.
Un runlevel è uno stato nel quale il sistema viene avviato e contiene una
collezione di script (runlevel script o initscript) che devono essere
eseguiti quando si entra o si lascia un runlevel.
In Gentoo, ci sono sette runlevel definiti: tre runlevel interni, e quattro
runlevel definiti dall'utente. I runlevel interni si chiamano sysinit,
shutdown e reboot e fanno esattamente quello che i nomi implicano:
inizializzano il sistema, spengono il sistema e riavviano il sistema.
I runlevel definiti dall'utente sono delle sottodirectory di
/etc/runlevels: boot, default,
nonetwork e single. Il runlevel boot
avvia tutti i servizi necessari al sistema che tutti gli altri runlevel
usano. I rimanenti tre differiscono per i servizi avviati: default
viene usato per le operazioni di tutti i giorni, nonetwork è usato
in caso non sia necessaria alcuna connettività, e single viene
usato per riparare il sistema.
Lavorare con gli script di Init
Gli script che il processo rc avvia sono chiamati init script.
Ogni script in /etc/init.d può essere eseguito con gli argomenti
start, stop, restart, pause, zap,
status, ineed, iuse, needsme, usesme o
broken.
Per avviare, fermare o riavviare un servizio (e tutti i servizi dipendenti),
vengono usati start, stop e restart:
Codice 1.6: Avviare Postfix |
# /etc/init.d/postfix start
|
Nota:
Solo i servizio necessari al servizio dato saranno fermati o riavviati.
Gli altri servizi dipendenti (quelli che usa ma non gli sono necessari)
non vengono toccati.
|
Per fermare un servizio, ma non i servizi che dipendono da lui si può usare
l'argomento pause:
Codice 1.7: Fermare Postfix ma mantenere in esecuzione i servizi dipendenti |
# /etc/init.d/postfix pause
|
Per vedere un servizio in che stato si trova (started, stopped, paused, ...) si
può usare l'argomento status:
Codice 1.8: Informazioni di stato per postfix |
# /etc/init.d/postfix status
|
Se le informazioni di stato dicono che un servizio è in esecuzione, ma non è
così, si può fare il reset delle informazioni di stato a "stopped" con
l'argomento zap:
Codice 1.9: reset delle informazioni di stato per postfix |
# /etc/init.d/postfix zap
|
Per sapere quali dipendenze ha un servizio si può usare iuse o
ineed. Con ineed vengono mostrati i servizi veramente necessari
per il corretto funzionamento del servizio. iuse invece mostra i servizi
che vengono usati ma non sono necessari al servizio per il corretto
funzionamento.
Codice 1.10: Richiedere la lista di tutti i servizi da cui Postfix dipende |
# /etc/init.d/postfix ineed
|
In modo simile si può chiedere la lista dei servizi che dipendono da lui
(needsme) o possono usarlo
Codice 1.11: Richiedere la lista dei servizi che richiedono Postfix |
# /etc/init.d/postfix needsme
|
Infine, si possono chiedere quali dipendenze, richieste da un servizio, sono
mancanti:
Codice 1.12: Richiedere la lista delle dipendenze mancanti per Postfix |
# /etc/init.d/postfix broken
|
4.b. Lavorare con rc-update
Cos'è rc-update?
Il sistema di init in Gentoo usa un albero di dipendenze per decidere quali
dipendenze vanno avviate prima. Essendo un compito tedioso da eseguire
manualmente c'è uno strumento che rende semplice l'amministrazione dei runlevel
e init script.
Con rc-update si possono aggiungere e rimuovere init script da un
runlevel. Lo strumento rc-update automaticamente interroga
depscan.sh per ricostruire l'albero delle dipendenze.
Aggiungere e rimuovere servizi
Lo script rc-update richiede un secondo argomento che definisce l'azione:
add, del o show.
Per aggiungere o rimuovere un'init script, bisogna passare a rc-update
l'argomento add o del, seguito dallo script di init e dal
runlevel. Per esempio:
Codice 2.1: Rimuovere Postfix dal runlevel default |
# rc-update del postfix default
|
Il comando rc-update -v show mostra tutti gli script di init disponibili
e in quale runlevel vengono eseguiti:
Codice 2.2: Ricevere informazioni sugli init script |
# rc-update -v show
|
È possibile anche usare rc-update show (senza -v) per vedere
solamente gli script di init abilitati e il loro runlevel.
4.c. Configurare i servizi
Perchè una configurazione aggiuntiva?
Gli Init script possono essere complessi. Qui non si è interessati a far
modificare direttamente gli init script, dato che sono piuttosto proni a
errori. È comunque importante saper configurare bene un servizio, ad esempio per
per dare più opzioni al servizio stesso.
Un secondo motivo è di avere la configurazione al di fuori dell'init script per
aggiornare gli init script senza preoccuparsi di perdere i cambiamenti alla
configurazione.
La directory /etc/conf.d
Gentoo fornisce un modo semplice per configurare i servizi: ogni init script
che può esser configurato ha un file in /etc/conf.d. Per esempio,
l'init script di apache2 (chiamato /etc/init.d/apache2) ha un file
di configurazione chiamato /etc/conf.d/apache2, che contiene le
opzioni che si vogliono passare al server Apache 2 quando esso viene avviato:
Codice 3.1: Variabili definite in /etc/conf.d/apache2 |
APACHE2_OPTS="-D PHP5"
|
I file di configurazione contengono variabili e solo quello (tipo
/etc/portage/make.conf), e rendono davvero facile configurare un servizio.
Permettono inoltre di aggiungere molte informazioni sulle variabili (come
commenti).
4.d. Scrivere Init Scripts
È necessario?
No. Scrivere init script non è solitamente necessario dato che Gentoo fornisce
init script pronti all'uso per ogni servizio. Comunque, si potrebbe installare
un servizio senza usare Portage, nel qual caso probabilmente è necessario creare
un init script.
È consigliabile non usare init script forniti dal servizio se non sono scritti
esplicitamente per Gentoo: gli init script di Gentoo non sono compatibili con
quelli usati dalle altre distribuzioni!
Layout
Il layout di base di un init script è mostrato sotto.
Codice 4.1: Layout di base di un init script |
#!/sbin/runscript
depend() {
}
start() {
}
stop() {
}
|
Ogni init script richiede che la funzione start() sia definita.
Tutte le altre sezioni sono opzionali.
Dipendenze
Ci sono due tipi di impostazioni simili alle dipendenze che possono influenzare
l'avvio o la sequenza degli script: use e need. Oltre a queste
due, ci sono altri due metodi che influenzano l'ordine di esecuzione, chiamati
before e after. Gli ultimi due non sono delle vere dipendenze -
non provocano il fallimento dell'init script originale se quello indicato
non è programmato per avviarsi (o fallisce l'avvio).
-
L'impostazione use informa il sistema init che lo script usa
le funzionalità offerte dallo script indicato, ma non dipende direttamente
da quello. Un buon esempio potrebbe essere use logger o use
dns. Se questi servizi sono disponibili, verranno adeguatamente
utilizzati, ma se non si ha un logger o un server DNS i servizi
funzioneranno ugualmente. Se i servizi esistono, allora verranno avviati
prima dello script che ne fa uso.
-
L'impostazione need è una vera dipendenza. Significa che lo script
che ha bisogno di un altro script non partirà prima che l'altro si sia
avviato correttamente. Inoltre, se l'altro script verrà riavviato, allora
anche lo script che ne ha bisogno verrà riavviato.
-
Quando si usa before, lo script verrà avviato prima di quello
indicato se quello indicato fa parte del livello di init. Quindi, im
init script xdm che dichiara before alsasound partirà
prima dello script alsasound, ma solo se alsasound
è programmato per avviarsi nello stesso livello di init. Se
alsasound non è programmato per avviarsi, allora questa
impostazione non ha effetto e xdm verrà avviato quando il
sistema init lo riterrà appropriato.
-
In modo analogo, after informa il sistema init che lo script dovrà
essere avviato dopo quello indicato, se quello indicato fa parte del
livello di init. Altrimenti l'impostazione non ha effetto e lo script verrà
avviato quando il sistema init lo riterrà appropriato.
Dovrebbe essere chiaro da quanto scritto sopra che need è l'unica "vera"
dipendenza, in quanto determina se lo script verrà avviato o meno. Tutte le
altre sono semplici indicazioni al sistema init per chiarire in quale ordine gli
script devono (o dovrebbero) essere eseguiti.
Ora, se si osservano i molti init script disponibili in Gentoo, si noterà che
alcuni hanno dipendenze rispetto a cose che non sono init script. Chiamiamo
queste "cose" dipendenze virtuali.
Una dipendenza virtuale è una dipendenza che fornisce un servizio, ma non
è fornita solo da quel servizio. L'init script può dipendere da logger di
sistema, ma possono essercene molti altri disponibili (metalogd, syslog-ng,
sysklogd, ...). Dato che non è possibile mettere need per ognuno di loro
(nessun sistema ha tutti questi logger di sistema installati e in esecuzione) ci
si assicura che tutti questi servizi forniscano una dipendenza virtuale.
Ora verranno esaminate le informazioni relative alle dipendenze del servizio
postfix.
Codice 4.2: Informazioni di dipendenze per Postfix |
depend() {
need net
use logger dns
provide mta
}
|
Com'è possibile vedere, il servizio postfix:
-
richiede la dipendenza (virtuale) net(che è fornita, per esempio,
da /etc/init.d/net.eth0)
-
usa la dipendenza (virtuale) logger (che è fornita per esempio, da
/etc/init.d/syslog-ng)
-
usa la dipendenza (virtuale) dns (che è fornita, per esempio da
/etc/init.d/named)
-
fornisce la dipendenza (virtuale) mta (che è comune a tutti i mail
server)
Controllare l'ordine
Come descritto nella sezione precedente, si può istruire il sistema init
sull'ordine da seguire per avviare (o fermare) gli init script. L'ordine è
governato da entrambe le use e need, ma anche dalle impostazioni
di ordinamento before e after. Poich* queste impostazioni sono
state già descritte in precedenza, prendiamo il servizio Portmap come esempio
di init script.
Codice 4.3: La funzione depend() nel servizio Portmap |
depend() {
need net
before inetd
before xinetd
}
|
Si può anche usare "*" per selezionare tutti i servizi nello stesso runlevel,
ma non è consigliabile.
Codice 4.4: Eseguire un init script come primo script nel runlevel |
depend() {
before *
}
|
Se il servizio deve scrivere su dischi locali, dovrebbe aver bisogno di
localmount. Se non mette niente in /var/run, come un
pidfile, allora dovrebbe partire dopo bootmisc:
Codice 4.5: Esempio di funzione depend() |
depend() {
need localmount
after bootmisc
}
|
Funzioni Standard
Dopo la funzione depend(), è necessario definire la funzione
start(). Questa contiene tutti i comandi necessari ad inizializzare il
servizio. È consigliabile usare le funzioni ebegin e eend per
informare l'utente su cosa sta accadendo:
Codice 4.6: Esempio di funzione start() |
start() {
if [ "${RC_CMD}" = "restart" ];
then
fi
ebegin "Starting my_service"
start-stop-daemon --start --exec /path/to/my_service \
--pidfile /path/to/my_pidfile
eend $?
}
|
Sia --exec che --pidfile dovrebbero essere usati nelle funzioni
start e stop. Se il servizio non crea un pidfile, usare se possibile
--make-pidfile. Altrimenti non usare pidfile. Si può anche aggiungere
--quiet alle opzioni start-stop-daemon, ma non è raccomandato.
L'uso di --quiet potrebbe ostacolare il debugging se il servizio non si
avvia correttamente.
Un'altra impostazione di rilievo utilizzata nell'esempio precedente è il
controllo dela varaibile RC_CMD. A differenza del sistema init
precedente, il nuovo sistema openrc non supporta una funzione specifica
per il restart. Di conseguenza, lo script ha bisogno di controllare il contenuto
di RC_CMD per vedere se una funzione (che sia start() o
stop()) deve essere invocata come parti di un restart o meno.
Nota:
Assicurarsi che --exec chiami un servizio e non uno script shell che
lancia servizi e esce: è a questo che serve l'init script.
|
Se si ha bisogno di più esempi della funzione start(), leggere il codice
sorgente degli init script disponibili nella propria directory
/etc/init.d.
Un'altra funzione che può essere definita è stop(). Non si è obbligati a
definire questa funzione! Il sistema di init è abbastanza intelligente da
inserire da solo questa funzione se si usa start-stop-daemon.
Ecco une esempio di una funzione stop():
Codice 4.7: Esempio funzione stop() |
stop() {
ebegin "Stopping my_service"
start-stop-daemon --stop --exec /path/to/my_service \
--pidfile /path/to/my_pidfile
eend $?
}
|
Se il servizio esegue qualche altro script (per esempio bash, python o perl), e
questo script più avanti cambia i nomi (per esempio da foo.py a
foo), si deve aggiungere --name a start-stop-daemon. Si
deve specificare il nome che sarà cambiato dallo script. In questo esempio, un
servizio fa partire foo.py, che cambia nome in foo:
Codice 4.8: Un servizio che fa partire lo script foo |
start() {
ebegin "Starting my_script"
start-stop-daemon --start --exec /path/to/my_script \
--pidfile /path/to/my_pidfile --name foo
eend $?
}
|
start-stop-daemon ha una eccellente pagina man per vedere maggiori
opzioni:
Codice 4.9: Pagina Man di start-stop-daemon |
$ man start-stop-daemon
|
La sintassi di init script di Gentoo è basata su POSIX così
si possono usare costrutti compatibili sh nei propri init script.
Tenere altri costrutti come bash specifici, al di fuori dallo script
di init per essere sicuri che lo script funzioni indipendentemente
dai cambi che Gentoo potrebbe fare sul proprio sistema di init.
Aggiungere opzioni personalizzate
Se si ha bisogno di maggiori opzioni negli init script, si può aggiungere
l'opzione alla variabile extra_commands, e creare una funzione con lo
stesso nome dell'opzione. Per esempio, per il supporto di un'opzione chiamata
restartdelay:
Codice 4.10: Aggiungere l'opzione restartdelay |
extra_commands="restartdelay"
restartdelay() {
stop
sleep 3
start
}
|
Importante:
La funzione restart() non può essere sovrascritta in openrc!
|
Variabili di configurazione dei servizi
Non occorre fare nulla per supportare un file di configurazione in
/etc/conf.d: se l'init script viene eseguito, vengono
automaticamente processati i seguenti file (e per esempio le variabili sono
pronte per essere usate):
- /etc/conf.d/<vostro init script>
- /etc/conf.d/basic
- /etc/rc.conf
Inoltre, se l'init script fornisce una dipendenza virtuale (come net),
viene processato anche il file associato a questa dipendenza (come
/etc/conf.d/net).
4.e. Cambiare il comportamento del Runlevel
Può effettivamente essere utile?
Molti utenti di portatili conoscono la situazione: a casa si ha bisogno di
avviare net.eth0 ma non si vuole avviare net.eth0 quando si è in
giro (se non c'è nessuna rete disponibile). Con Gentoo si può alterare il
comportamento del runlevel per venire incontro alle proprie esigenze.
Per esempio si può creare un secondo runlevel "default" con cui effettuare il
boot contenente altri init script assegnati ad esso. Si può selezionare al
momento del boot quale runlevel predefinito usare.
Usare softlevel
Per prima cosa, creare la directory di runlevel per il secondo "default"
runlevel. Per esempio per creare il runlevel offline:
Codice 5.1: Creare la directory di runlevel |
# mkdir /etc/runlevels/offline
|
Aggiungere i necessari init script al nuovo runlevel creato. Per esempio, per
avere una copia del corrente runlevel default ma senza net.eth0:
Codice 5.2: Aggiungere gli init script necessari |
# cd /etc/runlevels/default
# for service in *; do rc-update add $service offline; done
# rc-update del net.eth0 offline
# rc-update show offline
acpid | offline
domainname | offline
local | offline
net.eth0 |
|
Anche se net.eth0 è stato rimosso dal runlevel offline, udev
potrebbe tentare ancora di avviare ogni dispositivo che rileva e avviare i
servizi relativi, una funzionalità chiamata hotplugging. Come
impostazione predefinita, Gentoo non abilita l'hotplugging.
Se si vuole abilitare l'hotplugging, ma solo per un certo insime di script, si
può usare la variabile rc_hotplug in /etc/rc.conf:
Codice 5.3: Disabilitare i servizi iniziati dai dispositivi in /etc/rc.conf |
rc_hotplug="net.wlan !net.*"
|
Nota:
Per maggiori informazioni sui servizi inizializzati per i diversi componenti, si
invita a porre attenzione nei commenti del file /etc/rc.conf.
|
Ora bisogna configurare il bootloader e aggiungere una nuova voce per il
runlevel offline. Per esempio in /boot/grub/grub.conf:
Codice 5.4: Aggiungere una voce per offline runlevel |
title Gentoo Linux Offline Usage
root (hd0,0)
kernel (hd0,0)/kernel-2.4.25 root=/dev/hda3 softlevel=offline
|
Se per il boot del sistema si seleziona la nuova voce il runlevel offline
viene usato al posto del default.
Usare bootlevel
Usare bootlevel è completamente analogo a softlevel. L'unica
differenza è che si sta definendo un secondo runlevel di "boot" invece di un
secondo runlevel "default".
[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
I contenuti di questo documento sono rilasciati sotto la licenza Creative
Commons - Attribution / Share Alike.
|