26.1. Objective 1: Customizing System Startup and Boot ProcessesIn Chapter 14, we discussed boot procedures for a Linux system. Specifically, we covered boot-time kernel parameters, boot initialization scripts, and how to change system runlevels. The 201 exam takes this subject a step further and addresses how to customize your system's startup procedures. When the kernel has mounted the root filesystem, it executes /sbin/init. This program's first task is to read /etc/inittab, which defines everything done thereafter. 26.1.1. /etc/inittabThe /etc/inittab file describes what processes are started at boot time and during normal operation. This file is well-documented. For the examples in this section, we'll use a typical inittab file from a Red Hat system. After some initial comments, the file might contain: # Default runlevel. The runlevels used by RHS are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, with no networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:3:initdefault: The comments explain when the various runlevels are used on this machine. The first noncomment line is the one tagged id:, which defines the default runlevel for this system. As explained in the listing, this is multiuser mode with no X Window System. On a Debian system, the default runlevel is 2. Debian specifies only that 25 are multiuser. In virtually all distributions, runlevel 0 is used to halt the system, 1 to run it in single-user mode, and 6 to reboot. After your system is booted into a particular runlevel, you can change to another runlevel using the init or telinit commands. By issuing init 6 at the root prompt, you can command the system to reboot. Issuing init 1 commands the system to boot into single-user mode. These commands can be issued only by root. The inittab file continues: # System initialization. si::sysinit:/etc/rc.d/rc.sysinit 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 The si line defines that the script /etc/rc.d/rc.sysinit is to run first (because there are no other lines before it). It is run on all runlevels, because the second parameter on the line is empty (::). Debian also uses the sysinit script, but runs /etc/init.d/rcS instead. This in turn runs the contents of the /etc/rcs.d directory and then the /etc/rc.boot directory. Red Hat's script is monolithic. The six lines following, labeled l0 tHRough l6, execute the /etc/rc.d/rc script with an argument corresponding to the runlevel. This script runs the contents of the corresponding /etc/rcrunlevel.d directory as explained in Chapter 14. The next section sets specific commands and options. In particular, it maps the Ctrl+Alt+Delete key sequence, which automatically reboots the system. You can disable or change that option here. This section also has some options regarding SmartUPS settings. If the system is connected to a UPS with serial feedback that instructs the system when the UPS will run out of power, the system can automatically shut itself down with this entry. Debian systems have one additional action here for powerfailnow. # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # When our UPS tells us power has failed, assume we have a few # minutes of power left. Schedule a shutdown for 2 minutes from # now. This does, of course, assume you have power installed and # your UPS connected and working correctly. pf::powerfail:/sbin/shutdown -f -h +2"Power Failure;System Shutting Down" # If power was restored before the shutdown kicked in, cancel it. pr:12345:powerokwait:/sbin/shutdown -c"Power Restored;Shutdown Cancelled" The next section of the /etc/inittab file sets up your virtual consoles. The setup shown here is the default on Red Hat, and allows up to six virtual consoles. To add additional virtual consoles, duplicate the lines and then change the first field as well as the tty field to represent the appropriate number of your virtual console. # Run gettys in standard runlevels 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 26.1.2. System Initialization ScriptsSystem initialization scripts, most of which are found under the /etc/init.d directory, are used to boot the system and start daemons and services. The scripts you are looking for are in /etc/rc0.d through /etc/rc6.d (runlevel directories), as well as the all-important initial script, which is named /etc/rc.d/rc.sysinit in Red Hat and /etc/init.d/rcS in Debian. 26.1.2.1. System initializationOn Debian, the /etc/init.d/rcS script is the first startup script. On Red Hat, the corresponding script is /etc/rc.d/rc.sysinit. They do a lot of chores that you might never have thought were needed and are an education to read. Because the Red Hat script is monolithic (indeed, currently more than 800 lines), it is perhaps easiest to read. One of the most important tasks the script performs is to check all the local filesystems. If a problem is found, the script drops into a sulogin shell to let the administrator intervene and fix the problem. For some kinds of filesystem problems, the machine is now rebooted. If there is a quota executable and quotas are configured, the rc.sysinit script enables the quotas. The following are some excerpts from the Red Hat rc.sysinit script. The excerpts include the information related to filesystem checking and quotas. If you have a Red Hat system, take a glance at your /etc/rc.sysinit file for a complete tour. # Start up swapping. action "Activating swap partitions" swapon -a -e # Check filesystems if [ -z "$fastboot" ]; then STRING=$"Checking filesystems" echo $STRING initlog -c "fsck -T -R -A -a $fsckoptions" rc=$? if [ "$rc" = "0" ]; then success "$STRING" echo elif [ "$rc" = "1" ]; then passed "$STRING" echo fi # A return of 2 or higher means there were serious problems. if [ $rc -gt 1 ]; then if [ "$BOOTUP" = "graphical" ]; then chvt 1 fi failure "$STRING" echo echo echo $"*** An error occurred during the file system check." echo $"*** Dropping you to a shell; the system will reboot" echo $"*** when you leave the shell." str=$"(Repair filesystem)" PS1="$str \# # "; export PS1 sulogin echo $"Unmounting file systems" umount -a mount -n -o remount,ro / echo $"Automatic reboot in progress." reboot -f elif [ "$rc" = "1" -a -x /sbin/quotacheck ]; then _RUN_QUOTACHECK=1 fi fi # Mount all other filesystems (except for NFS and /proc, which is already # mounted). Contrary to standard usage, # filesystems are NOT unmounted in single user mode. action $"Mounting local filesystems: " mount -a -t nonfs,smbfs,ncpfs -O no_netdev # check remaining quotas other than root if [ X"$_RUN_QUOTACHECK" = X1 -a -x /sbin/quotacheck ]; then if [ -x /sbin/convertquota ]; then # try to convert old quotas for mountpt in 'awk '$4 ~ /quota/{print $2}' /etc/mtab' ; do if [ -f "$mountpt/quota.user" ]; then action $"Converting old user quota files: " \ /sbin/convertquota -u $mountpt && \ rm -f $mountpt/quota.user fi if [ -f "$mountpt/quota.group" ]; then action $"Converting old group quota files: " \ /sbin/convertquota -g $mountpt && \ rm -f $mountpt/quota.group fi done fi action $"Checking local filesystem quotas: " /sbin/quotacheck -aRnug fi if [ -x /sbin/quotaon ]; then action $"Enabling local filesystem quotas: " /sbin/quotaon -aug fi # Configure machine if necessary. if [ -f /.unconfigured ]; then if [ "$BOOTUP" = "graphical" ]; then chvt 1 fi if [ -x /usr/bin/passwd ]; then /usr/bin/passwd root fi if [ -x /usr/sbin/netconfig ]; then /usr/sbin/netconfig fi if [ -x /usr/sbin/timeconfig ]; then /usr/sbin/timeconfig fi if [ -x /usr/sbin/kbdconfig ]; then /usr/sbin/kbdconfig fi if [ -x /usr/sbin/authconfig ]; then /usr/sbin/authconfig --nostart fi if [ -x /usr/sbin/ntsysv ]; then /usr/sbin/ntsysv --level 35 fi # Reread in network configuration data. if [ -f /etc/sysconfig/network ]; then . /etc/sysconfig/network # Reset the hostname. action $"Resetting hostname ${HOSTNAME}: " hostname ${HOSTNAME} fi rm -f /.unconfigured fi # Clean out /. rm -f /fastboot /fsckoptions /forcefsck /.autofsck /halt /poweroff One weakness of the single-user runlevel is that, as you can see from the lines just quoted, all the filesystems are mounted and the operating system itself is almost completely initialized. If you're experiencing bad filesystem or hardware problems, this script may never complete. The only way to avoid this problem is to not run init when booting. This is dealt with in more detail in "Objective 2: System Recovery" later in this chapter. 26.1.2.2. Runlevel directoriesThe system run-level directories on Red Hat are named /etc/rc0.d through /etc/rc6.d. These directories don't actually contain real files or scripts. Instead, they contain links to scripts that are located in the /etc/init.d directory. Tip: Due to some silly antics during an earlier release, Red Hat still stores the rc scripts in /etc/rc.d/init.d and /etc/rc.d/rcn.d. But now at least the system provides symbolic links from the more standard paths of /etc/init.d and /etc/rcn.d. The links in the rcn.d directories run through after the system has completed the system initialization script. Each directory contains symbolic links to real scripts. Here is a list of some of the files in a typical /etc/rc0.d directory: lrwxrwxrwx 1 root root 14 Dec 10 10:27 K00cups -> ../init.d/cups* lrwxrwxrwx 1 root root 18 Dec 23 01:07 K05keytable -> ../init.d /keytable* lrwxrwxrwx 1 root root 16 Sep 17 2001 K08autofs -> ../init.d/autofs* lrwxrwxrwx 1 root root 16 Dec 23 00:59 K10psacct -> ../init.d/psacct* lrwxrwxrwx 1 root root 14 Aug 29 2002 K10wine -> ../init.d/wine* lrwxrwxrwx 1 root root 13 Sep 17 2001 K10xfs -> ../init.d/xfs* lrwxrwxrwx 1 root root 16 Sep 17 2001 K12mysqld -> ../init.d/mysqld* lrwxrwxrwx 1 root root 13 Sep 17 2001 K15gpm -> ../init.d/gpm* lrwxrwxrwx 1 root root 15 Dec 23 01:03 K15httpd -> ../init.d/httpd* lrwxrwxrwx 1 root root 15 Sep 17 2001 K15sound -> ../init.d/sound* Every symbolic link in each of the rcn.d directories is named with an initial S or K. S indicates that the service is to be started; K indicates that it should be stopped. Following the S or K is a two-digit number that indicates the order in which the scripts are to be run. For example, 10 gets run before 15. In the rc0.d directory just shown, for instance, CUPS starts first and sound support starts last. 26.1.3. Customizing RunlevelsAs you can see, quite a lot of a system's behavior is determined through what is in the system startup scripts. Whenever you add a service to your system, a script should be deposited in /etc/init.d and links to it from the right runlevel directories should be made. In Red Hat and some other distributions, the chkconfig is used for this. On Debian and many others, you can use update-rc.d. Once a script to start and stop services is in /etc/init.d, symbolic links to it can be made in the individual runlevel directories, so that the script runs at the proper runlevels . 26.1.3.1. Customizing runlevels on Red HatAs said in the previous section, Red Hat and some related distributions use the helper utility chkconfig to make this easy.
26.1.4. Customizing initrd ImagesChapter 25 discussed how to generate initrd images to enable booting all sorts of hardware with a skinny kernel that contains next to no hardware support. The initrd is not just a ram disk containing some modules, but a standalone root filesystem. The modules in it are loaded by a script or executable on the disk. If they are loaded by a script, it must have an interpreter. The following documentation of the initrd boot process is found in Documentation/initrd.txt in any kernel source tree. We won't include a customization example here, but we'll attempt to explain how initrd boots and what the environments look like on Red Hat and Debian.
By studying your distribution's mkinitrd script, you can see how the /linuxrc script works and how you can customize it. Additionally, the documentation present in Documentation/initrd.txt is very detailed and extensive. Your most likely reasons to customize an initrd in this way are to support something that is too new to be supported by the mkinitrd script or to construct a universal rescue floppy that autodetects the root filesystem and other interesting things on the computer it boots on. As you can see from the list of steps just enumerated, the key filename in the boot process is /linuxrc. If you take a copy of the mkinitrd script to customize and look in it for /linuxrc, you will be able to deduce how the bootstrap works. In both Debian and Red Hat, /linuxrc is a script. 26.1.4.1. initrd and /linuxrc on DebianIn Debian, the /linuxrc script interpreter is either dash or, more likely, ash. As you can see in the manpage for the interpreter, it offers a pretty complete set of built-in commands. (It is not, however, the standard command interpreter for the system, as the manpage claimsthat honor goes to bash.) And in the mkinitrd script, you will find which other external commands are available. When /linuxrc starts, it reads configuration data from /linuxrc.conf, which was written by mkinitrd. And then the Debian people have thrown in a twist. The /linuxrc file does not execute pivot_root as it should. Instead, when the kernel sees that /linuxrc has terminated, it executes /sbin/init, which is the script that does the real work. One of the things it does is to execute the contents of the /scripts directory in shell sorting order. After that, the real root filesystem is mounted, pivot_root is executed, and the real init command is executed. The supported way to modify this process is to put your scripts into /etc/mkinitrd/scripts. They will then be executed in order. This solution requires no changes in the system tools. The alternatives are to change the template /linuxrc, the /sbin/init script it installs, or the /linuxrc.conf file. All these options are fairly straightforward, as long as you recall your limited range of commands until the root filesystem is mounted. Debian offers the following external commands in addition to the regular shell built-ins listed in the ash manpage:
In addition, there is a custom-built /dev directory that matches your hardware pretty well. To support the executables, /lib and /usr/lib are filled with shared libraries. /lib/modules contains a complement of kernel modules that fits your setup. Altogether, Debian offers a pretty rich starting point. 26.1.4.2. initrd and /linuxrc on Red HatRed Hat generates the /linuxrc file dynamically, line by line. Customizing it thus becomes a question of generating the lines you need in the place you need. In the Red Hat initrd environment, customization is probably not as easy as in Debian. Few tools are provided. The shell used by Red Hat is /bin/nash, which is linked statically. It has the commands needed in an initrd environment built in, but it has very little in the way of general shell syntax. Therefore, the filesystem contains practically nothing to support it; just the following files:
/dev and /lib/modules have contents suitable for your setup. Red Hat does not need a real modprobe because the mkinitrd script analyzes the module dependencies at build time and makes sure that they are loaded in the correct order. Altogether this environment is very sparse. To customize the Red Hat initrd could turn out to be a great deal of work. But it does support booting off LVM-managed USB disks. |