Title: Reproducible clean $HOME in OpenBSD using impermanence | |
Author: Solène | |
Date: 15 March 2022 | |
Tags: openbsd reproducible nixos unix | |
Description: Bringing some NixOS tech to OpenBSD | |
# Introduction | |
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 | |
home-impermanence for OpenBSD | |
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. | |
# Implementation | |
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. | |
# How to use | |
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. | |
home-impermanence README | |
## Installation | |
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. | |
## Configuration | |
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. | |
```configuration yaml file | |
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. | |
## Result | |
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… | |
lrwxr-xr-x 1 root wheel 35 Mar 15 09:08 .Xresources -> /home/permanen… | |
-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//s… | |
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/permanen… | |
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… | |
drwx------ 3 solene wheel 512 Mar 15 12:32 .gnupg | |
lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 .kshrc -> /home/permanent//so… | |
drwx------ 3 solene wheel 512 Mar 15 09:08 .local | |
lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .mozilla -> /home/permanent//… | |
lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .profile -> /home/permanent//… | |
lrwxr-xr-x 1 solene wheel 30 Mar 15 12:10 .sbclrc -> /home/permanent/so… | |
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//sole… | |
lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .tmux.conf -> /home/permanent… | |
lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 .xsession -> /home/permanent/… | |
-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/… | |
lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 Downloads -> /home/permanent/… | |
lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 HANGAR -> /home/permanent//so… | |
lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 dev -> /home/permanent//solen… | |
lrwxr-xr-x 1 root wheel 29 Mar 15 09:08 notes -> /home/permanent//sol… | |
lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 quicklisp -> /home/permanent/… | |
lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 tmp -> /home/permanent//solen… | |
``` | |
## Rollback | |
If you want to rollback it's easy, disable impermanence, move | |
/home/persist/user to /home/user and you are done. | |
# Conclusion | |
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. |