💾 Archived View for perso.pw › blog › articles › openbsd-impermanence.gmi captured on 2024-08-18 at 17:37:00. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-05-24)
-=-=-=-=-=-=-
Let me present you my latest project: home-impermanence, under this name is a reference to the NixOS community project impermanence. The name may not be obvious about what it is doing, let me explain.
NixOS wiki about Impermanence, a community module
The original goal of impermanence in NixOS is to have a fully reproducible system mounted on tmpfs where only user-defined files and directories are hooked into the temporary file system to be persistent (such as /home, /var/lib and some /etc files for instance). Why this is something achievable on NixOS, on OpenBSD side we are far from having the tooling to go that deep so I wrote home-impermanence that allows an user to just do that at their $HOME level.
What does it mean exactly? When you start your system, your $HOME directory will be mounted with an empty memory based file system (using mfs) and symbolic links to files and directories listed in the configuration file will be done in your $HOME. Every time you reboot, you will have the exact same set of files, extra files created meanwhile will be lost. When you hold a $HOME directory for long, you know you get many directories and files created in various ~/.config or ~/.local or directly as dotfiles in the top level of the home directory, with impermanence you can get ride of all the noise.
A benefit is that you can run software as if it was their first run, in some software upgrade you will avoid old settings that would create troubles, or settings that would disturb a whole class of applications (like a gtk setting affecting all gtk programs), with impermanence the user can decide exactly what should remain across reboots or disappear.
My implementation is a Perl script relying on some libraries packaged on OpenBSD, it will run as root from a rc service and the settings done in rc.conf.local. It will read the configuration file from the persistent directory holding the user data and create symlinks in the target directory to the files and directories, doing some sanitizing in the process to prevent listed files to be included in listed directories which would nest symlinks incorrectly.
I chose Perl because it's a stable language, OpenBSD ships with Perl and the very few dependencies required were already available in the ports tree.
The program could easily be ported to Linux, FreeBSD and maybe NetBSD, the mount_mfs calls could be replaced by a mount_tmpfs and the directories symlinks could be done with a mount_bind or mount_nullfs which we don't have on OpenBSD, if someone wants to port my project to another system I could help adding the required logic.
I wrote a complete README file explaining the installation and configuration process, for full instructions refer to this document and the man page that ships with home-impermanence.
Quick method:
git clone https://tildegit.org/solene/home-impermanence/ cd home-impermanence doas make install doas rcctl enable impermanence doas rcctl set impermanence flags -u user -d /home/persist/ doas install -d /home/persist/
From now, you may want to make things quickly, logout from your user and run these commands, this will move your user directory and prepare the mountpoint.
mv /home/user /home/persist/user install -d -o user -g wheel /home/user
Now, it's time to configure impermanence before running it.
Reusing the paths from the installation example, the configuration file should be in /home/persist/user/impermanence.yml , the file must be using YAML formatting. Here is my personal configuration file that you can use as a base.
size: 500m files: - .Xdefaults - .Xresources - .bashrc - .gitconfig - .kshrc - .profile - .xsession - .tmux.conf - .config/kwalletrc directories: - .claws-mail - .config/Thunar - .config/asciinema - .config/gajim - .config/kak - .config/keepassxc - .config/lagrange - .config/mpv - .config/musikcube - .config/openttd - .config/xfce4 - .config/zim - .local/share/cozy - .local/share/gajim - .local/share/ibus-typing-booster - .local/share/kwalletd - .mozilla - .ssh - Documents - Downloads - Music - bin - dev - notes - tmp
When you think you are done, start the impermanence rc service with rcctl start impermanence and log-in. You should see all the symlinks you defined in your configuration file.
Here is the content of my $HOME directory when I use impermanence.
solene@daru ~> ls -la total 104 drwxr-xr-x 8 solene wheel 1024 Mar 15 12:10 . drwxr-xr-x 17 root wheel 512 Mar 14 15:36 .. -rw------- 1 solene wheel 165 Mar 15 09:08 .ICEauthority -rw------- 1 solene solene 53 Mar 15 09:08 .Xauthority lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .Xdefaults -> /home/permanent//solene/.Xdefaults lrwxr-xr-x 1 root wheel 35 Mar 15 09:08 .Xresources -> /home/permanent//solene/.Xresources -rw-r--r-- 1 solene wheel 48 Mar 15 12:07 .aspell.en.prepl -rw-r--r-- 1 solene wheel 42 Mar 15 12:07 .aspell.en.pws lrwxr-xr-x 1 root wheel 31 Mar 15 09:08 .bashrc -> /home/permanent//solene/.bashrc drwxr-xr-x 9 solene wheel 512 Mar 15 12:10 .cache lrwxr-xr-x 1 root wheel 35 Mar 15 09:08 .claws-mail -> /home/permanent//solene/.claws-mail drwx------ 8 solene wheel 512 Mar 15 12:27 .config drwx------ 3 solene wheel 512 Mar 15 09:08 .dbus lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .gitconfig -> /home/permanent//solene/.gitconfig drwx------ 3 solene wheel 512 Mar 15 12:32 .gnupg lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 .kshrc -> /home/permanent//solene/.kshrc drwx------ 3 solene wheel 512 Mar 15 09:08 .local lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .mozilla -> /home/permanent//solene/.mozilla lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .profile -> /home/permanent//solene/.profile lrwxr-xr-x 1 solene wheel 30 Mar 15 12:10 .sbclrc -> /home/permanent/solene/.sbclrc drwxr-xr-x 2 solene wheel 512 Mar 15 09:08 .sndio lrwxr-xr-x 1 root wheel 28 Mar 15 09:08 .ssh -> /home/permanent//solene/.ssh lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .tmux.conf -> /home/permanent//solene/.tmux.conf lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 .xsession -> /home/permanent//solene/.xsession -rw------- 1 solene wheel 25273 Mar 15 13:26 .xsession-errors lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 Documents -> /home/permanent//solene/Documents lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 Downloads -> /home/permanent//solene/Downloads lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 HANGAR -> /home/permanent//solene/HANGAR lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 dev -> /home/permanent//solene/dev lrwxr-xr-x 1 root wheel 29 Mar 15 09:08 notes -> /home/permanent//solene/notes lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 quicklisp -> /home/permanent//solene/quicklisp lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 tmp -> /home/permanent//solene/tmp
If you want to rollback it's easy, disable impermanence, move /home/persist/user to /home/user and you are done.
I really don't want to go back to not using impermanence since I tried it on NixOS. I thought implementing it only for $HOME would be good enough as a start and started thinking about it, made a proof of concept to see if the symbolic links method was enough to make it work, and it was!
I hope you will enjoy this as much as I do, feel free to contact me if you need some help understanding the setup.