Chapter 20. System initialization

Table of Contents
20.1. The bootloader
20.2. init
20.3. Initialization scripts
20.4. Hotplugging

This chapter describes the initialization of Slackware Linux. Along the way various configuration files that are used to manipulate the initialization process are described.

20.1. The bootloader

Arguably the most important piece of an operating system is the kernel. The kernel manages hardware resources and software processes. The kernel is started by some tiny glue between the system BIOS (Basic Input/Output System) and the kernel, called the bootloader. The bootloader handles the complications that come with loading a specific (or less specific) kernel.

Most bootloader actually work in two stages. The first stage loader loads the second stage loader, that does the real work. The boot loader is divided in two stages on x86 machines, because the BIOS only loads one sector (the so-called boot sector) that is 512 bytes in size.

Slackware Linux uses the LILO (LInux LOader) boot loader. This bootloader has been in development since 1992, and is specifically written to load the Linux kernel. Lately LILO has been replaced by the GRUB (GRand Unified Bootloader) in most GNU/Linux distributions. GRUB is available as an extra package on the Slackware Linux distribution media.

20.1.1. LILO configuration

LILO is configured through the /etc/lilo.conf configuration file. Slackware Linux provides an easy tool to configure LILO. This configuration tool can be started with the liloconfig command, and is described in the installation chapter (Section 5.3).

Manual configuration of LILO is pretty simple. The LILO configuration file usually starts off with some global settings:


# Start LILO global section
boot = /dev/sda (1)
#compact        # faster, but won't work on all systems.
prompt (2)
timeout = 50 (3)
# Normal VGA console
vga = normal (4)
        
(1)
The boot option specifies where the LILO bootloader should be installed. If you want to use LILO as the main bootloader for starting Linux and/or other operating systems, it is a good idea to install LILO in the MBR (Master Boot Record) of the hard disk that you use to boot the system. LILO is installed to the MBR by omitting the partition number, for instance /dev/hda or /dev/sda. If you want to install LILO to a specific partition, add a partition number, like /dev/sda1. Make sure that you have another bootloader in the MBR, or that the partition is made active using fdisk. Otherwise you may end up with an unbootable system.

Be cautious if you use partitions with a XFS filesystem! Writing LILO to an XFS partition will overwrite a part of the filesystem. If you use an XFS root (/) filesystem, create a non-XFS /boot filesystem to which you install LILO, or install LILO to the MBR.

(2)
The prompt option will set LILO to show a boot menu. From this menu you can select which kernel or operating system should be booted. If you do not have this option enabled, you can still access the bootloader menu by holding the <Shift> key when the bootloader is started.
(3)
The timeout value specifies how long LILO should wait before the default kernel or OS is booted. The time is specified in tenths of a second, so in the example above LILO will wait 5 seconds before it proceeds with the boot.
(4)
You can specify which video mode the kernel should use with the vga option. When this is set to normal the kernel will use the normal 80x25 text mode.

The global options are followed by sections that add Linux kernels or other operating systems. Most Linux kernel sections look like this:


image = /boot/vmlinuz (1)
  root = /dev/sda5 (2) 
  label = Slack (3)
  read-only (4)
        
(1)
The image option specifies the kernel image that should be loaded for this LILO item.
(2)
The root parameter is passed to the kernel, and will be used by the kernel as the root (/) filesystem.
(3)
The label text is used as the label for this entry in the LILO boot menu.
(4)
read-only specifies that the root filesystem should be mounted read-only. The filesystem has to be mounted in read-only state to conduct a filesystem check.

20.1.2. LILO installation

LILO does not read the /etc/lilo.conf file during the second stage. So, you will have to write changes to the second stage loader when you have changed the LILO configuration. This is also necessary if you install a new kernel with the same filename, since the position of the kernel on the disk may have changed. Reinstalling LILO can simply be done with the lilo command:


# lilo
Added Slack26 *
Added Slack
        

20.2. init

After the kernel is loaded and started, the kernel will start the init command. init is the parent of all processes, and takes care of starting the system initialization scripts, and spawning login consoles through agetty. The behavior of init is configured in /etc/inittab.

