Combien de fois vous êtes-vous retrouvé chez tonton Louis ou beau-père Michel, fiers de leur nouvelle bête de course équipée d'un accès DSL, tétanisé devant un écran bleu pastel arborant en guise de login un jeune en skateboard ou une pièce d'échiquier ? Ne vous êtes-vous pas maudit à ce moment, alors que vous alliez passer le week-end entier à cet endroit, de ne pas avoir pris dans vos bagages un live CD quelconque, un OS muni d'un shell digne de ce nom, ainsi que de tous les outils indispensables à un week-end de repos ? Et vous avez, dans votre poche, cette clé USB, pleine à craquer de mp3 – libres évidemment –, de photos de vacances et autres captures vidéo de la dernière Solutions Linux. Il restait pourtant dans cette clé 64 mégas octets inutilisés, 64 mégas dans lesquels vous auriez pu caser un UNIX minimal, un diamant qui serait muni d'un OpenSSH, d'un Irssi et d'un Links, que vous aurait présenté un Ion 3 à peine configuré.
Voici ce que cet article vous propose : disposer à tout instant du couteau suisse de l'administrateur système UNIX, un NetBSD minimal, mais fonctionnel, qui se logera dans un coin de votre clé USB, sans pour autant la rendre inexploitable par d'autres systèmes. Le but de l'opération sera d'obtenir une clé amorçable, qui n'utilisera pas le système de fichiers de la clé, mais une image brute, générée à l'aide de l'outil dd(1), qu'un noyau affublé d'un RAMDISK ira mounter comme root filesystem.
Pour construire notre OS minimal, nous utiliserons, sur une machine NetBSD 3.1, des outils présents dans le basesystem, mais également Grub, disponible dans pkgsrc (pkgsrc/sysutils/grub). Enfin, Qemu, installable depuis pkgsrc/emulators/qemu, nous servira à tester nos travaux. Cet article s'appuie sur un projet sur lequel j'ai travaillé en 2006 : the NetBSD LiveKey (http://imil.net/nlk/). J'utiliserai donc tout naturellement quelques scripts écrits pour l'occasion qui nous simplifieront grandement la tâche.
NOTE
Quelques notions des systèmes BSD, et particulièrement NetBSD, sont nécessaires pour la bonne compréhension de cet article. Si toutefois ces notions vous faisaient défaut, vous trouverez probablement de l'aide dans le fabuleux NetBSD Guide à cette adresse http:www.netbsd.org/guide/en/ ou en version française (mais un peu dépassée) à cette adresse : http:www.mclink.it/personal/MG2508/nbsdfra/netbsd.html.
1. Création du noyau
La première étape de notre périple va consister à créer un noyau muni d'un RAMDISK. Pour cela, nous allons compiler un noyau NetBSD de manière habituelle (voir http://netbsd.org/Documentation/kernel/#how_to_build_a_kernel), en nous assurant que les options suivantes sont bien activées/renseignées :
# Nous allons utiliser UNION filesystem pour mounter # les partitions "réelles" sur le ramdisk file-system UNION # vnd est le device permettant de mounter des images, # notre root filesystem sera une image pseudo-device vnd 4 # et pour stocker encore un peu plus de données, # nous utiliserons une image compressée options VND_COMPRESSION # Les directives de création et d'espace nécessaire # au RAMDISK options MEMORY_DISK_HOOKS options MEMORY_DISK_IS_ROOT options MEMORY_DISK_SERVER=0 options MEMORY_DISK_ROOT_SIZE=32768 options MEMORY_RBFLAGS=0
Procédons donc à la compilation de ce noyau custom (on considère que le fichier de configuration utilisé est NBUSB) :
# pwd /usr/src/sys/arch/i386/conf # config NBUSB # cd ../compile/NBUSB # make depend && make
Si tout s'est bien déroulé, vous devriez maintenant disposer d'un noyau nommé netbsd à cet endroit de l'arborescence.
Il nous faut maintenant affubler ce noyau anormalement gros d'un root filesystem minimal, qui constituera le pivot de notre mini-OS. Afin de simplifier l'opération, nous allons peupler ce RAMDISK de quelques outils compilés statiquement, que nous piocherons dans le répertoire /rescue de notre NetBSD souche. Pour peupler ce disque d'amorçage du système, nous devons réfléchir aux différentes étapes : 1. obligatoires dans une séquence de boot, 2. dont nous allons avoir besoin dans le cas spécifique qui nous occupe, à savoir, utiliser autre chose que le système de fichiers initial.
Nous savons que le premier processus qui sera appelé est init(8), classiquement situé dans /sbin. Créons donc une fausse arborescence munie de cette ébauche d'OS :
# mkdir -p /home/pinpin/nbusb/fakeroot/sbin # cp /rescue/init /home/pinpin/nbusb/fakeroot/sbin
init(8), sur un système héritier de 4.0BSD, exécute le script /etc/rc, qui habituellement s'occupe de démarrer différents services à l'aide des divers /etc/rc.*. Nous allons utiliser rc(8) de manière beaucoup plus basique. En effet, cet /etc/rc sera exécuté dans le contexte d'un boot singulier, et c'est à lui que reviendra la charge d'effectuer le pivot entre le RAMDISK et l'image root contenant les moult outils qui motivent cette tâche. Voici un exemple de fichier fakeroot/etc/rc minimal et commenté :
 # debut de /etc/rc
echo "Initialisation du système..."
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
# on exporte la variable qui contient le point
# de montage de la clé
KEYMOUNTPOINT=/mnt
# puis une variable contenant les données utiles
KEYFILESPATH=${KEYMOUNTPOINT}/nbusb
# enfin, le nom de l'image que nous créerons plus tard
IMGNAME=nbusb.zimg
sleep 2 # on attend la fin de l'affichage
echo
echo "--------------------------------------------"
echo " . Stage 2: montage de l'image disque"
echo "--------------------------------------------"
echo
echo "Nous allons monter le système de fichier VFAT."
echo -n "Entrez le device sur lequel se trouve " \
"l'image root (wd0a, wd0e, sd0e...): "
read dev
# 1ere passe, on monte la clé avec le système
# de fichiers VFAT
echo "Montage de /dev/${dev}"
mount_msdos /dev/${dev} ${KEYMOUNTPOINT}
# Nous avons maintenant la main sur le filesystem de la clé,
# nous allons pouvoir créer le device virtuel vnd qui sera
# associé au fichier image
vnconfig -z vnd0 ${KEYFILESPATH}/${IMGNAME}
# /!\ issu de man vnconfig :
#
# -z Assume that regular file is compressed
# disk image in cloop2 format, and
# configures it read-only.
# ^^^^^^^^^
# 2eme passe, nous pouvons maintenant monter / issu
# du device vnd
mount_ffs -o ro,union /dev/vnd0a / >/dev/null 2>&1
# puis on monte le reste du filesystem en Memory
# FileSystem (vnd compressé et en lecture seule)
echo "montages mfs"
mount_mfs -s 262144 swap /tmp
mount_mfs -s 12000 swap /dev
mount_mfs -s 262144 swap /var
mount_mfs -s 131072 swap /etc
mount_mfs -s 262144 swap /home
mount_mfs -s 262144 swap /usr/pkg
sleep 1
echo "Création des devices..."
cd /dev && sh MAKEDEV all
echo
echo "--------------------------------------------"
echo " . Stage 3: multiutilisateur"
echo "--------------------------------------------"
echo
# on appelle maintenant le "vrai" rc
sh /etc/rc
# fin de /etc/rc
Ce rc fait appel à différents exécutables que nous devons donc copier sur notre clé : sh (sans lui, point de rc !) et sleep dans fakeroot/bin, puis mount_msdos, mount_ffs, mount_mfs et vnconfig dans fakeroot/sbin. Copiez également les bibliothèques desquelles dépendent ces outils, typiquement tout /lib, /usr/lib/libc.so* ainsi que /usr/lib/libutil.so.* et évidemment /libexec/ld.elf_so.
Maintenant que nous disposons de la structure de fichiers initiale, il nous faut la greffer à notre noyau. Nous allons pour cela utiliser les outils makefs(8) et mdsetimage(8). Ces outils servent respectivement à générer une image à partir d'une structure de fichiers et à copier cette image dans le RAMDISK du noyau.
Créons une image de 16 mégaoctets du filesystem basique créé plus haut. Nous choisissons évidemment FFS comme type de système de fichiers :
# makefs -s 16m -t ffs md.img fakeroot
Copions maintenant cette image dans notre RAMDISK :
# mdsetimage netbsd md.img
Afin de ne gaspiller aucun octet, compressons ce noyau :
# gzip -9 netbsd && mv netbsd.gz netbsd
Votre noyau est fin prêt.
2. Création du root filesystem
Muni de son système initial, notre noyau va dérouler, init(8) va invoquer rc qui va tenter de monter l'image nbusb.zimg. Ce fichier image n'est rien de plus qu'un disque virtuel créé à l'aide de dd(1), que nous allons peupler comme une simple partition.
Créons donc un disque vide de 128 mégaoctets :
# dd if=/dev/zero of=nbusb.img count=262144 bs=512
Associons-le à un device virtuel de type vnd :
# vnconfig -c -v /dev/vnd0 nbusb.img
On génère, comme pour un véritable disque, un label :
 # cat > nbusb.disktab << EOF miniroot:\ :ty=floppy:se#512:nt#1:rm#3600:ns#262144:nc#1:\ :pa#262144:oa#0:ba#4096:fa#512:ta=4.2BSD:\ :pb#262144:ob#0:\ :pc#262144:oc#0: EOF
On inscrit ce label :
# disklabel -w -f nbusb.disktab /dev/vnd0 nbusb
Puis, on construit le système de fichiers :
# newfs -m 0 /dev/vnd0a
Il est désormais possible de monter ce disque :
# mount /dev/vnd0a /mnt
Reste à peupler ce disque avec les packages de base de votre choix. Pour cette petite démonstration, nous nous contenterons des sets base et etc, que vous pourrez télécharger ici : ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-3.1/i386/binary/sets/. Remplissons notre faux disque des packages fraîchement récupérés :
# cd /mnt # tar zxvfp /home/pinpin/tmp/base.tgz # tar zxvfp /home/pinpin/tmp/etc.tgz
Notre image dispose maintenant d'un système minimal, mais parfaitement fonctionnel. Reste à lui apporter quelques petites modifications afin de le rendre exploitable ; comme placer la variable rc_configured à YES dans etc/rc.conf, éventuellement ajouter un utilisateur ou en tout cas s'assurer qu'on pourra passer root. Pourquoi pas spécifier un nom d'hôte dans /etc/myname ou configurer quelques variables d'environnement dans l’/etc/profile.
Notre disque créé et peuplé, il nous reste à le compresser afin qu'il occupe le moins de place possible sur notre clé. Ceci est réalisé à l'aide de la commande vndcompress(1) :
On démonte notre disque virtuel :
# umount /mnt
On le désassocie du device vnd0 :
# vnconfig -u vnd0
Et on compresse l'image :
# vndcompress nbusb.img nbimg.zimg
Nous avons spécifié dans le fichier rc du RAMDISK que l'image se situera dans le répertoire nbusb/ sur la clé au format VFAT. C’est donc dans ce répertoire que nous allons copier notre image :
# mount_msdos /dev/sd0e /mnt
sd0e représente le device associé à la partition VFAT de notre clé :
# mkdir /mnt/nbusb # cp netbsd /mnt/nbusb # cp nbusb.zimg /mnt/nbusb
Reste à rendre notre clé amorçable grâce à Grub :
# grub-install --root-directory=/mnt /dev/sd0
Et créer un menu.lst idoine :
# cat > /mnt/boot/grub/menu.lst << EOF title NetBSD LiveKey root (hd0,0) kernel --type=netbsd /nbusb/netbsd boot EOF
C'est terminé !
Vous pouvez maintenant tester votre NetBSD-light grâce, par exemple, à l'excellent Qemu en utilisant la syntaxe suivante :
# qemu /dev/sda
Si tout se passe bien, vous devriez admirer un magnifique menu Grub.

ATTENTION
Pour Qemu, le disque source sera exploité comme un disque IDE. Aussi, lorsque rc demandera quel device utiliser comme root filesystem, c'est bien wd0X (ou X=a, e...) qu'il faudra entrer, a contrario d'une vraie utilisation lors de laquelle le noyau NetBSD associera votre clé à un device de type sdXY.

À la fin de la séquence de boot, vous devriez normalement vous trouver devant un TTY qui vous présente fièrement sa demande de login. Y'a plus qu'à .

3. Au revoir président
L'article se finit ici, mais vous avez certainement compris que c'est également ici que démarrent les insomnies, car il ne tient qu'à vous de créer autant de configurations de NetBSD " embarquées " que vous le souhaitez, de faire le ménage dans le basesystem, de retoucher, réécrire, repenser le rc basique !
De plus, il reste dans notre image basique plusieurs dizaines de mégas inutilisés. Faites donc une petite sélection de packages (FTP : ftp.netbsd.org/pub/NetBSD/packages/3.0/i386/), puis à l'aide de pkg_add -p, installez-les dans votre environnement minimal. Attention, l'image compressée est en lecture seule. Il faudra travailler sur l'image décompressée puis regénérer le .zimg à l'aide de VNDcompress.
Vous trouverez quelques ajouts, ainsi que des scripts automatisant les étapes que nous avons vues à l'adresse suivante : http://imil.net/nlk/. L’/etc/rc de ce projet utilise par exemple un autre répertoire sur la clé afin de pouvoir modifier des fichiers de configuration classiques sans devoir reconstruire la clé. Il est également capable d'installer au boot des packages qui se trouvent dans le répertoire livekey/ et il mounte /root en lecture écriture sur un répertoire situé sur la clé. Bien des améliorations sont imaginables, et il est sans aucun doute possible d'accélérer entre autres le processus de boot. Et comme d'habitude, commentaires et contributions sont les bienvenus :)
Références
Quelques liens connexes :
- http://pkgsrc.se/sysutils/mklivecd
- http://www.yazzy.org/docs/NetBSD/netbsd-livecd.txt
- http://wiki.netbsd.se/index.php/How_to_build_your_own_NetBSD_LiveCD
- http://www.wifibsd.org/


