Chapter 6. Automating Startup & Shutdown

Table of Contents

1. Analysis
2. Design
2.1. Determining necessary utilities
2.2. Obtaining source code
2.3. Checking dependencies
2.4. Designing a simple GRUB configuration file.
2.5. Outlining start-up scripts
3. Construction
3.1. Create a GRUB configuration file
3.2. Install sysvinit utilities
3.3. Create /etc/inittab file
3.4. Create /etc/init.d/rc script
3.5. Modify /etc/init.d/local_fs script
3.6. Create a hostname script
3.7. Create halt & reboot scripts
3.8. Create rcN.d directories and links
3.9. Create the root disk image
3.10. Copy the image to diskette
4. Implementation
4.1. System Startup
4.2. Verify success of startup scripts
4.3. System shutdown

1. Analysis

The root disk from the last chapter is looking pretty good. It has about seventy percent of the commands that the Filesystem Hierarchy Standard (FHS) document requires for the root filesystem. Plus it has commands for checking and mounting filesystems. But even with all of this the root disk is far from perfect. The list below outlines three things that could use some improvement if the Pocket Linux system is to stand up next to the more professional looking distributions.

  1. The system currently requires the kernel parameters to be typed at the grub> prompt in order to start properly. On any other GNU/Linux system this is only done in an emergency situation when the system is corrupted.

  2. Checking and mounting the root filesystem has to be done manually by running a script at a shell prompt. On most modern operating systems this function is handled automatically as part of the system start-up process.

  3. Using CTRL-ALT-DELETE for system shutdown is not very graceful. Filesystems should be unmounted and cached information should be flushed prior to shutdown. Again, this is something that most operating systems handle automatically.

Taking the above list into consideration, the goals for this phase are defined as follows:

  • Kernel loads without manual intervention.

  • Automated system start-up sequence.

  • Graceful shutdown capability.

2. Design

2.1. Determining necessary utilities

Loading the kernel without manually typing parameters is easy to do if we read the grub info page. According to the section entitled "configuration" all of the commands used for booting can be put in a file called menu.lst and placed in the /boot/grub directory.

Note

Be sure to type the menu.lst filename correctly with a lowercase L after the dot and not a number one.

To automate system start-up we will need an init daemon. We know this because the Bootdisk-HOWTO and From-Powerup-To-BASH-Prompt-HOWTO both make mention of init as the first program to start after the kernel loads. The latter HOWTO also goes into some detail about the /etc/inittab file and the organization of startup scripts. This could be helpful since FHS, the blueprint we have used so far, makes no recommendation for init scripts.

We will also need to find the shutdown command to fulfill the second goal of graceful shutdown capability.

2.2. Obtaining source code

Searching the Linux Software Map on Ibiblio for the keyword "init" gives a large number of results. From reading the From-Powerup-To-BASH-Prompt-HOWTO however, we know that most Linux systems use a System V style init daemon. Narrowing the search with the additional key phrase of "System V" gives much better results. The sysvinit package contains init, shutdown, halt and reboot which is everything we need. The version listed in the LSM entry looks to be pretty old, but there is a primary-site URL that will probably lead to the latest version.

2.3. Checking dependencies

The manpage for init mentions a FIFO called /dev/initctl that is required for init to communicate with other programs in the sysvinit package. We will have to create this file for init to function properly.

2.4. Designing a simple GRUB configuration file.

Using a GRUB configuration file is slightly more complex than specifying the bootloader commands manually. There are directives for features like menus, default selections and timeouts that need to be specified in the configuration file as well as the familiar kernel loading command. The info page for GRUB gives much of the necessary information. We may also be able to use the GRUB configuration file on the development system as a template. However, there is some inconsistency between vendors as to the name and location of the file. Regardless of what the path is on the development system it should be /boot/grub/menu.lst on the Pocket Linux System.

2.5. Outlining start-up scripts

Many of the popular GNU/Linux distributions use System V style init scripts. Since we are using a "sysvinit" daemon it makes sense to use System V style scripts as well. The following documents all touch upon the System V style init scripts in some way and will serve as references when building the scripts for this project:

