6.3 Device Entries

A device entry is in many ways the same as a regular file. You can move it using the mv command and delete it using the rm command. If you try to copy a device entry using cp, though, you'll read bytes from the device (if the device supports reading) and write them to the destination file. If you try to overwrite a device entry, you'll write bytes to the corresponding device instead.

You can create a device entry in the file system using the mknod command (invoke man 1 mknod for the man page) or the mknod system call (invoke man 2 mknod for the man page). Creating a device entry in the file system doesn't automatically imply that the corresponding device driver or hardware device is present or available; the device entry is merely a portal for communicating with the driver, if it's there. Only superuser processes can create block and character devices using the mknod command or the mknod system call.

To create a device using the mknod command, specify as the first argument the path at which the entry will appear in the file system. For the second argument, specify b for a block device or c for a character device. Provide the major and minor device numbers as the third and fourth arguments, respectively. For example, this command makes a character device entry named lp0 in the current directory. The device has major device no. 6 and minor device no. 0. These numbers correspond to the first parallel port on the Linux system.

% mknod ./lp0 c 6 0 

Remember that only superuser processes can create block and character devices, so you must be logged in as root to invoke this command successfully.

The ls command displays device entries specially. If you invoke ls with the -l or -o options, the first character on each line of output specifies the type of the entry. Recall that - (a hyphen) designates a normal file, while d designates a directory. Similarly, b designates a block device, and c designates a character device. For the latter two, ls prints the major and minor device numbers where it would the size of an ordinary file. For example, we can display the block device that we just created:

% ls -l lp0 
crw-r-----    1 root     root       6,   0 Mar  7 17:03 lp0 

In a program, you can determine whether a file system entry is a block or character device and then retrieve its device numbers using stat. See Section B.2, "stat," in Appendix B, for instructions.

To remove the entry, use rm. This doesn't remove the device or device driver; it simply removes the device entry from the file system.

% rm ./lp0 

6.3.1 The /dev Directory

By convention, a GNU/Linux system includes a directory /dev containing the full complement of character and block device entries for devices that Linux knows about. Entries in /dev have standardized names corresponding to major and minor device numbers.

For example, the master device attached to the primary IDE controller , which has major and minor device numbers 3 and 0, has the standard name /dev/hda. If this device supports partitions, the first partition on it, which has minor device no. 1, has the standard name /dev/hda1. You can check that this is true on your system:

% ls -l /dev/hda /dev/hda1 
brw-rw----    1 root     disk       3,   0 May  5  1998 /dev/hda 
brw-rw----    1 root     disk       3,   1 May  5  1998 /dev/hda1 

Similarly, /dev has an entry for the parallel port character device that we used previously:

% ls -l /dev/lp0 
crw-rw----    1 root     daemon     6,   0 May  5  1998 /dev/lp0 

In most cases, you should not use mknod to create your own device entries. Use the entries in /dev instead. Non-superuser programs have no choice but to use preexisting device entries because they cannot create their own. Typically, only system administrators and developers working with specialized hardware devices will need to create device entries. Most GNU/Linux distributions include facilities to help system administrators create standard device entries with the correct names.

6.3.2 Accessing Devices by Opening Files

How do you use these devices? In the case of character devices, it can be quite simple: Open the device as if it were a normal file, and read from or write to it. You can even use normal file commands such as cat, or your shell's redirection syntax, to send data to or from the device.

For example, if you have a printer connected to your computer's first parallel port, you can print files by sending them directly to /dev/lp0. [1] To print the contents of document.txt, invoke the following:

[1] Windows users will recognize that this device is similar to the magic Windows file LPR1.

% cat document.txt > /dev/lp0 

You must have permission to write to the device entry for this to succeed; on many GNU/Linux systems , the permissions are set so that only root and the system's printer daemon (lpd) can write to the file. Also, what comes out of your printer depends on how your printer interprets the contents of the data you send it. Some printers will print plain text files that are sent to them, [2] while others will not. PostScript printers will render and print PostScript files that you send to them.

[2] Your printer may require explicit carriage return characters, ASCII code 14, at the end of each line, and may require a form feed character, ASCII code 12, at the end of each page.

In a program, sending data to a device is just as simple. For example, this code fragment uses low-level I/O functions to send the contents of a buffer to /dev/lp0.

int fd = open ("/dev/lp0", O_WRONLY); 
write (fd, buffer, buffer_length); 
close (fd);