== Some ways to implement _/dev/fd_ in Unix kernels The idea of _/dev/fd_, which gives filesystem names to file descriptors, is the core of [[the modern implementation of process substitution ProcessSubstitutionWhyLate]]. There are several ways to implement this idea in the Unix kernel, starting from an old, simple, and brute force method to the modern methods that generally use some form of [[virtual filesystem VFSImportance]] for reasons that we'll get to. The simple but brute force way to implement _/dev/fd_ is with a real directory containing a bunch of miscellaneous [[character devices https://en.wikipedia.org/wiki/Device_file#Character_devices]], somewhat similar to _/dev/null_. Inside the kernel, the device driver for these miscellaneous devices can arrange to do the necessary magic when they're opened, including failing to open if your process doesn't have that particular file descriptor. This implementation has been possible for a very long time (since before V7 Unix), but it has two drawbacks. First, the _/dev/fd_ directory has to contain character device inodes for all of the potentially available file descriptors, regardless of whether or not the current process has those file descriptors available. Second, you potentially need a lot of minor device numbers, since you need one minor device number for every potential file descriptor number. Together, these two issues generally made this brute force approach unpopular and, I believe, pretty much never implemented in Unix. The closest people came was _/dev/stdin_, _/dev/stdout_, and _/dev/stderr_, which were sometimes implemented this way. Having only these three common file descriptors available wasn't anywhere near as useful, but it could be a lot more feasible. The second possible approach is to have _/dev/fd_ be a virtual filesystem but the nodes in the filesystem be miscellaneous character devices. Modern Unixes generally allow really large minor device numbers, so that side's not a problem, and as a virtual filesystem _/dev/fd_ can materialize only the file descriptors that the current process actually has. I'm not certain if anyone actually implements _/dev/fd_ this way. Although FreeBSD can sometimes have character devices appear in _/dev/fd_, I think that FreeBSD's [[fdescfs https://www.freebsd.org/cgi/man.cgi?query=fdescfs&sektion=5&format=html]] is implemented differently and the character device _stat()_ result is basically an illusion. (For FreeBSD fdescfs, see [[``fdesc_vnops.c'' https://github.com/freebsd/freebsd-src/blob/main/sys/fs/fdescfs/fdesc_vnops.c]].) The third approach is to have both _/dev/fd_ and _/dev/fd/N_ be completely virtual, as a full virtual filesystem or as part of one. Modern Linux effectively works this way; _/dev/fd_ is a symbolic link to _/proc/self/fd_, which is a [[procfs https://man7.org/linux/man-pages/man5/proc.5.html]] directory with magical contents. Linux makes this very magical; the files in /proc/[pid]/fd are nominally symbolic links (which is what _stat()_ and _ls_ will report), but when you open them they have special behavior instead of being followed as normal symlinks would be. (We'll wave our hands about how the virtual filesystem reaches into the depths of the kernel to get access to your process's file descriptors. Let's just assume that the kernel developers make it all work.) Since both of the good approaches to _/dev/fd_ need some sort of virtual filesystem, both of them had to wait for [[the idea of the virtual filesystem switch to be invented VFSImportance]]. Before the days of the VFS, the only possible implementation of _/dev/fd_ was the unattractive brute force one of a real directory with a lot of character devices in it.