In this section, we’re going to talk about exactly what happens when the system boots. Understanding this process and the files involved is important for performing various kinds of system configuration.
The first step
is booting the kernel. As
described in the previous section, this can be done from floppy or
hard drive. As the kernel loads into memory, it will print messages
to the system console, but usually also saves them in the system log
files as well. As root
, you can always check the
file
/var/log/messages
(which contains kernel messages
emitted during runtime as well). The command dmesg
prints out the last lines of the kernel message ring buffer; directly
after booting, naturally, you will get the boot messages.
In the following few paragraphs, we’ll go through a couple of the more interesting messages and explain what they mean. These messages are all printed by the kernel itself, as each device driver is initialized. The exact messages printed depend on what drivers are compiled into your kernel and what hardware you have on your system. You are likely to have more, fewer or different messages; we’ll concentrate here on the messages that are quite common.
The line:
Linux version 2.4.10-64GB-SMP (root@SMP_X86.suse.de) (gcc version 2.95.3 20010315) #1 SMP Fri Sep 28 17:26:36 GMT 2001
tells you the version number of the kernel, on which machine, when, and with which compiler it was built.
Next, the kernel reports which processors it has found and, because this output is from a system with two processors, how the processors will work together:
Intel MultiProcessor Specification v1.1 Virtual Wire compatibility mode. OEM ID: OEM00000 Product ID: PROD00000000 APIC at: 0xFEE00000 Processor #0 Pentium(tm) Pro APIC version 17 Floating point unit present. Machine Exception supported. 64 bit compare & exchange supported. Internal APIC present. Bootup CPU Processor #1 Pentium(tm) Pro APIC version 17 Floating point unit present. Machine Exception supported. 64 bit compare & exchange supported. Internal APIC present. ... I/O APIC #2 Version 17 at 0xFEC00000. Processors: 2 mapped APIC to ffffe000 (fee00000) mapped IOAPIC to ffffd000 (fec00000) Detected 498673 kHz processor.
Then, it tells us which console font it has picked and which console type it has detected:
Console: color VGA+ 80x25
Note that this involves only the text mode being used by the kernel,
not the capabilities of your video card. (An SVGA
video card is reported as VGA+
as far as the
console text mode is concerned.)
The kernel gathers information about the PCI bus and checks for any PCI cards present in the system:
PCI: PCI BIOS revision 2.10 entry at 0xfb140, last bus=1 PCI: Using configuration type 1 PCI: Probing PCI hardware PCI: Using IRQ router PIIX [8086/7110] at 00:07.0 PCI: Found IRQ 14 for device 00:07.2 PCI: Sharing IRQ 14 with 00:0b.0 Limiting direct PCI/PCI transfers.
You’ll then see the “BogoMIPS” calculation for your processor:
Calibrating delay loop... 996.14 BogoMIPS Calibrating delay loop... 996.14 BogoMIPS Total of 2 processors activated (1992.29 BogoMIPS).
This is an utterly bogus (hence the name) measurement of processor speed, which is used to obtain optimal performance in delay loops for several device drivers. The kernel also prints information on the system memory:
Memory: 770672k/786368k available (1390k kernel code, 15308k reserved, 392k data, 128k init, 0k highmem)
Here, we see that 770672 KB of RAM are available for the system to use; the kernel itself is using 1390 KB.
Various memory structures and properties of the CPU are then determined. For example, the line:
CPU serial number disabled.
tells you that the Linux kernel has simply turned off the infamous serial number feature of the Pentium III CPU.
Linux then sets up networking, the mouse port, and the serial driver. A line such as:
ttyS00 at 0x03f8 (irq = 4) is a 16550A
means that the first serial device (/dev/ttyS00
,
or COM1) was detected at address 0x03f8, IRQ 4,
using 16550A UART functions. Next comes some more
hardware detection like the real-time clock and the floppy drive:
Real Time Clock Driver v1.10e ... Floppy drive(s): fd0 is 1.44M FDC 0 is a post-1991 82077 loop: loaded (max 8 devices) ide-floppy driver 0.97.sv ...
A bit later, the system is checking for a SCSI host adapter. The kernel prints out information about all SCSI devices found; this is verbose and not really worth reproducing here. The line:
Adding Swap: 120480k swap-space (priority 42)
tells you how much swap space the kernel has found. Among the further
tasks performed during a typical boot are finding and configuring a
parallel port (lp1
), detecting and configuring the
network card, and finally setting up the
USB subsystem.
Once the device
drivers are initialized, the kernel
executes the program init, which is found in
/etc
, /bin
, or
/sbin
(it’s
/sbin/init
on most systems).
init is a general-purpose program that spawns new
processes and restarts certain programs when they exit. For example,
each virtual console has a getty process running
on it, started by init. Upon login, the
getty process is replaced with another. After
logging out, init starts a new
getty process, allowing you to log in again.
init is also responsible for running a number of
programs and scripts when the system boots. Everything
init does is controlled by the file
/etc/inittab
. In order to understand this file,
you need to understand the concept of runlevels
first.
A runlevel is a
number or letter that specifies the current system state, as far as
init is concerned. For example, when the system
runlevel is changed to 3, all entries in
/etc/inittab
containing 3 in the column
specifying the runlevels will be executed. Runlevels are a useful way
to group entries in /etc/inittab
together. For
example, you might want to say that runlevel 1 executes only the bare
minimum of configuration scripts, runlevel 2 executes everything in
runlevel 1 plus networking configuration, runlevel 3 executes
everything in levels 1 and 2 plus dial-in login access, and so on.
Today, the Red Hat distribution is set up so that runlevel 5
automatically starts the X Window System graphical interface. The
SuSE distribution does it at runlevel 3, and the Debian distribution
does so at runlevel 2 — provided you have installed X.
For the most part, you don’t need to concern
yourself with runlevels. When the system boots, it enters the default
runlevel (set in /etc/inittab
, as we will soon
show). On most systems, this default is runlevel 2 or 3. After we
discuss normal booting, we’ll show you how to enter
another runlevel that you will sometimes need to use — runlevel
1, or single-user mode.
Let’s take a look at a sample
/etc/inittab
file:
# Set the default runlevel to three id:3:initdefault: # Execute /etc/rc.d/rc.sysinit when the system boots si:S:sysinit:/etc/rc.d/rc.sysinit # Run /etc/rc.d/rc with the runlevel as an argument l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # Executed when we press ctrl-alt-delete ca::ctrlaltdel:/sbin/shutdown -t3 -rf now # Start agetty for virtual consoles 1 through 6 c1:12345:respawn:/sbin/agetty 38400 tty1 c2:12345:respawn:/sbin/agetty 38400 tty2 c3:45:respawn:/sbin/agetty 38400 tty3 c4:45:respawn:/sbin/agetty 38400 tty4 c5:45:respawn:/sbin/agetty 38400 tty5 c6:45:respawn:/sbin/agetty 38400 tty6
Fields are separated by colons. The last field is the most recognizable: it is the command that init executes for this entry. The first field is an arbitrary identifier (it doesn’t matter what it is so long as it’s unique in the file) while the second indicates what runlevels cause the command to be invoked. The third field tells init how to handle this entry; for example, whether to execute the given command once or to respawn the command whenever it exits.
The exact contents of /etc/inittab
depend on
your system and the distribution of Linux you have installed.
In our sample file, we see first that the default runlevel is set to
3. The action
field for this entry is
initdefault
, which causes the given
runlevel
to be set to the default.
That’s the runlevel normally used whenever the
system boots. You can override the default with any level you want by
running init manually (which you might do when
debugging your configuration) and passing in the desired runlevel as
an argument. For instance, the following command shuts down all
current processes and starts runlevel 5 (warn all your users to log
off before doing this!):
tigger# init 5
LILO can also boot in single-user mode (usually runlevel 1) — see Section 5.2.2.3 earlier in this chapter.
The next entry tells init to execute the script
/etc/rc.d/rc.sysinit
when the system boots. (The
action
field is
sysinit
, which specifies that this entry should be
executed when init is first started at system
boot.) This file is simply a shell script containing commands to
handle basic system initialization; for example, swapping is enabled,
filesystems are checked and mounted, and the system clock is
synchronized with the CMOS clock. You can take a
look at this file on your system; we’ll be talking
more about the commands contained therein in Chapter 6; sees Section 6.1 and Section 6.2. On other distributions,
this file might be elsewhere. For example, on SuSE it is
/etc/init.d/boot
, which is also where it should
be according to the Linux Filesystem Hierarchy Standard
(FHS).
Next, we see that the system executes the script
/etc/rc.d/rc
when it enters any of the runlevels
through 6, with the appropriate runlevel as an argument.
rc
is a generic startup script that executes
other scripts as appropriate for that runlevel. The
action
field here is
wait
, which tells init to
execute the given command
, and to wait for
it to complete execution before doing anything else.
Linux stores
startup commands in files with
rc
in the name, using an old Unix convention.
The commands do all the things necessary to have a fully functioning
system, like starting the servers or daemons mentioned in Chapter 4. Thanks to these commands, the system comes up
ready with logging facilities, mail, a web server, or whatever you
installed and asked it to run. As explained in the previous section,
the files are invoked from /etc/inittab
. The
commands are standard shell commands, and you can simply read the
various rc
files to see what they do.
In this section, we describe the structure of the
rc
files so that you can understand where
everything starts, and so that you can start or stop servers manually
in the rare case that they don’t do what you want
them to do. We’ll use Red Hat as our model, but once
you get the idea of what to look for, you can find the corresponding
files on any Linux distribution. Red Hat is both a good and a bad
example because it violates the FHS. The Linux
FHS is a distribution-neutral initiative to define
standard directory names and filenames for important system files.
Any Linux distribution that wants to be a good Linux citizen should
follow this standard. Red Hat has decided — not for the first
time — not to be a good citizen, so the path- and file-names
given here for Red Hat give you an example of the variety that you
may encounter when looking for system files. Examples for
distributions following the FHS are SuSE and
Debian.
On Red Hat, the top-level rc
script is
/etc/rc.d/rc
. The path is slightly different in
other distributions (/etc/init.d/rc
on SuSE, for
instance), but the contents are similar. In the previous section, you
saw how the /etc/inittab
invokes the script
under a variety of circumstances with different numbers from 0 to 6
as arguments. The numbers correspond to runlevels, and each one
causes the rc
files to invoke a different set of
scripts. So our next step is to find the scripts corresponding to
each runlevel.
On Red Hat, scripts for each runlevel are stored in the directory
/etc/rc.d/rc
N
.d
where N
is the runlevel being started.
Thus, for runlevel 3, scripts in /etc/rc.d/rc3.d
would be used. Again, slightly different conventions are the rule in
other distributions. On Debian, for instance, the directory for each
runlevel is
/etc/rc
N
.d/
.
Take a look in one of those directories; you will see a number of
filenames of the form
S
nnxxxx
or
K
nnxxxx
where
nn
is a number from 00 to 99, and
xxxx
is the name of some system service.
The scripts whose names begin with K are executed by
/etc/rc.d/rc
first to kill any existing
services, and then the scripts whose names begin with S are executed
to start new services.
The numbers nn
in the names are used to
enforce an ordering on the scripts as they are executed: scripts with
lower numbers are executed before those with higher numbers. The name
xxxx
is simply used to help you identify
to which system service the script corresponds. This naming
convention might seem odd, but it makes it easy to add or remove
scripts from these directories and have them automatically executed
at the appropriate time by /etc/rc.d/rc
. For
customizing startup scripts, you’ll find it
convenient to use a graphical runlevel editor, such as
ksysv in KDE.
For example, the script to initialize networking might be called
S10network
, while the script to stop the system
logging daemon might be called K70syslog
. If
these files are placed in the appropriate
/etc/rc.d/rc
N
.d
directories, /etc/rc.d/rc
will run them, in
numerical order, at system startup or shutdown time. If the default
runlevel of your system is 3, look in
/etc/rc.d/rc3.d
to see which scripts are
executed when the system boots normally.
Because the same services are started or stopped at different
runlevels, the Red Hat distribution uses symbolic links instead of
repeating the same script in multiple places. Thus, each S or K file
is a symbolic link that points to a central directory that stores
startup or shutdown scripts for all services. On Red Hat, this
central directory is /etc/rc.d/init.d
, while on
SuSE and Debian, it is /etc/init.d
. On Debian
and SuSE, the directory contains a script called
skeleton
that you can adapt to start and stop
any new daemons you might write.
Knowing the location of a startup or shutdown script is useful in
case you don’t want to completely reboot or enter a
different runlevel, but need to start or stop a particular service.
Look in the init.d
directory for a script of the
appropriate name and execute it, passing the parameter
start
or stop
. For example, on
SuSE, if you want the Apache web server to be running but your system
is in a runlevel that does not include Apache, just enter the
following:
tigger# /sbin/init.d/apache start
Another important system configuration script is
/etc/rc.d/rc.local
, which is executed after the
other system initialization scripts are run. (How is this
accomplished? Generally, a symbolic link to
rc.local
is made in each
/etc/rc.d/rc
N
.d
directory with the name S99local
. Because 99 is
the largest numerical order any of the S scripts can have, it is
executed last. Voilà!) You can edit
rc.local
to accomplish any peculiar or otherwise
out-of-place system commands at boot time, or if
you’re not sure where else they should be executed.
Debian doesn’t have an equivalent of the
rc.local
script, but nothing stops you from
adding it and invoking it from rc
if
you’re used to having it.
The next entry, labeled ca
, is executed when the
key combination Ctrl-Alt-Delete is pressed on the console. This key
combination produces an interrupt that usually reboots the system.
Under Linux, this interrupt is caught and sent to
init, which executes the entry with the
action
field of
ctrlaltdel
. The command shown here,
/sbin/shutdown -t3 -rf now, will do a
“safe” reboot of the system. (See
Section 5.5 later in
this chapter.) This way we protect the system from sudden reboot when
Ctrl-Alt-Delete is pressed.
Finally, the inittab
file includes entries that
execute /sbin/agetty
for the first six virtual
consoles. agetty
is one of the several
getty variants available for Linux. These programs
permit logins on terminals; without them the terminal would be
effectively dead and would not respond when a user walked up and
pressed a key or mouse button. The various getty
commands open a terminal device (such as a virtual console or a
serial line), set various parameters for the terminal driver, and
execute /bin/login
to initiate a login session
on that terminal. Therefore, to allow logins on a given virtual
console, you must be running getty or
agetty on it. agetty is the
version used on a number of Linux systems, but others use
getty, which has a slightly different syntax. See
the manual pages for getty and
agetty on your system.
agetty takes two arguments: a baud rate and a
device name. The port names for Linux virtual consoles are
/dev/tty1
, /dev/tty2
, and
so forth. agetty assumes the given device name is
relative to /dev
. The baud rate for virtual
consoles should generally be 38400.
Note that the action
field for each
agetty entry is respawn
. This
means that init should restart the command given
in the entry when the agetty process dies, which
is every time a user logs out.
Now you should be familiar with init, but the
various files and commands in /etc/rc.d
, which
do all the work, remain a mystery. We can’t delve
into these files without more background on other system
administration tasks, such as managing filesystems.
We’ll lead you through these tasks in the next few
chapters, and eventually all
should be clear.