rcNG, l'anti systemd

Magazine
Marque
GNU/Linux Magazine
Numéro
156
|
Mois de parution
janvier 2013
|
Domaines


Résumé
À l'heure ou plusieurs distributions GNU/Linux sont sur le point de complexifier de façon irrémédiable (d'aucuns diront aberrante) leur processus d'amorce, les systèmes dérivés de BSD UNIX articulent leur mécanisme d'initialisation autour d'une cascade de scripts logiques, lisibles et contrôlables à souhait. Bien loin des usines à gaz que l'on voit germer de-ci [1] et de-là [2], rc(8) tel que nous le connaissons prend ses racines dans 4.0BSD (1980), et est devenu à travers les âges une machinerie bien huilée, devenu « rcNG » sous l'impulsion du Projet NetBSD.

Body

init-rc

/etc/rc en action. Pfff, c'est pourri ton truc, y'a même pas des [OK] verts fluo :(

1. Un peu d'histoire

Branchons la DeLorean sur 1980 et voyons à quoi ressemblait un /etc/rc dans 3BSD :

echo '' >/dev/console

date >/dev/console

echo entering rc >/dev/console

HOME=/

export HOME

echo clearing mtab >/dev/console

cp /dev/null /etc/mtab

echo mounting /usr on /dev/rp0g >/dev/console

/etc/mount /dev/rp0g /usr

echo preserving Ex temps and clearing /tmp >/dev/console

cd /tmp

(/usr/lib/ex3.2preserve -a; rm -f *)

cd /

echo starting update >/dev/console

/etc/update&

: echo clearing lock and starting printer >/dev/console

: rm -f /usr/lpd/lock

echo starting cron >/dev/console

/etc/cron&

: echo starting accounting >/dev/console

: /etc/accton /usr/adm/acct

: echo starting net daemon >/dev/console

: sh /usr/net/bin/start &

chmod 666 /etc/motd

echo leaving rc >/dev/console

*tousse* *tousse* ah ça oui, ça sent un peu le renfermé et on distingue mal les caractères à travers toutes ces toiles d'araignées. Mais tout de même, depuis ce script, 33 ans nous observent ! Et de confirmer que la voie était toute tracée en lisant le code source de init(8) d'alors, appelé init.vm et situé dans /etc :

[...]

char    shell[] = "/bin/sh";

char    getty[] = "/etc/getty.vm";

char    minus[] = "-";

char    runc[] = "/etc/rc";

[...]

runcom()

{

        register pid, f;

        pid = fork();

        if(pid == 0) {

                open("/", 0);

                dup(0);

                dup(0);

                execl(shell, shell, runc, (char *)0);

                exit(0);

        }

        while(wait((int *)0) != pid)

[...]

Nous y sommes, les prémices de rcNG.

En 1998, NetBSD apporte sa première pierre dans la rénovation des scripts de démarrage en introduisant le fichier /etc/rc.conf dans la version 1.3 de l'OS. Ce fichier ouvrait la voie à une plus fine configuration des services à démarrer, les conditions étant malgré tout réalisées dans /etc/rc, /etc/netstart et /etc/rc.lkm.

C'est en décembre 2000, 20 ans plus tard tout de même, que Luke Mewburn (oui, celui-là même à qui nous « devons » le drapeau orange...) révolutionne le design historiquement monolithique de rc hérité de 4.4BSD pour intégrer une petite révolution dans NetBSD 1.5 : rc.d(8)[3]. Cette nouvelle implémentation propose :

- Une mécanique d'ordre de démarrage des scripts indépendante des noms de fichiers (au contraire des SXXservice de l'init des UNIX System V).

- La possibilité d'intégrer des scripts tiers, issus par exemple de paquets.

- La manipulation de scripts autonomes pour gérer les services indépendamment.

- L'utilisation intensive du fichier /etc/rc.conf pour contrôler le comportement des services démarrés.

- Promouvoir la portabilité et la réutilisation du code (une vieille habitude chez NetBSD).

- Éviter les inutiles runlevels .

La nouvelle infrastructure est un véritable succès, simple mais souple, comme à son habitude, le Projet réalise une évolution dans la continuité et la philosophie propre aux UNIces BSD. Peu après cette release, ce sera au tour de FreeBSD d'intégrer ce nouveau dispositif à partir de sa version 5.0 en janvier 2003, sous le nom de rcNG[4].

2. Oil of Codaz

Les concepts et origines étant maintenant acquis, rentrons un peu plus dans le détail. Notre noyau s'en est remis à init(8) après avoir mis en place les briques essentielles au bon fonctionnement d'un système BSD UNIX multitâches. Nous articulerons notre explication sur des morceaux de code issus de NetBSD 6.0 :

Issu de sys/kern/init_main.c :

        /*

         * Create process 1 (init(8)). We do this now, as Unix has

         * historically had init be process 1, and changing this would

         * probably upset a lot of people.

         *

         * Note that process 1 won't immediately exec init(8), but will

         * wait for us to inform it that the root file system has been

         * mounted.

         */

        if (fork1(l, 0, SIGCHLD, NULL, 0, start_init, NULL, NULL, &initproc))

                panic("fork init");

init(8), dans le cas d'un démarrage en mode multi-utilisateurs, va invoquer notre fameux /etc/rc en argument de sh :

Issu de src/sbin/init/pathnames.h :

#define _PATH_RUNCOM    "/etc/rc"

Issu de src/sbin/init/init.c :

        switch ((pid = fork())) {

        case 0:

                (void)sigemptyset(&sa.sa_mask);

                sa.sa_flags = 0;

                sa.sa_handler = SIG_IGN;

                (void)sigaction(SIGTSTP, &sa, NULL);

                (void)sigaction(SIGHUP, &sa, NULL);

                setctty(_PATH_CONSOLE);

                argv[0] = "sh";

                argv[1] = _PATH_RUNCOM;

                argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0);

                argv[3] = 0;

La séquence d'initialisation va maintenant prendre la main ; en premier lieu, rc va interpréter le fichier /etc/rc.subr, qui regroupe les fonctions communes à la manipulation de scripts de démarrage. Comme exposé par Luke, la nouvelle infrastructure rc.d se doit d'être portable et de partager tout le code qui peut l'être, ainsi, tout script de contrôle de service doit s'assurer que rc.subr est bien chargé afin de ne pas réecrire inutilement du code factorisé et utilisé par l'ensemble de la chaîne.

Une fois les fonctions chargées, rc interprétera le fichier /etc/rc.conf qui indiquera la liste des services à démarrer ainsi que leurs éventuels paramètres. Cette vérification est réalisée par la fonction checkyesno, par exemple :

if ! checkyesno rc_configured; then

        echo "/etc/rc.conf is not configured. Multiuser boot aborted."

        exit 1

fi

Simple, efficace, élégant. Notez que toutes les opérations, succès comme échecs, sont enregistrées dans le fichier de log /var/run/rc.log, ce qui peut s'avérer fort pratique si vous avez activé la variable rc_silent apparue avec NetBSD 6.0 qui ordonne à rc de ne pas afficher de statut sur la sortie standard.

Les services de base bénéficient tous d'une configuration par défaut située dans /etc/defaults/rc.conf, ces variables sont bien entendu écrasées par les valeurs placées dans le fichier /etc/rc.conf, il est défendu de modifier des variables directement dans le fichier /etc/defaults/rc.conf !

Voici un exemple de rc.conf sur une machine de bureau, également utilisée pour mener quelques tests :

# $NetBSD: rc.conf,v 1.96 2000/10/14 17:01:29 wiz Exp $

#

# see rc.conf(5) for more information.

#

# Use program=YES to enable program, NO to disable it. program_flags are

# passed to the program on the command line.

#

# Load the defaults in from /etc/defaults/rc.conf (if it's readable).

# These can be overridden below.

#

if [ -r /etc/defaults/rc.conf ]; then

. /etc/defaults/rc.conf

fi

# If this is not set to YES, the system will drop into single-user mode.

#

rc_configured=YES

# Add local overrides below

#

wscons=YES

sshd=YES

pf=YES

powerd=YES

postfix=YES

dovecot=YES

dbus=YES

hal=YES

rpcbind=YES

famd=YES

avahidaemon=YES

xdm=YES

cupsd=YES

rpcbind=yes

nfs_client=yes

lockd=yes

statd=yes

nginx=YES

php_fpm=YES

mysqld=YES

estd=YES

estd_flags="-a -P -m 1500"

ntpdate=YES

ntpd=YES

smbd=YES

nmbd=YES

Bien évidemment, l'ordre des services dans cette configuration n'a aucune importance, car c'est l'exécutable rcorder(8) qui va avoir la charge d'ordonner le démarrage des services en analysant leurs interdépendances ; rcorder réalise cette tâche en se basant sur des mots-clés que nous trouvons dans les scripts de démarrage. Par exemple :

# PROVIDE: ppp

# REQUIRE: mountcritremote syslogd

# BEFORE: SERVERS

Dans ce cas, le rc-script fournit ppp et nécessite mountcritremote (montage des systèmes de fichiers possiblement distants) et syslog (démon syslogd lancé).

3. Anatomie d'un rc-script

À quel point l'infrastructure rcNG est-elle puissante, factorisée et facile à mettre en œuvre ? Jugez plutôt :

$ cat /etc/rc.d/apmd # apmd est un démon de monitoring de la gestion de l'énergie

#!/bin/sh

#

# $NetBSD: apmd,v 1.6 2004/08/13 18:08:03 mycroft Exp $

#

# PROVIDE: apmd

# REQUIRE: DAEMON

# BEFORE: LOGIN

$_rc_subr_loaded . /etc/rc.subr

name="apmd"

rcvar=$name

command="/usr/sbin/${name}"

load_rc_config $name

run_rc_command "$1"

Shocking, isn't it? Avec ces seules six lignes de shell, rc.d est capable des actions suivantes :

Usage: /etc/rc.d/apmd [fast|force|one](start stop restart rcvar status poll)

Mais quelle est cette sorcellerie ! Revoyons la scène au ralenti :

$_rc_subr_loaded . /etc/rc.subr

- On s'assure que les fonctions issues de rc.subr sont bien chargées, $_rc_subr_loaded vaut : lorsque c'est le cas, inhibant ainsi l'interprétation à suivre.

name="apmd"

- $name est la variable principale dans la mécanique rcNG, il s'agit du nom du script/service.

rcvar=$name

- La variable utilisée pour contrôler le script, elle peut avoir un nom différent de $name, mais c'est évidemment peu souhaitable pour des raisons de clarté

command="/usr/sbin/${name}"

- La commande effective, celle qui sera exécutée par le script

load_rc_config $name

- Chargement de la configuration liée au service dans /etc/rc.conf ou /etc/rc.conf.d/$name. Précisons que ces fichiers de configuration sont sourcés, il peut donc s'avérer pratique dans certains cas d'ajouter des commandes spécifiques à un service dans /etc/rc.conf.d/$name, comme une redéfinition de ulimit pour un service très gourmand en file descriptors

run_rc_command "$1"

- Exécution de la commande rc.d souhaitée.

Arrêtons-nous un instant sur cette dernière fonction, véritable centre de contrôle du service. La fonction run_rc_command comprend les actions standards start, stop, reload, restart, status, poll et rcvar par défaut, chacune de ces actions pouvant être surchargée d'un préfixe fast, force et one. Par exemple :

# /etc/rc.d/apmd onestart

aura pour effet de démarrer une fois le service même si ce dernier n'est pas explicitement activé dans le fichier /etc/rc.conf. Mais notre fonction est capable de gérer bien plus de situations, en effet, sans plus de programmation, run_rc_command sait tirer profit des variables suivantes :

- command_args, arguments optionnels à passer à la commande à exécuter ;

- command_interpreter, un nom d'interpréteur, typiquement lorsque le service est en réalité un script et que le PID à considérer est celui de l'interpréteur (python, perl , php...) ;

- extra_commands, la liste des commandes supplémentaires acceptées par le rc-script ;

- pidfile, rc.subr utilisera un fichier de PID pour vérifier l'existence du processus ;

- procname, si on souhaite donner un nom de processus à vérifier différent de $command ;

- ${name}_chroot, répertoire dans lequel on souhaite chroot'er le service ;

- ${name}_chdir, répertoire dans lequel on souhaite se déplacer avant d'exécuter $command ;

- ${name}_flags, des arguments supplémentaires à passer $command ;

- ${name}_env, variables d'environnement supplémentaires nécessaires à l'exécution de $command ;

- ${name}_nice, niveau de priorité (nice level) avec lequel démarrer $command ;

- ${name}_user, utilisateur avec lequel démarrer $command ;

- ${name}_group, groupe avec lequel démarrer $command ;

- ${name}_groups, groupes supplémentaires ;

- ${rc_arg}_cmd, surcharge le comportement par défaut pour la commande passée en argument au script, par exemple start_cmd=“start_service” appellera la fonction (à définir) start_service au lieu de simplement invoquer $commmand ;

- ${rc_arg}_precmd, commande à invoquer avant l'action passée en argument au script ;

- ${rc_arg}_postcmd, commande à invoquer après l'action passée en argument au script ;

- required_dirs, répertoires dont il faudra vérifier l'existence avant de démarrer le service ;

- required_files, fichiers dont il faudra vérifier l'existence avant de démarrer le service ;

- required_vars, variables dont il faudra vérifier l'existence avant de démarrer le service.

Ces variables sont toutes utilisables dans le rc-script et les variables ${name}_* sont en général définies dans /etc/rc.conf ; par exemple, pour signifier au démon named de chrooter dans /var/chroot/named avant de démarrer :

$ grep ^named /etc/rc.conf

named=YES

named_chrootdir="/var/chroot/named"

Autre exemple plus complet, l'initialisation de variables particulières dans le script de démarrage du démon mysqld :

# [...]

name="mysqld"

rcvar=${name}

command="/usr/pkg/bin/mysqld_safe"

procname="/usr/pkg/sbin/${name}"

: ${mysqld_user:=mysql}

: ${mysqld_group:=mysql}

: ${mysqld_datadir:=/var/mysql}

extra_commands="initdb"

initdb_cmd="mysqld_initdb"

start_precmd="mysqld_precmd"

start_cmd="mysqld_start"

# [...]

Ici, si on n'a pas spécifié d'utilisateur, groupe et répertoire de travail dans le fichier /etc/rc.conf, alors on renseigne mysqld_user, mysqld_group et mysqd_datadir par des valeurs par défaut.

On ajoute au script une fonction supplémentaire, initdb, réalisée par la fonction mysqld_initdb, on demande explicitement d'exécuter la fonction mysqld_precmd avant le démarrage du service et on écrase la fonction de démarrage avec la fonction mysqld_start.

À l'issue de ce chapitre, et munis de ces seuls exemples, vous disposez de toutes les connaissances nécessaires et suffisantes à créer à peu près n'importe quel type de script rcNG.

4. Portabiliquoi ?

Au contraire des bloatware [1] dont je vous entretenais au début de cet article, nous avons pu constater que l'infrastructure rc.d se veut hautement portable ; n'utilisant aucune spécificité de son système d'exploitation d'origine, ce mécanisme de démarrage peut s'intégrer dans n'importe quel OS disposant d'un shell « standard » [5]. L'unification de ce dispositif de démarrage nous assure que les services de base comme les logiciels tierce partie bénéficient du même séquencement et permet en outre de s'appuyer sur les très nombreux exemples disponibles dans le système initial.

L'argumentaire en vogue prétend que faire dépendre le démarrage de son système d'exploitation d'une cascade de scripts shell induit un temps de démarrage abominablement long ; mon poste de travail sous NetBSD 6.0[6] démarre en approximativement 30 secondes, depuis le bootloader jusqu'à xdm, je ne suis pas exactement friand des concours de ce type, mais le ratio flexibilité/temps d’exécution me semble parfaitement honorable.

Liens

[1] http://www.freedesktop.org/wiki/Software/systemd

[2] http://upstart.ubuntu.com/

[3] http://static.usenix.org/event/usenix01/freenix01/full_papers/mewburn/mewburn_html/

[4] http://www.freebsd.org/releases/5.0R/relnotes.html

[5] http://pubs.opengroup.org/onlinepubs/009695399/utilities/sh.html

[6] http://imil.net/wp/2012/08/22/6-month-later/


Sur le même sujet

Du Sysadmin au Dev : Git, le gestionnaire de versions pour tous les développeurs

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
105
|
Mois de parution
novembre 2019
|
Domaines
Résumé

Git est un gestionnaire de versions (distribué) très sophistiqué et souple. Il est souvent vu comme un outil pour développeur expérimenté et même s’il a été largement adopté depuis l’apparition de GitHub, tous les développeurs ne l’utilisent pas encore. Cet article propose de faire le tour de différents profils de développeurs, du plus amateur au plus professionnel et d’illustrer que, pour chacun, Git peut se révéler un outil précieux. Démonstration.

Un poste de travail sous OpenBSD : installation et configuration

Magazine
Marque
Linux Pratique
Numéro
116
|
Mois de parution
novembre 2019
|
Domaines
Résumé

Dans le monde des systèmes d’exploitation libres, le projet OpenBSD a toujours été reconnu comme étant le plus sécurisé. Outre ce point important, ce système d’exploitation est un logiciel dont il faut relever l’exemplarité du développement notamment concernant la qualité du code, élaboré par une communauté de développeurs.

Découvrir SQL avec SQLite

Magazine
Marque
Linux Pratique
Numéro
116
|
Mois de parution
novembre 2019
|
Domaines
Résumé

Grâce au langage SQL (Structured Query Language), il est aisé de rédiger des requêtes pour définir la structure d’une base de données et manipuler son contenu. Partons à la découverte de ces sujets à l’aide de SQLite, un moteur de base de données au nom trompeur, car s’il fait preuve de modestie, il constitue un produit performant et polyvalent.

Élévation de privilèges sur macOS avec CVE-2018-4193

Magazine
Marque
MISC
Numéro
106
|
Mois de parution
novembre 2019
|
Domaines
Résumé

Cet article explique comment exploiter la CVE-2018-4193, une élévation de privilèges affectant les versions de macOS inférieures à 10.13.5, en moins de 10 secondes. Les différents prérequis nécessaires à la compréhension de l’exploit seront détaillés de sorte qu’aucune connaissance préalable de macOS ne soit nécessaire, ce qui permet d’aborder l’exploitation de vulnérabilités dans les démons macOS en général.

Par le même auteur

Amazon <3 Linux

Magazine
Marque
GNU/Linux Magazine
Numéro
207
|
Mois de parution
septembre 2017
|
Domaines
Résumé
Qui d'entre vous n'a jamais entendu parler de AWS (Amazon Web Services), LE cloud public qui domine le marché, la panacée du DevOps, le destructeur de toute une industrie, l'hébergeur qui soutient désormais un bon 40% du Web mondial ? Si tu réponds « moi » à cette question, tu devrais visiter autre chose que des sites en HTML v2 et cesser d’éditer tes fichiers de conf à la main.La triple pique d'entrée de jeu c'est gratos, ça me fait plaisir. AWS, c'est le rouleau compresseur, et cette position de leader n'est pas liée à la chance, puisque comme nombre de solutions disruptives, les analystes les plus pointus proféraient à son lancement que « ça marchera jamais » ©®™ ; non, le succès de ce cloud réside en grande partie dans son API, ses outils, le plus souvent libres, et la puissante communauté qui s'est construite autour. Ce que je vous propose dans cet article, c'est de faire connaissance avec ces outils, et en particulier l'AWS cli [1] basée sur boto3[2], tous les deux sous licence Apache 2[3].

Des bits comme s'il en pleuvait : une appliance SAN/NAS sous NetBSD

Magazine
Marque
GNU/Linux Magazine
Numéro
181
|
Mois de parution
avril 2015
|
Domaines
Résumé
À Noël, je suis le désespoir de ma famille. En effet, là où d'autres demandent des Blu-ray, de quoi s'habiller en hiver ou encore une nouvelle poêle à frire, moi je demande des composants. Des disques, des cartes, des trucs super pas excitants pour les personnes qui vous les offrent. Cette année, je voulais plus de place sur mon NAS [1], plein de bits pour y coller des documents à haute teneur multimédia.

Les différents BSD

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
74
|
Mois de parution
septembre 2014
|
Domaines
Résumé

« Salut, je voudrais installer *BSD, vous me conseillez quoi ? »Cette phrase, lue et relue des centaines, des milliers de fois, est fondamentalement incorrecte. *BSD n'existe pas. Plus important, lorsque l'on souhaite mettre le pied à l'étrier d'un système BSD, un minimum de contexte est nécessaire, car chacun des héritiers de BSD UNIX suit une philosophie bien définie, et si chacun d'entre eux s'avère éminemment versatile, certains seront plus adaptés et faciles d'accès fonction de l'utilisation souhaitée. Nous allons ici faire connaissance avec les trois systèmes BSD les plus connus, NetBSD, FreeBSD et OpenBSD et évoquer leurs forces et faiblesses afin de guider votre choix de façon la plus objective possible.

NetBSD, le système du futur du subjonctif

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
74
|
Mois de parution
septembre 2014
|
Domaines
Résumé
« The Original UNIX », c'est pour cette punchline que j'avais voté lorsque le groupe chargé du marketing chez NetBSD cherchait une approche différente du classique « of course it runs NetBSD » ; néanmoins, s'il est l'héritier le plus direct des travaux du CSRG [1] et l'un des plus grands défenseurs de la portabilité du code, le projet NetBSD n'est certainement pas un système d'exploitation du passé, loin s'en faut. Bénéficiant des avancées standards d'autres OS, NetBSD dispose en outre d'avantages uniques dont l'administrateur système aguerri saura faire usage. Dans cet article, nous allons monter un serveur web articulé autour de briques modernes, et allons dans notre périple découvrir l'ensemble des éléments nécessaires au déploiement d'un système aussi réactif que respectueux des standards.

Préface

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
74
|
Mois de parution
septembre 2014
|
Résumé

Huit ans. Huit ans se sont écoulés depuis les deux derniers numéros hors-séries BSD et le mook que vous tenez entre les mains. Il y a huit ans, il est probable qu'une bonne partie d'entre vous n'avait même jamais touché un système UNIX/Linux, et réalisait plutôt son grand œuvre Lego(c)(tm).

Pendant ces huit années, le monde du Libre a proprement explosé, il est partout, omniprésent sur vos mobiles, vos tablettes, votre télé ou votre point d'accès Wi-Fi ; et si des sociétés telles que Google ne se cachent pas d'utiliser le système GNU/Linux comme socle entre l'espace utilisateur et le matériel, d'autres, sans totalement le masquer, ne font pas étalage des technologies libres constituant la pierre angulaire de leurs systèmes. En tête de liste notons particulièrement la société Apple, dont l'espace utilisateur du système d'exploitation Mac OS X est directement issu de FreeBSD.

Demandez la Lune à nginx !

Magazine
Marque
GNU/Linux Magazine
Numéro
172
|
Mois de parution
juin 2014
|
Domaines
Résumé
Nginx n'est plus un logiciel à la marge, avec près de 20% de parts de marché du top un million des sites les plus fréquentés au monde, il représente même un acteur sur lequel on peut (et doit !) compter.