mirror of https://github.com/tLDP/LDP
519 lines
17 KiB
XML
519 lines
17 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter id="phase5">
|
|
<title>Automating Startup & Shutdown</title>
|
|
|
|
<sect1>
|
|
<title>Analysis</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>The system currently requires the kernel parameters to be typed
|
|
at the <prompt>grub></prompt> 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.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>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.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Using
|
|
<keycap>CTRL</keycap>-<keycap>ALT</keycap>-<keycap>DELETE</keycap> 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.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>Taking the above list into consideration, the goals for this phase
|
|
are defined as follows:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Kernel loads without manual intervention.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Automated system start-up sequence.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Graceful shutdown capability.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>Design</title>
|
|
|
|
<sect2>
|
|
<title>Determining necessary utilities</title>
|
|
|
|
<para>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 <filename>menu.lst</filename> and placed in the
|
|
<filename>/boot/grub</filename> directory.</para>
|
|
|
|
<note>
|
|
<para>Be sure to type the <filename>menu.lst</filename> filename
|
|
correctly with a lowercase L after the dot and not a number
|
|
one.</para>
|
|
</note>
|
|
|
|
<para>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 <command>init</command> as the first program to
|
|
start after the kernel loads. The latter HOWTO also goes into some
|
|
detail about the <filename>/etc/inittab</filename> 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.</para>
|
|
|
|
<para>We will also need to find the <command>shutdown</command> command
|
|
to fulfill the second goal of graceful shutdown capability.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Obtaining source code</title>
|
|
|
|
<para>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 <command>init</command>,
|
|
<command>shutdown</command>, <command>halt</command> and
|
|
<command>reboot</command> 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.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Checking dependencies</title>
|
|
|
|
<para>The manpage for <command>init</command> mentions a FIFO called
|
|
<filename>/dev/initctl</filename> that is required for
|
|
<command>init</command> to communicate with other programs in the
|
|
sysvinit package. We will have to create this file for
|
|
<command>init</command> to function properly.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Designing a simple GRUB configuration file.</title>
|
|
|
|
<para>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
|
|
<filename>/boot/grub/menu.lst</filename> on the Pocket Linux
|
|
System.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Outlining start-up scripts</title>
|
|
|
|
<para>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:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>The Debian Policy Manual -- available online at <ulink
|
|
url="http://www.debian.org/doc/debian-policy">http://www.debian.org/doc/debian-policy</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The Linux Standard Base specification -- downloadable in many
|
|
formats from <ulink
|
|
url="http://www.linuxbase.org/spec/index.shtml">http://www.linuxbase.org/spec/index.shtml</ulink>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Essential System Administration, 3rd Edition by Aeleen Frisch
|
|
-- available at libraries, bookstores or directly from O'Reilly
|
|
Publishing at <ulink
|
|
url="http://www.oreilly.com/">http://www.oreilly.com/</ulink>.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>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:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Create an <filename>inittab</filename> file to call an
|
|
<filename>rc</filename> script with a numerical argument giving the
|
|
runlevel.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Write an <filename>rc</filename> script that uses the runlevel
|
|
argument to execute the appropriate "K" and "S" scripts.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Modify the previously built <filename>local_fs</filename>
|
|
script to take <parameter>start</parameter> and
|
|
<parameter>stop</parameter> arguments.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Create new scripts for <filename>shutdown</filename> and
|
|
<filename>reboot</filename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Set up <filename>/etc/rcN.d</filename> directories and links
|
|
to scripts in <filename>/etc/init.d</filename>.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>As always, the BASH(1) manpage and the Advanced BASH Scripting
|
|
Guide are very helpful for writing and understanding shell
|
|
scripts.</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>Construction</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<sect2>
|
|
<title>Create a GRUB configuration file</title>
|
|
|
|
<para>Insert and mount the floppy labeled "boot disk".</para>
|
|
|
|
<programlisting><prompt>bash#</prompt> mount /dev/fd0 /mnt
|
|
<prompt>bash#</prompt> cd /mnt/boot/grub</programlisting>
|
|
|
|
<para>Use your favorite text editor to create the following file and
|
|
save it as /mnt/boot/grub/menu.lst:</para>
|
|
|
|
<programlisting>default 0
|
|
timeout 3
|
|
title Pocket Linux Boot Disk
|
|
kernel (fd0)/boot/vmlinuz root=/dev/fd0 load_ramdisk=1 prompt_ramdisk=1</programlisting>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Install sysvinit utilities</title>
|
|
|
|
<para>Download the latest sysvinit source from <ulink
|
|
url="ftp://ftp.cistron.nl/pub/people/miquels/software/">ftp://ftp.cistron.nl/pub/people/miquels/software/</ulink></para>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> cd /usr/src/sysvinit-2.85/src
|
|
<prompt>bash#</prompt> make CC="gcc -mcpu=i386"
|
|
<prompt>bash#</prompt> cp halt init shutdown ~/staging/sbin
|
|
<prompt>bash#</prompt> ln -s halt ~/staging/sbin/reboot
|
|
<prompt>bash#</prompt> ln -s init ~/staging/sbin/telinit
|
|
<prompt>bash#</prompt> mknod ~/staging/dev/initctl p</programlisting></para>
|
|
|
|
<note>
|
|
<para>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.</para>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create /etc/inittab file</title>
|
|
|
|
<para>Use a text editor to create the following file and save it as
|
|
<filename>~/staging/etc/inittab</filename></para>
|
|
|
|
<para><programlisting># /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</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create /etc/init.d/rc script</title>
|
|
|
|
<para>Use a text editor to create the following file and save it as
|
|
<filename>~/staging/etc/init.d/rc</filename></para>
|
|
|
|
<para><programlisting>#!/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</programlisting></para>
|
|
|
|
<para>Make the file executable.</para>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> chmod +x ~/staging/etc/init.d/rc</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Modify /etc/init.d/local_fs script</title>
|
|
|
|
<para>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.</para>
|
|
|
|
<para><programlisting>#!/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</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create a hostname script</title>
|
|
|
|
<para>Use a text editor to create the following script and save it as
|
|
<filename>~/staging/etc/init.d/hostname</filename></para>
|
|
|
|
<para><programlisting>#!/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</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create halt & reboot scripts</title>
|
|
|
|
<para>Use a text editor to create
|
|
<filename>~/staging/etc/init.d/halt</filename> as shown below.</para>
|
|
|
|
<para><programlisting>#!/bin/sh
|
|
#
|
|
# halt - halt the system
|
|
#
|
|
PATH=/sbin:/bin ; export PATH
|
|
|
|
echo "Initiating system halt."
|
|
halt
|
|
#
|
|
# end of /etc/init.d/halt</programlisting></para>
|
|
|
|
<para>Create the following script and save it as
|
|
<filename>~/staging/etc/init.d/reboot</filename></para>
|
|
|
|
<para><programlisting>#!/bin/sh
|
|
#
|
|
# reboot - reboot the system
|
|
#
|
|
PATH=/sbin:/bin ; export PATH
|
|
|
|
echo "Initiating system reboot."
|
|
reboot
|
|
#
|
|
# end of /etc/init.d/reboot</programlisting></para>
|
|
|
|
<para>Flag all script files as executable.</para>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> chmod +x ~/staging/etc/init.d/*</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create rcN.d directories and links</title>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> cd ~/staging/etc
|
|
<prompt>bash#</prompt> mkdir rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rcS.d
|
|
<prompt>bash#</prompt> cd ~/staging/etc/rcS.d
|
|
<prompt>bash#</prompt> ln -s ../init.d/local_fs S20local_fs
|
|
<prompt>bash#</prompt> ln -s ../init.d/hostname S30hostname
|
|
<prompt>bash#</prompt> cd ~/staging/etc/rc0.d
|
|
<prompt>bash#</prompt> ln -s ../init.d/local_fs K10local_fs
|
|
<prompt>bash#</prompt> ln -s ../init.d/halt K90halt
|
|
<prompt>bash#</prompt> cd ~/staging/etc/rc6.d
|
|
<prompt>bash#</prompt> ln -s ../init.d/local_fs K10local_fs
|
|
<prompt>bash#</prompt> ln -s ../init.d/reboot K90reboot</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Create the root disk image</title>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> cd /
|
|
<prompt>bash#</prompt> dd if=/dev/zero of=/dev/ram7 bs=1k count=4096
|
|
<prompt>bash#</prompt> mke2fs -m0 /dev/ram7 4096
|
|
<prompt>bash#</prompt> mount /dev/ram7 /mnt
|
|
<prompt>bash#</prompt> cp -dpR ~/staging/* /mnt
|
|
<prompt>bash#</prompt> umount /dev/ram7
|
|
<prompt>bash#</prompt> dd if=/dev/ram7 of=~/phase5-image bs=1k
|
|
<prompt>bash#</prompt> gzip -9 ~/phase5-image</programlisting></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Copy the image to diskette</title>
|
|
|
|
<para>Insert the diskette labeled "root disk" into drive fd0.</para>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> dd if=~/phase5-image.gz of=/dev/fd0 bs=1k</programlisting></para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>Implementation</title>
|
|
|
|
<sect2>
|
|
<title>System Startup</title>
|
|
|
|
<para>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:</para>
|
|
|
|
<para><screen>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
|
|
# _</screen></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Verify success of startup scripts</title>
|
|
|
|
<para>Use the <command>mount</command> command to check that local
|
|
filesystems are mounted as read-write. The output should look like the
|
|
example below.</para>
|
|
|
|
<para><screen><prompt>bash#</prompt> mount
|
|
/dev/root on / type ext2 (rw)
|
|
proc on /proc type proc (rw)</screen></para>
|
|
|
|
<para>Check the hostname.</para>
|
|
|
|
<para><screen><prompt>bash#</prompt> uname -n
|
|
gnu-linux</screen></para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>System shutdown</title>
|
|
|
|
<para>Bring the system down gracefully with the
|
|
<command>shutdown</command> command.</para>
|
|
|
|
<para><programlisting><prompt>bash#</prompt> shutdown -h now</programlisting></para>
|
|
|
|
<para>We should see the following output from <command>init</command>
|
|
and the shutdown scripts:</para>
|
|
|
|
<para><screen>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.</screen></para>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter> |