General Unix and Advanced C
8
crw-rw-rw- 1 root root 5, 0 Sep 2 15:06 /dev/tty
crw-rw-rw- 1 root root 1, 5 Aug 26 13:12 /dev/zero
This brings us to the file-descriptor, which is the handle user-space uses to talk to the underlying device.
In a broad-sense, what happens when a file is opened is that the kernel is using the path information to
map the file-descriptor with something that provides an appropriate read and write, etc. API. When
this open is for a device (/dev/sr0 above), the major and minor number of the opened device-node
provides the information the kernel needs to find the correct device-driver and complete the mapping. The
kernel will then know how to route further calls such as read to the underlying functions provided by
the device-driver.
A non-device file operates similarly, although there are more layers in-between. The abstraction here is
the mount-point; mounting a file-system has the dual purpose of setting up a mapping so the file-system
knows the underlying device that provides the storage and the kernel knows that files opened under that
mount-point should be directed to the file-system driver. Like device-drivers, file-systems are written to
a particular generic file-system API provided by the kernel.
There are indeed many other layers that complicate the picture in real-life. For example, the kernel will go
to great efforts to cache as much data from disks as possible in otherwise free-memory; this provides many
speed advantages. It will also try to organise device access in the most efficient ways possible; for example
trying to order disk-access to ensure data stored physically close to each other is retrieved together, even if
the requests did not arrive in such an order. Further, many devices are of a more generic class such as USB
or SCSI devices which provide their own abstraction layers to write too. Thus rather than writing directly
to devices, file-systems will go through these many layers. Understanding the kernel is to understand how
these many APIs interrelate and coexist.
The Shell
The shell is the gateway to interacting with the operating system. Be it bash, zsh, csh or any of the
many other shells, they all fundamentally have only one major task — to allow you to execute programs
(you will begin to understand how the shell actually does this when we talk about some of the internals
of the operating system later).
But shells do much more than allow you to simply execute a program. They have powerful abilities to
redirect files, allow you to execute multiple programs simultaneously and script complete programs. These
all come back to the everything is a file idiom.
Redirection
Often we do not want the standard file descriptors mentioned in the section called “File Descriptors” to
point to their default places. For example, you may wish to capture all the output of a program into a file
on disk, or, alternatively have it read its commands from a file you prepared earlier. Another useful task
might like to pass the output of one program to the input of another. With the operating system, the shell
facilitates all this and more.
Table 1.2. Standard Shell Redirection Facilities
Name Command Description Example
Redirect to a file > filename Take all output from
standard out and place
it into filename. Note
using >> will append
to the file, rather than
overwrite it.
ls > filename