2.3 Devices

2.3 Devices

You will find it very easy to manipulate devices on a Unix system because the kernel normally presents the device I/O interface to system and user processes as files. Not only can a programmer use regular file operations to work with a device, but some devices are also accessible to standard programs like cat, so you don't have to be a programmer to use a device. Linux uses the same design of device files as other Unix flavors, but device filenames and functionality vary among flavors.

Linix device files are in the /dev directory, and running ls /dev reveals that there are more than a few files in /dev. So how do you work with devices?

To get started, consider this command:

echo blah blah > /dev/null

Like any command with redirected output, this sends some stuff on the standard output to a file. However, the file is /dev/null, a device, and the kernel decides what to do with any data written to this device. In the case of /dev/null, the kernel simply ignores the data (making /dev/null a bitbucket). Of course, other devices actually do things, such as /dev/dsp, which plays a sound if you send appropriate output there (for example, cat blab.wav > /dev/dsp).

To identify a device, use ls -l to get a long listing and look at the permissions. Here are four examples:

brw-rw----   1 root   disk     3,  65 Jul 20  1998 hdb1
crw-rw-rw-   1 root   root     1,   3 Jul 20  1998 null
prw-r--r--   1 root   root          0 Mar  3 19:17 gpmdata
srw-rw-rw-   1 root   root          0 Dec 18 07:43 log

Notice the very first character of each line in the listing. If this character is b, c, p, or s, then the file is a device. These letters stand for block, character, pipe, and socket, respectively:

  • Block device Programs access data in a block device in fixed chunks. The hdb1 in the preceding example is a disk device. Because disks break down into blocks of data, it is only natural that a disk be a block device. A block device's total size is fixed, and a program has random access to any block in the device.

  • Character device Character devices work with data streams. You can only read characters from or write characters to these devices, like /dev/null in the previous example. Character devices don't have a size; when you read from or write to a character device, the kernel usually performs a read or write operation on the device, leaving no record of the activity inside the kernel. Printers are character devices, and after the kernel sends data to a printer, the responsibility for that data passes to the printer; the kernel cannot back up and reexamine the data stream.

  • Pipe device Named pipes are like character devices, but there is another process at the other end of the I/O stream instead of a kernel driver. An example of such a process is gpm, a program that can duplicate mouse events and send them to the named pipe /dev/gpmdata for use by other programs.

  • Socket device Sockets are special-purpose I/O files offering a type of network interface. For example, the gpm program accepts control commands through the /dev/gpmctl socket. You don't need to worry about sockets if you're not a network programmer.

The numbers before the dates in the first two lines of the previous listing are the major and minor device numbers that help the kernel identify the device. Similar devices usually have the same major number, such as hda3 and hdb1 (these are both hard disk partitions).

2.3.1 dd and Devices

The name dd stands for convert and copy. dd is extremely useful when working with block and character devices. This program's sole function is to read from an input file or stream and write to an output file or stream, possibly doing some encoding conversion on the way. It was originally developed for reblocking.

dd copies data in blocks of a fixed size. Here is an example of using dd with a character device and some common options:

dd if=/dev/zero of=new_file bs=1024 count=1

As you can see, the dd option format is different than the option formats of most other Unix commands; rather than use the - character to signal an option, you name an option and set its value to something with the = sign. The preceding example copies a single 1024 -byte block from /dev/zero (a continuous stream of zero bytes) to the file new_file. These are the important dd options:

  • if=file The input file. The default is the standard input.

  • of=file The output file. The default is the standard output.

  • bs=size The block size; dd reads and writes this many bytes of data at a time. To abbreviate large chunks of data, you may use b and k to signify 512 and 1024 bytes. Therefore, the example above could read bs=1k instead of bs=1024.

  • ibs=size, obs=size The input and output block sizes. If you can use the same block size for both input and output, use the bs option, but if this is impossible, then use ibs and obs for input and output, respectively.

  • count=num The total number of blocks to copy. When working with a huge file, or with a device that supplies an endless stream of data (like /dev/zero), you want dd to stop at a fixed point. Otherwise you could waste a lot of disk space, CPU time, or both. count can be used in conjunction with the skip parameter to copy a small piece out of a large file or device.

  • skip=num Skip past the first num blocks in the input file or stream; do not copy them to the output.

2.3.2 Device Name Summary

Sometimes it is difficult to find the name of a device (for example, when partitioning a disk). Here are two tactics for finding out:

  • Guess the name from the output of the dmesg command (which prints out the last few kernel messages) or the kernel system log file (see Section 4.1); this output might contain a description of the devices on your system.

  • Run cat /proc/devices to see the block and character devices for which your system currently has drivers. Each line consists of a number and name. The number is the major number of the device described in Section 2.3. If you can guess the device from the name, look in /dev for the character or block devices with the corresponding major number, and you've found the device files.

