[ << ]
[ < ]
[ Sommaire ]
[ > ]
[ >> ]
4. Les scripts d'initialisation
Table des matières :
4.a. Les niveaux d'exécution
Démarrer votre système
Quand vous démarrez votre système, vous voyez beaucoup de texte défiler à
l'écran. Vous remarquerez sans doute que ce texte est le même à chaque
démarrage. La séquence d'actions qui se déroule devant vos yeux s'appelle la
séquence de démarrage et elle est définie de façon plus ou moins
statique.
D'abord, votre chargeur de démarrage charge l'image du noyau que vous avez
définie dans son fichier de configuration et ensuite, il exécute ce noyau. Ce
dernier s'initialise, démarre les tâches spécifiques au noyau et lance le
processus init.
Ce processus monte les systèmes de fichiers définis dans
/etc/fstab et exécute quelques scripts placés dans le répertoire
/etc/init.d qui, à leur tour, démarrent les services nécessaires
au bon fonctionnement du système.
Finalement, quand tous les scripts ont été exécutés, init active les
terminaux (en général, les consoles virtuelles que vous obtenez avec les
touches Alt-F1, Alt-F2, etc.) et attache un processus appelé
agetty à chacun. Ce processus vous permet de vous identifier sur ces
terminaux avec login.
Les scripts d'initialisation
En fait, init n'exécute pas les scripts du répertoire
/etc/init.d n'importe comment. De plus, il n'exécute pas non plus
tous les scripts, mais seulement ceux qui doivent l'être. Les scripts à
exécuter sont définis dans /etc/runlevels.
Le processus init exécute d'abord les scripts de
/etc/init.d vers lesquels un lien symbolique existe dans
/etc/runlevels/boot. Les scripts sont généralement exécutés par
ordre alphabétique, mais certains contiennent des dépendances qui indiquent
quels scripts doivent être exécutés en premier.
Quand tous les scripts liés dans /etc/runlevels/boot ont été
exécutés, init poursuit avec ceux liés dans
/etc/runlevels/default. Ici aussi, les scripts sont généralement
exécutés par ordre alphabétique, sauf quand ils contiennent des informations
sur des dépendances qui spécifient une séquence d'exécution particulière.
Comment init fonctionne-t-il ?
Évidemment, init ne décide pas tout seul de ce qu'il doit faire. Il a
besoin d'un fichier de configuration qui lui indique quelles actions il doit
effectuer. Ce fichier est /etc/inittab.
Dans la séquence de démarrage que nous venons d'expliquer, nous avons dit que
la première action de init était de monter les systèmes de fichiers. La
ligne du fichier /etc/inittab qui provoque cela est la
suivante :
Exemple de code 1 : La ligne d'initialisation du système dans /etc/inittab |
si::sysinit:/sbin/rc sysinit
|
En fait, cette ligne indique à init qu'il doit exécuter /sbin/rc
sysinit pour initialiser le système. C'est le script /sbin/rc
qui fait vraiment le travail d'initialisation et pas init qui ne fait
que déléguer les tâches.
Ensuite, init exécute tous les scripts vers lesquels un lien symbolique
est défini dans /etc/runlevels/boot. La ligne suivante provoque
cela :
Exemple de code 2 : L'initialisation du système, suite |
rc::bootwait:/sbin/rc boot
|
Encore une fois, le script rc fait le travail. Remarquez que l'option
boot passée au script rc correspond au nom du sous-répertoire qui
se trouve dans /etc/runlevels.
Ensuite, init lit son fichier de configuration pour savoir quel
runlevel il doit exécuter (N.D.T. : un « runlevel », ou
niveau d'exécution, correspond à l'état dans lequel il faut amener la machine).
La ligne suivante définit le niveau d'exécution :
Exemple de code 3 : La ligne initdefault |
id:3:initdefault:
|
Dans ce cas (la majorité des utilisateurs de Gentoo sont dans ce cas), le
niveau d'exécution est le numéro 3. Avec ce numéro, init trouve ce qu'il
doit exécuter pour lancer le niveau d'exécution 3 :
Exemple de code 4 : Les définitions des niveaux d'exécution |
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 ligne qui définit le niveau 3 utilise à nouveau le script rc pour
démarrer les services, cette fois avec le paramètre default. Remarquez
que, encore une fois, le paramètre correspond au nom du sous-répertoire dans
/etc/runlevels.
Quand le script rc a terminé, init trouve la liste des consoles
virtuelles à activer et quelles commandes il doit utiliser dans son fichier de
configuration :
Exemple de code 5 : La définition des consoles virtuelles |
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
|
Qu'est-ce qu'un niveau d'exécution ?
Vous avez constaté que init numérote les niveaux d'exécution qu'il doit
activer. Un niveau d'exécution définit un état dans lequel votre système se
trouve et contient les scripts nécessaires pour entrer dans ou quitter cet
état.
Dans Gentoo, sept niveaux d'exécution sont définis :trois internes et
quatre définis par l'utilisateur. Les niveaux d'exécution internes sont
sysinit, shutdown et reboot et sont utilisés
respectivement pour initialiser, éteindre et redémarrer le système.
Les niveaux d'exécution définis par l'utilisateur sont ceux qui correspondent à
un sous-répertoire dans /etc/runlevels : boot,
default, nonetwork et single. Le niveau
d'exécution boot est utilisé pour démarrer tous les services
système utilisés par les autres niveaux d'exécution. Les autres niveaux
d'exécution se différencient par les services qu'ils activent :
default est utilisé en temps normal, nonetwork est
utilisé quand aucune connexion réseau n'est souhaitée et single
est utilisé pour résoudre d'éventuels problèmes du système.
Utiliser les scripts d'initialisation
Les scripts que rc exécute sont appelés des scripts
d'initialisation. Chaque script peut être exécuté avec les options
start, stop, restart, pause, zap,
status, ineed, iuse, needsme, usesme ou
broken.
Pour démarrer, arrêter ou relancer un service (et les autres services
nécessaires éventuels), utilisez start, stop et restart.
Exemple de code 6 : Démarrer postfix |
# /etc/init.d/postfix start
|
Note :
Seuls les services qui ont besoin du service spécifié sont arrêtés ou
redémarrés. Les services qui l'utilisent ne sont pas affectés.
|
Pour stopper un service sans toucher aux services qui l'utilisent, utilisez
l'option pause :
Exemple de code 7 : Stopper postfix sans toucher aux services qui l'utilisent |
# /etc/init.d/postfix pause
|
Pour afficher le statut d'un service (démarré, arrêté, en pause), utilisez
l'option status :
Exemple de code 8 : Afficher le statut du service postfix |
# /etc/init.d/postfix status
|
Si le système affirme qu'un service est actif, mais que vous savez qu'il
ne l'est pas, utilisez l'option zap pour réinitialiser son statut à
« arrêté ».
Exemple de code 9 : Réinitialiser le statut de postfix |
# /etc/init.d/postfix zap
|
Vous pouvez aussi afficher les services dont un service a besoin avec les
options iuse ou ineed. Avec l'option ineed, les services
réellement nécessaires sont affichés. Avec iuse, ce sont les services
qui peuvent être utilisés sans être indispensables qui sont affichés.
Exemple de code 10 : Afficher la liste des services dont Postfix a besoin |
# /etc/init.d/postfix ineed
|
De la même façon, vous pouvez afficher la liste des services qui ont besoin
(needsme) ou qui utilisent (usesme) un service particulier :
Exemple de code 11 : Afficher la liste des services qui ont besoin de Postfix |
# /etc/init.d/postfix needsme
|
Enfin, vous pouvez aussi demander la liste des services requis qui
manquent :
Exemple de code 12 : Afficher la liste des services manquants dont Postfix a besoin |
# /etc/init.d/postfix broken
|
4.b. Utiliser rc-update
Qu'est-ce que rc-update ?
Gentoo construit un arbre de dépendances pour déterminer l'ordre d'exécution
des services. Cela est loin d'être trivial et nous avons donc créé des outils
qui facilitent l'administration des niveaux d'exécution et des scripts
d'initialisation.
La commande rc-update permet d'ajouter ou d'enlever un script d'un
niveau d'exécution. Cette commande utilise automatiquement le script
depscan.sh qui reconstruit l'arbre des dépendances.
Ajouter et enlever des services
Vous avez déjà ajouté des scripts d'initialisation au niveau d'exécution
« default » pendant l'installation de Gentoo. Vous ignoriez alors la
signification de « default », mais maintenant, vous la connaissez. Le
script rc-update a besoin d'un second argument qui spécifie l'action à
effectuer : add, del ou show pour respectivement
ajouter, supprimer ou afficher.
Pour ajouter ou supprimer un service, ajoutez simplement add ou
del à la commande rc-update et spécifiez ensuite le nom du script
d'initialisation et le niveau d'exécution. Par exemple :
Exemple de code 13 : Supprimer Postfix du niveau d'exécution « default » |
# rc-update del postfix default
|
La commande rc-update show affiche la liste des scripts d'initialisation
disponibles et les niveaux d'exécution dans lesquels ils ont été ajoutés :
Exemple de code 14 : Afficher la liste des scripts d'initialisation |
# rc-update show
|
4.c. Configurer les services
Pourquoi encore configurer ?
Les scripts d'initialisation peuvent être complexes. Il vaut donc mieux éviter
que les utilisateurs ne doivent les modifier. Cela évite bien des problèmes.
Cependant, les services ont parfois besoin d'être configurés ou de recevoir
certaines options.
Une autre raison pour séparer les scripts de leur configuration est que cela
vous permet de mettre à jour les scripts sans que leur configuration ne soit
perdue.
Le répertoire /etc/conf.d
Gentoo offre un système facile pour configurer les services. Chaque script
d'initialisation qui peut être configuré a un fichier de configuration dans le
répertoire /etc/conf.d. Par exemple, le script d'initialisation
d'apache2 (/etc/init.d/apache2) a un fichier de configuration
/etc/conf.d/apache2 qui contient les options à passer au serveur
Apache 2 quand ce dernier est lancé.
Exemple de code 15 : Variables définies dans /etc/conf.d/apache2 |
APACHE2_OPTS="-D PHP4"
|
Un tel fichier de configuration ne contient que des définitions de
variables (tout comme /etc/make.conf), ce qui permet de configurer
facilement un service. Cela permet aussi de fournir des explications sur ces
options sous forme de commentaires.
4.d. Écrire un script d'initialisation
Dois-je faire cela ?
Non. Rédiger un script d'initialisation n'est généralement pas nécessaire
puisque Gentoo fournit des scripts complets pour tous les services supportés.
Cependant, si vous avez installé un service sans l'aide de Portage, vous devrez
sans doute écrire un tel script.
N'utilisez pas le script fourni avec le logiciel à moins qu'il ne soit écrit
spécifiquement pour Gentoo, car les scripts d'initialisation de Gentoo ne sont
pas compatibles avec ceux des autres distributions.
Structure
La structure de base d'un script d'initialisation est décrite ci-dessous.
Exemple de code 16 : Structure de base d'un script d'initialisation |
#!/sbin/runscript
depend() {
}
start() {
}
stop() {
}
restart() {
}
|
La partie start() est indispensable, les autres sont
facultatives.
Dépendances
Il existe deux types de dépendances : use et need. Comme
mentionné précédemment, la dépendance need est plus stricte que
use. Vous devez faire suivre le type de dépendance par le nom du service
dont votre service dépend, ou par une dépendance virtuelle.
Une dépendance virtuelle est une dépendance qui peut être satisfaite par
plusieurs services différents. Par exemple, votre service pourrait dépendre du
système de journalisation qui peut être fourni par plusieurs services
différents (metalogd, syslog-ng, sysklogd...) Étant donné que votre service ne
peut pas dépendre de tous ces services (on ne peut installer qu'un seul système
de journalisation), nous avons défini une seule dépendance virtuelle que chacun
de ces services satisfait.
Jetons un œil aux dépendances du service postfix.
Exemple de code 17 : Dépendances de Postfix |
depend() {
need net
use logger dns
provide mta
}
|
Comme vous pouvez le voir, postfix :
-
a besoin du service virtuel net qui est fourni par
/etc/init.d/net.eth0, par exemple ;
-
utilise un système de journalisation (service virtuel logger) qui est
fourni par /etc/init.d/syslog-ng, par exemple ;
-
utilise le service (virtuel) dns qui est fourni par
/etc/init.d/named, par exemple ;
-
fournit le service virtuel mta qui indique qu'un serveur de courrier
est disponible.
Ordonner la séquence d'exécution
Dans certains cas, vous voudrez peut-être démarrer un service avant ou après un
autre, pour autant que cet autre service soit disponible. Notez qu'il ne s'agit
plus d'une dépendance, mais simplement d'une demande de lancement de services
dans un ordre défini au sein d'un même niveau d'exécution. Pour définir une
séquence d'exécution, utilisez les mots-clefs before ou after.
Voyez, par exemple, le service portmap :
Exemple de code 18 : La fonction depend() du service Portmap |
depend() {
need net
before inetd
before xinetd
}
|
Vous pouvez aussi remplacer le nom de service par une étoile ("*") pour
spécifier tous les services d'un niveau d'exécution, mais cela n'est pas
recommandé.
Exemple de code 19 : Lancer un script avant tous les autres dans un niveau d'exécution |
depend() {
before *
}
|
Si votre service doit écrire sur des disques locaux, il aura besoin du
localmount. S'il place quelque chose dans /var/run, tel
un fichier .pid, alors il devra démarrer après bootmisc :
Exemple de code 20 : Exemple de fonction depend() |
depend() {
need localmount
after bootmisc
}
|
Fonctions standard
En plus de la fonction depend(), vous devez définir la fonction
start() qui doit contenir les commandes nécessaires pour activer le
service. Il est conseillé d'utiliser les fonctions ebegin et eend
pour afficher des messages à l'écran et ainsi informer l'utilisateur que le
service démarre.
Exemple de code 21 : Exemple de fonction start() |
start() {
ebegin "Starting my_service"
start-stop-daemon --start --exec /chemin/vers/mon_service \
--pidfile /chemin/vers//mon_fichier_pid
eend $?
}
|
Les options --exec et --pidfile devraient être utilisées
dans les fonctions start et stop. Si le service ne crée pas de fichier .pid,
alors utilisez --make-pidfile, si possible, bien que vous devriez
le tester pour en être sûr. Dans le cas contraire, n'utilisez pas de fichier
.pid. Vous pouvez aussi ajouter --quiet aux options
start-stop-daemon, bien que cela soit déconseillé à moins que le
service soit extrêmement verbeux. En effet, utiliser --quiet peut
cacher des informations de débogage utiles si le démarrage du service
échoue.
Note :
Assurez-vous que --exec appelle effectivement un service et pas
simplement un script shell qui lance des services (c'est ce que le script
init est censé faire).
|
Vous trouverez plus d'exemples de fonctions start() dans les sources des
scripts d'initialisation, localisés dans le répertoire
/etc/init.d.
Vous pouvez aussi définir les fonctions facultatives stop() et
restart() pour respectivement arrêter et relancer un service, mais
Gentoo est capable de s'en passer si vous avez utilisé la commande
start-stop-daemon.
Bien que vous ne devriez pas créer de fonction stop(), en
voici quand même un exemple :
Exemple de code 22 : Exemple de fonction stop() |
stop() {
ebegin "Arrêt de mon_service"
start-stop-daemon --stop --exec /chemin/vers/mon_service \
--pidfile /chemin/vers/mon_fichier_pid
eend $?
}
|
Si votre service exécute un script (Bash, Python ou Perl par exemple) dont le
nom change par la suite (par exemple, toto.py devient toto), il
faut alors ajouter l'option --name à la commande
start-stop-daemon. Vous devez y spécifier le nom du script après
changement. Dans cet exemple, un service démarre toto.py dont le nom
devient toto :
Exemple de code 23 : Un service qui lance le script toto |
start() {
ebegin "Démarrage de mon_script"
start-stop-daemon --start --exec /chemin/vers/mon_script \
--pidfile /chemin/vers/mon_fichier_pid --name toto
eend $?
}
|
Pour de plus amples informations, un excellent manuel est disponible pour la
commande start-stop-daemon :
Exemple de code 24 : Consulter le manuel de start-stop-daemon |
$ man start-stop-daemon
|
Les scripts d'initialisation utilisent bash. Vous pouvez utiliser toutes
les fonctionnalités de bash dans vos scripts.
Ajouter une option non prévue
Si vous voulez utiliser une option non prévue par nos scripts, vous devez
l'ajouter à la variable opts et créer une fonction qui a le même nom. Par
exemple, pour ajouter une option restartdelay :
Exemple de code 25 : Ajouter une option restartdelay |
opts="${opts} restartdelay"
restartdelay() {
stop
sleep 3
start
}
|
Variables de configuration d'un service
Vous ne devez rien faire de particulier pour utiliser un fichier de
configuration dans /etc/conf.d : avant que votre script
d'initalisation ne soit exécuté, les variables des fichiers suivants sont
initialisées dans cet ordre :
- /etc/conf.d/<votre_script>
- /etc/conf.d/basic
- /etc/rc.conf
De plus, si votre script fournit un service virtuel (comme net),
le fichier de configuration correspondant (comme /etc/conf.d/net)
sera également lu.
4.e. Modifier le comportement des niveaux d'exécution
Quel intérêt et pour qui ?
Les utilisateurs d'ordinateurs portables connaissent bien le problème :
vous devez démarrer net.eth0 à la maison, mais pas lorsque vous êtes en
vadrouille puis que vous n'êtes alors plus connecté à votre réseau. Vous pouvez
adapter le comportement de Gentoo.
Par exemple, vous pouvez créer un second niveau d'exécution similaire au niveau
« default », mais sans les options réseau. Vous pourrez ensuite
sélectionner le niveau d'exécution au démarrage de votre machine.
Utiliser « softlevel »
Créez votre second niveau d'exécution similaire à « default ». Dans
notre exemple, nous créons un niveau « offline ».
Exemple de code 26 : Créer le répertoire du nouveau niveau d'exécution |
# mkdir /etc/runlevels/offline
|
Ajoutez les scripts d'initialisation à votre nouveau niveau d'exécution. Par
exemple, pour copier le niveau « default » sauf le script
net.eth0 :
Exemple de code 27 : Recopier les scripts d'initialisation |
# 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 |
|
Même si net.eth0 a été retiré du niveau d'exécution offline,
udev va quand même essayer de démarrer les interfaces qu'il détecte
et lancer les services associés. C'est pourquoi vous devez ajouter les
services réseaux que vous ne souhaitez pas voir démarrés au fichier
/etc/conf.d/rc (cela est vrai pour tout autre service pouvant
être lancé par udev) :
Exemple de code 28 : Désactiver un service démarré par une interface dans /etc/conf.d/rc |
RC_COLDPLUG="yes"
RC_PLUG_SERVICES="!net.eth0"
|
Note :
Vous trouverez plus d'informations sur les services démarrés par les
interfaces en consultant les commentaires du fichier
/etc/conf.d/rc.
|
Ensuite, modifiez la configuration de votre chargeur de démarrage pour y
ajouter une nouvelle option pour le niveau offline. Par exemple, pour
grub, modifiez /boot/grub/grub.conf :
Exemple de code 29 : Ajouter une entrée dans le menu de démarrage |
title Gentoo Linux Offline
root (hd0,0)
kernel (hd0,0)/kernel-2.4.25 root=/dev/hda3 softlevel=offline
|
Voilà, c'est terminé. Si vous redémarrez votre machine et que vous choisissez
la nouvelle entrée, le niveau d'exécution offline sera utilisé au lieu
du niveau default.
Utiliser « bootlevel »
Vous pouvez aussi remplacer le niveau d'exécution « boot » avec
l'option bootlevel exactement de la même façon qu'avec softlevel.
[ << ]
[ < ]
[ Sommaire ]
[ > ]
[ >> ]
Ce document est protégé par la licence Creative
Commons : Paternité - Partage des Conditions Initiales à
l'Identique 2.5.
|