• Aucun résultat trouvé

Gestion des threads au niveau noyau

8 Le démarrage d’un système Linux

shell (interpréteur de commandes), afin que l'utilisateur ait accès au système. Si cela échoue également, le noyau affiche un message d'erreur et s'arrête.

Le processus lance toujours quatre threads (kupdate et bdflush qui gèrent le cache disque, et kswap et kpiod qui gèrent la mémoire virtuelle). Puis, init va charger tous les autres processus. Le comportement d'init se configure à l'aide du fichier

« /etc/inittab ». En voici un exemple d'extrait : id:5:initdefault:

si::sysinit:/etc/rc.sysinit l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

Chaque ligne est construite de la même manière avec les champs suivants : Identifiant:Niveau d’exécution:Action:Programme

Identifiant : une chaîne de caractères choisie par l'utilisateur (sauf dans certains cas particuliers) et permettant d'identifier la ligne.

Niveaux d'exécution : les niveaux d'exécution (détaillés dans le chapitre suivant) pour lesquels cette ligne doit être prise en compte.

Action : contient une des actions prédéfinies indiquant ce qui doit être fait. Le tableau suivant les liste.

Programme : le programme qui doit être exécuté lorsque l'on rentre dans les niveaux indiqués.

Selon l'action choisie, le comportement sera différent et certains champs peuvent être ignorés. Voici la description des actions le plus souvent utilisées :

initdefault : permet d'indiquer le niveau d'exécution à utiliser par défaut. Le champ « Niveaux d'exécution » contiendra alors une seule valeur qui sera ce niveau par défaut. Dans une telle ligne, le champ « Programme » est ignoré ;

sysinit : le champs « Programme » contient le chemin vers un exécutable qui sera lancé en tout premier par « init » (donc juste après que le noyau ait terminé ses initialisations). Dans une telle ligne, le champ « Niveaux d’exécution » est ignoré ;

wait : lorsque le système passera dans le niveau d'exécution spécifié, « init » exécutera la commande indiquée puis attendra qu'elle se termine ;

respawn : semblable à « wait », si ce n'est qu'à chaque fois que le programme se termine, « init » le relancera ;

ctrlaltdel : permet d'indiquer une commande devant être exécutée lorsque l'utilisateur presse la combinaison de touches Ctrl-Alt-Suppr. Dans une telle ligne, le champ « Niveaux d’exécution » est ignoré.

8.3 Les niveaux d'exécution

Sur les systèmes GNU/Linux, il existe plusieurs niveaux d'exécution possibles (appelés aussi modes d'exécution). Il s'agit en fait de modes de démarrage différents, qui diffèrent les uns des autres par les services qui y sont lancés.

La convention choisie est celle appelée « System V init » qui définit la manière dont doivent être gérés les différents niveaux. Dans le fichier « /etc/inittab » donné en exemple dans le chapitre précédent, on peut voir que c'est le programme « /etc/rc.d/rc » qui gère cela. Il est lancé avec en paramètre le numéro de niveau lorsque l'on a besoin de basculer dans un certain niveau d'exécution.

On trouve en général 7 niveaux d'exécution numérotés de 0 à 6. Leur utilisation est libre, mais traditionnellement, ils prennent la signification suivante :

0 (arrêt) : passer dans ce niveau provoque un arrêt de la machine ;

1 (maintenance, ou sigle user) : on a directement accès à un shell, mais quasiment aucun service n'est lancé. Utile pour le dépannage en cas de problème important ;

2 (multi-utilisateurs simple) : plusieurs utilisateurs peuvent se connecter en mode texte. Mais les services sont limités (souvent pas de réseau par exemple) ;

3 (multi-utilisateurs complet) : tous les services nécessaires sont démarrés et plusieurs utilisateurs peuvent se connecter en mode texte ;

4 (mode utilisateur) : généralement non employé, il peut être librement utilisé ;

5 (mode graphique) : identique au mode 3, mais les utilisateurs peuvent se connecter en mode graphique (X11) et disposer d'un gestionnaire de fenêtre (Gnome, KDE, etc.) ;

6 (redémarrage) : passer dans ce niveau entraîne un redémarrage de la machine.

Après le démarrage, le système se trouve dans le mode indiqué par « initdefault » dans « /etc/inittab ». Pour pouvoir changer, il existe un outil appelé « telinit ». Il suffit de le lancer en lui passant en paramètre le numéro du niveau souhait. Par exemple, pour redémarrer la machine, il suffit de lancer la commande suivante en étant identifié comme étant l’utilisateur root :

# telinit 6

Bien qu'il y ait des conventions pour ce qui doit être fait dans chaque mode, cela peut être entièrement changé.

Pour comprendre comment influer sur ce comportement, il faut d'abord savoir ce que fait le programme « /etc/rc.d/rc » (ou un autre selon les systèmes et le contenu du fichier

« inittab »).

Ce programme (souvent, un scipt shell, ou perl) gère les niveaux d'exécution en allant consulter le contenu du répertoire « /etc/rc.d/rcX.d » (ou « /etc/rcX.d » dans certain systèmes comme la distribution Debian), avec X correspondant au numéro du niveau devant être changé.

Ce script va rechercher d'abord tous les exécutables s'y trouvant et dont le nom commence par la lettre « K » (pour Kill) suivie par deux chiffres. Il lance ces programmes en leur passant en paramètre « stop ». Cela correspond aux services qui doivent être arrêté dans ce mode d’exécution là. Ils sont lancés dans l'ordre croissant du nombre indiqué après le K, ce qui permet de les ordonner (démarrer tel service avant tel autre).