Neither method is terribly reliable, especially because the kernel does not load certain device drivers until you try to use them. (Section 10.8 has information on the driver-loading mechanism.)

The following sections list the most common Linux devices and their naming conventions.

Hard Disks: /dev/hd*

These are the ATA (IDE) disks and partitions. All are block devices.

Two example names are /dev/hda1 and /dev/hdb. The letter after hd identifies the disk, and the number represents the partition. A device without a number is a device for an entire disk. (Information on how to partition disks is in Section 2.3.4. To connect disks to your current systems, start at Section 2.4.3.)

SCSI Disks: /dev/sd*

SCSI disks carry the names /dev/sda, /dev/sdb, and so on, and the disks work much like their ATA counterparts, although the SCSI disk names do not directly correspond to a SCSI host controller and target. Linux assigns the devices in the order that it encounters the disks.

For example, if you have two SCSI controllers, scsi0 and scsi1, with disks at scsi0 targets 0, 3, and scsi1 target 1, the device assignments are as shown in Table 2-1.

Table 2-1: Sample Device Assignments



Device Assignment










This naming scheme can cause problems when reconfiguring hardware. Let's say that scsi0 target 3 explodes and you must remove the disk so that the machine can work again. When you do so, scsi1 target 1 moves to /dev/sdb from /dev/sdc, and you have to change the fstab file (described later in this chapter).

