%------------------------------------------------------------------------
\chapter{\cmd{init}}
\label{ch:init}
%------------------------------------------------------------------------

        \begin{chapterquote}
Uuno on numero yksi \\
        \end{chapterquote}

	\noindent
	Questo capitolo descrive \cmd{init}, che è il primo processo a livello utente inizializzato dal kernel. \cmd{init} ha molti doveri importanti, come inizializzare le \cmd{getty} (in modo che gli utenti si possano collegare), implementare i runlevel, e prendersi cura dei processi orfani. Questo capitolo spiega come si configura \cmd{init} e come si possano usare i diversi runlevel.

	
\index{init|see{/sbin/init}}
\index{daemon!init|see{/sbin/init}}
\index{/sbin/init}
	
\section{\cmd{init} prima di tutto}

	\cmd{init} è uno di quei programmi che sono assolutamente necessari per il funzionamento di un sistema Linux, ma che si può quasi sempre ignorare. Una buona distribuzione di Linux avrà una configurazione di \cmd{init} che funzioni con la maggior parte dei sistemi, e su questi sistemi non ci sarà bisogno di fargli niente. Di solito preoccuparsi di \cmd{init} serve solo se agganciate terminali seriali, modem in ingresso (non in uscita) o se volete cambiare il runlevel di default.

	Quando si è avviato il kernel (cioè quando è stato caricato in memoria, si è inizializzato ed ha inizializzato tutti i driver di device, le strutture dati e cose del genere), finisce la sua parte del processo di boot facendo partire un programma a livello utente, \cmd{init}; quindi, \cmd{init} è sempre il primo processo (e il suo numero di processo è sempre~1).

	Il kernel cerca \cmd{init} in alcuni posti in cui viene tenuto storicamente, ma il suo posto corretto (su un sistema Linux) è \fn{/sbin/init}. Se il kernel non trova \cmd{init} cerca di avviare \fn{/bin/sh}, e se non riesce a fare neanche quello fallisce l'avvio del sistema.
	
	Quando \cmd{init} parte completa il processo di boot portando a termine diversi compiti di amministrazione, come il controllo dei filesystem, la pulizia di \fn{/tmp}, l'avvio di svariati servizi e di una \cmd{getty} per ogni terminale e console virtuale a cui si possano collegare gli utenti (vedere il capitolo~\ref{ch:logins}).

