1. 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.
2. 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.
3. 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
3.1. 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.
3.2. 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.
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.
3.3. 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//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
3.4. Rollback §
If you want to rollback it's easy, disable impermanence, move /home/persist/user to /home/user and you are done.
4. 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.