URL: https://linuxfr.org/users/djojo/journaux/de-la-facon-dont-un-probleme-de-boot-est-resolu-sous-freebsd Title: De la façon dont un problème de boot est résolu sous FreeBSD Authors: Joris Dedieu Date: 2012年07月27日T17:44:03+02:00 License: CC By-SA Tags: franglais Score: 42 En ces temps troublés par l'arrivée de ```systemd``` dans ArchLinux et les histoires de SecureBoot et de ```grub2``` je trouve intéressant de faire un petit journal pour raconter un peu ce qui se passe ailleurs. # Lancer init # FreeBSD par défaut utilise son propre boot loader appelé ```boot```. Il se décompose en trois phases boot0, boot1 et boot2. Ces programmes n'ont rien de folichon, sinon qu'ils permettent éventuellement de choisir un disque et un noyau pour booter. Ils finissent normalement par lancer un programme un peut plus évolué (```loader```) qui présente un menu avec différentes options de maintenance (single user ...) et un petit shell avec quelques commandes essentielles : charger décharger un noyau et des modules, lister des fichiers et des périphériques, placer des variables d'environnement. ```loader```, comme son nom l'indique fini par charger un noyau et l’exécuter. Lorsqu'il a terminé de se lancer, ce dernier passe la main à ```init``` qui exécute le script ```/etc/rc```. # /etc/rc # Ce script commence par sourcer quelques fichiers afin d'avoir ses fonctions et sa configuration puis lance ```rcorder``` pour déterminer l'ordre d’exécution des scripts. On peut connaitre cet ordre en utilisant la commande ```bash rcorder /etc/rc.d/* ``` On constate alors plusieurs choses. ## Déterminer si un script doit être exécuté ou pas ## Tous les scripts présent dans ```/etc/rc.d/``` seront exécutés. C'est le script lui même qui détermine s'il doit faire quelque chose. Prenons l'exemple de ssh. Dans ```/etc/default/rc.conf``` on a : ```bash sshd_enable="NO" # Enable sshd sshd_program="/usr/sbin/sshd" # path to sshd, if you want a different one. sshd_flags="" # Additional flags for sshd. ``` Dans ```/etc/rc.conf``` : ```bash sshd_enable="YES" ``` Dans ```/etc/rc.d/sshd``` ```bash ... name="sshd" rcvar="sshd_enable" ... load_rc_config $name run_rc_command "1ドル" ``` ```load_rc_config``` source différents fichiers susceptible de contenir une directive déterminant si sshd doit être lancé ou pas. Ensuite ```run_rc_command``` appelle la fonction ```checkyesno``` qui évalue la valeur de ```rcvar``` ```bash checkyesno() { eval _value=\$${1} debug "checkyesno: 1ドル is set to $_value." case $_value in # "yes", "true", "on", or "1" [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0 ;; # "no", "false", "off", or "0" [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1 ;; *) warn "\$${1} is not set properly - see ${rcvar_manpage}." return 1 ;; esac } ``` Dans notre cas ssh sera lancé mais ce n'est pas le cas dans une installation par défaut. ## Gestion des dépendances ## Il existe quelques pseudo scripts marquant des étapes importantes du démarrage. Dans l'ordre : ```bash ... /etc/rc.d/FILESYSTEMS ... /etc/rc.d/NETWORKING ... /etc/rc.d/SERVERS ... /etc/rc.d/DAEMON ... /etc/rc.d/LOGIN ``` Ceux-ci permettent de déterminer à quel moment du boot nous en sommes et de gérer les dépendances. Si on reprend le cas de ```sshd```. Dans ```/etc/rc.d/sshd``` on a : ```bash # PROVIDE: sshd # REQUIRE: LOGIN cleanvar # KEYWORD: shutdown ``` On sait donc que le script ```sshd``` doit être exécuté après le script ```cleanvar``` et le pseudo script ```LOGIN```. ```bash cat /etc/rc.d/LOGIN #!/bin/sh # # $FreeBSD: src/etc/rc.d/LOGIN,v 1.6.2.1.8.1 2012年03月03日 06:15:13 kensmith Exp $ # # PROVIDE: LOGIN # REQUIRE: DAEMON # This is a dummy dependency to ensure user services such as xdm, # inetd, cron and kerberos are started after everything else, in case # the administrator has increased the system security level and # wants to delay user logins until the system is (almost) fully # operational. ``` On sait aussi que chaque script déclarant ```REQUIRE: sshd``` doit être exécuté après celui-ci. Enfin ```KEYWORD: shutdown``` permet de déterminer qu'il sera nécessaire d’exécuter ce script lors de l’arrêt du système : ```bash /etc/rc.d/sshd stop ``` Voila donc à peu près comment les choses se passent. Après ```/etc/rc.d```, ```rc`` passe à ```/usr/local/etc/rc.d``` puis à ```/etc/rc.local``` et le système a démarré. # L'affreux spanning tree # Spanning tree est un protocole bien sympa mais il pose au moins un problème. Suivant la configuration, le réseau peut être relativement lent à monter. L'interface et up mais le serveur reste inaccessible durant quelques secondes. Cela n'est pas très grave en soit si ce n'est que ```ntpd``` à besoin de pouvoir résoudre le nom des serveurs de temps pour démarrer. Sinon, il ne fait rien, il ne met pas le serveur à l'heure ... Pour résoudre se problème (et d'autres) un petit script de ```rc``` a été introduit : ```bash #!/bin/sh # $FreeBSD: src/etc/rc.d/netwait,v 1.2.2.3.2.1 2012年03月03日 06:15:13 kensmith Exp $ # # PROVIDE: netwait # REQUIRE: NETWORKING # KEYWORD: nojail # # The netwait script is intended to be used by systems which have # statically-configured IP addresses in rc.conf(5). If your system # uses DHCP, you should use synchronous_dhclient="YES" in your # /etc/rc.conf instead of using netwait. . /etc/rc.subr name="netwait" rcvar="netwait_enable" start_cmd="${name}_start" stop_cmd=":" netwait_start() { local ip rc count output link if [ -z "${netwait_ip}" ]; then err 1 "You must define one or more IP addresses in netwait_ip" fi if [ ${netwait_timeout} -lt 1 ]; then err 1 "netwait_timeout must be>= 1" fi # Handle SIGINT (Ctrl-C); force abort of while() loop trap break SIGINT if [ -n "${netwait_if}" ]; then echo -n "Waiting for $netwait_if to have link" count=1 while [ ${count} -le ${netwait_if_timeout} ]; do if output=`/sbin/ifconfig ${netwait_if} 2>/dev/null`; then link=`expr "${output}" : '.*[:blank](http://fr.wikipedia.org/wiki/:blank: "Définition Wikipédia")status: \(no carrier\)'` if [ -z "${link}" ]; then echo '.' break fi else echo '' err 1 "ifconfig ${netwait_if} failed" fi sleep 1 count=$((count+1)) done if [ -n "${link}" ]; then # Restore default SIGINT handler trap - SIGINT echo '' warn "Interface still has no link. Continuing with startup, but" warn "be aware you may not have a fully functional networking" warn "layer at this point." return fi fi # Handle SIGINT (Ctrl-C); force abort of while() loop trap break SIGINT for ip in ${netwait_ip}; do echo -n "Waiting for ${ip} to respond to ICMP" count=1 while [ ${count} -le ${netwait_timeout} ]; do /sbin/ping -t 1 -c 1 -o ${ip}>/dev/null 2>&1 rc=$? if [ $rc -eq 0 ]; then # Restore default SIGINT handler trap - SIGINT echo '.' return fi count=$((count+1)) done echo ': No response from host.' done # Restore default SIGINT handler trap - SIGINT warn "Exhausted IP list. Continuing with startup, but be aware you may" warn "not have a fully functional networking layer at this point." } load_rc_config $name run_rc_command "1ドル" ``` Du coup, si on ne souhaite pas que la machine continue son démarrage avant d'avoir _réellement_ du réseau, il suffit donc de rajouter : ```bash netwait_enable="YES" netwait_ip="XXX.XXX.XXX.XXX" ``` dans ```/etc/rc.conf``` # Conclusion # Aucune. C'était gratuit. Pour peut-être éclairer un peu le débat.