URL: https://linuxfr.org/users/giga/journaux/aujourd-hui-c-est-deja-demain-systemd-dans-l-initrd-sous-arch-linux Title: Aujourd'hui c'est déjà demain : systemd dans l'initrd sous Arch Linux Authors: Jean-Philippe Garcia Ballester Date: 2014年10月16日T10:25:51+02:00 License: CC By-SA Tags: systemd et initrd Score: 33 Introduction ============ Nous allons voir dans ce petit article comment utiliser systemd dans l'initrd. La construction d'un initrd étant spécifique à la distribution, nous verrons comment l'utiliser avec Arch Linux mais avec un peu de travail cela devrait pouvoir donner le principe général de fonctionnement et être adaptable sur d'autres distributions. **ATTENTION** : nous allons modifier une partie très importante du démarrage de la machine, et il est probable que la machine ne démarre plus. Prévoyez donc un live-cd quelconque pour pouvoir réparer en cas de soucis ! Quelques généralités sur l'initrd ================================= L'initrd, c'est une archive cpio qui est chargée en RAM par le noyau juste après son lancement. Elle est montée sur `/`, et le fichier `/init` est lancé. Ce fichier est censé s'occuper de lancer tout ce qui est nécessaire au montage du vrai `/` et qui n'est pas en dur dans le noyau, comme le chargement de modules noyau, lvm, le déchiffrement, montage de `/usr` s'il est sur une partition séparée... Traditionnellement, ce fichier init est un script shell construit par des outils spécifiques à la distribution. La construction classique de l'initrd sous Arch Linux ----------------------------------------------------- Sous Arch Linux, la construction d'un initrd se fait à l'aide du logiciel mkinitcpio. Il se configure en utilisant le fichier `/etc/mkinitcpio.conf`. La variable `HOOKS` est celle qui nous intéresse présentement. Pour chaque hook présent dans cette variable, deux fichiers seront utilisés, un script `install` qui sera chargé d'ajouter les fichiers nécessaire à l'initrd lors de la construction, et un script `hook` qui sera lancé par le script shell `init` lors du boot. L'ordre d'apparition des hooks dans la variable `HOOKS` est important car c'est l'ordre utilisé pour lancer les scripts lors du boot. L'utilisation de systemd dans l'initrd -------------------------------------- Lorsqu'on utilise systemd dans l'initrd, le fichier `/init` de l'initrd n'est plus un script shell, mais directement systemd. Ainsi, lors de la construction de l'initrd avec mkinitcpio, le script `hook` n'a plus aucun effet, et le script `install` est chargé, outre les fichiers nécessaires tels les démons et modules noyaux, d'installer les unités systemd nécessaire à monter la vraie racine. L'ordre d'aparition des hooks dans la variable `HOOKS` n'a plus d'importance (a une exception près que nous verrons plus bas), car ce sont les unités systemd qui détermineront l'ordre de lancement des différentes unités (et donc de tous les binaires lancés, car tout est lancé via systemd). systemd dans l'initrd, ça sert à quoi ? ---------------- Il y a sûrement des avantages secondaires, comme la parallèlisation, une configuration de démarrage unique et centralisée, et peut-être d'autres, mais l'avantage principal est quand même de faire rager les anti-systemd en le mettant partout et à toutes les sauces. Configuration du système pour utiliser systemd ============================================== Le problème principal est que le support d'Arch Linux pour systemd dans l'initrd est un peu balbutiant, et il faut donc mettre un peu les mains dans le cambouis pour que tout fonctionne. Nous verrons ici comment configurer un système utilisant une partition chiffrée contenant du lvm et plymouth, puisque c'est ma configuration. L'ajout du raid ne doit pas être très compliqué. La base ======= Les hooks `base`, `usr`, `udev` et `timestamp` ne sont plus nécessaires et sont remplacés par le hook `systemd`. Les hooks `autodetect`, `block`, `filesystems`, `btrfs` et `keyboard` sont toujours nécessaires (au moins sur ma machine). Les autres hooks (`lvm`, `encrypt`, `plymouth`, etc) seront par la suite remplacés par des équivalents `sd-machin`. Les hooks `sd-machin` doivent toujours être après le hook `systemd`. En effet, ce hook ajoute une fonction utilisable dans les autres hooks, `add_systemd_unit`. Cette fonction ajoute dans l'initrd l'unité passée en paramètre, ainsi que toutes ces dépendances. Patch 1 : unités dans `/etc` ---------------------------- Cette fonction a un problème : elle n'utilise que le dossier `/usr/lib/systemd/system`, et ignore donc totalement les unités crées par l'utilisateurs situées dans le dossier `/etc/systemd/system` (voir le [bug report](https://bugs.archlinux.org/task/42396)). Nous allons donc modifier le hook, en copiant `/usr/lib/initcpio/install/systemd` vers `/etc/initcpio/install/systemd`. Nous allons donc pouvoir le modifier sans risquer de voir nos modifications écrasées par une mise-à-jour. Le patch est le suivant ```diff --- /usr/lib/initcpio/install/systemd 2014年09月02日 00:11:28.000000000 +0630 +++ /etc/initcpio/install/systemd 2014年10月16日 13:39:11.291460470 +0630 @@ -51,7 +51,7 @@ local unit= rule= entry= key= value= binary= dep= - unit=$(PATH=/usr/lib/systemd/system:/lib/systemd/system type -P "1ドル") + unit=$(PATH=/etc/systemd/system:/usr/lib/systemd/system:/lib/systemd/system type -P "1ドル") if [[ -z $unit ]]; then # complain about not found unit file return 1 @@ -78,18 +78,23 @@ done <"$unit" # preserve reverse soft dependency - for dep in {/usr,}/lib/systemd/system/*.wants/${unit##*/}; do + for dep in {{/usr,}/lib,/etc}/systemd/system/*.wants/${unit##*/}; do if [[ -L $dep ]]; then add_symlink "$dep" fi done # add hard dependencies - if [[ -d $unit.requires ]]; then - for dep in "$unit".requires/*; do - add_systemd_unit ${dep##*/} - done - fi + for dir in {{/usr,}/lib,/etc}/systemd/system/${unit##*/}.requires; do + if [[ -d "$dir" ]]; then + for dep in "$dir"/*; do + if [[ -L $dep ]]; then + add_symlink "$dep" + fi + add_systemd_unit ${dep##*/} + done + fi + done } build() { ``` Patch 2 : `emergency.target` ---------------------------- Second problème de ce hook, il n'ajoute pas les utilitaires nécessaire au fonctionnement de `emergency.target`, une unité spéciale qui est lancée lorsque le boot plante et donne un shell à l'utilisateur pour essayer de sauver les meubles (voir un [bug report](https://bugs.archlinux.org/task/42399) et [un autre](https://bugs.archlinux.org/task/36265)). On va donc le modifier pour rajouter `sulogin` ainsi que les utilitaires de `busybox`. ```diff --- /etc/initcpio/install/systemd.old 2014-10-16 13:44:23.135993657 +0630 +++ /etc/initcpio/install/systemd 2014-10-16 13:43:23.657715653 +0630 @@ -98,12 +98,22 @@ } build() { - local rules unit + local rules unit applet # from base add_binary /bin/mount add_binary /usr/bin/kmod /usr/bin/modprobe + add_binary /usr/lib/initcpio/busybox /bin/busybox + for applet in $(/usr/lib/initcpio/busybox --list); do + add_symlink "/usr/bin/$applet" busybox + done + + # sulogin is needed for emergency target + add_binary /sbin/sulogin + add_file /etc/shadow + add_file /etc/gshadow + # systemd add_binary /usr/lib/systemd/systemd /init add_binary /usr/bin/systemd-tmpfiles ``` À ce stade, si l'on a une partition racine simple, on a terminé. Partition chiffrée ================== S'il y a une partition chiffrée nécessaire au démarrage, il faut ajouter le hook `sd-encrypt`. Attention, les paramètres de ligne de commande du noyau (probablement configurés dans `/etc/default/grub`) pour indiquer les partitions et leurs options ont changé. Le paramètre `cryptdevice` est remplacé par `luks.machin` (`man systemd-cryptsetup-generator` pour plus d'infos). Cependant, plutôt que ces paramètres, il est plus utile d'utiliser le fichier `/etc/crypttab.initramfs`, qui suit la syntaxe de `/etc/crypttab`. LVM === Il suffit d'ajouter le fichier `sd-lvm`. Aucune configuration particulière, car un scan est lancé dès l'apparition d'un nouveau block device, et activé si celui est un lvm (donc on peut avoir une partition chiffrée dans un lvm et un lvm dans une partition chiffrée sans avoir à préciser d'ordre particulier, et même avoir une partition chiffrée dans un lvm dans une partition chiffrée). Resume ====== Il n'y a rien dans la version stable de systemd pour s'occuper de sortir le système de l'hibernation. C'est prévu pour la prochaine version, mais en attendant, il va falloir faire les choses à la main. On créé donc une unité `/etc/systemd/system/resume.target` ``` [Unit] Description=Resume from disk Before=initrd-root-fs.target sysroot.mount [Install] WantedBy=initrd.target ``` Et on l'active avec `systemctl enable resume.target`. Puis une unité générique `/etc/systemd/system/resume@.service` ``` [Unit] Description=Resume from disk using %I Before=resume.target DefaultDependencies=no BindsTo=%i.device After=%i.device [Service] Type=oneshot ExecStart=/bin/sh -c "echo $(mountpoint -x %I)> /sys/power/resume" [Install] RequiredBy=resume.target ``` On l'active en utilisant le chemin de sa partition de swap, dans mon cas `systemctl enable resume@dev-main-swap.service`. On créé enfin le hook mkinitcpio `/etc/initcpio/install/sd-resume` ``` #!/bin/bash build() { add_systemd_unit resume.target } help() { cat <

AltStyle によって変換されたページ (->オリジナル) /