LDP/LDP/guide/docbook/Pocket-Linux-Guide/phase4.xml

513 lines
21 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<chapter id="phase4">
<title>Checking and Mounting Disks</title>
<sect1>
<title>Analysis</title>
<para>In the previous chapter we added many new commands by installing
coreutils and as a result the root disk has a lot more functionality. But
there are still a few things lacking. One thing that really stands out is
that there was no way to mount disks. In order to get a read-write root
filesystem we had to resort to passing the <parameter>rw</parameter>
kernel parameter at the <prompt>grub&gt;</prompt> prompt. This is fine for
an emergency situation, but a normal system boot process should do things
differently.</para>
<para>Most GNU/Linux distributions take several steps to mount
filesystems. Watching the boot process or digging into the startup scripts
on one of the popular Linux distributions reveals the following sequence
of events:</para>
<orderedlist>
<listitem>
<para>The kernel automatically mounts the root filesystem as
read-only.</para>
</listitem>
<listitem>
<para>All local filesystems are checked for errors.</para>
</listitem>
<listitem>
<para>If filesystems are clean, root is remounted as
read-write.</para>
</listitem>
<listitem>
<para>The rest of the local filesystems are mounted.</para>
</listitem>
<listitem>
<para>Network filesystems are mounted.</para>
</listitem>
</orderedlist>
<para>So far our Pocket Linux system can do step one and that is it. If we
want to have a professional looking boot / root diskset we will have to do
better than one out of five. In this phase of the project we will work on
steps two and three. Steps four and five can wait. Since this is a
diskette-based system, there really are no other filesystems to mount
besides root.</para>
<para>Taking into account all of the above information, the goals for this
phase are defined as follows:</para>
<itemizedlist>
<listitem>
<para>A way to check filesystem integrity.</para>
</listitem>
<listitem>
<para>The ability to mount filesystems.</para>
</listitem>
<listitem>
<para>A script to automate checking and mounting of local
filesystems.</para>
</listitem>
</itemizedlist>
</sect1>
<sect1>
<title>Design</title>
<sect2>
<title>Determining necessary utilities.</title>
<para>We can use the Filesystem Hierarchy Standard (FHS) document to
help find the names of utilities we need and where they reside in the
directory structure. The FHS <filename>/sbin</filename> directory lists
<command>fsck</command> and something called <command>fsck.*</command>
for checking filesystems. Since we are using a Second Extended (ext2)
filesystem the <command>fsck.*</command> becomes
<command>fsck.ext2</command> for our purposes. Mounting filesystems is
done using the commands <command>mount</command> and
<command>umount</command> in the <filename>/bin</filename> directory.
However, the name of a script to automatically mount local filesystems
cannot be found. On most systems this type of script is in the
<filename>/etc</filename> directory, but while FHS does list
requirements for <filename>/etc</filename>, it does not currently make
recommendations for startup scripts. Several GNU/Linux distributions use
<filename>/etc/init.d</filename> as the place to hold startup scripts so
we will put our filesystem mounting script there.</para>
</sect2>
<sect2>
<title>Finding source code</title>
<para>In the previous chapter we used manpages to help us find source
code. In this chapter we will use a tool called the Linux Software Map
(LSM). LSM is a database of GNU/Linux software that tracks such things
as package name, author, names of binaries that make up the package and
download sites. Using an LSM search engine we can locate packages using
command names as keywords.</para>
<para>If we search Ibiblio's Linux Software Map (LSM) at <ulink
url="http://www.ibiblio.org/pub/Linux/">http://www.ibiblio.org/pub/Linux/</ulink>
for the keyword "fsck" we get a large number of matches. Since we are
using a Second Extended filesystem, called ext2 for short, we can refine
the search using "ext2" as a keyword. Supplying both keywords to the LSM
search engine comes up with a package called e2fsprogs. Looking at the
LSM entry for e2fsprogs we find out that this package contains the
utilities <command>e2fsck</command>, <command>mke2fs</command>,
<command>dumpe2fs</command>, <command>fsck</command> and more. We also
find out that the LSM entry for e2fsprogs has not been updated for a
while. There is almost certainly a newer version out there somewhere.
Another good Internet resource for source code is SourceForge at <ulink
url="http://sourceforge.net/">http://sourceforge.net/</ulink>. Using the
keyword "e2fsprogs" in the SourceForge search engine results in a much
newer version of e2fsprogs.</para>
<para>Finding <command>fsck</command> was quite an adventure, but now we
can move on to finding <command>mount</command> and
<command>umount</command>. A search on LSM comes up with a number of
matches, but most of them point to various versions of a package called
util-linux. All we have to do is scroll through and pick the most recent
release. The LSM entry for util-linux lists a lot of utilities besides
just mount and umount. We should definitely scan through the list to see
if any of the other util-linux commands show up in the FHS requirements
for <filename>/bin</filename> and <filename>/sbin</filename>.</para>
<para>Below is a list of packages we have gathered so far and the
utilities that match up with FHS.</para>
<itemizedlist>
<listitem>
<para>e2fsprogs -- <command>fsck</command>,
<command>fsck.ext2</command> (<command>e2fsck</command>),
<command>mkfs.ext2</command> (<command>mke2fs</command>)</para>
</listitem>
<listitem>
<para>util-linux -- <command>dmesg</command>,
<command>getty</command> (<command>agetty</command>),
<command>kill</command>, <command>login</command>,
<command>mount</command>, <command>swapon</command>,
<command>umount</command></para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>Automating fsck and mount</title>
<para>Now that we have <command>fsck</command> and
<command>mount</command> commands we need to come up with a shell script
to automate checking and mounting the local filesystems. An easy way to
do this would be to write a short, two line script that calls
<command>fsck</command> and then <command>mount</command>. But, what if
the filesystems are not clean? The system should definitely not try to
mount a corrupted filesystem. Therefore we need to devise a way of
determining the status of the filesystems before mounting them. The
manpage for <command>fsck</command> gives some insight into how this can
be accomplished using return codes. Basically, if
<command>fsck</command> returns a code of zero or one it means the
filesystem is okay and a return code of two or greater means some kind
of manual intervention is needed. A simple if-then statement could
evaluate the <command>fsck</command> return code to determine whether or
not the filesystem should be mounted. For help on writing shell scripts
we can turn to the BASH(1) manpage and the
Advanced-BASH-Scripting-Guide. Both references are freely available from
the Linux Documentation Project web site at <ulink
url="http://www.tldp.org/">http://www.tldp.org/</ulink>.</para>
</sect2>
<sect2>
<title>File dependencies</title>
<para>The last thing to do is to figure out if any other files besides
the binaries are needed. We learned about using <command>ldd</command>
to check for library dependencies in the last phase of the project and
we will use it to check the utilities in this phase too. There are also
some other files that <command>fsck</command> and
<command>mount</command> will need and the fsck(8) and mount(8) manpages
give some insight into what those files are. There is
<filename>/etc/fstab</filename> that lists devices and their mount
points, <filename>/etc/mtab</filename> that keeps track of what is
mounted, and a number of <filename>/dev</filename> files that represent
the various disks. We will need to include all of these to have
everything work right.</para>
<sect3>
<title>/etc/fstab</title>
<para>The <filename>/etc/fstab</filename> file is just a simple text
file that can be created with any editor. We will need an entry for
the root filesystem and for the proc filesystem. Information about the
format of this file can be found in the fstab(5) manpage or by looking
at the <filename>/etc/fstab</filename> file on any of the popular
GNU/Linux distributions.</para>
</sect3>
<sect3>
<title>/etc/mtab</title>
<para>The <filename>/etc/mtab</filename> file presents a unique
challenge, because it does not contain static information like
<filename>fstab</filename>. The <filename>mtab</filename> file tracks
mounted filesystems and therefore its contents change from time to
time. We are particularly interested in the state of
<filename>mtab</filename> when the system first starts up, before any
filesystems are mounted. At this point <filename>/etc/mtab</filename>
should be empty so we will need to configure a startup script to
create an empty <filename>/etc/mtab</filename> before any filesystems
are mounted. But it is not possible to create any files in the
<filename>/etc</filename> directory because <filename>/</filename> is
read-only at startup. This creates a paradox. We cannot create an
empty <filename>mtab</filename>, because the <filename>/</filename>
filesystem is not mounted as writable and we should not mount any
filesystems until we have created an empty <filename>mtab</filename>.
In order to sidestep this problem we need to do the following:</para>
<orderedlist>
<listitem>
<para>Remount <filename>/</filename> as read-write, but use the
<option>-n</option> option so that <command>mount</command> does
not attempt to write an entry to <filename>/etc/mtab</filename>
which is read-only at this point.</para>
</listitem>
<listitem>
<para>Create an empty <filename>/etc/mtab</filename> file now that
the filesystem is writable.</para>
</listitem>
<listitem>
<para>Remount <filename>/</filename> as read-write again, this
time using the <option>-f</option> option so that an entry is
written into <filename>/etc/mtab</filename>, but
<filename>/</filename> is not actually mounted a second
time.</para>
</listitem>
</orderedlist>
</sect3>
<sect3>
<title>Device files</title>
<para>The only thing left to do is to create device files. We will
need <filename>/dev/ram0</filename>, because that is where the root
filesystem is located. We also need <filename>/dev/fd0</filename> to
mount other floppy disks and <filename>/dev/null</filename> for use by
some of the system commands.</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>Construction</title>
<sect2>
<title>Install utilities from e2fsprogs</title>
<para>Download the e2fsprogs source code package from <ulink
url="http://sourceforge.net/projects/e2fsprogs/">http://sourceforge.net/projects/e2fsprogs/</ulink></para>
<para><programlisting><prompt>bash#</prompt> cd /usr/src/e2fsprogs-1.35
<prompt>bash#</prompt> export CC="gcc -mcpu=i386"
<prompt>bash#</prompt> ./configure --host=i386-pc-linux-gnu
<prompt>bash#</prompt> make
<prompt>bash#</prompt> cd e2fsck
<prompt>bash#</prompt> cp e2fsck.shared ~/staging/sbin/e2fsck
<prompt>bash#</prompt> ln -s e2fsck ~/staging/sbin/fsck.ext2
<prompt>bash#</prompt> cd ../misc
<prompt>bash#</prompt> cp fsck mke2fs ~/staging/sbin
<prompt>bash#</prompt> ln -s mke2fs ~/staging/sbin/mkfs.ext2</programlisting></para>
</sect2>
<sect2>
<title>Install utilities from util-linux</title>
<para>Get the latest util-linux source from <ulink
url="ftp://ftp.win.tue.nl/pub/linux-local/utils/util-linux/">ftp://ftp.win.tue.nl/pub/linux-local/utils/util-linux/</ulink></para>
<para><programlisting><prompt>bash#</prompt> cd /usr/src/util-linux-2.12h</programlisting></para>
<para>Use a text editor to make the following changes to
<filename>MCONFIG</filename>:</para>
<itemizedlist>
<listitem>
<para>Change "CPU=$(shell uname -m)" to "CPU=i386"</para>
</listitem>
<listitem>
<para>Change "HAVE_SHADOW=yes" to "HAVE_SHADOW=no"</para>
</listitem>
</itemizedlist>
<para><programlisting><prompt>bash#</prompt> ./configure
<prompt>bash#</prompt> make
<prompt>bash#</prompt> cp disk-utils/mkfs ~/staging/sbin
<prompt>bash#</prompt> cp fdisk/fdisk ~/staging/sbin
<prompt>bash#</prompt> cp login-utils/agetty ~/staging/sbin
<prompt>bash#</prompt> ln -s agetty ~/staging/sbin/getty
<prompt>bash#</prompt> cp login-utils/login ~/staging/bin
<prompt>bash#</prompt> cp misc-utils/kill ~/staging/bin
<prompt>bash#</prompt> cp mount/mount ~/staging/bin
<prompt>bash#</prompt> cp mount/umount ~/staging/bin
<prompt>bash#</prompt> cp mount/swapon ~/staging/sbin
<prompt>bash#</prompt> cp sys-utils/dmesg ~/staging/bin</programlisting></para>
</sect2>
<sect2>
<title>Check library requirements</title>
<para><programlisting><prompt>bash#</prompt> ldd ~/staging/bin/* | more
<prompt>bash#</prompt> ldd ~/staging/sbin/* | more
<prompt>bash#</prompt> ls ~/staging/lib</programlisting></para>
<para>All of the dependencies revealed by the <command>ldd</command>
command are for libraries already present in the staging area so there
is no need to copy anything new.</para>
</sect2>
<sect2>
<title>Strip binaries to save space</title>
<para><programlisting><prompt>bash#</prompt> strip ~/staging/bin/*
<prompt>bash#</prompt> strip ~/staging/sbin/*</programlisting></para>
</sect2>
<sect2>
<title>Create additional device files</title>
<para><programlisting><prompt>bash#</prompt> mknod ~/staging/dev/ram0 b 1 0
<prompt>bash#</prompt> mknod ~/staging/dev/fd0 b 2 0
<prompt>bash#</prompt> mknod ~/staging/dev/null c 1 3</programlisting></para>
</sect2>
<sect2>
<title>Create the fstab and mtab files</title>
<para><programlisting><prompt>bash#</prompt> cd ~/staging/etc
</programlisting></para>
<para>Use an editor like vi, emacs or pico to create the following file
and save it as <filename>~/staging/etc/fstab</filename>.</para>
<para><programlisting>proc /proc proc defaults 0 0
/dev/ram0 / ext2 defaults 1 1</programlisting></para>
<para>Create an empty mtab file.</para>
<programlisting><prompt>bash#</prompt> echo -n &gt;mtab</programlisting>
</sect2>
<sect2>
<title>Write a script to check and mount local filesystems</title>
<para>Use an editor to create the following shell script and save it as
<filename>~/staging/etc/init.d/local_fs</filename>:</para>
<para><programlisting>#!/bin/sh
#
# local_fs - check and mount local filesystems
#
PATH=/sbin:/bin ; export PATH
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 &gt;/etc/mtab
mount -f -o remount,rw /
echo "Mounting local filesystems."
mount -a -t nonfs,nosmbfs
fi
#
# end of local_fs</programlisting></para>
<para>Set execute permissions on the script.<programlisting><prompt>bash#</prompt> chmod +x local_fs</programlisting></para>
</sect2>
<sect2>
<title>Create a compressed 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=~/phase4-image bs=1k count=4096
<prompt>bash#</prompt> gzip -9 ~/phase4-image</programlisting></para>
</sect2>
<sect2>
<title>Write the root disk image to floppy</title>
<para>Insert the diskette labeled "root disk" into drive fd0.</para>
<para><programlisting><prompt>bash#</prompt> dd if=~/phase4-image.gz of=/dev/fd0 bs=1k</programlisting></para>
</sect2>
</sect1>
<sect1>
<title>Implementation</title>
<sect2>
<title>System startup</title>
<para>Start the system using the following procedure:</para>
<itemizedlist>
<listitem>
<para>Boot the PC using the floppy labeled "boot disk".</para>
</listitem>
<listitem>
<para>At the <prompt>grub&gt;</prompt> prompt, type the usual kernel
and boot commands, but without the <parameter>rw</parameter>
parameter this time. In other words, type <userinput>kernel
(fd0)/boot/vmlinuz init=/bin/sh root=/dev/fd0 load_ramdisk=1
prompt_ramdisk=1</userinput>, press <keycap>Enter</keycap> then type
<userinput>boot</userinput> and press <keycap>Enter</keycap>.</para>
</listitem>
<listitem>
<para>Put in the recently created root disk when prompted.</para>
</listitem>
</itemizedlist>
<para>The output should resemble the example below:</para>
<screen>GNU GRUB version 0.95
grub&gt; kernel (fd0)/boot/vmlinuz init=/bin/sh root=/dev/fd0 load_ramdisk=1 prompt_ramdisk=1
[Linux-bzImage, setup=0xc00, size=0xce29b]
grub&gt; boot
Linux version 2.4.26
..
.. [various kernel messages]
..
VFS: Insert root floppy disk 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
# _</screen>
</sect2>
<sect2>
<title>Test the local_fs script</title>
<para>Run the script by typing the following commands at the shell
prompt:</para>
<para><programlisting><prompt>bash#</prompt> PATH=/sbin:/bin:/etc/init.d ; export PATH
<prompt>bash#</prompt> cat /etc/mtab
<prompt>bash#</prompt> local_fs
<prompt>bash#</prompt> cat /etc/mtab
<prompt>bash#</prompt> df</programlisting></para>
<para>If everything is working properly, then the screen output should
look something like the example below.</para>
<para><screen><prompt>bash#</prompt> PATH=/sbin:/bin:/etc/init.d ; export PATH
<prompt>bash#</prompt> cat /etc/mtab
<prompt>bash#</prompt> local_fs
/dev/ram0: clean 74/1024 files 3178/4096 blocks
Remounting / as read-write.
Mounting local filesystems.
<prompt>bash#</prompt> cat /etc/mtab
/dev/ram0 / ext2 rw 0 0
proc /proc proc rw 0 0
<prompt>bash#</prompt> df
Filesystem 1k-blocks Used Available Use% Mounted on
/dev/ram0 3963 3045 918 77% /
</screen></para>
</sect2>
<sect2>
<title>Create and mount additional filesystems</title>
<para>Procure a blank floppy disk and label it as "home". Remove the
root disk floppy and insert the "home" diskette. Type the following
commands:</para>
<para><programlisting><prompt>bash#</prompt> mkfs -t ext2 /dev/fd0
<prompt>bash#</prompt> fsck /dev/fd0
<prompt>bash#</prompt> mount /dev/fd0 /home
<prompt>bash#</prompt> mkdir /home/floyd
<prompt>bash#</prompt> cd /home/floyd
<prompt>bash#</prompt> echo "Goodbye cruel world." &gt; goodbye.txt
<prompt>bash#</prompt> cat goodbye.txt</programlisting></para>
</sect2>
<sect2>
<title>System shutdown</title>
<para><programlisting><prompt>bash#</prompt> cd /
<prompt>bash#</prompt> umount /home</programlisting></para>
<para>Remove the diskette from fd0 and restart the system using
<keycap>CTRL</keycap>-<keycap>ALT</keycap>-<keycap>DELETE</keycap>.</para>
</sect2>
</sect1>
</chapter>