[indice generale] [precedente] [successivo] [indice analitico] [note introduttive]

18. Procedura di inizializzazione del sistema (System V)

Quando GNU/Linux viene avviato, il kernel si prende cura di avviare il processo init, a partire dal quale vengono poi generati tutti gli altri. Di solito si utilizza un meccanismo di inizializzazione derivato dallo UNIX System V.

init determina quali siano i processi da avviare successivamente, in base al contenuto di /etc/inittab il quale a sua volta fa riferimento a una serie di script contenuti normalmente all'interno della directory /etc/rc.d/ o in un'altra analoga.

All'interno di /etc/inittab si distinguono azioni diverse in funzione del livello di esecuzione, di solito un numero da 0 a 6. Per convenzione, il livello 0 identifica le azioni necessarie per fermare l'attività del sistema, in modo da permetterne lo spegnimento; il livello 6 riavvia il sistema; il livello 1 mette il sistema in condizione di funzionare in modalità monoutente.

Le distribuzioni GNU/Linux più sofisticate e confortevoli permettono di configurare il sistema attraverso dei programmi che guidano l'utente. Ciò significa che questi programmi sono in grado di produrre automaticamente script e file di configurazione tradizionali, ma per fare questo devono gestire un proprio sistema di file di configurazione che non appartiene allo standard generale.

L'organizzazione della procedura di inizializzazione del sistema e dei livelli di esecuzione costituisce il punto su cui si distinguono maggiormente le distribuzioni GNU/Linux. Benché alla fine si tratti sempre della stessa cosa, il modo di strutturare e di collocare gli script è molto diverso da una distribuzione all'altra. Quando si acquista più esperienza, ci si accorge che queste differenze non sono poi un grosso problema, ma all'inizio è importante comprendere e accettare che ciò che si usa (la propria distribuzione GNU/Linux) mostra un'interpretazione della soluzione del problema, non il risultato accettato generalmente.

Nel capitolo 186 viene descritto in modo più dettagliato come è organizzata questa procedura nella distribuzione RedHat.

18.1 init

init è il processo principale che genera tutti gli altri. All'avvio del sistema legge il file /etc/inittab il quale contiene le informazioni per attivare gli altri processi necessari, compresa la gestione dei terminali. Per prima cosa viene determinato il livello di esecuzione iniziale (run level), ottenendo l'informazione dalla direttiva initdefault di /etc/inittab. Quindi vengono attivati i processi essenziali al funzionamento del sistema e infine i processi che combaciano con il livello di esecuzione attivato.

18.1.1 # init

init [<opzioni>]

Durante il funzionamento del sistema, init può essere invocato per cambiare il livello di esecuzione.

Opzioni

-t <secondi>

Stabilisce il numero di secondi di attesa prima di cambiare il livello di esecuzione. In mancanza si intende 20 secondi.

0 | 1 | 2 | 3 | 4 | 5 | 6

Un numero da 0 a 6 stabilisce il livello di esecuzione.

a | b | c

Una lettera a, b o c indica a init di eseguire soltanto i processi indicati all'interno di /etc/inittab che hanno un livello di esecuzione pari alla lettera specificata. In pratica, una lettera non indica un livello di esecuzione vero e proprio; si tratta di una possibilità di configurazione del file /etc/inittab per definire i cosiddetti livelli «a richiesta» (on demand).

Q | q

Indica a init di riesaminare il file /etc/inittab.

S | s

Indica a init di passare alla modalità monoutente (single user), ma non è pensato per essere utilizzato direttamente.

Esempi

init 1

Pone il sistema al livello di esecuzione 1: monoutente.

init 0

Pone il sistema al livello di esecuzione 0: system halt. Equivale (in linea di massima) all'esecuzione di shutdown -h now.

init 6

Pone il sistema al livello di esecuzione 6: riavvio. Equivale (in linea di massima) all'esecuzione di shutdown -r now.

18.1.2 /etc/inittab

Il file inittab descrive quali processi vengono avviati al momento dell'avvio del sistema e durante il funzionamento normale di questo. init, il processo principale, distingue diversi livelli di esecuzione (run level), per ognuno dei quali può essere stabilito un gruppo diverso di processi da avviare.

La struttura dei record che compongono le direttive di questo file può essere schematizzata nel modo seguente:

