Handbook:AMD64/Working/Initscripts/it
The contents of this page do not apply to users that chose a systemd profile in Choosing the right profile.
Livelli di esecuzione
Avviare il sistema
Quando il sistema viene avviato, molto testo inizia a scorrere. Quando si presta attenzione, si noterà che quel testo (di solito) è lo stesso ogni volta che si riavvia il sistema. La sequenza di tutte queste azioni è chiamata sequenza di avvio ed è (più o meno) staticamente definita.
Innanzitutto, l'avviatore (bootloader) carica l'immagine del kernel definita nella configurazione del bootloader. Quindi, l'avviatore indica alla CPU di eseguire il kernel. Quando il kernel viene caricato ed eseguito, esso inizializza tutte le strutture e le attività specifiche del kernel ed avvia il processo di init.
Questo processo assicura poi che tutti i filesystem (definiti in /etc/fstab) siano montati e pronti per l'uso. Poi passa ad eseguire i diversi script situati in /etc/init.d/, che avvieranno i servizi necessari affinché il sistema sia avviato correttamente.
Infine, quando tutti gli script sono eseguiti, init attiva i terminali (nella maggior parte dei casi sono console virtuali nascoste e richiamabili con Alt+F1, Alt+F2, ecc.) associandogli un processo speciale chiamato agetty. Questo processo assicurerà poi gli utenti di poter accedere attraverso questi terminali eseguendo il login (accesso).
Gli script di init
Ora init non esegue solamente gli script in /etc/init.d/ a caso. Anzi, nemmeno esegue tutti gli script in /etc/init.d/, ma solo gli script che è stato detto di eseguire. Esso decide quali script eseguire ispezionando il contenuto di /etc/runlevels/.
Per prima cosa, init esegue gli script dentro /etc/init.d/ che hanno collegamenti simbolici con i file in /etc/runlevels/boot/. Solitamente, esso avvierà gli script in ordine alfabetico, ma alcuni script contengono informazioni sulle dipendenze, che dicono al sistema che un altro script deve essere eseguito prima di poter partire.
Quanto tutti gli script con un riferimento su /etc/runlevels/boot/ sono stati eseguiti, init prosegue con gli script che hanno un collegamento simbolico verso /etc/runlevels/default/. Ed ancora, sarà usato l'ordine alfabetico per decidere quale script eseguire prima, a meno che uno script abbia informazioni sulle sue dipendenze, in tal caso l'ordine sarà modificato per fornire una valida sequenza di avvio. Quest'ultima è anche la ragione per cui i comandi usati durante l'installazione di Gentoo Linux usano default
, come in rc-update add sshd default.
Come funziona init
Certamente init non decide tutto da solo. Esso necessita di un file di configurazione che specifica quali azioni devono essere compiute. Questo file di configurazione è /etc/inittab.
Tenere a mente la sequenza di avvio che è stata appena descritta - la prima azione di init è montare tutti i filesystem. Ciò viene definito con la seguente linea su /etc/inittab:
si::sysinit:/sbin/openrc sysinit
Questa linea dice ad init che deve eseguire /sbin/openrc sysinit per inizializzare il sistema. Lo script /sbin/openrc si prende cura dell'inizializzazione, così uno potrebbe pensare che init non fa molto - esso delega l'attività di inizializzazione del sistema ad un altro processo.
Come seconda cosa, init esegue tutti gli script che hanno collegamenti simbolici dentro /etc/runlevels/boot/. Ciò viene definito con la seguente linea:
rc::bootwait:/sbin/openrc boot
Nuovamente, lo script openrc esegue le attività necessarie. Notare che l'opzione data ad openrc (boot) è uguale alla sottodirectory di /etc/runlevels/ che viene usata.
Adesso init controlla il suo file di configurazione per vedere quale livello di esecuzione (runlevel) va eseguito. Per decidere ciò, legge la seguente riga da /etc/inittab:
id:3:initdefault:
In questo caso (che userà la maggior parte degli utenti Gentoo), l'ID del runlevel è 3. Usando queste informazioni, init controlla cosa deve essere eseguito per avviare il runlevel 3:
l0:0:wait:/sbin/openrc shutdown
l1:S1:wait:/sbin/openrc single
l2:2:wait:/sbin/openrc nonetwork
l3:3:wait:/sbin/openrc default
l4:4:wait:/sbin/openrc default
l5:5:wait:/sbin/openrc default
l6:6:wait:/sbin/openrc reboot
La linea che definisce il livello 3, nuovamente, usa lo script openrc per avviare i servizi (ora con argomento default
). Ancora una volta si noti che l'argomento openrc è uguale alla sotto cartella in /etc/runlevels/.
Quando openrc finisce, init decide quali console virtuali devono essere attivate e quali comandi devono essere eseguiti su ciascuna console:
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
Livelli di esecuzione disponibili
In una sezione precedente, abbiamo visto che init usa uno schema di numerazione per decidere quale livello di esecuzione (runlevel) vada eseguito. Un livello di esecuzione è uno stato nel quale il sistema sta funzionando e contiene una collezione di script (script di runlevel o init script) che devono essere eseguiti quando si entra dentro o si lascia un livello di esecuzione.
In Gentoo, ci sono sette livelli di esecuzione definiti: tre livelli di esecuzione interni, e quattro definiti dall'utente. I livelli di esecuzione interni sono chiamati sysinit, shutdown e reboot e fanno esattamente ciò che i loro nomi implicano: inizializzano il sistema, spengono il sistema e lo riavviano.
I livelli di esecuzione definiti dall'utente sono quelli con una sotto cartella in /etc/runlevels/ di accompagnamento: boot, default, nonetwork e single. Il livello di esecuzione boot avvia tutti i servizi necessari al sistema utilizzati dagli altri livelli di esecuzione. I rimanenti tre livelli differiscono in base ai servizi avviati: default è usato per le operazioni quotidiane, nonetwork è usato nel caso in cui la rete deve risultare sconnessa, e single è usato quando il sistema deve essere riparato.
Lavorare con gli script di init
Gli script che openrc processa all'avvio sono chiamati script di init. Ogni script in /etc/init.d/ può essere eseguito con gli argomenti start
, stop
, restart
, zap
, status
, ineed
, iuse
, needsme
, usesme
, or broken
.
Per avviare, fermare o riavviare un servizio (e tutti i servizi dipendenti), si devono usare gli argomenti start
, stop
, e restart
:
root #
/etc/init.d/postfix start
Solo i servizi che necessitano del servizio specificato vengono arrestati o riavviati. Gli altri servizi dipendenti (quelli che usano il servizio ma non ne hanno necessariamente bisogno) non vengono toccati.
Per arrestare un servizio, ma non i servizi che dipendono da esso, usare l'opzione --nodeps
insieme all'argomento stop
:
root #
/etc/init.d/postfix --nodeps stop
Per vedere in quale stato sta un servizio (avviato, arrestato, ...) usare l'argomento status
:
root #
/etc/init.d/postfix status
Se le informazioni sullo stato mostrano che il servizio è in esecuzione, ma in realtà non lo è, allora reimpostare le informazioni sullo stato su "stopped" con l'argomento zap
:
root #
/etc/init.d/postfix zap
Per chiedere inoltre quali dipendenze possiede il servizio, usare iuse
o ineed
. Con ineed
è possibile conoscere quali servizi sono effettivamente necessari per il corretto funzionamento del servizio. iuse
mostra invece quali servizi possono essere usati dal servizio, ma che non sono necessari al corretto funzionamento.
root #
/etc/init.d/postfix ineed
Analogamente, è possibile chiedere quali servizi richiedono il servizio interrogato (needsme
) o quali potrebbero usarlo (usesme
):
root #
/etc/init.d/postfix needsme
Aggiornare i livelli di esecuzione
rc-update
Il sistema init di Gentoo utilizza un albero delle dipendenze per decidere quale servizio vada avviato per primo. Siccome è un compito noioso e non vorremmo che i nostri utenti dovessero farlo manualmente, abbiamo creato strumenti che facilitano l'amministrazione dei livelli di esecuzione (runlevel) e degli script di init.
Con rc-update è possibile aggiungere o rimuovere script di init nei livelli di esecuzione. Lo strumento rc-update chiederà poi automaticamente allo script depscan.sh di ricostruire l'albero delle dipendenze.
Aggiungere e rimuovere servizi
Nelle precedenti istruzioni, gli script di init sono stati già aggiunti al livello di esecuzione "default" (predefinito). Ciò che significa "default" è stato spiegato in precedenza nel documento. Affianco all'argomento runlevel, lo script rc-update richiede un secondo argomento che definisce l'azione: add
(aggiungi), del
(rimuovi), o show
(mostra).
Per aggiungere o rimuovere uno script di init, basta dare a rc-update l'argomento add
o del
, seguito dallo script di init e dal livello di esecuzione. Per esempio:
root #
rc-update del postfix default
Il comando rc-update -v show mostrerà tutti gli script di init disponibili ed elencherà a quali livelli di esecuzione saranno eseguiti:
root #
rc-update -v show
È anche possibile eseguire rc-update show (senza -v
) per vedere giusto gli script di init abilitati ed i loro livelli di esecuzione.
Configurare i servizi
Perché è necessaria una configurazione aggiuntiva
Gli script di init possono essere piuttosto complessi. Pertanto, non è auspicabile che gli utenti modifichino direttamente gli script di init, in quanto tale azione sarebbe più soggetta ad errori. Tuttavia è importante poter configurare un servizio. Ad esempio, gli utenti potrebbero voler attivare più opzioni per il servizio stesso.
Una seconda ragione per tenere questa configurazione fuori dallo script di init è poter aggiornare gli script di init senza il timore che le modifiche della configurazione dell'utente siano annullate.
La cartella conf.d
Gentoo fornisce un modo facile per configurare tale servizio: ogni script di init che può essere configurato possiede un file dentro /etc/conf.d/. Per esempio, lo script di init apache2 (chiamato /etc/init.d/apache2) ha un file di configurazione chiamato /etc/conf.d/apache2, il quale può contenere le opzioni passate al server Apache 2 quando esso viene avviato:
APACHE2_OPTS="-D PHP5"
Questo file di configurazione contiene solo le variabili (proprio come /etc/portage/make.conf), rendendo molto facile configurare i servizi. Esso ci permette anche di fornire più informazioni riguardo le variabili (tramite i commenti).
Scrivere gli script di init
Another useful resource is OpenRC's service script guide.
È necessario?
No, scrivere uno script di init solitamente non è necessario in quanto Gentoo fornisce script di init pronti all'uso per tutti i servizi forniti. Comunque, alcuni utenti potrebbero aver installato un servizio senza usare Portage, in tal caso essi dovranno molto probabilmente creare uno script di init.
Non usare lo script di init fornito dal servizio se esso non è esplicitamente scritto per Gentoo: gli script di init di Gentoo non sono compatibili con gli script di init usati da altre distribuzioni! Così è, eccetto se l'altra distribuzione sta usando OpenRC!
Schema
Di seguito, lo schema base di uno script di init:
#!/sbin/openrc-run
depend() {
# (Informazioni sulle dipendenze)
}
start() {
# (Comandi necessari per avviare il servizio)
}
stop() {
# (Comandi necessari per arrestare il servizio)
}
#!/sbin/openrc-run
command=/usr/bin/foo
command_args="${foo_args} --bar"
pidfile=/var/run/foo.pid
name="FooBar Daemon"
description="FooBar is a daemon that drinks"
extra_started_commands="drink"
description_drink="Opens mouth and reflexively swallows"
depend() {
# (Dependency information)
}
start_pre() {
# (Commands necessary to prepare to start the service)
# Ensure that our dirs are correct
checkpath --directory --owner foo:foo --mode 0775 \
/var/run/foo /var/cache/foo
}
stop_post() {
# (Commands necessary to clean up after the service)
# Clean any spills
rm -rf /var/cache/foo/*
}
drink() {
ebegin "Starting to drink"
${command} --drink beer
eend $? "Failed to drink any beer :("
}
Tutti gli script di init richiedono che la funzione start()
sia definita. Tutte le altre sezioni sono opzionali.
Dipendenze
Ci sono due impostazioni similmente capaci di dipendenze che possono essere definite e che influenzano l'avvio o la sequenza degli script di init: use
e need
. Accanto a questi due, ci sono anche due metodi che influenzano l'ordinamento chiamati before
(prima) ed after
(dopo). Questi ultimi due non hanno dipendenze se considerati da soli: servono a non far fallire lo script di init originale se quello selezionato non è programmato per avviarsi (o fallisce nell'avvio).
- L'impostazione
use
informa il sistema di init che tale script usa funzionalità offerte da uno script selezionato, ma non dipende direttamente da esso. Un buon esempio potrebbe essereuse logger
ouse dns
. Se quei servizi sono disponibili, verranno usati, ma se il sistema non ha un logger o un server DNS, il servizio continuerà a funzionare. Se i servizi esistono, allora saranno avviati prima che lo script li usi. - L'impostazione
need
è una dipendenza rigida. Ciò significa che lo script che dipende da un altro script non sarà avviato finché l'altro script non sarà eseguito con successo. Inoltre, se quell'altro script viene riavviato, allora anche il primo sarà riavviato. - Quando si usa
before
, allora lo script selezionato viene eseguito prima, ma solo se quello selezionato è posto nello stesso livello di init. Così uno script di init come xdm che definiscebefore alsasound
avvierà prima lo script alsasound, ma solo se alsasound è programmato per l'avvio nel medesimo livello di init. Se alsasound non è stato programmato per l'avvio, questa particolare impostazione non genera effetti e xdm verrà avviato quando il sistema di init lo riterrà più appropriato. - Analogamente,
after
informa il sistema di init che lo script dovrebbe essere eseguito dopo quello selezionato e solo se quello selezionato è posto nello stesso livello di init. Se così non è, allora l'impostazione non genera effetti e lo script verrà avviato quando il sistema di init lo riterrà più appropriato.
Dovrebbe essere chiaro, stando a quanto detto, che need
è la sola "vera" impostazione per le dipendenze in quanto determina se lo script sarà avviato o meno. Tutte le altre sono solo puntatori nel sistema di init che chiariscono in quale ordine gli script possono (o dovrebbero) essere eseguiti.
Ora, guardiamo ai tanti script di init disponibili su Gentoo e notiamo che alcuni hanno delle dipendenze da cose che non sono script di init. Queste "cose" si chiamano virtuali.
Una dipendenza dai virtuali è una dipendenza che un servizio fornisce, ma non è fornita solamente da quel servizio. Uno script di init può dipendere da un logger (registratore di eventi) di sistema, ma ci sono molti logger di sistema disponibili (metalogd, syslog-ng, sysklogd, ...). Siccome uno script non può aver bisogno di ciascuno di essi (nessun sistema ragionevole ha tutti questi logger di sistema installati e funzionanti) ci assicuriamo che tutti questi servizi forniscano una dipendenza virtuale.
Per esempio, diamo un'occhiata alle informazioni sulle dipendenze di postfix:
depend() {
need net
use logger dns
provide mta
}
Come si può vedere, il servizio postfix:
- Richiede la dipendenza (virtuale) della rete (la quale è fornita, per esempio, da /etc/init.d/net.eth0).
- Usa la dipendenza (virtuale) logger (la quale è fornita, per esempio, da /etc/init.d/syslog-ng).
- Usa la dipendenza (virtuale) dns (la quale è fornita, per esempio, da /etc/init.d/named)
- Fornisce la dipendenza (virtuale) mta (la quale è comune a tutti i server di posta)
Controllare l'ordinamento
Come descritto nella precedente sezione, è possibile dire al sistema di init quale ordine dovrebbe seguire per avviare (o arrestare) gli script. Questo ordinamento è gestito sia attraverso le impostazioni delle dipendenze use (usa) e need (richiedi), ma anche attraverso le impostazione per l'ordine before (prima) ed after (dopo). Così come abbiamo descritto questi, diamo un'occhiata al servizio portmap come esempio per questi script di init.
depend() {
need net
before inetd
before xinetd
}
È possibile utilizzare l'asterisco "*" per intercettare tutti i servizi sullo stesso livello di esecuzione (runlevel), sebbene ciò non sia consigliabile.
depend() {
before *
}
Se il servizio deve scrivere sui dischi locali, dovrebbe richiedere localmount. Se si colloca qualsiasi cosa in /var/run/ come file pid, allora dovrebbe avviarsi dopo bootmisc:
depend() {
need localmount
after bootmisc
}
Funzioni standard
Accanto alla funzione depend()
, è necessario definire anche la funzione start()
. Questa contiene tutti i comandi necessari per inizializzare il servizio. Si consiglia di utilizzare le funzioni ebegin
e eend
per informare l'utente su ciò che sta accadendo:
start() {
if [ "${RC_CMD}" = "restart" ];
then
# Fai qualcosa nel caso in cui un riavvio richiede più che un arresto; avvia
fi
ebegin "Avvio di my_service in corso"
start-stop-daemon --start --exec /percorso/fino_a/il_mio_servizio \
--pidfile /percorso/fino_a/il_mio_file_pid
eend $?
}
Sia --exec
che --pidfile
dovrebbero essere usati nelle funzioni start e stop. Se il servizio non crea un file pid, usare --make-pidfile
se possibile, ed è consigliabile verificare che lo crei per essere sicuri. Altrimenti, non si usino file pid. È anche possibile aggiungere --quiet
(silenzioso) alle opzioni di start-stop-daemon, ma ciò non è raccomandato a meno che il servizio sia estremamente verboso. L'utilizzo di --quiet
può ostacolare l'individuazione di errori (debug) qualora il servizio fallisca l'avvio.
Un'altra rilevante impostazione utilizzata nell'esempio precedente è il controllo del contenuto della variabile RC_CMD. A differenza del precedente sistema di script di init, il nuovo sistema OpenRC non supporta la funzionalità di riavvio specifica per lo script. Piuttosto, lo script deve controllare il contenuto della variabile RC_CMD per vedere se una funzione (come start()
o stop()
) vada invocata o meno come parte del riavvio.
Assicurarsi che
--exec
chiami effettivamente un servizio e non solamente uno script della shell che lancia dei servizi ed esce - ovvero quel che si suppone faccia lo script di init.Per avere più esempi sulla funzione start()
, si legga il codice sorgente degli script di init disponibili nella cartella /etc/init.d/.
Un'altra funzione che può (anche se non deve) essere definita è stop()
. Il sistema di init è abbastanza intelligente da compilare questa funzione da solo se viene usato start-stop-daemon.
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 in seguito cambia i nomi (ad esempio, da foo.py a foo), allora è necessario aggiungere --name
a start-stop-daemon. Si deve specificare il nome con cui verrà modificato lo script. In questo esempio, un servizio avvia foo.py, il quale cambia i nomi in foo:
start() {
ebegin "Avvio di my_script"
start-stop-daemon --start --exec /path/to/my_script \
--pidfile /path/to/my_pidfile --name foo
eend $?
}
start-stop-daemon mette a disposizione un'eccellente pagina manuale se maggiori informazioni sono necessarie:
user $
man start-stop-daemon
La sintassi degli script di init di Gentoo si basa sulla shell POSIX, così le persone sono libere di usare costrutti sh-compatibili all'interno dei loro script di init. Si evitino altri costrutti, come quelli specifici di bash, negli script di init per essere sicuri che gli script rimangano funzionanti indipendentemente dai cambiamenti che Gentoo potrebbe ricevere al suo sistema di init.
Aggiungere opzioni personalizzate
Se lo script di init necessita di supportare più opzioni di quelle già incontrate, si aggiunga l'opzione alla variabile extra_commands e si crei una funzione con lo stesso nome dell'opzione. Ad esempio, per supportare un'opzione chiamata restartdelay
(riavvio con ritardo):
- extra_commands - Command is available with the service in any state
- extra_started_commands - Command is available when the service is started
- extra_stopped_commands - Command is available when the service is stopped
extra_commands="restartdelay"
restartdelay() {
stop
sleep 3 # Aspetta 3 secondi prima di ripartire
start
}
La funzione
restart()
non può essere sovra-definita (override) in OpenRC!Variabili di configurazione del servizio
Per supportare i file di configurazione in /etc/conf.d/, non è necessario implementare specifiche: quando viene eseguito lo script di init, i seguenti file vengono automaticamente acquisiti (ovvero le variabili sono disponibili per l'uso):
- /etc/conf.d/IL_TUO_SCRIPT_DI_INIT
- /etc/conf.d/basic
- /etc/rc.conf
Inoltre, se lo script di init fornisce una dipendenza virtuale (come net), verrà generato anche il file (come /etc/conf.d/net) associato a tale dipendenza.
Modificare il comportamento dei runlevel
Chi potrebbe beneficiarne
Molti utenti di portatili conoscono tale situazione: a casa hanno bisogno di avviare net.eth0, ma non vogliono avviare net.eth0 mentre sono in viaggio (dato che non ci sarà una rete disponibile). Con Gentoo il comportamento del livello di esecuzione (runlevel) può essere modificato a piacere.
Per esempio, è possibile creare un secondo livello di esecuzione (runlevel) "predefinito" che può essere avviato con altri script di init ad esso assegnati. Al momento dell'avvio, l'utente può quindi selezionare il livello di esecuzione predefinito da utilizzare.
Usare softlevel
Prima di tutto, creare la cartella del livello di esecuzione per il secondo livello "predefinito". Ad esempio, creiamo il livello di esecuzione "offline":
root #
mkdir /etc/runlevels/offline
Aggiungere gli script di init necessari al livello di esecuzione appena creato. Ad esempio, per avere una copia esatta del livello di esecuzione corrente predefinito, ma senza net.eth0:
root #
cd /etc/runlevels/default
root #
for service in *; do rc-update add $service offline; done
root #
rc-update del net.eth0 offline
root #
rc-update show offline
(Partial sample Output) acpid | offline domainname | offline local | offline net.eth0 |
Anche se net.eth0 è stato rimosso dal livello di esecuzione offline, udev potrebbe tentare di avviare qualsiasi dispositivo rilevato ed avviare i servizi appropriati, una funzionalità chiamata hotplugging (collegamento "a caldo"). Per impostazione predefinita, Gentoo non abilita l'hotplugging.
Per abilitare l'hotplugging, ma solo per un insieme di script selezionati, usare la variabile rc_hotplug in /etc/rc.conf:
rc_hotplug="net.wlan !net.*"
Per maggiori informazioni sui servizi avviati dal dispositivo, vedere i commenti all'interno di /etc/rc.conf.
Modificare la configurazione dell'avviatore (bootloader) e aggiungere una nuova voce per il livello di esecuzione (runlevel) offline. Per quella voce, aggiungere softlevel=offline
come parametro di avvio.
Usare bootlevel
Usare il livello di avvio (bootlevel) è del tutto analogo al livello soft (softlevel). L'unica differenza qui è che viene definito un secondo livello di esecuzione "di avvio" ("boot" runlevel) invece di un secondo livello di esecuzione "predefinito" ("default" runlevel).