+++

title = "OpenBSD en lecture seule"
date = 2013-07-12
aliases = [ "post/2013/07/12/OpenBSD-en-lecture-seule"]
[taxonomies]
tags = [ "système", "openbsd" ]
+++

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

<!-- more -->

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 ?