<id>:<livelli-di-esecuzione>:<azione>:<processo>

<id> -- è una sequenza unica di due caratteri che identifica il record (la riga) all'interno di inittab;

<livelli-di-esecuzione> -- elenca i livelli di esecuzione con cui l'azione indicata deve essere eseguita;

<azione> -- indica l'azione da eseguire;

<processo> specifica il processo da eseguire.

Se il nome del processo inizia con un simbolo +, init non eseguirà l'aggiornamento di /var/run/utmp e /var/log/wtmp per quel processo; ciò è utile quando il processo stesso provvede da solo a questa operazione.

Azione

Il penultimo campo identifica l'azione da compiere. Questa viene rappresentata attraverso una parola chiave.

respan

Quando il processo termina, viene riavviato.

wait

Il processo viene avviato una volta (sempre che il livello di esecuzione lo consenta) e init attende che termini prima di eseguirne degli altri.

once

Il processo viene eseguito una volta quando il livello di esecuzione lo consente.

boot

Il processo viene eseguito al momento dell'avvio del sistema. Il campo del livello di esecuzione viene ignorato.

bootwait

Il processo viene eseguito al momento dell'avvio del sistema e init attende la fine del processo prima di proseguire. Il campo del livello di esecuzione viene ignorato.

off

Non fa alcunché.

ondemand

Si tratta dei record «a richiesta» che vengono presi in considerazione quando viene eseguito init seguito da una lettera a, b o c, che rappresentano appunto tre possibili livelli di esecuzione on demand. a, b o c non sono livelli di esecuzione, ma solo un modo per selezionare una serie di processi on demand indicati all'interno del file inittab.

initdefault

Permette di definire il livello di esecuzione predefinito per l'avvio del sistema. Se non viene specificato, init richiede l'inserimento di questo valore attraverso la console.

sysinit

Il processo viene eseguito al momento dell'avvio del sistema, prima di quelli indicati come boot e bootwait. Il campo del livello di esecuzione viene ignorato.

powerwait

Il processo viene eseguito quando init riceve il segnale SIGPWR che indica un problema con l'alimentazione elettrica. init attende la fine del processo prima di proseguire.

powerfail

Il processo viene eseguito quando init riceve il segnale SIGPWR che indica un problema con l'alimentazione elettrica. init non attende la fine del processo.

powerokwait

Il processo viene eseguito quando init ha ricevuto il segnale SIGPWR, che indica un problema con l'alimentazione elettrica, ed è anche presente il file /etc/powerstatus contenente la parola OK. Ciò significa che l'alimentazione elettrica è tornata allo stato di normalità.

ctrlaltdel

Il processo viene eseguito quando init riceve il segnale SIGINT. Ciò significa che è stata premuta la combinazione di tasti [Ctrl+Alt+Canc] ([Ctrl+Alt+Del] nelle tastiere inglesi).

kbrequest

Il processo viene eseguito quando init riceve un segnale dal gestore della tastiera che sta a indicare la pressione di una combinazione speciale di tasti sulla tastiera della console.

Livelli di esecuzione

Il campo dei livelli di esecuzione può contenere diversi caratteri che stanno a indicare diversi possibili livelli di esecuzione. Per esempio, 123 indica che il processo specificato verrà eseguito indifferentemente per tutti i livelli di esecuzione da 1 a 3. Questo campo può contenere anche una lettera dell'alfabeto: a, b o c che sta a indicare un livello on demand. Nel caso di azioni del tipo sysinit, boot e bootwait, il campo del livello di esecuzione viene ignorato.

Esempi

Negli esempi seguenti, si mostra prima un record del file /etc/inittab e quindi, sotto, la sua descrizione.

id:5:initdefault:

Definisce il livello di esecuzione iniziale: 5.

si::sysinit:/etc/rc.d/rc.sysinit

Inizializzazione del sistema: è la prima cosa a essere eseguita dopo l'avvio del sistema stesso. In pratica viene avviato lo script /etc/rc.d/rc.sysinit (RedHat).

l1:1:wait:/etc/rc.d/rc 1

Indica di eseguire /etc/rc.d/rc, con l'argomento 1, nel caso in cui il livello di esecuzione sia pari a 1: singolo utente (RedHat)

