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

383 lines
13 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<chapter id="phase7">
<title>Filling in the Gaps</title>
<sect1>
<title>Analysis</title>
<para>The root disk has come a long way since its humble beginnings as a
statically-linked shell. It now shares many features with the popular,
ready-made distributions. For example it has:</para>
<itemizedlist>
<listitem>
<para>Several common utilities like <command>cat</command>,
<command>ls</command> and so on.</para>
</listitem>
<listitem>
<para>Startup scripts that automatically check and mount
filesystems.</para>
</listitem>
<listitem>
<para>Graceful shutdown capability.</para>
</listitem>
<listitem>
<para>Support for multiple users and virtual terminals.</para>
</listitem>
</itemizedlist>
<para>As a final test, we can put the root disk up against the Filesystem
Hierarchy Standard (FHS) requirements for the root filesystem. (We will
ignore anything in the <filename>/usr</filename> hierarchy because of
space constraints.) Compared to FHS requirement, the only files missing
are a few commands in the <filename>/bin</filename> directory.
Specifically, the root disk lacks the following commands:</para>
<itemizedlist>
<listitem>
<para><command>more</command></para>
</listitem>
<listitem>
<para><command>ps</command></para>
</listitem>
<listitem>
<para><command>sed</command></para>
</listitem>
</itemizedlist>
<para>In addition to the required commands, it might be nice to include
the "ed" editor listed as an option by the FHS. It is not as robust as vi
or emacs, but it works and it should fit onto the tiny root
filesystem.</para>
<para>So in order to finish up this phase of the project, we need to
accomplish the following goals:</para>
<itemizedlist>
<listitem>
<para>Add the <command>more</command>, <command>ps</command> and
<command>sed</command> commands.</para>
</listitem>
<listitem>
<para>Install the optional <command>ed</command> editor.</para>
</listitem>
</itemizedlist>
</sect1>
<sect1>
<title>Design</title>
<sect2>
<title>more</title>
<para>There is a <command>more</command> command that comes with
util-linux, but it will not work for this project. The reason is because
of library dependencies and space constraints. The util-linux supplied
<command>more</command> needs either the libncurses or libtermcap to
work and there just is not enough space on the root disk floppy to fit
everything in. So, in order to have a <command>more</command> command we
will have to get creative.</para>
<para>The <command>more</command> command is used to display a file page
by page. It's a little like having a <command>cat</command> command that
pauses every twenty-five lines. The basic logic is outlined
below.</para>
<itemizedlist>
<listitem>
<para>Read one line of the file.</para>
</listitem>
<listitem>
<para>Display the line on the screen.</para>
</listitem>
<listitem>
<para>If 25 lines have been displayed, pause.</para>
</listitem>
<listitem>
<para>Loop and do it again.</para>
</listitem>
</itemizedlist>
<para>Of course there are some details left out like what to do if the
screen dimensions are not what we anticipated, but overall it is a fair
representation of what <command>more</command> does. Given this simple
program logic, it should not be hard to put together a short shell
script that emulates the basic functionality of <command>more</command>.
The BASH(1) manpage and Adv-BASH-Scripting-Guide will serve as
references.</para>
</sect2>
<sect2>
<title>More device files</title>
<para>The <command>more</command> script will need access to device
files that are not on the root disk yet. Specifically
<command>more</command> needs to have <filename>stdin</filename>,
<filename>stdout</filename> and <filename>stderr</filename>, but while
we are at it we should check for any other missing
<filename>/dev</filename> files. The Linux Standard Base requires
<filename>null</filename>, <filename>zero</filename> and
<filename>tty</filename> to be present in the <filename>/dev</filename>
directory. Files for <filename>null</filename> and
<filename>tty</filename> already exist from previous phases of the
project, but we still need <filename>/dev/zero</filename>. We can refer
to <filename>devices.txt</filename> in the Linux source code
<filename>Documentation</filename> directory for major and minor
numbers.</para>
</sect2>
<sect2>
<title>ps, sed &amp; ed</title>
<para>These three packages can be found by using the Internet resources
we have used before plus one new site. The "sed" and "ed" packages can
be found at the same place we found BASH, on the <ulink
url="ftp://ftp.gnu.org">GNU FTP server</ulink>. The procps package shows
up in an Ibiblio LSM search, but it is an old version. In order to find
the latest version we can go to the Freshmeat website at <ulink
url="http://freshmeat.net">http://freshmeat.net</ulink> and search for
"procps" in projects.</para>
<para>Both "sed" and "ed" packages feature GNU's familiar
<command>configure</command> script and are therefore very easy to
build. There is no <command>configure</command> script for "procps" but
this does not make things too difficult. We can just read the package's
<filename>README</filename> file to find out about how to set various
configuration options. We can use one of these options to avoid the
complexity of using and installing libproc. Setting
<parameter>SHARED=0</parameter> makes <filename>libproc</filename> an
integrated part of <command>ps</command> rather than a separate, shared
library.</para>
</sect2>
</sect1>
<sect1>
<title>Construction</title>
<sect2>
<title>Write a "more" script</title>
<para>Create the following script with a text editor and save it as
<filename>~/staging/bin/more.sh</filename></para>
<para><programlisting>#!/bin/sh
#
# more.sh - emulates the basic functions of the "more" binary without
# requiring ncurses or termcap libraries.
#
# Assume input is coming from STDIN unless a valid file is given as
# a command-line argument.
if [ -f $1 ]; then
INPUT="$1"
else
INPUT="/dev/stdin"
fi
#
# Set IFS to newline only. See BASH(1) manpage for details on IFS.
IFS=$'\n'
#
# If terminal dimensions are not already set as shell variables, take
# a guess of 80x25.
if [ "$COLUMNS" = "" ]; then
let COLUMNS=80;
fi
if [ "$LINES" = "" ]; then
let LINES=25;
fi
#
# Initialize line counter variable
let LINE_COUNTER=$LINES
#
# Read the input file one line at a time and display on STDOUT until
# the page fills up. Display "Press &lt;Enter&gt;" message on STDERR and wait
# for keypress from STDERR. Continue until the end of the input file.
# Any input line greater than $COLUMNS characters in length is wrapped
# and counts as multiple lines.
#
while read -n $COLUMNS LINE_BUFFER; do
echo "$LINE_BUFFER"
let LINE_COUNTER=$LINE_COUNTER-1
if [ $LINE_COUNTER -le 1 ]; then
echo "Press &lt;ENTER&gt; for next page or &lt;CTRL&gt;+C to quit."&gt;/dev/stderr
read&lt;/dev/stderr
let LINE_COUNTER=$LINES
fi
done&lt;$INPUT
#
# end of more.sh</programlisting></para>
<para>Create a symbolic link for <filename>more</filename></para>
<para><programlisting><prompt>bash#</prompt> ln -s more.sh ~/staging/bin/more</programlisting></para>
</sect2>
<sect2>
<title>Create additional device files</title>
<para><programlisting><prompt>bash#</prompt> ln -s /proc/self/fd ~/staging/dev/fd
<prompt>bash#</prompt> ln -s fd/0 ~/staging/dev/stdin
<prompt>bash#</prompt> ln -s fd/1 ~/staging/dev/stdout
<prompt>bash#</prompt> ln -s fd/2 ~/staging/dev/stderr
bash# mknod -m644 ~/staging/dev/zero c 1 5</programlisting></para>
</sect2>
<sect2>
<title>Install ps</title>
<para>Get the latest procps source package from <ulink
url="http://procps.sourceforge.net/">http://procps.sourceforge.net/</ulink></para>
<para><programlisting><prompt>bash#</prompt> cd /usr/src/procps-3.2.3
<prompt>bash#</prompt> make SHARED=0 CC="gcc -mcpu=i386"
<prompt>bash#</prompt> cd ps
<prompt>bash#</prompt> cp ps ~/staging/bin</programlisting></para>
</sect2>
<sect2>
<title>Install sed</title>
<para>Download GNU's sed from <ulink
url="ftp://ftp.gnu.org/gnu/sed/">ftp://ftp.gnu.org/gnu/sed/</ulink></para>
<para><programlisting><prompt>bash#</prompt> cd /usr/src/sed-4.1.2
<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 sed
<prompt>bash#</prompt> cp sed ~/staging/bin</programlisting></para>
</sect2>
<sect2>
<title>Install ed</title>
<para>The ed package also comes from GNU at <ulink
url="ftp://ftp.gnu.org/gnu/ed/">ftp://ftp.gnu.org/gnu/ed/</ulink></para>
<para><programlisting><prompt>bash#</prompt> cd /usr/src/ed-0.2
<prompt>bash#</prompt> ./configure --host=i386-pc-linux-gnu
<prompt>bash#</prompt> make
<prompt>bash#</prompt> cp ed ~/staging/bin</programlisting></para>
</sect2>
<sect2>
<title>Strip binaries to save space</title>
<para><programlisting><prompt>bash#</prompt> strip ~/staging/bin/*</programlisting></para>
</sect2>
<sect2>
<title>Ensure proper permissions</title>
<para><programlisting><prompt>bash#</prompt> chown 0:0 ~/staging/bin/*
<prompt>bash#</prompt> chmod -R 755 ~/staging/bin
<prompt>bash#</prompt> chmod 4750 ~/staging/bin/su</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=~/phase7-image bs=1k
<prompt>bash#</prompt> gzip -9 ~/phase7-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=~/phase7-image.gz of=/dev/fd0 bs=1k</programlisting></para>
</sect2>
</sect1>
<sect1>
<title>Implementation</title>
<sect2>
<title>System startup</title>
<para>Boot from the diskset in the usual way and log in as root.</para>
</sect2>
<sect2>
<title>Test the "more" script</title>
<para>Display kernel messages by piping the output of
<command>dmesg</command> to <command>more</command>.</para>
<para><programlisting><prompt>bash#</prompt> dmesg | more</programlisting></para>
<para>Examine the <filename>local_fs</filename> script by using
<command>more</command> with a command-line argument.</para>
<para><programlisting><prompt>bash#</prompt> more /etc/init.d/local_fs</programlisting></para>
</sect2>
<sect2>
<title>Use ps to show running processes</title>
<para>Display processes for the user currently logged in.</para>
<para><programlisting><prompt>bash#</prompt> ps</programlisting></para>
<para>Display all available information about all running
processes.</para>
<para><programlisting><prompt>bash#</prompt> ps -ef</programlisting></para>
</sect2>
<sect2>
<title>Run a simple sed script</title>
<para>Use <command>sed</command> to display an alternate version of
<filename>/etc/passwd</filename>.</para>
<para><programlisting><prompt>bash#</prompt> sed -e "s/Legacy/Old School/" /etc/passwd</programlisting></para>
<para>Verify that sed did not make the changes permanent.</para>
<para><programlisting><prompt>bash#</prompt> cat /etc/passwd</programlisting></para>
</sect2>
<sect2>
<title>Test the "ed" editor</title>
<para>Use <command>ed</command> to change properties on the "daemon"
user.</para>
<para><programlisting><prompt>bash#</prompt> ed -p*
<prompt>ed*</prompt> r /etc/passwd
<prompt>ed*</prompt> %p
<prompt>ed*</prompt> /daemon/s/Legacy/Old School/
<prompt>ed*</prompt> %p
<prompt>ed*</prompt> w
<prompt>ed*</prompt> q</programlisting></para>
<para>Verify that the changes are permanent (at least until the system
is restarted.)</para>
<para><programlisting><prompt>bash#</prompt> cat /etc/passwd</programlisting></para>
</sect2>
<sect2>
<title>System shutdown</title>
<para>Bring the system down gracefully with the
<command>shutdown</command> command.</para>
</sect2>
</sect1>
</chapter>