My read-only home

Reading time: 5 Minutes — 986 Words
5 Minutes / 986 Words

I got so fed up with random programs putting random files and directories in my home directory, that I executed chmod -w "$HOME" a few months ago, making it impossible to create new directories or files in it. At first it was only meant as a temporary measure, until I have all the programs I use under control, but I think I’ll just keep my $HOME read-only.

It causes far less issues than anticipated and has forced me to add configuration for every single program, that by default puts stuff in my $HOME. The results are beautiful, predictable, and maintainable. No more surprises waiting for the next ls -A.

> ls -A
.cache/   .local/  .mozilla/  src/   tmp/  .vim/
.config/  mnt/     .profile@  .ssh/  var/  wrk/

Now this is an amount of output from ls(1) I feel I can handle. Not perfect, but a little closer to what I want.

The ideal world™

My goal with this is to get rid of most hidden files, which wouldn’t exist in my little rainbows-and-unicorns world I’m dreaming up (as in a file with a dot in the beginning is just that and gets no special handling)

> ls -A
etc/  mnt/  src/  tmp/  usr/  var/  wrk/

So where would the remaining hidden files move? I’ve made a little map.

.config      -> etc
.cache       -> var/cache
.local/bin   -> usr/bin
.local/lib   -> usr/lib
.local/share -> var/lib
.mozilla     -> etc/mozilla and var/lib/mozilla
.profile     -> etc/profile
.ssh         -> etc/ssh and var/lib/ssh
.vim         -> etc/vim

I could already get rid of .cache, .config, and .local but moving those on a running system is a bit cumbersome and I haven’t done it yet. I’d probably have to file a few bug reports as well, I’m not sure all the programs I use handle $XDG_CONFIG_HOME and friends properly. I’m not even sure if my dotfiles handle them properly. 😬

Ok, cool, but why?

The whole XDG situation is well defined and facilitates backups (include $XDG_DATA_HOME and $XDG_CONFIG_HOME, exclude $XDG_CACHE_HOME) or resetting to factory defaults without loosing user data (delete $XDG_CONFIG_HOME), among other advantages like making a setup as above possible with only a handful of environment variables.

Hidden files always felt messy and like a workaround to me. They don’t provide much benefit apart from hiding a mess of weirdly placed configuration files. A suspicion which gets reinforced by the old legend of them being nothing more than an exploited bug. On the other hand, hiding a mess might just be a good enough reason for them to exist. In the end it’s probably just personal preference.

My hierarchy is just that and does away with hidden files (in $HOME at least) and in my little dream world, we would get rid of some rather useless flags in ls(1) and similar special casing in file browsers and libraries. Even the likes of git wouldn’t strictly require them, they could just use git/ and git/ignore instead of .git and .gitignore. rcs(1) didn’t use hidden files, you know. 🙃

Realistically speaking, we won’t get rid of them of course, but above hierarchy would allow me to alias ls="ls -A", without being met with a massive listing in $HOME and I could at least pretend hidden files wouldn’t exist.

Lastly, this hierarchy mimics hier(7) to some degree, which makes it easier to build stuff locally and install it to $HOME. While this is already easy with specifying a prefix of $HOME/.local for make(1) or configure, it just feels more consistent to me.

Reality check

This hierarchy is not achievable as outlined above, at least not at the moment.

ssh(1) for example won’t ever change their default of ~/.ssh, since this directory has become something of an API, changing it would break a lot of code and will not happen. Other projects won’t change for similar reasons or because they flat out refuse everything mentioning, no matter what it is. ¯\_(ツ)_/¯ Given the naming conventions they tend to use, I can’t even blame those projects too much (who doesn’t like typing XDG_CONFIG_HOME).

This is another reason I haven’t moved the XDG directories so far, I realised I won’t be able to get the results I wanted. As mentioned above the following would be possible and I will move eventually, but for now laziness wins.

> ls -A
etc/  .mozilla/  src/   tmp/  var/   wrk/
mnt/  .profile@  .ssh/  usr/  .vim/

It’s still not enough to alias ls="ls -A" though. With some determined $ENV hackery I could also get rid of the .profile link, which I’ll probably do as well. I could also switch to neovim and get rid of .vim but that would be a bit excessive and wouldn’t look much cleaner anyways.

The rest of my files

Some people have asked me how I lay out my $HOME and this article is an explanation of some of the bits I find interesting and worth explaining in detail, but here’s the rest of my home-hierarchy for completeness:

> tree -L 2
├── mnt
│   └── * webdav/nfs/etc mountpoints
├── src
│   ├── archive
│   └── * sources of programs I've built locally/modified
├── tmp
│   └── * downloads and other temporary stuff
├── var
│   ├── archive
│   ├── backup
│   ├── books
│   ├── documents
│   ├── inbox
│   ├── music
│   ├── notes
│   ├── pictures
│   └── videos
└── wrk
    ├── archive
    └── * work and other projects, like this blog

How to get here

I hope I’ll manage to write a part two to this, where I outline the basic configuration needed to get a similar result, but for now I can only refer you to my dotfiles and the excellent Arch Linux Wiki, which has a rather complete listing of projects supporting XDG and what configurations can be massaged for those that don’t.