The linux foundation FHS is well understood, and partially supported in many places. It's also a bit shit.
Parts of the FHS come from making reatroactive rules around whichever directory name Ken Thompson or Dennis Ritchie chose in the early 70s. Seriously.
Additionally, some directories don't even make a lot of sense these days- who is distinguishing between mounting data in /media
, or /mnt
? What about people mounting directories in their home directory?
Tackling directories also allows us to rethink what a file looks like to SeoulOS, what modes files have, and how we can interact with them.
Thus, let's rethink things a bit.
Ignoring, for a minute, the tedious cliche of "eVeRyThInGs a FiLe", and forgetting everything we know about POSIX files (fuck it, for now do we even care about such distinctions as whether a file must end with an eol, and whether an eol contains a newline (it doesn, but that doesn't matter for this file, either), there are a number of important types of files and directories which we're going to want
File | Purpose | Notes |
---|---|---|
sda1 , usb1 |
Device files | Exposing these as files makes a certain amount of sense, especially for cloning or zeroing |
anything in proc, sys | Kernel tunables, details | Tunables should exist outside of read-only details, and stuff should be well gated |
binaries, configs, logs | to do stuff /shrug | Do we really need to separate this stuff off from one another? Perhaps for backing up config files, or putting logs in a tmpfs or something. Maybe opening files in different ways helps this |
user files | Whatever files a user wants | Obviously not going to fuck around with these. Users can do whatever the hell they want |
header files, kernel sources | Bootstrapping files, building software | This is another one of those things that makes sense to be completely freeform |
Realistically there are only a few classifications of files we care about
- Devices
- Psuedo files (kernel stuffs)
- Application files (logs, configs, binaries)
- Bootstrap files
- User files
Within this, then, most files are 'regular' files. Create, write, delete. They don't need much beyond an ACL of some sort, and modes (R/RW/A). Executionable files are pretty much the same; (R/RW/RWX/RX/ whatever) but with the addition of capabilities (kernel plugins, for instance).
Additionally, creating files as logs or configs makes sense. Log files should be append-only, with some kind of strategy for stopping them getting too large. Labelling config files as such (or maybe with a backupable
flag) and granting an interface to find these would be useful.
User files could come with a cool flag that, amongst other things, allows for the logging access by any other user (including root, or whatever)
A rough demonstration of this may be found here https://gist.github.com/rust-play/abc41037cceb0adf64fa2d6365834526
Thus: it becomes much easier to accomplish many of the things that shunting things into different directories gives us- no need to separate configs to one directory, binaries to another, logs to yet another. Keep them in one place, and then you get cool things like chroot
without needing to do anything else.
The FHS directory structure is based on fifty year old problems, made official by some sketchy backronyms and rules, and cemented by practice and convention (backing up /etc
and /home
, for instance, or mounting /tmp
as a tmpfs).
These directories are familiar; lots of operating systems use them, or at least a la carte, and lots of tools have been designed to work with them.
The problem comes, though, when there's a non-standard use case. Perhaps configuration for one program is in /opt
, and for another /etc
. Some tools store config in /etc/prog/prog.conf
, others /etc/prog.conf
, and others yet in /etc/prog.d/prog.conf
. Maybe config is then stored in /u01
(for those nasty oracle types). This stuff can be configured via xdg
per instance and is just bloody ridiculous again.
The FHS is just not fit for purpose anymore.
Instead, we have the hierarchy:
Directory | Purpose | Notes |
---|---|---|
/ |
Root of the filesystem | Umming and ahhing over this. Should it be an actual filesystem? Or an in-memory construct? Perhaps any file saved directly on / should disappear on reboot |
/device |
Device files | Pretty much as the FHS. Pseudo filesystem |
/application |
Applications | These applications are installed for all users |
/user |
Home directories | Like a non-shitty /Users on macos. Default cascading fileflags: FileFlags::USER_FILE |
/user/foo/application |
Applications | Applications installed for user foo only |
/process |
‘proc’ alike | This should contain just processes, like Plan9. Things like CPU or Memory info are device information, so put them in /device/cpu or /device/memory |
/toolchain |
Bootstrapping files, building software | Anything that usually goes in **/lib or **/src or so on- why bother with the distinction? |
Of note is that top-level directories are both full spelled out (we don't need to worry about files with too many characters- it's 2021 for fuck's sake), and singular. This is on purpose: paths should make semantic sense, conveying some information about what the file means in a wider context.
All a file name like /dev/sda1
tells you is that you have a date with the manual, if you've never seen this before. Hopefully a file like /device/disk-a/partition-1
tells you something more useful.
Further to the /application
directory, there's the convention:
Path | Access | Notes |
---|---|---|
/application/foo/bin |
$ foo |
A shell would look for command ‘$cmd’ as per: /application/$cmd/bin which is expected to be an executable |
/application/foo/some-command |
$ foo/some-command |
As above, in essence |
/application/foo/something.log |
open(‘something.log’, FLAG_LOG) |
Paths are relative to where the command is run from, probably. Maybe that’s a bad idea. In any case, FLAG_LOG sets stuff like max size, append_only |
/application/foo/blag.conf |
open(‘blag.conf’, FLAG_CONFIG) |
Ditto paths, dunno. A config flag might mean ‘persist to disk, and back me up’ |
The idea is that no matter where an application is installed, whatever resources an application needs (config files, logs, caches) should be accessible via a relative path. Files should be opened with the correct flags to ensure lifetimes and everything should work. An application can call its files whatever it wants, with the exception of the magic bin
file. When an application is called without an explicit second part, then bin
is assumed.
Emacs, then, might be stored with $ emacs
, which is expanded to /application/emacs/bin
.
This all should mean we no longer need to PREFIX=$HOME make
, or cp /usr/share/faa/laa/laa.conf.sample /etc/faa/laa.conf
or whatever.