rc:123456:wait:/etc/rc.d/rc.M

Indica lo script (/etc/rc.d/rc.M) da eseguire per tutti i livelli di esecuzione da 1 a 6 (Slackware).

ca::ctrlaltdel:/sbin/shutdown -t5 -rfn now

Indica il programma da eseguire in caso di pressione della combinazione [Ctrl+Alt+Canc]. Il livello di esecuzione non viene indicato perché è indifferente (Slackware).

l0:0:wait:/etc/rc.d/rc 0

Indica di eseguire /etc/rc.d/rc, con l'argomento 0, nel caso in cui il livello di esecuzione sia pari a 0: system halt (RedHat).

l6:6:wait:/etc/rc.d/rc 6

Indica di eseguire /etc/rc.d/rc, con l'argomento 6, nel caso in cui il livello di esecuzione sia pari a 6: riavvio (RedHat).

pf::powerfail:/sbin/shutdown -f +5 "THE POWER IS FAILING"

Indica il programma da eseguire quando si verifica un problema con l'alimentazione elettrica (Slackware).

pg:0123456:powerokwait:/sbin/shutdown -c "THE POWER IS BACK"

Indica il programma da eseguire se l'alimentazione elettrica torna normale prima del completamento del processo avviato quando si era verificato il problema (Slackware).

1:12345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

Si tratta dell'elenco di console virtuali utilizzabili. La prima si attiva per tutti i livelli di esecuzione da 1 a 5, le altre solo per i livelli superiori a 1. In questo caso è mingetty a essere responsabile dell'attivazione delle console virtuali (RedHat).

s1:45:respawn:/sbin/agetty 19200 ttyS0 vt100

Indica l'attivazione di un terminale connesso sulla prima porta seriale. Si attiva solo con i livelli di esecuzione 4 o 5 (Slackware).

d2:45:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS1 vt100

Indica l'attivazione di un terminale remoto connesso via modem sulla seconda porta seriale. Si attiva solo con i livelli di esecuzione 4 o 5 (Slackware).

x:5:respawn:/usr/bin/X11/xdm -nodaemon

Nel caso il livello di esecuzione sia pari a 5, esegue /usr/bin/X11/xdm che si occupa di avviare un login all'interno dell'ambiente grafico X (RedHat).

18.1.3 /etc/initscript

/etc/initscript <id> <livello-di-esecuzione> <azione> <processo>

Quando lo script di shell /etc/initscript esiste, viene utilizzato da init per avviare i processi indicati all'interno del file /etc/inittab.

Di solito questo script non è presente, tuttavia potrebbe essere utile per definire delle variabili di ambiente e altre impostazioni che riguardano l'interpretazione degli script della procedura di inizializzazione del sistema. La documentazione initscript(5) mostra un esempio simile a quello seguente, che dovrebbe chiarire il senso di questa possibilità.

# initscript   Executed by init(8) for every program it
#              wants to spawn like this:
#
#              /bin/sh /etc/initscript <id> <level> <action> <process>
#

# Set umask to safe level, and enable core dumps.
umask 022
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH

# Execute the program.
eval exec "$4"

Come si vede anche dai commenti dell'esempio, initscript riceve da init, attraverso gli argomenti, tutti i campi contenuti nel record corrispondente di /etc/inittab.

18.2 Script della procedura di inizializzazione del sistema

La prima differenza importante che distingue le varie distribuzioni GNU/Linux sta nell'organizzazione degli script della procedura di inizializzazione del sistema. Il punto di riferimento comune è init con il suo /etc/inittab, dal quale si intende quali siano il comandi avviati in presenza di un determinato livello di esecuzione; quello che c'è dopo costituisce il problema più grosso.

Volendo semplificare molto le cose, si può pensare al fatto che ci dovrebbe essere una directory specifica, contenente un gruppetto di script utilizzato esclusivamente per questi scopi. Volendo fare un esempio preciso, nel caso della distribuzione RedHat, tale directory è /etc/rc.d/; dagli esempi visti riguardo al file /etc/inittab, si può notare che all'interno di questa directory si trovano gli script rc.sysinit e rc.

