lundi 25 août 2014

Les protecteurs des anciennes machines

Il fait environ 25 ans maintenant que j'utilise régulièrement des ordinateurs, pour le travail autant que pour le loisir.  Je les utilise d'ailleurs si fréquemment que j'apprécie particulièrement de pouvoir m'en écarter pour 24 heures consécutives.

Le premier ordinateur que je pouvais utiliser régulièrement n'était nul autre qu'un Amiga 500.  Comme bien des amateurs d'Amiga, mes propos ressemblerons très fort à des éloges romantiques et nostalgiques.  Mais nombreux sont ceux, comme moi, qui décrivent les ordinateurs Amiga et le système d'exploitation en partie sur ROM (Kickstart), en partie sur disque (Workbench) comme étant si en avance de leur temps (on peut penser à des animations en couleur synchronisées à du son à 4 canaux alors que tous les autres ordinateurs en 1985 étaient encore au monochrome) que la série d'ordinateurs n'a pas pu trouver un succès commercial et a cessé production vers le milieu des années 1990.

L'Amiga 500 en question est encore chez moi, à la cave.  Je l'ai testé, il y a quelques mois, avec des jeux des années 1980, qui fonctionnent encore sans problème.  Ça aide, évidemment, qu'il n'y ait aucune pièce mobile sauf pour le lecteur de disquettes.  Les ordinateurs étaient bâtis pour durer, et le même modèle était vendu pendant plus d'une année.

Cette belle machine n'est qu'une d'une trentaine de pièces de musée (j'ai arrêté de compter) qui se reposent, inutilisées, à la cave, chez moi.  Mais occasionnellement, comme si je n'en avais pas assez, je fais un tour à un marché au puces pour y trouver une relique, généralement datant d'il y a cinq ou dix ans.  Puisque mon intérêt en ces machines est généralement limité à un de mes domaines d'expertise (la gestion de réseaux et de systèmes), des desktops d'il y a cinq ans sont amplement suffisants.

En parallèle, depuis 2003, faisant face des distros de Linux qui se démarquent les unes des autres par leur grande taille et exigences en mémoire vive et en espace de disque, tout en essayant alors de faire un routeur et serveur d'un 486 datant de 1994 que j'ai acheté en 2002 au prix de 20$, j'ai commencé ma propre distro de Linux. Sans compter le fait qu'il doit bien s'agir d'une des distros les moins utilisées au monde, une des choses qui la démarquent doit se trouver dans le fait que les versions des outils sont, dans biens des cas, des versions anciennes mais très stables.

Cela s'est surtout fait sentir la fin de semaine passée, alors que j'essayais d'améliorer la flexibilité du processus de démarrage. Ma stratégie initiale consistait d'utiliser le concept relativement récent du initramfs, selon lequel un "disque" en mémoire vive sans réelle limite logique de taille permet d'initialiser des disques (p.ex. RAID, LVM, un disque chiffré).

C'était exactement ce dont j'avais besoin, donc, me basant sur le wiki de Gentoo, j'ai commencé à assembler ça. Rendu au script d'initialisation, ça disait d'utiliser switch_root. Je ne le trouve pas dans mon installation de Linux, donc j'y vais plutôt avec pivot_root comme en 2006 (lorsque j'ai dû m'amuser à configurer Linux avec un hardware RAID avec le chipset de NVIDIA). Comme mon arrangement, cette fois-ci, était beaucoup plus simple, je me disais qu'il n'y à rien là.

Je ne dois pas attendre longtemps pour voir que pivot_root ne fonctionne pas. Les forums clarifient que pivot_root ne fonctionne pas avec le système de fichiers rootfs, et suggèrent de passer à switch_root.