After glancing at one or two of the above references we should have a pretty good idea of how the System V style system initialization process works. We should also know what it takes to create System V style init scripts for the Pocket Linux project. Below is a brief list of what needs to be done:

  • Create an inittab file to call an rc script with a numerical argument giving the runlevel.

  • Write an rc script that uses the runlevel argument to execute the appropriate "K" and "S" scripts.

  • Modify the previously built local_fs script to take start and stop arguments.

  • Create new scripts for shutdown and reboot.

  • Set up /etc/rcN.d directories and links to scripts in /etc/init.d.

As always, the BASH(1) manpage and the Advanced BASH Scripting Guide are very helpful for writing and understanding shell scripts.

3. Construction

There is a lot of typing to do in this section because of all of the start-up scripts that need to be created. Using a mouse to copy the text from this guide and paste it into a text editor can be a great time saving tool.

3.1. Create a GRUB configuration file

Insert and mount the floppy labeled "boot disk".

bash# mount /dev/fd0 /mnt
bash# cd /mnt/boot/grub

Use your favorite text editor to create the following file and save it as /mnt/boot/grub/menu.lst:

default 0
timeout 3
title Pocket Linux Boot Disk
kernel (fd0)/boot/vmlinuz root=/dev/fd0 load_ramdisk=1 prompt_ramdisk=1

3.2. Install sysvinit utilities

Download the latest sysvinit source from ftp://ftp.cistron.nl/pub/people/miquels/software/

bash# cd /usr/src/sysvinit-2.85/src
bash# make CC="gcc -mcpu=i386"
bash# cp halt init shutdown ~/staging/sbin
bash# ln -s halt ~/staging/sbin/reboot
bash# ln -s init ~/staging/sbin/telinit
bash# mknod ~/staging/dev/initctl p

Note

In the interest of speed we are skipping the steps for checking libraries and stripping binaries. The library requirements for sysvinit are very basic and the Makefile is configured to automatically strip the binaries.

3.3. Create /etc/inittab file

Use a text editor to create the following file and save it as ~/staging/etc/inittab

# /etc/inittab - init daemon configuration file
#
# Default runlevel
id:1:initdefault:
#
# System initialization
si:S:sysinit:/etc/init.d/rc S
#
# Runlevel scripts
r0:0:wait:/etc/init.d/rc 0
r1:1:respawn:/bin/sh
r2:2:wait:/etc/init.d/rc 2
r3:3:wait:/etc/init.d/rc 3
r4:4:wait:/etc/init.d/rc 4
r5:5:wait:/etc/init.d/rc 5
r6:6:wait:/etc/init.d/rc 6
#
# end of /etc/inittab

3.4. Create /etc/init.d/rc script

Use a text editor to create the following file and save it as ~/staging/etc/init.d/rc

#!/bin/sh
#
# /etc/init.d/rc - runlevel change script
#
PATH=/sbin:/bin
SCRIPT_DIR="/etc/rc$1.d"
#
# Check that the rcN.d directory really exists.
if [ -d $SCRIPT_DIR ]; then
#
# Execute the kill scripts first.
  for SCRIPT in $SCRIPT_DIR/K*; do
    if [ -x $SCRIPT ]; then
      $SCRIPT stop;
    fi;
  done;
#
# Do the Start scripts last.
  for SCRIPT in $SCRIPT_DIR/S*; do
    if [ -x $SCRIPT ]; then
      $SCRIPT start;
    fi;
  done;
fi
#
# end of /etc/init.d/rc

Make the file executable.

bash# chmod +x ~/staging/etc/init.d/rc

3.5. Modify /etc/init.d/local_fs script

A case statement is added to allow the script to either mount or unmount local filesystems depending on the command-line argument given. The original script is contained inside the "start" portion of the case statement. The "stop" portion is new.

#!/bin/sh
#
# local_fs - check and mount local filesystems
#
PATH=/sbin:/bin ; export PATH

case $1 in