Per una convenzione diffusa, lo script rc.local che dovrebbe essere contenuto in questa directory (/etc/rc.d/, o altra directory a seconda della propria distribuzione GNU/Linux), viene eseguito alla fine della procedura di inizializzazione del sistema, e viene lasciato a disposizione dell'amministratore che può modificarlo come crede. Volendo fare un'associazione con il sistema Dos, si potrebbe paragonare questo script al file AUTOEXEC.BAT.

Le motivazioni che spingono a un'impostazione differente di questi script della procedura di inizializzazione del sistema, possono essere varie. Anche la collocazione di tale directory è controversa, a cominciare dal fatto che la directory /etc/ non dovrebbe contenere programmi e nemmeno script. Infatti, a questo proposito, la distribuzione SuSE colloca questi script nella directory /sbin/init.d/.

18.3 Procedura di attivazione e disattivazione dei servizi

Il sistema di script della procedura di inizializzazione del sistema ha il compito di avviare il sistema e di fermarlo, attivando e disattivando tutti i servizi necessari, cioè intervenendo nell'avvio e nella conclusione del funzionamento dei demoni relativi.

Si può intuire che non sia possibile realizzare uno o più script del genere per avviare tutti i tipi di demone che possono essere presenti nel proprio sistema, anche perché ci possono essere dei servizi installati che però non si vogliono gestire. Di conseguenza, nella situazione più banale, quando si intende installare e gestire un nuovo servizio, occorre anche modificare la procedura di inizializzazione del sistema per attivare il demone relativo e per disattivarlo nel momento dell'arresto del sistema. Una cosa del genere può andare bene per una persona esperta, ma si tratta sempre di un'impostazione piuttosto scomoda.

Nel tempo si è diffuso uno standard per risolvere questo problema, ed è ciò che viene descritto nelle sezioni seguenti.

18.3.1 Script di avvio e interruzione di un singolo servizio

Secondo una convenzione diffusa, per facilitare l'avvio e la conclusione dei servizi si definisce una directory specifica, che potrebbe essere /etc/rc.d/init.d/, o /etc/init.d/, o ancora /sbin/init.d/, all'interno della quale si possono inserire degli script che hanno una sintassi uniforme.

<nome-servizio> {start|stop}

In pratica, il nome dello script tende a corrispondere a quello del servizio che si intende controllare; l'argomento costituito dalla parola chiave start fa sì che lo script avvii il servizio, mentre la parola chiave stop serve a concluderlo.

Questi script possono essere più o meno raffinati, per esempio possono accettare anche altri tipi di ordini (come restart, allo scopo di riavviare un servizio), ma la cosa più importante è che dovrebbero evitare di avviare dei doppioni, controllando prima di avviare qualcosa, se per caso questo risulta già attivo. Naturalmente, un servizio può essere ottenuto con l'avvio di diversi programmi demone, e in questo è molto comodo tale sistema di script specifici.

A titolo di esempio viene mostrato come potrebbe essere composto uno script del genere, per l'avvio del servizio ipotetico denominato pippo, che si avvale del programma omonimo per gestirlo. Per semplicità, non vengono indicati accorgimenti particolari per controllare che il servizio sia già attivo o meno.

#!/bin/sh
#
# init.d/pippo {start|stop|restart}
#

# Analisi dell'argomento usato nella chiamata.
case "$1" in
  start)
	echo -n "Avvio del servizio Pippo: "
	/usr/sbin/pippo &
	echo
	;;
  stop)
	echo -n "Disattivazione del servizio Pippo: "
	killall pippo
	echo
	;;
  restart)
	killall -HUP pippo
	;;
  *)
	echo "Utilizzo: pippo {start|stop|restart}"
	exit 1
esac

exit 0

Lo scopo e la vera utilità di questi script sta nel facilitare una standardizzazione della procedura di inizializzazione del sistema; tuttavia si può intuire la possibilità di sfruttarli anche per attivare e disattivare manualmente un servizio, senza intervenire direttamente sui programmi relativi.

18.3.2 Collegamenti simbolici per ogni livello di esecuzione

