« Busybox init » : différence entre les versions
(→Linux : Suppression de la dépendance inutile "git") |
(→Busybox : Ajout d'un lien vers les sources de Busybox en caches dans nos fichiers) |
||
(Une version intermédiaire par le même utilisateur non affichée) | |||
Ligne 19 : | Ligne 19 : | ||
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.sign -P ~ | wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.sign -P ~ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Note : le code source est également disponible dans [https://{{SERVERNAME}}/fichiers/système/noyaux/linux/linux-6.6.tar.xz nos fichiers]. | |||
Décompression de l'archive des sources | Décompression de l'archive des sources | ||
Ligne 54 : | Ligne 56 : | ||
wget https://www.busybox.net/downloads/busybox-1.36.1.tar.bz2.sha256 | wget https://www.busybox.net/downloads/busybox-1.36.1.tar.bz2.sha256 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Note : le code source est également disponible dans [https://{{SERVERNAME}}/fichiers/système/applications/busybox/busybox-1.36.1.tar.bz2 nos fichiers]. | |||
Vérification d'intégrité | Vérification d'intégrité | ||
Ligne 93 : | Ligne 97 : | ||
Création et formatage de la mémoire racine | Création et formatage de la mémoire racine | ||
dd if=/dev/zero of=~/busybox.dd bs=1M count=1024 | dd if=/dev/zero of=~/busybox.dd bs=1M count=1024 | ||
mkfs.ext4 ~/busybox.dd | mkfs.ext4 ~/busybox.dd | ||
Ligne 172 : | Ligne 175 : | ||
Note : si vous comptez poursuivre les étapes des sections suivantes, pensez à remonter ce système de fichier ou à en copier le contenu dans un autre répertoire de travail afin de ne pas recommencer à zéro. | Note : si vous comptez poursuivre les étapes des sections suivantes, pensez à remonter ce système de fichier ou à en copier le contenu dans un autre répertoire de travail afin de ne pas recommencer à zéro. | ||
Test du système avec ''Qemu'' | Test du système avec ''Qemu'' (<code>apt install --no-install-recommends qemu-system-x86</code>) | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> |
Dernière version du 28 janvier 2024 à 12:16
Busybox intègre init
, un programme pouvant être amorcé directement par un noyau Linux au démarrage d'une machine. Il est ainsi possible de concevoir un système d'exploitation léger composé uniquement d'un noyau et de Busybox. L'adjonction d'outils supplémentaires sur cette base minimaliste pourra engendrer une distribution spécifiquement conçue pour un besoin particulier. Cette association s’avère donc particulièrement intéressante dans des systèmes embarqués tel que les appliances réseau comme OpenWRT ou DD-WRT.
Nous verrons comment construire un tel système en partant des sources de chaque programmes depuis une GNU/Linux Debian 12 Bookworm. Les compilations se feront avec l'ensemble des paramètres par défaut. Je recommande d'utiliser une machine (virtuelle amd64 dans mon cas) spécifiquement installée pour cet usage car un grand nombre de dépendances est nécessaire et il serait dommage de pourrir votre environnement de travail...
L'espace de travail sera le répertoire personnel de l'utilisateur root.
Linux
Installation des dépendances
apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev libelf-dev libssl-dev libncurses-dev dwarves
Téléchargement des sources du dernier noyau stable (01/11/2023)
# Code source
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz -P ~
# Signature GPG
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.sign -P ~
Note : le code source est également disponible dans nos fichiers.
Décompression de l'archive des sources
unxz -k ~/linux-6.6.tar.xz
Vérification de la signature GPG de l'archive
apt install gnupg2 gpg2 --locate-keys torvalds@kernel.org gregkh@kernel.org gpg2 --tofu-policy good 38DBBDC86092693E gpg2 --tofu-policy good 79BE3E4300411886 gpg2 --trust-model tofu --verify ~/linux-6.6.tar.sign
Note : la dernière commande doit vous renvoyer plusieurs lignes de résultat dont gpg: Bonne signature de « Greg Kroah-Hartman <gregkh@kernel.org> » [totale]
.
Désarchivage des sources
tar xvf ~/linux-6.6.tar cd ~/linux-6.6/
Création d'une configuration de confection saine avec les paramètres par défaut et compilation avec 4 cœurs de processeur
make defconfig
make -j4
# Retour dans le répertoire personnel
cd ~
Le noyau compilé pour notre architecture x86 64bits se trouve à l'emplacement suivant : ~/linux-6.6/arch/x86/boot/bzImage
.
Busybox
Téléchargement des sources
wget https://www.busybox.net/downloads/busybox-1.36.1.tar.bz2
wget https://www.busybox.net/downloads/busybox-1.36.1.tar.bz2.sha256
Note : le code source est également disponible dans nos fichiers.
Vérification d'intégrité
sha256sum -c ~/busybox-1.36.1.tar.bz2.sha256
Note : la vérification d'intégrité doit renvoyer Réussi
.
Extraction de l'archive compressée
tar xvf ~/busybox-1.36.1.tar.bz2 cd ~/busybox-1.36.1/
Configuration par défaut et compilation du code avec lien statique afin d'embarquer les dépendances dans le binaire final
make defconfig
make -j4 LDFLAGS="--static"
# Retour dans le répertoire personnel
cd ~
Busybox est désormais disponible ici : ~/busybox-1.36.1/busybox
Média d'amorce
Nous avons dés à présent en notre possession tous les programmes de notre future système d'exploitation. Vous pouvez préparer les vôtres en vue de les intégrer dans les sections qui suivent.
Les méthodes d'amorçages peuvent varier selon les besoins et votre convenance. Je répertorie personnellement 3 cas d'usage :
- mémoire morte avec système de fichier classique type EXT4
- initramfs
- PXE
Toute les démonstrations seront réalisées via Qemu. La mise en œuvre du réseau ne sera pas détaillée car j'utilise des scripts personnalisés avec mon système. La création d'une interface tap et son exploitation via la directive -device virtio-net-pci,netdev=network0,mac=$tap_mac -netdev tap,id=network0,ifname=$int_tap,script=no,downscript=no
permet de lier la machine virtuel au réseau physique via l'adjonction d'un pont réseau.
L'étape 1
fera office de tronc commun aux autres sections afin de ne pas alourdir le document avec une redondance inutile et difficilement maintenable. Seule celle-ci nécessite l'utilisation d'un périphérique de type bloc, les deux autres peuvent êtres réalisées directement dans ~/rootfs
si vous le désirez. La réalisation successive des trois étapes est toutefois possible. Il faudra simplement penser à remonter ~/rootfs
afin de ne pas travailler dans un répertoire vide...
1. Amorçage en mémoire morte
Cette façon de faire permet de modifier simplement le contenu de votre distribution après coup. Il suffit pour se faire de monter le système de fichier en écriture pour y actualiser son contenu à votre guise.
Pour l'exemple, je créerai un fichier simulant un périphérique de type bloc du nom de busybox.dd
au même titre qu'une mémoire morte. En condition réelle, remplacez celui-ci par votre périphérique physique : /dev/sda
; /dev/mmcblk
; /dev/nvme0n1
...
Création et formatage de la mémoire racine
dd if=/dev/zero of=~/busybox.dd bs=1M count=1024 mkfs.ext4 ~/busybox.dd
Création et montage de l'environnement de travail
mkdir -p ~/rootfs mount ~/busybox.dd ~/rootfs cd ~/busybox-1.36.1/
Installation de l'arborescence du système Busybox dans notre système de fichiers avec lien statiques
make install CONFIG_PREFIX=../rootfs LDFLAGS="--static" cd ~
Cette étape a créée les répertoires standards permettant d’accueillir les binaires usuels du système selon la Filesystem Hierarchy Standard (FHS). L'exécutable busybox
précédemment compilé a été copié dans le nouveau /bin
et des liens symboliques ont étés créés pointant vers celui-ci avec le nom de tous les utilitaires qu'il contient.
Création des points montages des pseudos systèmes de fichiers usuels, de la table de montages statiques et du répertoire accueillant notre futur script d'initialisation
mkdir -p ~/rootfs/proc ~/rootfs/sys ~/rootfs/dev mkdir -p ~/rootfs/etc touch ~/rootfs/etc/fstab mkdir -p ~/rootfs/etc/init.d
Script d'initialisation du système
bash -c "cat > ~/rootfs/etc/init.d/rcS" << _EOF_
#!/bin/sh
# Message d'accueil
echo "Busybox ycharbi.fr"
# Pseudos systèmes de fichiers usuels
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
# Configuration réseau
ip addr add 10.0.0.1/24 dev eth0
ip link set dev eth0 up
ip route add default via 10.0.0.254 dev eth0
# Clavier en AZERTY
loadkmap < /etc/fr.map
_EOF_
Attribution du droit d'exécution au script d'initialisation
chmod +x ~/rootfs/etc/init.d/rcS
Configuration des Télétypes (TTY)
bash -c "cat > ~/rootfs/etc/inittab" << _EOF_
::sysinit:/etc/init.d/rcS
ttyS0::respawn:/bin/sh
tty2::askfirst:-/bin/sh
tty3::askfirst:-/bin/sh
tty4::askfirst:-/bin/sh
tty4::respawn:/sbin/getty 38400 tty5
tty5::respawn:/sbin/getty 38400 tty6
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
_EOF_
Ce fichier définit les TTY qui doivent êtres invoqués au lancement de init
. Vous devrez probablement adapter ceci à votre besoin. La documentation de ces lignes ainsi que de la configuration appliquée par défaut en cas d'absence du fichier est disponible dans ~/busybox-1.36.1/examples/inittab
.
Création du binaire de traduction clavier afin d'utiliser l'AZERTY
busybox dumpkmap > ~/rootfs/etc/fr.map
À ce stade, notre mémoire morte est prête.
Pour permettre son amorçage, un éventail de possibilités s'offre à vous : Grub; Systemd-boot; UEFI stub; Ipxe; Syslinux... Pour ma part et comme précisé en introduction, j'utiliserai Qemu afin de simplifier au maximum l'exposé.
Démontage du système de fichier
umount ~/rootfs
Note : si vous comptez poursuivre les étapes des sections suivantes, pensez à remonter ce système de fichier ou à en copier le contenu dans un autre répertoire de travail afin de ne pas recommencer à zéro.
Test du système avec Qemu (apt install --no-install-recommends qemu-system-x86
)
qemu-system-x86_64 \
--enable-kvm \
-m 2048 \
-device virtio-balloon \
-kernel ~/linux-6.6/arch/x86/boot/bzImage \
-append "ro root=/dev/sda console=ttyS0 quiet" \
-cpu host -smp cores=2,threads=1,sockets=1 \
-serial mon:stdio \
-drive id=disk,file="${HOME}"/busybox.dd,format=raw,if=none \
-device ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.0 \
-display none
Pour un affichage sans port console, il faut supprimer le paramètre console=ttyS0
de la directive -append
; supprimer la directive -display none
et remplacer la ligne ttyS0::respawn:/bin/sh
par tty1::respawn:/bin/sh
dans le inittab
.
2. Amorçage en initramfs
L'utilisation d'un système de fichiers initial en mémoire à accès aléatoire apporte encore plus de légèreté à la solution. Un unique fichier compressé vient s'ajouter au noyau en cours d'exécution pour servir la racine construite précédemment. Le système est exécuté intégralement en mémoire vive et peut donc se voir distribué via des protocoles réseaux tel que TFTP ou HTTP.
Construction de l'archive compressée Initramfs
cd ~/rootfs && find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz && cd ~
Test du système avec Qemu
qemu-system-x86_64 \
--enable-kvm \
-m 2048 \
-device virtio-balloon \
-kernel ~/linux-6.6/arch/x86/boot/bzImage \
-append "ro rootfstype=ramfs rdinit=/sbin/init console=ttyS0 quiet" \
-initrd ~/initramfs.cpio.gz \
-cpu host -smp cores=2,threads=1,sockets=1 \
-serial mon:stdio \
-display none
Les différences de lancement sont :
- modification des paramètres noyau (cmdline) de la directive
-append
- ajout de la directive
-initrd
- les directives concernant le disque SATA ont étés supprimées
3. Amorçage initramfs via PXE
Cette méthode d'amorçage ne varie pas beaucoup de la précédente puisque elle réutilise les mêmes éléments à savoir le noyau et l'Initramfs. Le delta sera sur la syntaxe du chargeur d'amorçage réseau utilisé ainsi que quelques paramètres passés au noyau. Voici la section fonctionnelle pour Ipxe :
#!ipxe
set menu-timeout 10000
set submenu-timeout ${menu-timeout}
isset ${menu-defaut} || set menu-defaut Debian_Buster
set serveur_ip 10.0.0.100
menu
item --gap -- -------------DEMARRAGE EN RAM----------------
item busybox Lancer Busybox
choose --timeout ${menu-timeout} --default ${menu-default} target && goto ${target}
:busybox
kernel http://${serveur_ip}/systemes/noyaux/busybox/bzImage ro initrd=initramfs.cpio.gz rootfstype=ramfs rdinit=/sbin/init console=ttyS0
initrd http://${serveur_ip}/systemes/noyaux/busybox/initramfs.cpio.gz
boot
# https://ipxe.org/cmd/kernel