C'est ensuite au tour des programmes dont le nom commence par la lettre « S » (pour Start) puis également un nombre sur deux chiffres. Ils sont lancés de la même manière que les précédents si ce n'est que c'est le paramètre « start » qui est passé.

Pour illustrer ceci, voici un contenu possible d'un de ces répertoires :

# ls /etc/rc.d/rc3.d K15httpd

K20samba K45named S10network S55sshd S99local

Dans cet exemple (qui est totalement farfelu), lorsque le système passe dans le niveau 3 (soit au démarrage si c'est celui par défaut, soit ensuite, si c'est l'utilisateur qui le demande), on arrêtera les services httpd (serveur web), samba (serveur de fichiers suivant le protocole CIF, c'est-à-dire « à la sauce Windows ») et named (serveur de noms). Ensuite seront démarrés les services network (pour la prise en charge du réseau), sshd (serveur de connexion distante sécurisée par le protocole SSL) et local (qui contient traditionnellement par convention des programmes devant être exécuté en fin de démarrage).

Comme des programmes peuvent exister dans plusieurs niveaux différents, on ne trouvera en réalité dans les répertoires « /etc[/rc.d]/rcX.d » que des liens symboliques pointant vers des fichiers situés dans le répertoire « /etc/rc.d/init.d » (ou « /etc/

init.d » sur certains systèmes). Ces fichiers sont en réalité pour la plupart des scripts shell, et le même sera lancé pour le démarrage ou l'arrêt. C'est donc de la responsabilité du script de voir s'il a été appelé avec le paramètre « start » ou le paramètre « stop », afin de savoir quelles actions entreprendre.

Sachant cela, ajouter ou supprimer des services dans un niveau donné revient uniquement à créer ou supprimer des liens symboliques. En reprenant l'exemple précédent, voici un exemple (tout aussi farfelu) de ce qui pourrait être fait :

# cd /etc/rc.d/rc3.d

# rm S55sshd

# ln -s /etc/rc.d/init.d/ftpd S40ftpd

Ces actions vont faire en sorte que dans le niveau 3, le serveur ssh ne sera plus exécuté.

En revanche, un serveur ftp sera lancé. Tout cela suppose qu'un script « ftpd » soit présent dans le répertoire « /etc/rc.d/init.d/ », et qu'il fournisse le service attendu (lancer un serveur FTP). Les distributions GNU/Linux incluent ce genre de script lorsqu'un service est installé. L'utilisateur n'a donc ensuite qu'à modifier les liens symboliques.

Le squelette d’un tel script situé dans le répertoire « /etc/rc.d/init.d/ » ressemble souvent à :

# Exemple de squelette de fichier /etc/init.d/xxx sur Debian :

# L'instruction 'set -e' au début du script

# pour qu'il s'interrompe dès qu'une commande

# retourne une valeur de retour non nulle (erreur).

set –e

# On positionne les variables d’environnement en

# fonction du système d’exploitation : PATH=/sbin:/bin:/usr/sbin:/usr/bin

DESC="description_de_ce_que_fait_le_demon"

NAME=nom_du_demon DAEMON=/usr/sbin/$NAME PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME

# Fonction qui démarre le service : d_start() {

start-stop-daemon --start --quiet \

--pidfile $PIDFILE --exec $DAEMON }

# Fonction qui arête le service : d_stop() {

start-stop-daemon --stop --quiet \

--pidfile $PIDFILE --name $NAME }

# Fonction qui force le service à relire sa configuration : d_reload() {

start-stop-daemon --stop --quiet \

--pidfile $PIDFILE --name $NAME --signal 1 }

# Reste à regarder quelle est la chaîne passée en paramètre,

# et à appeler la bonne fonction : case "$1" in

start)

echo -n "Starting $DESC: $NAME"

d_start echo "."

;;

stop)

echo -n "Stopping $DESC: $NAME"

d_stop echo "."

;;

reload)

echo -n "Reloading $DESC configuration..."

d_reload echo "done."

;;

restart|force-reload)

echo -n "Restarting $DESC: $NAME"

d_stop sleep 1 d_start echo "."

;;

*)

echo "Usage: $SCRIPTNAME {start|stop |restart|force-reload|reload}" >&2

exit 1 ;;

esac

exit 0

8.4 L’arborescence des processus

Vous l’aurez compris, le mécanisme de multitâche sous Linux repose sur le dédoublement des processus à l’aide de la fonction fork(), puis le recouvrement du processus fils à l’aide des fonctions de recouvrement execXX(), et enfin, l’utilisation de threads gérés au niveau du noyau.

La commande pstree permet de rendre compte de l’arborescence des processus lancés.

Exemple sur une station Debian :

# pstree -A -c –n init-+-ksoftirqd/0 |-events/0 |-khelper

|-kthread-+-kblockd/0 | |-pdflush | |-pdflush | |-aio/0 | |-kseriod | `-khubd |-xbox_extsmi |-kswapd0 |-kjournald |-portmap

|-apache2-+-apache2 | |-apache2 | |-apache2 | `-apache2 |-named

|-freepopsd |-spamd-+-spamd | `-spamd |-cron

|-klogd |-lpd

|-master-+-qmgr | `-pickup |-nmbd

|-smbd---smbd

|-sshd---sshd---bash---pstree |-syslogd

|-xinetd |-rpc.statd |-ntpd |-rpc.nfsd |-rpc.mountd |-miniserv.pl |-smartd

|-winbindd---winbindd |-getty

|-getty `-dhcpd3

De plus, la commande ps (Cf. man ps) permet d’obtenir un résultat moins visuel mais plus complet sur le chaînage de lancement des processus.