Procedendo intuitivamente, si potrebbe pensare di fare in modo che la procedura di inizializzazione del sistema, all'avvio, provveda a eseguire tutti gli script di controllo dei servizi, utilizzando l'argomento start, e allo spegnimento, provveda a eseguirli con l'argomento stop. Una cosa del genere è molto semplice da realizzare, ma si pongono due problemi: alcuni servizi potrebbero essere a disposizione, senza che la procedura di inizializzazione del sistema debba avviarli automaticamente; la sequenza di attivazione e di disattivazione dei servizi potrebbe essere importante.

In pratica, si utilizza un meccanismo molto semplice: si predispongono tante directory quanti sono i livelli di esecuzione gestiti attraverso il file /etc/inittab. Queste directory hanno il nome rcn.d/, dove n rappresenta il numero del livello di esecuzione corrispondente. La loro collocazione effettiva potrebbe essere /etc/rcn.d/, /etc/rc.d/rcn.d/ o anche /sbin/init.d/rcn.d/. All'interno di queste directory si inseriscono dei collegamenti simbolici che puntano agli script descritti nella sezione precedente, in modo che siano presenti i riferimenti ai servizi desiderati per ogni livello di esecuzione (distinto in base alla directory rcn.d/ particolare).

I nomi di questi collegamenti iniziano in modo speciale: Knn... e Snn... I collegamenti che iniziano con la lettera «S» (Start) servono per individuare gli script da utilizzare per l'attivazione dei servizi, vengono avviati con l'argomento start, in ordine alfabetico, e a questo servono le due cifre numeriche successive: a distinguerne la sequenza. I collegamenti che iniziano con la lettera «K» (Kill) servono per individuare gli script da utilizzare per la disattivazione dei servizi, vengono avviati con l'argomento stop, anche questi in ordine alfabetico.

Ecco, a titolo di esempio, cosa potrebbe contenere una di queste directory.

lrwxrwxrwx 1 root root 13 13:39 K15gpm -> ../init.d/gpm
lrwxrwxrwx 1 root root 13 13:39 K60atd -> ../init.d/atd
lrwxrwxrwx 1 root root 15 13:39 K60crond -> ../init.d/crond
lrwxrwxrwx 1 root root 16 13:39 K96pcmcia -> ../init.d/pcmcia
lrwxrwxrwx 1 root root 17 13:39 S01kerneld -> ../init.d/kerneld
lrwxrwxrwx 1 root root 17 13:39 S10network -> ../init.d/network
lrwxrwxrwx 1 root root 15 13:39 S15nfsfs -> ../init.d/nfsfs
lrwxrwxrwx 1 root root 16 13:39 S20random -> ../init.d/random
lrwxrwxrwx 1 root root 16 13:39 S30syslog -> ../init.d/syslog
lrwxrwxrwx 1 root root 14 13:39 S50inet -> ../init.d/inet
lrwxrwxrwx 1 root root 18 13:39 S75keytable -> ../init.d/keytable

Osservando i servizi syslog e inet, si può notare il numero attribuito per l'avvio, che serve a fare in modo che il servizio syslog sia avviato prima di inet.

Sempre a titolo di esempio, viene mostrato un pezzo di uno script, per una shell Bourne o derivata, fatto per scandire un elenco di collegamenti del genere, allo scopo di attivare e di disattivare i servizi, a partire dai collegamenti contenuti nella directory /etc/rc.d/rc3.d/. Per un lettore inesperto, questo potrebbe essere un po' difficile da leggere, ma l'esempio viene aggiunto per completare l'argomento.

#!/bin/sh

#...

# Attivazione dei servizi del livello di esecuzione 3.

for I in /etc/rc.d/rc3.d/K*;
do
    # Disattiva il servizio.
    $I stop
done

for I in /etc/rc.d/rc3.d/S*;
do
    # Attiva il servizio.
    $I start
done

In pratica, prima si disattivano i servizi corrispondenti ai collegamenti che iniziano con la lettera «K», quindi si attivano quelli che hanno la lettera «S». Si può intuire che le directory rc0.d/ e rc6.d/ contengano prevalentemente, o esclusivamente, riferimenti che iniziano con la lettera «K», dal momento che i livelli di esecuzione corrispondenti portano all'arresto del sistema o al suo riavvio.

---------------------------

Appunti Linux 1999.07.12 --- Copyright © 1997-1999 Daniele Giacomini --  daniele @ evo.it

[indice generale] [precedente] [successivo] [indice analitico] [note introduttive]