1.4. System Features
1.4.1. A Note on Linux Version Numbers
One potentially confusing aspect of Linux for newcomers is the way in which different pieces of software are assigned a version number. When you first approach Linux, chances are you'll be looking at a CD-ROM distribution, such as "Red Hat Version 5.2" or "SuSE Linux Version 6.0." It's important to understand that these version numbers only relate to the particular distribution (which is a prepackaged version of Linux along with tons of free application packages, usually sold on CD-ROM). Therefore, the version number assigned by Red Hat, SuSE, or Debian might not have anything to do with the individual version numbers of the software in that distribution. Don't be fooled--just because one distribution company uses a higher version number than another doesn't mean that the software is any more up-to-date.
The Linux kernel, as well as each application, component, library, or software package in a Linux distribution, generally has its own version number. For example, you might be using gcc Version 220.127.116.11, as well as the XFree86 graphical user interface Version 3.3.1. As you can guess, the higher the version number, the newer the software is. By installing a distribution (such as Red Hat and SuSE), all of this is simplified for you since the latest versions of each package are usually included in the distribution.
The Linux kernel has a peculiar version numbering scheme that you should be familiar with. As mentioned before, the kernel is the core operating system itself, responsible for managing all of the hardware resources in your machine--such as disks, network interfaces, memory, and so on. Unlike Windows systems, the Linux kernel doesn't include any application-level libraries or graphical user interfaces. In some sense, as a user you will never interact with the kernel directly, but rather through interfaces such as the shell or the GUI (more on this later).
However, many people still consider the Linux kernel version to be the version of the "entire system," which is somewhat misleading. Someone might say, "I'm running kernel Version 2.3.32," but this doesn't mean much if everything else on the system is years out of date.
The Linux kernel versioning system works as follows. At any given time, there are two "latest" versions of the kernel out there (meaning available for download from the Internet)--the "stable" and "development" releases. The stable release is meant for most Linux users who aren't interested in hacking on bleeding-edge experimental features, but who need a stable, working system that isn't changing underneath them from day to day. The development release, on the other hand, changes very rapidly as new features are added and tested by developers across the Internet. Changes to the stable release consist mostly of bug fixes and security patches, while changes to the development release can be anything from major new kernel subsystems to minor tweaks in a device driver for added performance. The Linux developers don't guarantee that the development kernel version will work for everyone, but they do maintain the stable version with the intention of making it run well everywhere.
The stable kernel release has an even minor version number (such as 2.2), while the development release has an odd minor version number (such as 2.3). Note that the current development kernel always has a minor version number exactly one greater than the current stable kernel. So, when the current stable kernel is 2.4, the current development kernel will be 2.5. (Unless, of course, Linus decides to rename Version 2.4 to 3.0--in which case the development version will be 3.1, naturally).
Each of these kernel versions has a third "patch level" version number associated with it, such as 2.2.19 or 2.3.85. The patch level specifies the particular revision of that kernel version, with higher numbers specifying newer revisions. As of the time of this writing in July 1999, the latest stable kernel is 2.2.10 and the latest development kernel is 2.3.11.
1.4.2. A Bag of Features
Linux is a complete multitasking, multiuser operating system (just like all other versions of Unix). This means that many users can be logged into the same machine at once, running multiple programs simultaneously. Linux also supports multiprocessor systems (such as dual-Pentium motherboards), with support for up to 16 processors in a system, which is great for high-performance servers and scientific applications.
The Linux system is mostly compatible with a number of Unix standards (inasmuch as Unix has standards) on the source level, including IEEE POSIX.1, System V, and BSD features. Linux was developed with source portability in mind: therefore, you will probably find features in the Linux system that are shared across multiple Unix implementations. A great deal of free Unix software available on the Internet and elsewhere compiles on Linux out of the box.
If you have some Unix background, you may be interested in some other specific internal features of Linux, including POSIX job control (used by shells such as the C shell, csh, and bash), pseudoterminals ( pty devices), and support for national or customized keyboards using dynamically loadable keyboard drivers. Linux also supports virtual consoles, which allow you to switch between multiple login sessions from the system console in text mode. Users of the screen program will find the Linux virtual console implementation familiar.
Linux can quite happily co-exist on a system that has other operating systems installed, such as Windows 95/98, Windows NT, OS/2, or other versions of Unix. The Linux boot loader (LILO) allows you to select which operating system to start at boot time, and Linux is compatible with other boot loaders as well (such as the one found in Windows NT).
Linux can run on a wide range of CPU architectures, including the Intel x86 (386, 486, Pentium, Pentium Pro, II, and III), SPARC, Alpha, PowerPC, MIPS, and m68k. Ports to various other architectures are underway, and it is expected that Linux will run just fine on Intel's next-generation "Merced" processors. There has even been work to port Linux to embedded processors, such as the one found in the 3Com PalmPilot personal digital assistant.
Linux supports various filesystem types for storing data. Some filesystems, such as the Second Extended (ext2fs) filesystem, have been developed specifically for Linux. Other filesystem types, such as the Minix-1 and Xenix filesystems, are also supported. The MS-DOS filesystem has been implemented as well, allowing you to access Windows and DOS on hard drive or floppy directly. Support is included for OS/2, Apple, Amiga, and Windows NT filesystems as well. The ISO 9660 CD-ROM filesystem type, which reads all standard formats of CD-ROMs, is also supported. We'll talk more about filesystems in Chapter 3, "Installation and Initial Configuration", and Chapter 5, "Essential System Management".
Networking support is one of the greatest strengths of Linux, both in terms of functionality and performance. Linux provides a complete implementation of TCP/IP networking. This includes device drivers for many popular Ethernet cards, PPP and SLIP (allowing you to access a TCP/IP network via a serial connection), Parallel Line Internet Protocol (PLIP), and the NFS Network File System. The complete range of TCP/IP clients and services is supported, such as FTP, Telnet, NNTP, and Simple Mail Transfer Protocol (SMTP). The Linux kernel includes complete network firewall support, allowing you to configure any Linux machine as a firewall (which screens network packets, preventing unauthorized access to an intranet, for example). It is widely held that networking performance under Linux is superior to other operating systems. We'll talk more about networking in Chapter 15, "TCP/IP and PPP".
The kernel is the guts of the operating system itself; it's the code that controls the interface between user programs and hardware devices, the scheduling of processes to achieve multitasking, and many other aspects of the system. The kernel is not a separate process running on the system. Instead, you can think of the kernel as a set of routines, constantly in memory, that every process has access to. Kernel routines can be called in a number of ways. One direct method to utilize the kernel is for a process to execute a system call, which is a function that causes the kernel to execute some code on behalf of the process. For example, the read system call will read data from a file descriptor. To the programmer, this looks like another C function, but in actuality the code for read is contained within the kernel.
Kernel code is also executed in other situations. For example, when a hardware device issues an interrupt, the interrupt handler is found within the kernel. When a process takes an action that requires it to wait for results, the kernel steps in and puts the process to sleep, scheduling another process in its place. Similarly, the kernel switches control between processes rapidly, using the clock interrupt (and other means) to trigger a switch from one process to another. This is basically how multitasking is accomplished.
The Linux kernel is known as a monolithic kernel, in that all device drivers are part of the kernel proper. Some operating systems employ a microkernel architecture whereby device drivers and other components (such as filesystems and memory management code) are not part of the kernel--rather, they are treated similarly to regular user applications. There are advantages and disadvantages to both designs: the monolithic architecture is more common among Unix implementations and is the design employed by classic kernel designs, such as System V and BSD. Linux does support loadable device drivers (which can be loaded and unloaded from memory through user commands); this is the subject of the section "Section 7.5, "Loadable Device Drivers"" in Chapter 7, "Upgrading Software and the Kernel".
The Linux kernel on Intel platforms is developed to use the special protected-mode features of the Intel 80x86 processors (starting with the 80386). In particular, Linux makes use of the protected-mode descriptor-based memory management paradigm and many of the other advanced features of these processors. Anyone familiar with 80386 protected-mode programming knows that this chip was designed for a multitasking system such as Unix (it was actually inspired by Multics). Linux exploits this functionality.
The Linux kernel supports demand-paged loaded executables. That is, only those segments of a program that are actually used are read into memory from disk. Also, if multiple instances of a program are running at once, only one copy of the program code will be in memory.
In order to increase the amount of available memory, Linux also implements disk paging: that is, a certain amount of swap space  can be allocated on disk. When the system requires more physical memory, it will swap out inactive pages to disk, thus allowing you to run larger applications and support more users at once. However, swap is no substitute for physical RAM; it's much slower due to the time required to access the disk.
The kernel also implements a unified memory pool for user programs and disk cache. In this way, all free memory is used for caching, and the cache is reduced when the processor is running large programs.
Executables use dynamically linked shared libraries, meaning that executables share common library code in a single library file found on disk, not unlike the SunOS shared library mechanism. This allows executable files to occupy much less space on disk, especially those files that use many library functions. This also means that a single copy of the library code is held in memory at one time, thus reducing overall memory usage. There are also statically linked libraries for those who wish to maintain "complete" executables without the need for shared libraries to be in place. Because Linux shared libraries are dynamically linked at runtime, programmers can replace modules of the libraries with their own routines.
To facilitate debugging, the Linux kernel does core dumps for post-mortem analysis. Using a core dump and an executable linked with debugging support, you can determine what caused a program to crash. We'll talk about this in the section "Section 14.1.2, "Examining a Core File"" in Chapter 14, "Tools for Programmers".
Copyright © 2001 O'Reilly & Associates. All rights reserved.