Gentoo Logo

[ << ] [ < ] [ 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() {
  (Informazioni di dipendenza)
}

start() {
  (Comando necessario per avviare un servizio)
}

stop() {
  (Comando necessario per fermare un servizio)
}

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
    # Aggiungere qualcosa nel caso che un restart richieda più che stop, start
  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    # Attendere 3 secondi prima di avviarsi nuovamente
  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

(Copia tutti i servizi dal runlevel default al runlevel offline)
# cd /etc/runlevels/default
# for service in *; do rc-update add $service offline; done
(Rimuove servizi non desiderati da runlevel offline)
# rc-update del net.eth0 offline
(Visualizza i servizi attivi per runlevel offline)
# rc-update show offline
(Parte di un output esempio)
               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

# Abilitare net.wlan così come ogni altro servizio, eccetto quelli net.*
# per essere avviati al rilevamento
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 ] [ > ] [ >> ]


Stampa

Visualizza tutto

Aggiornato il 31 ottobre 2012

La versione originale di questo documento è più recente ed è stata aggiornata il 1 agosto 2013

Oggetto: Gentoo usa un formato speciale di initscript che, tra le altre caratteristiche, permette risoluzioni guidate delle dipendenze e initscript virtuali. Questo capitolo spiega tutti questi aspetti e spiega come utilizzare questi script.

Sven Vermeulen
Autore

Grant Goodyear
Autore

Roy Marples
Autore

Daniel Robbins
Autore

Chris Houser
Autore

Jerry Alexandratos
Autore

Seemant Kulleen
Sviluppo x86

Tavis Ormandy
Sviluppo Alpha

Jason Huebel
Sviluppo AMD64

Guy Martin
Sviluppo HPPA

Pieter Van den Abeele
Sviluppo PPC

Joe Kallar
Sviluppo SPARC

John P. Davis
Redazione

Pierre-Henri Jondot
Redazione

Eric Stockbridge
Redazione

Rajiv Manglani
Redazione

Jungmin Seo
Redazione

Stoyan Zhekov
Redazione

Jared Hudson
Redazione

Colin Morey
Redazione

Jorge Paulo
Redazione

Carl Anderson
Redazione

Jon Portnoy
Redazione

Zack Gilburd
Redazione

Jack Morgan
Redazione

Benny Chuang
Redazione

Erwin
Redazione

Joshua Kinard
Redazione

Tobias Scherbaum
Redazione

Xavier Neys
Redazione

Joshua Saddler
Redazione

Gerald J. Normandin Jr.
Revisione

Donnie Berkholz
Revisione

Ken Nowack
Revisione

Lars Weiler
Contributi

Marco Mascherpa
Traduzione

Stefano Pacella
Traduzione

Enrico Morelli
Traduzione

Davide Cendron
Traduzione

Sergio Vaccaro
Traduzione

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.