Donc je m'amuse à quérir la plus récente version d'util-linux sur kernel.org. Je lance la compilation, et assez vite, je vois que switch_root ne peut être bâti que si une certaines fonctions sont disponibles dans la librairie C. La version de glibc requise serait 2.7, alors que j'en suis à 2.3.6 depuis une dizaine d'années (depuis lors, j'ai gardé les versions les plus stables des librairies clés).

Donc il faut que j'oublie initramfs pour plutôt m'amuser avec initrd, l'ancêtre d'initramfs. Mais la documentation disponible sur internet a bien changé depuis 2006: trouver des exemples concrets et complets d'initrd est bien moins facile. La plupart des exemples proposent d'utiliser des mécanismes existants dans les distros pour lesquels ils ont été écrits, alors que ma propre distro ne comporte encore aucun tel mécanisme. (Il va sans dire que je m'en occuperai, là!)

Donc voici la formule magique:
1. Créer un fichier vide de la taille d'un "RAM disk" (/dev/ram?*) tel que défini dans le noyau (4 Mo par défaut) :
  dd if=/dev/zero of=initrd bs=1k count=4k

2. Nous utiliserons le mode loop pour faire du fichier image un device utilisable. Si loop est compilé comme module au lieu d'être intégré au noyau, chargeons-le si ce n'est pas déjà fait:
  modprobe loop

3. Faisons du fichier image un /dev/loop?* et conservons-en l'identité :
  LOOP_DEV=`losetup -f initrd --show`

4. Formattons l'image. J'utilise ext2 pour la simplicité:
  mke2fs $LOOP_DEV
(Notons qu'il y a moyen d'utiliser certains paramètres, ou encore d'autres FS, pour maximiser l'espace disponible.  L'exercice est laissé au lecteur ou à la lectrice!)

5. Accédons à l'espace de l'image:
  mkdir initrd_dir
  mount $LOOP_DEV initrd_dir

6. Créons la structure des répertoires de base et ajoutons-y les fichiers essentiels:
  pushd initrd_dir
  mkdir bin dev etc lib mnt sbin
  cp -a /dev/{console,null,tty) dev/
  touch etc/mtab
  cp -a /bin/{bash,mount,umount} bin/
  cp -a /usr/sbin/chroot /sbin/pivot_root sbin/

7. Il faut y ajouter le « device node » pour la racine réelle du système de fichiers, dans notre cas, hda3 :
  cp -a /dev/hda3 dev/

8. Les programmes de l'étape 6 ont été bâties et liées à des librairies dynamiques qu'il faudra copier :
  cp -a `ldd bin/* sbin/* | grep /lib/ | awk -F"=>" '{ print $NF }' | awk '{ print $1 }' | sort | uniq` lib/

9. Les librairies copiées sont parfois des liens, donc il faudra aussi copier les vrais fichiers:
  for name in `ls -l lib/ | awk -F" -> " '{ print $2 }' | sed -e '/^$/d'`; do
      cp -a /lib/$name lib/
  done

10. Il faut ensuite créer le script d'initialisation et le rendre exécutable.  Ajustez le contenu tel que nécessaire :
  cat >linuxrc <<EOF
#!/bin/bash
export PATH=/sbin:/bin:/usr/sbin:/usr/bin

# Mount real root filesystem
mount -t auto /dev/hda3 /mnt    # Change the real root device as required

# Pivot to real filesystem and run the real init
cd /mnt
pivot_root . mnt/oldroot    # Change this "put_old" directory as required
exec chroot . sh -c 'umount /mnt/oldroot; exec /sbin/init' \
    <dev/console >dev/console 2>&1
EOF
  chmod +x linuxrc

11. Tout y est, donc nous pouvons fermer l'image :
  popd
  umount initrd_dir
  losetup -d $LOOP_DEV

12. Et là nous comprimerons l'image et la mettrons au bon endroit :
  gzip -9 initrd
  cp initrd.gz /boot/

13. Pour l'utiliser, il faut l'ajouter dans la configuration du Linux loader, tout en devant spécifier le script d'initialisation. Donc par exemple, si on utilise LILO, la section de lilo.conf pour notre installation pourrait avoir l'air de ceci :
  image = /boot/vmlinuz
       label = linux
       root = /dev/rd0
       initrd = /boot/initrd.gz
       apprend = "init=/linuxrc"

14. Il faudra aussi que le noyau Linux soit configuré pour s'attendre justement à l'utilisation d'initrd, et que le pilote RAM disk soit compilé dans le noyau.

15. Si nécessaire, faire en sorte que le Linux loader soit au courant de la nouvelle configuration.  Avec lilo, il est nécessaire de mettre à jour le MBR, et voici la façon dont nous le faisons :
  lilo

Et en principe, tout devrait baigner dans l'huile. On peut ensuite faire évoluer le principe pour des situations plus compliquées.

Alors qu'en tout et pour tout, cet arrangement de style plutôt historique fonctionne bien, la charge de travail associée au maintient des pratiques historiques croît progressivement au cours des années, et il revient à un petit nombre d'individus comme moi de préserver la pratique non seulement en documentant et partageant, mais aussi en utilisant ces pratiques.

Aucun commentaire:

Publier un commentaire