Dopo che il sistema è partito correttamente, ogni volta che un utente si scollega \cmd{init} fa ripartire una \cmd{getty} nel terminale corrispondente (in modo che l'utente successivo possa ricollegarsi). \cmd{init} adotta anche i processi orfani: quando un processo avvia un processo figlio e muore prima di esso, quest'ultimo diventa figlio di \cmd{init}; è importante per varie ragioni tecniche, ma è bene saperlo, perché facilita la comprensione degli elenchi e degli alberi dei processi.\footnote{\cmd{init} non può morire. Non si può uccidere nemmeno con SIGKILL.}

	Sono disponibili anche alcune varianti di \cmd{init}: la maggior parte dei sistemi Linux usano \cmd{sysvinit} (scritto da Miquel van Smoorenburg), che è basato sull'\cmd{init} del System V. Le versioni BSD di Unix hanno un \cmd{init} diverso. La differenza principale sono i runlevel: il BSD non ce l'ha (almeno tradizionalmente), ma non è una differenza essenziale. Noi vedremo solo il \cmd{sysvinit}.
	
	
\section{Configurazione di \cmd{init} per inizializzare le \cmd{getty}: il file \fn{/etc/inittab}}

	Quando si avvia, \cmd{init} legge il file di configurazione \fn{/etc/inittab}. Durante il funzionamento del sistema il file verrà riletto se gli si manda il segnale HUP;\footnote{Usando ad esempio il comando \cmd{kill~-HUP~1} da root.} questa caratteristica rende inutile riavviare il sistema per attivare delle modifiche alla configurazione di \cmd{init}. 

	Il file \fn{/etc/inittab} è piuttosto complicato; cominceremo con il caso semplice della configurazione delle linee per le \cmd{getty}. Le linee del file \fn{/etc/inittab} consistono di quattro campi delimitati da due punti:
		%
\begin{quote}
\textsl{id:runlevel:azione:processo}
\end{quote}
		%
	I campi sono descritti qui sotto. Oltre a ciò, \fn{/etc/inittab} può contenere linee vuote e linee che cominciano con un cancelletto (`\verb|#|'): entrambe vengono ignorate.
	
	\begin{dispitems}
	\item[id]	Identifica la linea del file. Per le linee di \cmd{getty} specifica il terminale su cui gira (il carattere dopo \fn{/dev/tty} nel nome del file di device). Per altre linee non vuol dire niente (tranne che per le restrizioni sulla lunghezza), ma non deve essere univoco.
	
	\item[runlevel] Il runlevel per cui va considerata la linea. I runlevel vengono indicati da una sola cifra, senza delimitatori (i runlevel sono descritti nella prossima sezione).
			
	\item[azione] 	L'azione che deve corrispondere alla linea, ad esempio fare riavviare a \texttt{respawn} il comando nel campo successivo, quando esiste, o a \texttt{once} una volta sola.
			
	\item[processo]	Il comando da avviare.
	\end{dispitems}
	
	Per aprire una \cmd{getty} sul primo terminale virtuale (\fn{/dev/tty1}) in tutti i normali runlevel multiutente (2--5) si dovrebbe scrivere la seguente linea:
		%
\begin{tscreen}
1:2345:respawn:/sbin/getty 9600 tty1
\end{tscreen}
		%
	Il primo campo dice che questa è la linea di \fn{/dev/tty1}; il secondo dice che si applica ai runlevel 2, 3, 4 e 5. Il terzo campo significa che il comando deve essere riavviato quando esce (in modo che ci si possa collegare, scollegare e collegare di nuovo). L'ultimo campo è il comando che avvia la \cmd{getty} sul primo terminale virtuale.\footnote{Versioni diverse di \cmd{getty} funzionano in maniera diversa. Consultate la pagina man---ed assicuratevi che sia quella giusta.}

	Se voleste aggiungere ad un sistema dei terminali o delle linee modem in ingresso, dovreste aggiungere altre linee ad \fn{/etc/inittab}, una per ciascun terminale o linea. Per altri dettagli consultate le pagine man di \man{init}(8), \man{inittab}(5) e \man{getty}(8).

	Se un comando non parte, e \cmd{init} è configurato per farlo ripartire (\texttt{restart}), userà moltissime risorse di sistema: \cmd{init} lo avvia, fallisce, \cmd{init} lo avvia, fallisce, e così via all'infinito. Per evitare una cosa del genere, \cmd{init} tiene traccia di quanto spesso avvia un comando, e se la frequenza cresce aspetterà cinque minuti prima di avviarlo di nuovo.	
	
\section{I runlevel}

	Un \defin{runlevel} è uno stato di \cmd{init} e dell'intero sistema che definisce quali servizi di sistema sono operativi. I runlevel sono identificati da numeri; vedere la tabella~\ref{tab:run-levels}. Non c'è un parere comune per come usare i runlevel definiti a livello utente (dal 2 al 5): alcuni amministratori di sistema usano i runlevel per definire quali sottosistemi funzionano, cioè se gira X, se la rete è operativa e così via. Altri hanno tutti i sottosistemi che girano sempre, o li avviano e li fermano individualmente senza cambiare runlevel, perché i runlevel sono uno strumento troppo grezzo per controllare il sistema. Potete decidere da voi, ma può essere più semplice seguire come fa la vostra distribuzione di Linux.
	
		\begin{table}[h]
		\caption{Numeri dei runlevel}
		\label{tab:run-levels}
		\begin{center}
		\begin{tabular}{ll}
		\hline
		0 & Ferma il sistema. \\
		1 & Modalità utente singolo (per l'ammistrazione straordinaria). \\
		2--5 & Operazione normale (definiti dall'utente). \\
		6 & Reboot. \\
		\hline
		\end{tabular}
		\end{center}
		\end{table}

	I runlevel sono configurati da \fn{/etc/inittab} da linee come questa:
		%
\begin{tscreen}
l2:2:wait:/etc/init.d/rc 2
\end{tscreen}
		%
	Il primo campo è un livello arbitrario, il secondo significa che la linea si applica per il runlevel 2. Il terzo campo dice che \cmd{init} dovrebbe avviare il programma che sta nel quarto campo una sola volta, quando si entra nel runlevel, e che \cmd{init} deve aspettare che sia completato. Il comando \fn{/etc/init.d/rc} avvia qualsiasi comando sia necessario per far partire o interrompere i servizi per entrare nel runlevel 2.

	Il comando nel quarto campo fa tutto il lavoro duro di impostare un runlevel; inizializza i servizi che non stanno girando e ferma quelli che non dovrebbero farlo più nel nuovo runlevel. Quale è esattamente il comando e come sono configurati i runlevel dipende dalla distribuzione di Linux.

	Quando parte, \cmd{init} cerca una linea in \cmd{/etc/inittab} che specifichi il runlevel di default:
		%
\begin{tscreen}
id:2:initdefault:
\end{tscreen}
		%
	Potete chiedere a \cmd{init} di andare in un runlevel non di default all'avvio dando al kernel da linea di comando l'argomento \texttt{single} o \texttt{emergency};\footnote{Gli argomenti al kernel da linea di comando si danno ad esempio con LILO. Vedere la sezione~\ref{sec:single-user-mode}.} in questo modo si può scegliere la modalità a utente singolo (runlevel 1), che è descritta nella sezione~\ref{sec:single-user-mode}.

	Mentre il sistema gira, il comando \cmd{telinit} può cambiare il runlevel; quando accade, \cmd{init} avvia il comando appropriato da \fn{/etc/inittab}.


\section{Configurazioni speciali in \fn{/etc/inittab}}

	Il file \fn{/etc/inittab} ha alcune caratteristiche speciali che permettono ad \cmd{init} di reagire a circostanze particolari; tali caratteristiche vengono segnate da speciali parole chiave nel terzo campo. Alcuni esempi:
	
	\begin{dispitems}
	\item[\texttt{powerwait}]
		Permette ad \cmd{init} di spegnere il sistema, quando viene a mancare la corrente. Assume l'uso di un UPS, e di un software che lo controlli ed informi \cmd{init} che non c'è più corrente.
		
	\item[\texttt{ctrlaltdel}]
		Permette ad \cmd{init} di riavviare il sistema, quando l'utente preme \key{ctrl-alt-del} sulla tastiera di console. Notare che l'amministratore di sistema può configurare la reazione a \key{C-A-D} in modo che sia qualcos'altro, ad esempio che venga ignorata, se il sistema è accessibile al pubblico.\footnote{Oppure che avvii \cmd{nethack}.}

	\item[\texttt{sysinit}]
		Il comando da far partire all'avvio del sistema. Di solito fa cose come pulire la \fn{/tmp}.
	\end{dispitems}

	La lista qui sopra non è completa. Vedere la pagina man di \man{inittab}(5) per controllare tutte le possibilità, e per dettagli su come usare quelle riportate qui sopra.	

\section{Fare il boot in modalità utente singolo}
\label{sec:single-user-mode}

	Un runlevel importante è la \defin{modalità utente singolo} (runlevel~1), in cui solo l'amministratore di sistema usa la macchina e girano il minor numero possibile di servizi di sistema---compresi i login. La modalità a utente singolo è  necessaria per portare avanti dei compiti di amministrazione,\footnote{Non dovrebbe essere usata per giocare con \cmd{nethack}.} come usare \cmd{fsck} sulla partizione \fn{/usr}---il che richiede che la partizione non sia montata, cosa che non può accadere a meno che quasi tutti i servizi di sistema non vengano uccisi.

	Si può portare un sistema funzionante in modalità utente singolo usando il comando \cmd{telinit} per richiedere il runlevel~1. All'avvio ci si può entrare dando \texttt{single} o \texttt{emergency} sulla linea di comando del kernel: il kernel passa la linea di comando anche a \cmd{init}, e \cmd{init} riconosce così che non deve usare il runlevel di default (la linea di comando del kernel viene attivata in modi diversi a seconda di come avviate il sistema).

	Fare il boot in modalità utente singolo talvolta è necessario per poter usare \cmd{fsck} a mano, prima che vengano montate delle partizioni o che venga toccata una partizione \fn{/usr} corrotta (qualsiasi attività su un filesystem corrotto probabilmente lo rovinerà ancora di più, quindi bisogna usarci \cmd{fsck} il prima possibile).


	Gli script di avvio che \cmd{init} usa faranno entrare automaticamente in modalità utente singolo se l'\cmd{fsck} automatico al boot fallisce, in modo da evitare che il sistema usi un filesystem talmente rovinato da non poter essere riparato da \cmd{fsck}. Una cosa del genere è relativamente rara, e di solito comporta che l'hard disk sia rotto o che si stia usando una versione del kernel sperimentale, ma è bene essere preparati.


	Come misura di sicurezza, un sistema configurato correttamente chiederà la password di \texttt{root} prima di avviare una shell in modalità utente singolo, altrimenti sarebbe facile dare una linea a LILO per entrare come \texttt{root} (non funzionerà se il file \fn{/etc/passwd} è stato rovinato da problemi al filesystem, naturalmente, ed il quel caso sarà meglio avere un floppy di boot a portata di mano).	