start)
  echo "Checking local filesystem integrity."
  fsck -ATCp
  if [ $? -gt 1 ]; then
    echo "Filesystem errors still exist!  Manual intervention required."
    /bin/sh
  else
    echo "Remounting / as read-write."
    mount -n -o remount,rw /
    echo -n > /etc/mtab
    mount -f -o remount,rw /
    echo "Mounting local filesystems."
    mount -a -t nonfs,smbfs
  fi
;;

stop)
  echo "Unmounting local filesystems."
  umount -a -r
;;

*)
  echo "usage: $0 start|stop";
;;

esac
#
# end of local_fs

3.6. Create a hostname script

Use a text editor to create the following script and save it as ~/staging/etc/init.d/hostname

#!/bin/sh
#
# hostname - set the system name to the name stored in /etc/hostname
#
PATH=/sbin:/bin ; export PATH

echo "Setting hostname."
if [ -f /etc/hostname ]; then
  hostname $(cat /etc/hostname)
else
  hostname gnu-linux
fi
#
# end of hostname

3.7. Create halt & reboot scripts

Use a text editor to create ~/staging/etc/init.d/halt as shown below.

#!/bin/sh
#
# halt - halt the system
#
PATH=/sbin:/bin ; export PATH

echo "Initiating system halt."
halt
#
# end of /etc/init.d/halt

Create the following script and save it as ~/staging/etc/init.d/reboot

#!/bin/sh
#
# reboot - reboot the system
#
PATH=/sbin:/bin ; export PATH

echo "Initiating system reboot."
reboot
#
# end of /etc/init.d/reboot

Flag all script files as executable.

bash# chmod +x ~/staging/etc/init.d/*

3.8. Create rcN.d directories and links

bash# cd ~/staging/etc
bash# mkdir rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rcS.d
bash# cd ~/staging/etc/rcS.d
bash# ln -s ../init.d/local_fs S20local_fs
bash# ln -s ../init.d/hostname S30hostname
bash# cd ~/staging/etc/rc0.d
bash# ln -s ../init.d/local_fs K10local_fs
bash# ln -s ../init.d/halt K90halt
bash# cd ~/staging/etc/rc6.d
bash# ln -s ../init.d/local_fs K10local_fs
bash# ln -s ../init.d/reboot K90reboot

3.9. Create the root disk image

bash# cd /
bash# dd if=/dev/zero of=/dev/ram7 bs=1k count=4096
bash# mke2fs -m0 /dev/ram7 4096
bash# mount /dev/ram7 /mnt
bash# cp -dpR ~/staging/* /mnt
bash# umount /dev/ram7
bash# dd if=/dev/ram7 of=~/phase5-image bs=1k
bash# gzip -9 ~/phase5-image

3.10. Copy the image to diskette

Insert the diskette labeled "root disk" into drive fd0.

bash# dd if=~/phase5-image.gz of=/dev/fd0 bs=1k

4. Implementation

4.1. System Startup

Boot the PC using the floppy labeled "boot disk". Place the recently created root disk in fd0 when prompted. The output should resemble the example below:

GNU GRUB version 0.95

Uncompressing Linux... Ok, booting kernel.
..
.. [various kernel messages]
..
VFS: Insert root floppy to be loaded into RAM disk and press ENTER
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 178k freed
Checking local filesystem integrity.
/dev/ram0: clean 105/1024 files 2842/4096 blocks
Remounting / as read-write.
Mounting local filesystems.
Setting the hostname.
INIT: Entering runlevel: 1
# _

4.2. Verify success of startup scripts

Use the mount command to check that local filesystems are mounted as read-write. The output should look like the example below.

bash# mount
/dev/root on / type ext2 (rw)
proc on /proc type proc (rw)

Check the hostname.

bash# uname -n
gnu-linux

4.3. System shutdown

Bring the system down gracefully with the shutdown command.

bash# shutdown -h now

We should see the following output from init and the shutdown scripts:

INIT: Switching to runlevel: 0
INIT: Sending processes the TERM signal
Terminated
INIT: Sending processes the KILL signal
Unmounting local filesystems.
Initiating system halt.
System halted.