Devices roughly fall into two categories: character devices and block devices. Character devices deal with IO on a character by character basis. The most obvious example is a keyboard, where every key generates a character on the device. The mouse is another. Every motion or button click sends a character to the /dev/mouse device.
Block devices read data in larger chunks. Data storage devices, such as IDE hard drives (/dev/hd), SCSI hard drives (/dev/sd), and CD-ROMs (/dev/cdrom) are block devices. IO interactions with block devices transact with chunks of data, which allows large quantities of data to be moved back and forth more efficiently.
Device names: Devices are often named after the equipment they represent. Devices named /dev/fb represent the frame buffers for graphics. /dev/hd devices represent IDE hard disks. In some cases, symbolic links are employed to clarify what a device is, for example /dev/mouse, the device representing a mouse, may be linked to a serial, USB or PS2 device, depending on the physical hardware. The symbolic link makes it easier for both humans and machines to figure out which device is the mouse.
In some cases, there may be multiple devices of the same type. For instance, a machine may have two ATAPI CD-ROMS. Two devices will be used -- one for each device. For instance, /dev/cdrom0 will be the first CD-ROM, and /dev/cdrom1 will be the second.
The naming gets a little more confusing in cases like hard disks. A hard disk device name is composed of the type of disk followed by the position of the disk, and then the disk partition. The first hard disk may be called /dev/hda, with the "hd" part indicating that it is an IDE hard disk, and the "a" part indicating that it is the first hard disk. /dev/hdb would then refer to the second hard disk. Each hard disk is divided into partitions. The first partition on the first hard drive would be /dev/hda1, where the one at the end indicates the location of the partition. Note that where some devices (like /dev/cdrom0) may begin the index from 0, devices with partitions typically begin from 1. So a listing of all of the partitions on the two IDE hard drives on my computer might look like this:
/dev/hda /dev/hda1 /dev/hda2 /dev/hda3 /dev/hda4 /dev/hdb /dev/hdb1 /dev/hdb2 /dev/hdb3
SCSI hard disks use /dev/sd instead of /dev/hd, but otherwise the convention is the same. /dev/sda1 refers to the first partition on the first SCSI hard disk. Special Devices: There are a few special devices that come in useful every once in a while, /dev/null, /dev/zero, /dev/full, and /dev/random.
The null device, /dev/null, is sort of the "trash" device. Put simply, things that go in never come out. Many times, some program may generate unnecessary output. Shell scripts often employ /dev/null to prevent the user from having to see unnecessary output generated by utilities that it calls. The example below inserts a kernel module and sends the output from modprobe to /dev/null.
$ modprobe cipher-twofish > /dev/null
Closely related to /dev/null is /dev/zero. Like /dev/null, it can be used to dump unwanted data, but reads from /dev/zero return \0 characters (reads from /dev/null return end-of-file characters). For this reason, /dev/zero is commonly used to create empty files.
dd if=/dev/zero of=/my-file bs=1k count=100
The command above will create a file 100k in size, full of null characters.
/dev/full mimics a full device. Writing to /dev/full will generate an error. The full device is useful when testing how an application will act when it accesses a device that is full.
$ cp test-file /dev/full cp: writing `/dev/full": No space left on device $ df -k /dev/full file system 1k-blocks Used Available Use% Mounted on /dev/full 0 0 0 -
The random devices, /dev/random and /dev/urandom, generate "random" data. Though the output to both may appear to be completely random, /dev/random is actually more random than /dev/urandom. /dev/random generates random characters based on "environmental noise" that is not determinable. Since there is only a limited supply of this random noise, the /dev/random device is slow, and may pause in order to collect more data. /dev/urandom uses the same pool of noise as /dev/random, but if it runs out of random data, it generates pseudo-random data. This makes it faster, but less secure. Old /dev File System: In the past, the /dev file system has been part of the normal file system. It consisted of special files created once (usually when the system was installed) and stored on a hard disk.
On systems with this setup, the /dev file system needed to contain entries for any devices that might be connected to that computer. Consequently, /dev was very large, having entries for multiple hard drives, consoles, floppy drives, etc. Earlier, we saw the list of hard drive partitions on hdb. Under the old /dev file system, entries would exist for /dev/hdb1 through /dev/hdb11. In order to figure out which devices actually mapped to partitions on the device (remember, I only have three partitions on my hdb drive), some utility would have to be used to determine which devices were valid. the command "file -s hdb*" was one way to figure that sort of thing out, printing something like this:
$ file -s /dev/hdb? /dev/hdb1: Linux/i386 ext2 file system /dev/hdb2: Linux/i386 ext2 file system /dev/hdb3: Linux/i386 ext2 file system /dev/hdb4: empty /dev/hdb5: empty /dev/hdb6: empty /dev/hdb7: empty /dev/hdb8: empty /dev/hdb9: empty
If a given device file wasn't already present, it had to be created by mknod or another program (like MAKEDEV). Though the "old way" worked, it was complex, and got tedious to manage. DevFS: In the 2.4 kernel tree, an alternative to the cumbersome disk-based /dev file system was introduced. The alternative, DevFS, incorporated new device handling code into the kernel. In DevFS, the /dev file system is created during each boot-up cycle and stored in RAM, instead of on the hard disk. Under this model, there is no need to maintain a list of all possible devices, and when new devices are added to hardware, the kernel just makes an entry for it in /dev. In the occasional cases where devices need special configuration to appear correctly in DevFS, there is a configuration file usually stored in /etc/devfsd.conf.
/proc: A file system for processes
Processes: At any given time, Linux will have many processes running at once. Some, such as window managers, email clients, and Web browsers, will be visible to the end user. Others, like servers and helper processes, are not immediately visible, but run in the background, handling tasks that do not require the user"s interaction. Running "ps -ef" in a shell will print a list of all the currently running processes. It should look something like this:
$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 11:08 ? 00:00:04 init root 2 1 0 11:08 ? 00:00:00 [keventd] root 3 0 0 11:08 ? 00:00:00 [ksoftirqd_CPU0] root 4 0 0 11:08 ? 00:00:00 [kswapd] root 5 0 0 11:08 ? 00:00:00 [bdflush] root 6 0 0 11:08 ? 00:00:00 [kupdated] root 8 1 0 11:08 ? 00:00:00 [kjournald] root 86 1 0 11:08 ? 00:00:00 /sbin/devfsd /dev root 165 1 0 11:09 ? 00:00:00 [kjournald] root 168 1 0 11:09 ? 00:00:00 [khubd] root 294 1 0 11:09 ? 00:00:00 [kapmd] root 515 1 0 11:09 ? 00:00:00 metalog [MASTER] root 521 515 0 11:09 ? 00:00:00 metalog [KERNEL] root 531 1 0 11:09 ? 00:00:00 /sbin/dhcpcd eth0 /etc/X11/fs/config -droppriv -user xfs root 572 1 0 11:09 ? 00:00:00 /usr/kde/2/bin/kdm root 593 572 2 11:09 ? 00:04:27 /usr/X11R6/bin/X -auth /var/lib/kdm/authfiles/A:0-25pIgI root 644 1 0 11:09 vc/1 00:00:00 /sbin/agetty 38400 tty1 linux root 1045 572 0 12:16 ? 00:00:00 -:0 mbutcher 1062 1045 0 12:16 ? 00:00:00 /bin/sh /etc/X11/Sessions/kde-2.2.2 mbutcher 1091 1062 0 12:16 ? 00:00:00 /bin/bash --login /usr/kde/2/bin/startkde mbutcher 1132 1 0 12:16 ? 00:00:00 kdeinit: Running... mbutcher 1157 1132 0 12:16 ? 00:00:01 kdeinit: kwin mbutcher 1159 1 0 12:16 ? 00:00:07 kdeinit: kdesktop mbutcher 1168 1 0 12:16 ? 00:00:00 kdeinit: kwrited mbutcher 1171 1168 0 12:16 pty/s0 00:00:00 /bin/cat mbutcher 1173 1 0 12:16 ? 00:00:00 alarmd mbutcher 1207 1132 0 12:23 ? 00:00:08 kdeinit: konsole -icon konsole -miniicon konsole mbutcher 1219 1207 0 12:23 pty/s2 00:00:00 /bin/bash mbutcher 1309 1260 0 13:48 pty/s3 00:00:01 vi dev-and-proc.html root 1314 1220 0 14:03 pty/s2 00:00:00 ps -ef
Many of the tasks in the output to ps are background processes. Those that are contained in square brackets are kernel processes. Only a few, like the kde processes and the entries toward the end, are processes that I interact with.
In order to manage the system, the kernel must keep track of every process running, including itself. Many user-level applications, too, must be able to find out what processes are running ("ps" is a good example. "top" is another.). The /proc file system is where the kernel stores information about processes.
Like DevFS, /proc is stored in memory, rather than on disk. If you look at the file /proc/mounts (which lists all of the mounted file systems, much like the "mount" command), you should see a line in it that looks like this:
proc /proc proc rw 0 0
/proc is controlled by the kernel and does not have an underlying device. Because it contains mainly state information controlled by the kernel, the most logical place to store the information is in memory controlled by the kernel.
Information about running processes: To keep track of processes, the kernel assigns each one a Process ID (PID) number. Running the command "ps -ef" as we did above, will print a list of all running processes ordered by the PID number (which is in the second column). The /proc file system stores information about each PID.
In /proc, many of the directory names are numbers. These directories correspond to PID numbers. Inside of the directories are files that provide important details about the state, environment, and details regarding a process. In the output of ps (above), there was a line that read:
mbutcher 1219 1207 0 12:23 pty/s2 00:00:00 /bin/bash
This process is running the bash shell, and has PID 1219. The directory /proc/1219 contains information about this process.
$ ls /proc/1219 cmdline cpu cwd environ exe fd maps mem root stat statm status
The file "cmdline" contains the command invoked to start the process. The "environ" file contains the environment variables for the process. "status" has status information on the process, including the user (UID) and group (GID) identification for the user executing the process, the parent process ID (PPID) that instantiated the PID, and the current state of the process,such as "Sleeping" or "Running."
$ cat status Name: bash State: S (sleeping) Tgid: 1219 Pid: 1219 PPid: 1207 TracerPid: 0 Uid: 501 501 501 501 Gid: 501 501 501 501 FDSize: 256 Groups: 501 10 18 VmSize: 2400 kB VmLck: 0 kB VmRSS: 1272 kB VmData: 124 kB VmStk: 20 kB VmExe: 544 kB VmLib: 1604 kB SigPnd: 0000000000000000 SigBlk: 0000000080010000 SigIgn: 8000000000384004 SigCgt: 000000004b813efb CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000
Every process directory also has a couple symbolic links. "cwd" is a link to the current working directory for that process. "exe" is a link to the executable program the process is running, and "root" links to the directory the process sees as its root directory (usually "/"). The directory "fd" contains a list of symbolic links to the file descriptors that the process is using.
There are other files in the process directory that provide information about everything from processor and memory usage to the amount of time a process has been running. Most of these files are documented in the kernel source under "Documentation/file systems/proc.txt" and are available as a man page -- "man proc."
Kernel Information: In addition to storing information about specific processes, the /proc file system contains a great deal of information generated by the kernel itself to describe the state of the system.
The kernel and its modules may generate files in /proc to provide information about their current state. For instance, /proc/fb provides information about the currently available frame buffer devices (frame buffers are most often used to display a boot logo).
$ cat fb 0 VESA VGA
Note that the 0 refers to the frame buffer"s index, and corresponds to the device /dev/fb0. If I had a second framebuffer, the proc entry would also contain a line starting with a 1, corresponding to /dev/fb1. Often, proc data will refer to (and explain) entries in /dev.
Lots of information about hardware is stored in /proc. The file /proc/pci has info about every PCI device detected on the system. Running the command "lspci" ought to generate data that looks similar to this file, as it uses /proc/pci as its source of information. /proc/bus contains directories for various bus architectures (PCI, PCCard, USB), which in turn contain information about the devices connected via those buses. Various network information and statistics are stored in /proc/net. Information about hard disks is stored in /proc/ide and /proc/scsi, depending on the hard drive type. /proc/devices lists all of the devices (divided into the "block" and "character" categories) available on the system.
$ cat /proc/devices Character devices: 1 mem 2 pty/m%d 3 pty/s%d 4 tts/%d 5 cua/%d 7 vcs 10 misc 14 sound 29 fb 116 alsa 162 raw 180 usb 226 drm 254 pcmcia Block devices: 1 ramdisk 2 fd 3 ide0 22 ide1
There are many more files in /proc than can be covered here. Each kernel may, in fact, have different entries depending on what was built into the kernel, what hardware and software is present, and what state the computer is currently in. Some of these files are clearly meant for a machine to read, but others offer information that is intuitive. Most of these files are documented in various places in the kernel documentation. A good starting point in the kernel source is Documentation/file systems/proc.txt.
Interacting with processes via /proc: Some files in proc are not just for reading. Writing to them may alter the state of the kernel. Looking to see what's in a file in /proc is usually harmless, but writing to files without being sure of the outcome can be dangerous. Nevertheless, sometimes writing to /proc is the only way to communicate with the kernel.
For instance, in recent versions of the kernel, there is the option to include a kernel-level high-performance Web server (khttp). Because starting a Web server by default can be a security risk, khttp requires explicit startup through messages sent to a file in proc.
echo 1 > /proc/sys/net/khttpd/start
When the kernel sees the contents of /proc/sys/net/khttps/start change from 0 (the default) to 1, it starts the khttpd server.
There are dozens of other configurable parameters in /proc -- some for tuning hardware, others for managing the kernel internals. Almost all of them, though, are low level and can cause bad things to happen if set to the wrong values. As a rule of thumb, /proc entries should not be changed unless you know what you are doing.
Conclusion
/proc and /dev provide file-based interfaces to the internals of Linux. They
assist in determining the configuration and state of various devices and processes
on a system. They provide capabilities necessary to make the operating system
easy to upgrade, analyze, debug, and run. Understanding and applying knowledge
of these two file systems is key to making the most of your Linux system.