Parce que de temps en temps, il faut savoir fermer sa gueule…

OpenBSD, c'est beau, c'est bien et ça a du poil aux pattes et tout ce qui va avec. Pour faire un routeur maison, c'est simplement du bonheur en terme de stabilité, de fiabilité et de fonctionnalités. Il ne reste qu'un problème : la robustesse vis-à-vis des coupures électriques.

Un bon routeur est un routeur mort se doit de pouvoir résister en cas de coupure de jus, d'attaque nucléaire ou de pénurie de café. Et en l'occurence, le système de base d'OpenBSD ne le peut pas sans un petit coup de pouce de notre ami mfs(8) (nan, ce n'est pas sale, c'est vraiment son nom).

Un copain de RamFS

mfs(8), pour Memory File System, est un copain de RamFS (et vaguement de tmpfs) avec grosso mode les mêmes fonctionnalités : il s'agit de charger en RAM un morceau de système de fichier présent sur disque de sorte à pouvoir passer ce dernier en lecture seule et ne plus risquer de désagrément en cas de redémarrage intempestif. Bien entendu, ça a un coût en RAM, mais tu vas pouvoir constater qu'il n'est pas bien difficile de faire tourner un système basique mais parfaitement fonctionnel avec finalement pas grand chose.

Admettons, t'installes un OpenBSD

Petit note préliminaire : il est relativement facile de basculer un système déjà installé en lecture seule. Ça demande simplement un peu plus de manip et il faut être très prudent à chaque étape. Je préfère décrire ici la méthode pour installer un OpenBSD en lecture seule (c'est moins barbant…).

Première chose : à l'installation, virer la partition de swap (b) et ne garder que un / (a disons 1Gio) et un /mfs (d disons 1Gio aussi) ; bon, les tailles importent peu, tu fais comme tu le sens mais souviens-toi bien que tu vas charger des trucs en RAM… Faudrait donc pas non plus prévoir un disque de 1Tio si tu n'as que 256Mio de RAM.

Bref, une fois l'installation terminée, tu vas te retrouver avec un partitionnement qui ressemble à peu près à ça :

# mount
/dev/wd0a on / type ffs (local)
/dev/wd0d on /mfs type ffs (local, nodev, nosuid)

Et là, le file system, il prend le chocolat et il encule la marmotte

Il s'agit maintenant de transférer les éléments indispensables au bon fonctionnement du système sur la partition /mfs, j'ai nommé /dev, /var et /tmp.

Pour /dev, c'est assez simple :

# mkdir -p /mfs/dev
# cd /mfs/dev
# sh /dev/MAKEDEV all

Tu peux d'ores et déjà reprendre ton /etc/fstab et le modifier pour mettre /dev en RAM. Pour cela, il suffit d'ajouter cette ligne :

swap    /dev    mfs     rw,nosuid,noatime,noexec,-P=/mfs/dev,-s=4M,-i=2048      0       0

Le -P sert à indiquer quel répertoire doit être chargé en RAM au démarrage ; le -s sert à indiquer la taille du mfs en question ; les autres options sont simplement là pour la déco.

Il s'agit maintenant de passer /var en mfs. Là, c'est un peu plus sioux :

# rm -Rf /var/{account,admin,audit,crash,games,rwho,www}
# cd /
# tar cpf - ./var |( cd /mfs ; tar xpf - )
tar: Ustar cannot archive a socket ./var/cron/tabs/.sock
tar: Ustar cannot archive a socket ./var/empty/dev/log
# sync

On commence donc par supprimer les répertoires inutiles (bien entendu, si tu te sers d'un de ces répertoires, mieux vaut éviter de le supprimer…) et on utilise tar pour tout transférer, comme ça on peut s'assurer que les droits d'accès et certains fichiers spéciaux sont bien conservés à l'identique.

Pour /tmp, tu peux y aller comme une grosse brute :

# rm -Rf /tmp
# ln -s /var/tmp /tmp

On va maintenant pouvoir créer le mfs correspondant à /var dans /etc/fstab :

swap    /var    mfs     rw,nosuid,noatime,noexec,nodev,-P=/mfs/var,-s=64M       0       0

Et paf ! Ça fait des Chocapic ! Reste plus qu'à passer tout le rest en lecture seule, proprement :

/dev/wd0a / ffs ro,noatime,softdep 1 1
/dev/wd0d /mfs ffs ro,nodev,nosuid,softdep 1 2

L'option softdep permet de s'assurer de la cohérence du système de fichiers pendant le peu de temps qu'il sera en lecture/écriture (pendant une partie du boot en fait).

Oui, mais maintenant, tout ce que je mets dans /var disparaît après un reboot :(

J'arrive, petit con. Une fois que tu as rebooté (en ayant pris la précaution de bien relire ton /etc/fstab pour être certain qu'il n'y a pas de connerie de dedans), tu peux voir que tout se passe à merveille :

# mount
/dev/wd0a on / type ffs (local, noatime, read-only)
/dev/wd0d on /mfs type ffs (local, noatime, nodev, nosuid, read-only, softdep)
mfs:26119 on /dev type mfs (asynchronous, local, noatime, noexec, nosuid, size=8192 512-blocks)
mfs:1977 on /var type mfs (asynchronous, local, noatime, nodev, noexec, nosuid, size=131072 512-blocks)

Tous les systèmes de fichiers sont en lecture seule ou en RAM, tu peux donc bourriner comme un goret sur la prise électrique, tu auras très peu de chance de mettre en danger une partition. Par contre, effectivement les changements dans /var ne sont plus persistents. Mais on va pouvoir arranger ça très vite à grand coup de rsync.

Je te propose donc le script suivant :

#! /bin/sh

mount -uw /mfs
/usr/local/bin/rsync -a --delete --exclude=spool /var/ /mfs/var/
mount -ur /mfs

À mettre dans /usr/local/bin avec les droits d'exécution en ayant au préalable installer rsync via pkg_add.

Pour te simplifier la vie, tu peux mettre ce script dans la crontab de root et éventuellement dans le /etc/rc.shutdown (comme ça en cas de reboot « propre », tout est synchronisé).

Alors, on dit merci qui ?