The /etc/inittab file is documented fairly well. It specifies what scripts the system should run for different runlevels. A runlevel is a state the system is running in. For instance, runlevel 1 is single user mode, and runlevel 3 is multi-user mode. We will have a short look at a line from /etc/inittab to see how it works:


rc:2345:wait:/etc/rc.d/rc.M
      

This line specifies that /etc/rc.d/rc.M should be started when the system switches to runlevel 2, 3, 4 or 5. The only line you probably ever have to touch is the default runlevel:


id:3:initdefault:
      

In this example the default runlevel is set to 3 (multiuser mode). You can set this to another runlevel by replacing 3 with the new default runlevel. Runlevel 4 can particularly be interesting on desktop machines, since Slackware Linux will try to start the GDM, KDM or XDM display manager (in this particular order). These display managers provide a graphical login, and are respectively part of GNOME, KDE and X11.

Another interesting section are the lines that specify what command should handle a console. For instance:


c1:1235:respawn:/sbin/agetty 38400 tty1 linux
      

This line specifies that agetty should be started on tty1 (the first virtual terminal) in runlevels 1, 2, 3 and 5. The agetty command opens the tty port, and prompts for a login name. agetty will then spawn login to handle the login. As you can see from the entries, Slackware Linux only starts one console in runlevel 6, namely tty6. One might ask what happened to tty0, tty0 certainly exists, and represents the active console.

Since /etc/inittab is the right place to spawn agetty instances to listen for logins, you can also let one or more agetties listen to a serial port. This is especially handy when you have one or more terminals connected to a machine. You can add something like the following line to start an agetty instance that listens on COM1:


s1:12345:respawn:/sbin/agetty -L ttyS0 9600 vt100
      

20.3. Initialization scripts

As explained in the init (Section 20.2) section, init starts some scripts that handle different runlevels. These scripts perform jobs and change settings that are necessary for a particular runlevel, but they may also start other scripts. Let's look at an example from /etc/rc.d/rc.M, the script that init executes when the system switches to a multi-user runlevel:


# Start the sendmail daemon:
if [ -x /etc/rc.d/rc.sendmail ]; then
  . /etc/rc.d/rc.sendmail start
fi
      

These lines say "execute /etc/rc.d/rc.sendmail start if /etc/rc.d/rc.sendmail is executable". This indicates the simplicity of the Slackware Linux initialization scripts. Different functionality, for instance network services, can be turned on or off, by twiddling the executable flag on their initialization script. If the initialization script is executable, the service will be started, otherwise it will not. Setting file flags is described in Section 8.3.3, but we will have a look at a quick example how you can enable and disable sendmail.

To start sendmail when the system initializes, execute:


# chmod +x /etc/rc.d/rc.sendmail
      

To disable starting of sendmail when the system initializes, execute:


# chmod -x /etc/rc.d/rc.sendmail
      

Most service-specific initialization scripts accept three parameters to change the state of the service: start, restart and stop. These parameters are pretty much self descriptive. For example, if you would like to restart sendmail, you could execute:


# /etc/rc.d/rc.sendmail restart
      

If the script is not executable, you have to tell the shell that you would like to execute the file with sh. For example:


# sh /etc/rc.d/rc.sendmail start
      

20.4. Hotplugging

Slackware Linux has supported hotplugging since Slackware Linux 9.1. When enabled, the kernel passes notifications about device events to the hotplug command. If a device was added to the system, the hotplugging system will look whether there are any module mappings for the device. If there are, the appropriate device driver module for the device is automatically loaded. Hotplug will remove the module when the device is removed.

The hotplugging system is initialized in /etc/rc.d/rc.M by executing /etc/rc.d/rc.hotplug start. As with most functionality, you can enable or disable hotplugging by twiddling the executable flag of the /etc/rc.d/rc.hotplug script (see Section 20.3).

If hotplug automatically loads modules that you do not want to load, you can add them to the /etc/hotplug/blacklist file. This file lists modules that should never be loaded by the hotplugging system, module entries are line separated.

20.4.1. Executing scripts on hotplug events

