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.
       
 (HTM) NixOS wiki about Impermanence, a community module
 (HTM) 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.
       
 (HTM) 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//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
       ```
       
       ## 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.