2013/01/13

Software Rants 9: Sensible Filesystem Layout

I run Arch as my main OS now, and it is pleasing how Lib and Lib64 in / symlink to /usr/lib. So in this post I'm going to express my ideas behind filesystem layout and a way to make one that makes sense.

First, the aspects of a good VFS:
  • The ability to "search" on target directories to find things - libraries, executables, pictures - almost any search-able thing should have some simple directory you can search on and find the thing you are after.
  • A layout that facilitates not searching at all, because search is expensive. You want the ability to say, with certainty, that the the foo library is in /something/dir/libs/foo. Even if foo isn't on this machine, there should be one path to foo that produces the library you want, in any environment (Windows completely fails on this, and the /usr/local and /usr/share nonsense on Linux does too, good thing almost nobody uses those anymore).
  • Directory names that make sense. System32, etc, SysWOW64, usr, etc completely screw this up. So does Android, it calls the internal memory sdcard, and any sd card you actually plug into the device is external, and that is just from the non-root view of the filesystem.
  • The ability to mount anywhere, and the ability to mount anything, be it actual storage media, a web server, a socket layer, process views, etc.
  • The filesystem should be naturally a tree, with special files (symlinks, which should just be "links" because if you mount anything, you can "link" to a website under /net like /http/google.com/search?q=Google, or you could link to the root directory). Or to a process id. This creates graphs, but because graphs aren't inherent in the filesystem and are provided by specialized files, you can navigate a filesystem as a tree without risking loops if you ignore links.
  • Forced file extensions or static typing by some metric. Don't leave ambiguity in what a file does, and make extensionless files illegal, and require definitions of what files do what - ex: if you have a binary data backage, use the extension .bin rather than nothing, because .bin would be registered as application specific binary data. If you have a utf-8 encoded text file, use .txt - the file would have a forced metadata header containing the encoding. Once you have an extension, you can embed file specific metadata that can be easily understood and utilized. Without extensions, you read the file from the beginning hoping to find something useful, or rely on metadata in the filesystem, which is often not transferable, especially over network connections.
With these considerations, here is a layout I'd like:
  • Root
    • Boot
    • Resources
      • http
        • google.com
          • search?q=bacon
      • ftp
      • smb
      • ssh
      • temp
      • AltimitSocket
        • IPC Here 
      • TCP
        • 80
          • http
    • Users
      • Zanny
        • Programs
        • Videos
        • Pictures
        • Music
        • Documents.dir
        • Config.dir
        • libs
      • root
      • guest (or default)
    • Groups
      • default
      • printers
      • display
      • audio
      • mount
      • admin
      • network
      • devices
      • virtual
    • System
      • power
      • hypervisor
      • firmware
      • proc
      • dev
        • usb
        • mice
        • keyboards
        • touchscreens
        • displays
        • disks
          • by-label
            • Storage.disk
          • by-uuid
        • printers
        • microphones
        • speakers
        • memory
        • mainboard
        • processors
        • accelerators
Boot should be kind of obvious, it contains the kernel payload and anything the kernel needs to immediately set up the running environment, which would probably include drivers to propagate the base file system, plus whatever init is.

Resources is the collection of trasport protocols the machine supports, and subaddressing these directories accesses their resources (by address or dns resolution). This would include any locally mounted media not forming some other component of the filesystem.
The implication is that all resources are treated similarly. The remote ones are mounted by protocol, and local disks can (if you want) be mounted by fs type or the driver used to control them, the same way ftp, http, etc are all served by different daemons.

The socket layer is also in resources, and can provide external socket based network access or local IPC with message passing. Different daemons will process writes or reads from their own directories provided here. Resources is thus very dynamic, because it represents accessing everything provided by device controllers and daemons.

Users are the discretization of anything on a per-user basis. This includes programs, libraries, configurations, etc. Root isn't a special user, it is just a member of every group, and owns the top level directories. Each user has a personal Configuration directory, to hold application configuration.

Groups are an abstraction, like many things in this vfs - they can either be policy controls or file systems to be merged into the homes of the users that are members of them. For example, all users are members of default, and new user creation would inherit all application defaults from the default group. Until a user overrides default configuration, you could just have a symlink to default configurations, avoiding some redundancy. Any user who inherits a configuration from default could also have systemwide configuration changed to match. You could even create a default user to force usage of applications as default. Thus, if you ran something as default, you would always run it in its default configuration, and if a user doesn't have execute privileges on something they might have to run it as default. Sounds very nice in a corporate or locked down setting. I parethensize guest with default, because in general you want some "base" user everyone else inherits from. If you have a public user, that might be the guest account, or it might be a dedicated default account. Applications installed to this user would thus be accessable from everyone, and if they have execute privlidges in that user they could then have their own configurations and states stored locally for applications in one place. 

Likewise, libraries could be treated the same way. The default or guest user could have their ~/libs as the fallback of all other library searches through any other user and any groups they are members of (that act as skeleton users). If you don't have a dedicated guest or default user, you could have the default group be its own filesystem containing a libs folder to search on, as could any other group. The idea here is that the user and group policy holds that you have a cascade search pattern from the perspective of a user - first the user itself, then the groups it is a member of in some profile defined precedence. This has the nice capacity to run applications, like in Linux, in user sandboxes. If the user has no grooup policy outside itself, and has all the applications it needs local to itself with any libraries, you could in effect jail and sandbox that session so it can't effect other users. You could even give it no access pirivlges to other top level directories to prevent it from having any outside interaction.

 This also has a nice effect of providing easy mandatory access control - you can have default MAC in the default group, and per-user execution control for the things they are groups of, and elevated access control in the root account. I would definitely expect any next-gen OS to have MAC and security at the deepest levels, including the filesystem - that is why this VFS has per-user and per-application views of the environment.

Devices are the hardware components of the system to be accessible in their hardware form by daemons to control them. Daemons can individually publicize the control directories to other processes so they can either hide or show themselves. They can make virtual writable or read only files for block IO directly with them - the idea is that "displays" and "accelerators" would provide the resources for a display manager to provide a graphical environment, by showing a display accelerator (GPU) and any screens it can broadcast to (even networked ones (provided by link), which might be found under /Network/miracast/... as well).

System is another abstraction, provided by the kernel or any listening daemons on it. You can expect hardware devices to be shown here, including hardware disks to mount, or network controllers to inhereit. Since resources is an abstraction, hardware controllers for these devices use the System devices folder to access them, and their memory. In practice, a normal user shouldn't need a view on System at all, since application communication should be done over sockets, so /proc is only for the purpose of terminating other processes. An application can have a view of /proc to show itself, its children, and anything that makes itself visible. You shouldn't need signals, since with the socket layer you can just write a signal message to an application. The difference is rather than having dedicated longjumps to handle signals, an application needs some metric of processing the messages it receives. I think it is a better practice than having an arbitrary collection of signals that may or may not be implemented in program logic and have background kernel magic going on to jump a program to execute them.

I think this is much better than what we have in any OS, even Plan 9. Even if you don't consider a generic user, from a sysadmin standpoint, discretizing the difference between users, groups, and resources is a useful abstraction. I'd almost consider moving System itself into resources, since it is just the kernel providing utilities itself. You might want to allow applications to generate their own /Resources/ directories, maybe under a user subdirectory, to allow even more generic sharing and access to other processes goods.

No comments:

Post a Comment