One of the useful aspects of the hotplug scripts is that you can execute scripts when a device is added or removed. When a device event occurs, hotplug will execute all scripts with the .hotplug suffix in /etc/hotplug.d/<class>/, in which <class> denotes the class in which the device is in that caused the event. There most important classes are:

Table 20-1. Hotplug device classes

Prefix Description
default Scripts for this device class are started after any hotplug event.
ieee1394 IEEE1394/Firewire devices.
input Input devices like keyboards and mice.
net Network devices. Network devices will also trigger bus-specific hotplug events.
pci Devices on the PCI bus.
scsi SCSI disks, CD-ROM and tape devices.
usb Devices that use the USB bus.

Besides the device class, there is something some other convention that is worth observing: it is best to add a number and a dash as a prefix to the script, because this will allow you to order the priority of the scripts. For example, 10-dosomething.hotplug will be executed before 20-dosomething.hotplug.

Note

There is black no magic going on with the priority of the script :^). /sbin/hotplug uses a wildcard to loop through the scripts, and 10 matches earlier than 20:


for I in "${DIR}/$1/"*.hotplug "${DIR}/"default/*.hotplug ; do
          

Hopefully this will give some taste of the power of shell scripting.

Now, let's look at an example stub script, that does nothing besides outputting debug messages:


#!/bin/sh

cd /etc/hotplug
. ./hotplug.functions

DEBUG=yes export DEBUG

debug_mesg "arguments ($*) env (`env`)"

case $ACTION in
  add|register)
    # Stub 
  ;;
  remove|unregister)
    # Stub 
  ;;
esac
        

By default, the hotplug scripts log at the notice level. The standard syslog configuration on Slackware Linux does not log this. To debug hotplugging scripts, it is best to change the logging level. You can do this by replacing the following line in /etc/hotplug/hotplug.functions:


$LOGGER -t $(basename $0)"[$$]" "$@"
        

to:


$LOGGER -p user.info -t $(basename $0)"[$$]" "$@"
        

After this change hotplug debug messages will be visible in /var/log/messages.

As you can see the script makes use of the $ACTION variable to see what kind of hotplug action took place. Let's take a look at an example action when this script is used for handling USB events, and named 10-stub.hotplug:


Jul 19 16:13:23 mindbender 10-stub.hotplug[18970]: arguments (usb) env
(SUBSYSTEM=usb OLDPWD=/ DEVPATH=/devices/pci0000:00/0000:00:10.0/usb2/2-1/2-1.3/2-1.3:1.2
PATH=/bin:/sbin:/usr/sbin:/usr/bin ACTION=add PWD=/etc/hotplug HOME=/ SHLVL=2
DEVICE=/proc/bus/usb/002/009 PHYSDEVDRIVER=snd-usb-audio INTERFACE=1/2/0
PRODUCT=d8d/651/1 TYPE=0/0/0 DEBUG=yes PHYSDEVBUS=usb SEQNUM=1528 _=/usr/bin/env)
        

That is nice, when I plugged an USB device, the script gets loaded (a couple of times, this is just one of the interesting bits). Actually, this is my USB Phone, which is represented as an USB audio device under GNU/Linux. The problem with USB audio devices is that the device volumes that are saved with alsactl store are not automatically set when the device is plugged. But right know we can easily execute alsactl restore when the device is plugged. Please note that the script gets very useful information through some environment variables.

To solve the volume problem, we can create a script, say /etc/hotplug.d/usb/50-usb-audio-volume.hotplug, that looks like this:


#!/bin/sh

cd /etc/hotplug
. ./hotplug.functions
# DEBUG=yes export DEBUG

debug_mesg "arguments ($*) env (`env`)"

case $ACTION in
  add|register)
    if [ $PHYSDEVDRIVER = "snd-usb-audio" ]; then
      /usr/sbin/alsactl restore
    fi
  ;;
  remove|unregister)
  ;;
  *)
    debug_mesg "Unknown action '$ACTION'"
  ;;
esac
        

Based on the environment variables this script can be refined to restrict running alsactl for specific USB audio devices.