In UNIX systems, devices are represented as special files, or, more accurately, nodes. These special nodes provide a means of communication between userland programs and the kernel and, by extension, the hardware. All reads, writes, selects/polls, ioctls, opens, closes, seeks, etc. on these nodes are handled by device-specific kernel code. Devices, therefore device nodes, are divided into two main categories: character and block. Generally speaking, block device nodes are used for storage devices, such as /dev/hda1 and /dev/loop0, and can be mounted as directories in the filesystem. Character device nodes, on the other hand, represent all user input/output devices, like /dev/tty and /dev/psaux, plus any miscellaneous devices (/dev/apm_bios, /dev/rtc) that can't be classified as block devices. (Actually, there's a third device category, network devices, but UNIX doesn't use filesystem entries to represent network devices. Network devices are in a separate namespace entirely and are accessed via the socket calls. They aren't further discussed here.) In addition to being marked "char" or "block", devices are identified by their major and minor numbers, each of which is an eight-bit unsigned value that forms the link between the user-visible name ("/dev/random") and the appropriate kernel code (see "random_fops" in linux/drivers/char/random.c). The combination of char/block and the major number provides the general device type, such as "Pseudo-TTY masters" or "Floppy disks", and the minor number gives the exact device, like "First PTY master" or "Controller 0, drive 0, autodetect". See linux/Documentation/devices.txt for a full list. Device nodes are customarily stored in the /dev directory. In traditional UNIX systems, the system administrator creates them with the mknod command (see mknod(1) for more information), and the node's name, type, owner, group, permissions, major, and minor numbers are stored on disk. (Recent versions of Linux support extended attributes and access control lists.) Unfortunately, this leads to an extremely messy /dev directory structure, with inconsistent node names and a flat structure, all shackled by backward compatibility. /dev often contains hundreds if not thousands of device nodes, most of which don't actually map to supported or installed hardware but are simply there on the off-chance that they may some day be useful. Like the ioctl system, it looks ugly, but it does work surprisingly well. Linux 2.4 and up (plus older versions with the appropriate patches) correct the situation with the devfs system, in which the /dev directory is actually a special filesystem whose contents are generated and managed by the kernel rather than (or, in addition to) the system administrator. The most obvious advantage is /dev nodes only appear for devices actually supported by the running kernel, thus making the /dev directory listing far cleaner. As kernel modules are loaded and unloaded, device nodes appear and disappear. Using the module autoloading facility, kernel modules are automatically inserted into the running kernel when programs attempt to access /dev nodes not already present. Since user programs only care about the filename of a device node rather than its major and minor numbers, the devfs system can dynamically allocate major and minor numbers for nodes as they are created, and even then the major and minor numbers are just for show since devfs binds filenames rather than numbers to devices, avoiding unnecessary lookups and tables. The devfs system also provides a much nicer /dev directory structure, moving the myriad /dev/fd*, /dev/hd*, /dev/sd*, /dev/tty*, etc nodes into their own directories. If necessary, the devfsd program can be used to generate compatibility symlinks mapping from traditional /dev node names to the new devfs node names. For more information, see linux/Documentation/filesystems/devfs/README or http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html. Devfs is not without its problems, chief of which is the disappearance of its maintainer, so Linux 2.6 has yet another system to do essentially the same thing albeit in a different way with less policy placed in the kernel.