Terminals: /dev/tty*, /dev/pts/*, /dev/tty

Terminals are devices for moving characters between the system and an I/O device, usually for text output to a terminal screen. The terminal device interface goes back a long way, to the days when terminals were typewriter-based devices.

Pseudo-terminal devices are emulated terminals that understand the I/O features of real terminals, but rather than talk to a real piece of hardware, the kernel presents the I/O interface to a piece of software, such as a shell window.

Two common terminal devices are /dev/tty1 (the first virtual console) and /dev/pts/0 (the first pseudo-terminal device).

The /dev/tty device is the controlling terminal of the current process. If a program is currently reading from and writing to a terminal, this device is a synonym for that terminal. A process does not need to be attached to aterminal.

Serial Ports: /dev/ttyS*

Serial ports are special terminal devices. You can't do much on the command line with serial port devices because there are too many settings to worry about, such as baud rate and flow control.

The port known as COM1 on Windows is /dev/ttyS0, COM2 is /dev/ttyS1, and so on. For add-in modem cards, check the output of the dmesg command for the port assignment.

Floppy Disks: /dev/fd*

Section 11.1.1 covers operations on these block devices. The 3.5-inch floppy on most modern systems is /dev/fd0.

Parallel Ports: /dev/lp0, /dev/lp1

These unidirectional port devices correspond to LPT1 and LPT2 in Windows. You can send files (such as a file to be printed) directly to a parallel port with the cat command, but you might need to give the printer an extra form feed or reset afterward.

The bidirectional parallel ports are /dev/parport0 and /dev/parport1.

Audio Devices: /dev/dsp, /dev/audio, /dev/mixer, /dev/snd/*, etc.

Linux has two different sets of audio devices. There are separate devices for the OSS (Open Sound System) and the newer ALSA (Advanced Linux Sound Architecture) system interface. Linux systems that use ALSA usually contain OSS compatibility devices, because most applications still use OSS. Some rudimentary operations are possible with the dsp and audio devices that belong to OSS. As mentioned earlier, the computer plays any WAV file that you send to /dev/dsp. However, it may not sound right due to frequency mismatches. The ALSA devices are in the /dev/snd directory, but you can't do much by redirecting standard I/O to them.


The play and aplay programs can play samples from the command line. To adjust the volume and mixer settings, aumix and alsamixer are available on most systems.

2.3.3 Creating Device Files

To create one individual device file, use mknod. You must know the device name as well as its major and minor numbers. For example, if you remove /dev/hda2 by accident, you can create it again with this command:

mknod /dev/hda2 b 3 2

The b 3 2 specifies a block device with a major number 3 and a minor number 2. For character or named pipe devices, use c or p instead of b.

The mknod command is useful only for creating the occasional missing device or named pipe. As you upgrade your system and add device drivers, you may need to create entirely new groups of devices. Because there are so many devices, it's better to use the MAKEDEV program (found in /dev) to create groups of devices. Device groups can be named after the common part of several device names, such as hda, or they can have a completely separate name, such as std-hd. For example, to create all devices beginning with hda, run this command:

/dev/MAKEDEV hda


The MAKEDEV command is harmless if the devices already exist on your system.


Before you go to the trouble of making any device files, you should see whether you're running devfs, an automatic device-file generation system. The easiest way to check for devfs is to run mount and look for devfs in the output.

If your system runs devfs, you should not have to create missing device files because the kernel maintains the directory of available device files. Linux kernels typically configure devfs at boot time, starting a special auxiliary system program called devfsd that gives the administrator the ability to customize the device system.


devfs was an experimental feature in older Linux kernels, but is classified as obsolete in the latest Linux kernels.

2.3.4 Partitioning Disk Devices

Before you can use a new disk on your system, you need to know how to partition disks with their device files. If you've never worked with partitions before, don't worry. A disk partition is just a piece of the disk dedicated to one purpose, such as a specific directory tree. On PCs, partitions have numbers starting at 1.

To get started, identify the disk device that you want to partition. Most PCs have two ATA interfaces, called primary and secondary interfaces, and each interface can have a master and slave disk, for a total of four disk devices. The standard ATA disk assignments are as follows:

  • /dev/hda Master disk, primary interface

  • /dev/hdb Slave disk, primary interface

  • /dev/hdc Master disk, secondary interface

  • /dev/hdd Slave disk, secondary interface

There are several partitioning utilities, but the most simple and direct is fdisk. To get started, run fdisk dev (where dev is one of the devices listed above), then print the current partition list with p.

Here is sample from fdisk output for a device with three partitions, two containing filesystems and one with swap (see Section 2.5 for more information on swap partitions).

Disk /dev/hda: 240 heads, 63 sectors, 2584 cylinders
Units = cylinders of 15120 * 512 bytes

Device Boot       Start       End    Blocks   Id  System
/dev/hda1             1       136   1028128+  83  Linux
/dev/hda2           137       204    514080   82  Linux swap
/dev/hda3           205      2584  17992800   83  Linux

Partition dimensions are usually in units of cylinders. Each partition has a start and end cylinder, determining its size, but the amount of space per cylinder varies depending on the disk. The second line in the preceding output shows you the cylinder size, but you don't need to do any weird computations to create partitions.

When creating a new partition, you only need to know the starting cylinder. Cylinders do not overlap in PC partitions, so if you're partitioning a disk, pick the first available cylinder in the fdisk partition list output. In the preceding example, you would choose 2585 as the starting cylinder.

Each partition also has a system ID, a number that represents an operating system. Linux uses 83 for partitions containing files and 82 for Linux swap.

When you partition a new disk, there is usually one partition on the disk already, containing some sort of variant on the FAT filesystem for Microsoft systems. If you want only a single partition on the disk, just change the system ID to Linux with the t command inside fdisk. However, if you want to customize the partitions, use d to delete any old partitions and n to add new ones.

fdisk is easy to use because each command steps you through the partition number and size. In addition, there is an important safety feature: fdisk does not actually change the partition table until you tell it to with the w command. If you're uneasy about your changes, or you were just testing something, use q to exit without altering the disk.

Here is an example of fdisk in action on a very small disk. Command input is in boldface:

# fdisk /dev/hdc

Command (m for help): p

Disk /dev/hdc: 2 heads, 16 sectors, 247 cylinders
Units = cylinders of 32 * 512 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/hdc1   *         1       494      7891+   1  FAT12

Command (m for help): d
Partition number (1-4): 1

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
Partition number (1-4): 1
Last cylinder or +size or +sizeM or +sizeK (1-247, default 247): 120

Command (m for help): t
Partition number (1-4): 1
Hex code (type L to list codes): 83

Command (m for help): p

Disk /dev/hdc: 2 heads, 16 sectors, 247 cylinders
Units = cylinders of 32 * 512 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/hdc1             1       120      1912   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional
Syncing disks.

When you write the partition table to the disk with the w command, fdisk tells the kernel to re-read the partition table from the disk and update the system's in-memory partition list (fdisk does not relay the new partition list directly to the kernel). Therefore, you should never write the partition table to a disk that already has a mounted (attached) filesystem; doing so risks damage to the filesystem.


The ioctl operation that causes the kernel to re-read the partition table can fail on rare occasions. If such a failure occurs, you need to reboot the system to get the kernel to see the changes.

After writing the partition table, a new list of partition tables should appear on the console. If you don't see this list, run dmesg to see the kernel messages and look at the end of the output. For the fdisk session earlier in this section, here is what you would see:

 hdc: hdc1

The hda indicates the disk that you repartitioned. The new partition list appears after the colon. For example, if you create three partitions on the disk, the output might appear as hdc: hdc1 hdc2 hdc3.


Looking at the fdisk session in this section, you may be wondering what the difference between a primary and an extended partition is. The standard PC disk-partitioning scheme originally only allowed a maximum of four partitions, 1–4. These are the primary partitions. If you want more partitions, fdisk can designate one of these primary partitions as an extended partition, allowing you to place subpartitions in the extended partition. Each of these subpartitions is called a logical partition.

After partitioning a disk, you're not quite ready to attach it to your system because you must put a filesystem on your partition(s) first.