You may have heard the phrase "Everything is a file" in relation to how things work in Linux or Unix.
Normal files
What's meant by this, is that most things in Linux share something in common with files.
For example, regular files are opened with the open(2) system call,
but so are directories with the O_DIRECTORY
flag, which is how the
standard library's opendir(3) works.
Symbolic links aren't generally openable, but every file path is openable
with the O_PATH
option, which along with directory file descriptors,
can be passed to system calls like fchdir(2) or the *at(2)
family of system calls.
Devices
Along with all the normal files, there's also special device files in
/dev
.
There's block devices, like /dev/sda
, which represent your physical
devices. These let you store persistent data, usually by mounting them as a file system with the mount(2) system call.
Because block devices are files, they can be copied like any normal file to make backups.
There's also a variety of character devices, you are unlikely to need to
know all of them, but there's a hand-full of useful ones that everyone
should be aware of, like /dev/null
, which allows you to discard all
writes to a file, everywhere a file is needed, but you don't need the
output that would be written there.
There's also /dev/full
, which can be used to test how a program handles
low space conditions, by always saying that there's no space to write
to the file.
/dev/zero
produces an inexhaustible supply of zero-bytes, which can be convenient for obliterating the contents of another file.
/dev/random
and /dev/urandom
are the traditional interfaces to the
random number generator, though getrandom(2) is a recent addition,
which doesn't require a file to be opened, so it's available when /dev
is not reachable, and when you are at your file descriptor limit.
There's also many files in /dev
that only work with open(2),
close(2) and the device-specific ioctl(2) system call, which is
not massively like regular files, but there is still value in sharing
the same ownership semantics.
Sockets
There is also the mkfifo(3) system call, which creates a "named pipe", which is an alternative way of creating pipes to the pipe(2) system call, which is often easier to use to have two processes have either end of a pipe.
Speaking of which, the read end of a pipe can be read like any regular file, and the write end can be written like any regular file. This is how pipelines work.
unix(7) sockets also appear on the file system, and unlike pipes, the resultant file descriptor can be both read from and written to.
There's also a variety of other types of sockets that can't be opened from the file system, typically created with the socket(2) or socketpair(2) system calls.
Other files
There's plenty of other file-like objects that are made availably by more esoteric system calls.
There's the memfd_create(2) system call for creating anonymous memory maps, which can later be sealed and passed to another process, as a way of sharing data structures between processes.
Sealing the file descriptor is required so that the data can safely be passed around, since if the receiver can't trust that it won't be modified by the sender, then it can't safely use it, since you could change it while it is being used.
Most system calls that handle resources will reference them with a file descriptor, so an exhaustive list would be both boring and very long, but if you're interested in learning about others, just browse man7.org.