Almost all the files under /dev
are device files. Whereas reading and writing to a regular file stores data on a disk or other filesystem, accessing a device file communicates with a driver in the kernel, which generally in turn communicates with a piece of hardware (a hardware device, hence the name).
There are two types of device files: block devices (indicated by b
as the first character in the output of ls -l
), and character devices (indicated by c
). The distinction between block and character devices is not completely universal. Block devices are things like disks, which behave like large, fixed-size files: if you write a byte at a certain offset, and later read from the device at that offset, you get that byte back. Character devices are just about anything else, where writing a byte has some immediate effect (e.g. it's emitted on a serial line) and reading a byte also has some immediate effect (e.g. it's read from the serial port).
The meaning of a device file is determined by its number, not by its name (the name matters to applications, but not to the kernel). The number is actually two numbers: the major number indicates which driver is responsible for this device, and the minor number allows a driver to drive several devices¹. These numbers appear in the ls -l
listing, where you would normally find the file size. E.g. brw-rw---- 1 root disk 8, 0 Jul 12 15:54 /dev/sda
→ this device is major 8, minor 0.
Some device files under /dev
don't correspond to hardware devices. One that exists on every unix system is /dev/null
; writing to it has no effect, and reading from it never returns any data. It's often convenient in shell scripts, when you want to ignore the output from a command (>/dev/null
) or run a command with no input (</dev/null
). Other common examples are /dev/zero
(which returns null bytes ad infinitum) /dev/urandom
(which returns random bytes ad infinitum).
A few device files have a meaning that depends on the process that accesses it. For example, /dev/stdin
designates the standard input of the current process; opening from has approximately the same effect as opening the original file that was opened as the process's standard input. Somewhat similarly, /dev/tty
designates the terminal to which the process is connected. Under Linux, nowadays, /dev/stdin
and friends are not implemented as character devices, but instead as symbolic links to a more general mechanism that allows every file descriptor to be referenced (as opposed to only 0, 1 and 2 under the traditional method); for example /dev/stdin
is a symbolic link to /proc/self/fd/0
. See How does /dev/fd relate to /proc/self/fd/?.
You'll find a number of symbolic links under /dev
. This can occur for historical reasons: a device file was moved from one name to another, but some applications still use the old name. For example, /dev/scd0
is a symbolic link to /dev/sr0
under Linux; both designate the first CD device. Another reason for symbolic links is organization: under Linux, you'll find your hard disks and partitions in several places: /dev/sda
and /dev/sda1
and friends (each disk designated by an arbitrary letter, and partitions according to the partition layout), /dev/disk/by-id/*
(disks designated by a unique serial number), /dev/disk/by-label/*
(partitions with a filesystem, designated by a human-chosen label); and more. Symbolic links are also used when a generic device name could be one of several; for example /dev/dvd
might be a symbolic link to /dev/sr0
, or it might be a link to /dev/sr1
if you have two CD readers and the second one is to be the default DVD reader.
Finally, there are a few other files that you might find under /dev
, for traditional reasons. You won't find the same on every system. On most unices, /dev/log
is a socket that programs use to emit log messages. /dev/MAKEDEV
is a script that creates entries in /dev
. On modern Linux systems, entries in /dev/
are created automatically by udev, obsoleting MAKEDEV
.
¹ This is actually no longer true under Linux, but this detail only matters to device driver writers.
The file descriptor 1 translates to the stdout FILE structure in the Kernel's Open Files Table.
This is a misunderstanding. The kernel's file table has nothing whatsoever to do with user-space file structures.
In any event, the kernel has two levels of indirection. There is the internal structure that represents the file itself, which is reference counted. There is an "open file description" that is reference counted. And then there is the file handle, which is not reference counted. The file structure points the way to the inode itself. The open file description contains things like the open mode and file pointer.
When you call close, you always close the file handle. When a file handle is closed, the reference count on its open file description is decremented. If it goes to zero, the open file description is also released and the reference count on the file itself is decremented. Only if that goes to zero is the kernel's file structure freed.
There is no chance for one process to release a resource another process is using because shared resources are reference counted.
Best Answer
All four of
/dev/fd/0
,/dev/stdin
,/proc/self/fd/0
and/dev/pts/2
are file names, as are/////dev/../dev/fd//0
,/bin/sh
,/etc/fstab
,/fioejfoeijf
, etc. All but that last example are likely to be the name of an existing file on your machine. A file name is a string that can designate a file on your filesystem; under Linux, any string that does not contain a null byte and that is at most 4096 bytes long is a valid file name. Many of these names are equivalent, e.g./bin/sh
is equivalent to///bin/sh
,/bin/../bin/sh
(assuming/bin
is an existing directory), etc. All the examples I've given so far are absolute file names; there are also relative file names, which do not begin with a/
and whose meaning depends on the current directory.The terminology surrounding file names isn't universal; sometimes “file name” means a full path to a file, and sometimes it means the name of a directory entry. The POSIX terminology is “filename” or “pathname component” for the name of a directory entry, and “pathname” for a full path.
A file descriptor designates an open file in a particular process. The kernel maintains a table of file descriptors for each process. Each entry in the file descriptor table indicates what to do if the process requests reading, writing and other operations on the file descriptor.
File descriptors may correspond to a file and have an associated name, but not all of them do. For those that do, the file may be a regular file, a directory, a device file or a named pipe (also called FIFO) (the kind created by
mkfifo
); some systems have further possibilities such as Unix sockets and doors. Examples of file descriptors that don't have an associated named file include pipes (the kind created by thepipe
system call) and networking sockets./dev/fd/0
,/dev/stdin
and/proc/self/fd/0
are file names (all equivalent) with a peculiar meaning: they all designate whichever file is currently accessed via file descriptor 0. When a process opens these, the kernel copies the entry with index 0 in the file descriptor table to a new descriptor. Opening any of these files is equivalent to callingdup(0)
. The named files are a way to indirectly get a process to use one of its already-open files rather than open a new file; they are mostly useful to pass on a program's command line, where the program expects the name of a file to open.