Chapter 4. Some Basic Utilities

Table of Contents

1. Analysis
2. Design
2.1. Determining Required Commands
2.2. Locating Source Code
2.3. Leveraging FHS
2.4. Downloading Source Code
3. Construction
3.1. Create a staging area
3.2. Copy contents of phase 2 rootdisk
3.3. Install binaries from GNU coreutils
3.4. Copy additional libraries
3.5. Strip binaries and libraries
3.6. Create a compressed root disk image
3.7. Write the root disk image to floppy
4. Implementation
4.1. System startup
4.2. Testing new commands
4.3. System shutdown

1. Analysis

In the previous chapter it might seem like we did not accomplish very much. A lot of energy was expended redesigning the root disk, but the functionality is basically the same as in the initial prototype phase. The root disk still does not do very much. But we did make significant improvements when it comes to space savings. In this chapter we will put that extra space to good use and start cramming the root disk with as many utilities as it can hold.

The first two root disks we built only had shell built-in commands like echo and pwd. This time it would be nice to have some of the commonly used external commands like cat, ls, mkdir, rm and such on the root disk. Keeping this in mind we can define the goals for this phase as follows:

  • Retain all of the functionality from the previous root disk.

  • Add some of the commonly used external commands.

2. Design

2.1. Determining Required Commands

The first question that might come to mind is, "How do we know which commands are needed?" It is possible to just start with cat and ls then install other commands as we discover a need for them. But this is terribly inefficient. We need a plan or a blueprint to work from. For this we can turn to the Filesystem Hierarchy Standard (FHS) available from http://www.pathname.com/fhs/. The FHS dictates which commands should be present on a Linux system and where they should be placed in the directory structure.

2.2. Locating Source Code

The next logical question is, "Now that we know what we need, where do we get the source code?" One way to find the answer to this question is to check the manpages. We can either search the manpages included with one of the popular GNU/Linux distributions or use one of the manpage search engines listed at http://www.tldp.org/docs.html#man. One thing that should tip us off as to where to find the source code for a particular command is the email address listed for reporting bugs. For example the cat manpage lists bug-textutils@gnu.org. From this email address we can deduce that cat is part of the textutils package from GNU.

2.3. Leveraging FHS

So let's look at the FHS requirements for the /bin directory. The first few commands in the list are cat, chgrp, chmod, chown and cp. We already know that cat is part of GNU's textutils. Using the next few commands as keywords in a manpage search we discover that we need GNU's fileutils package for chmod, chgrp, chown and cp. In fact quite a few of the commands in /bin come from GNU's fileutils. The date command also comes from a GNU package called sh-utils. So a good way to tackle the problem of finding source code might be to group the commands together by package as shown below.

  • The BASH shell -- echo, false, pwd, sh, true

  • GNU textutils -- cat

  • GNU fileutils -- chgrp, chmod, chown, cp, dd, df, ln, ls, mkdir, mknod, mv, rm, rmdir, sync

  • GNU sh-utils -- date, hostname, stty, su, uname

These four packages do not contain all of the commands in the /bin directory, but they do represent of over 70% of them. That should be enough to accomplish our goal of adding some of the commonly used external commands. We can worry about the other commands in later phases of the project.

2.4. Downloading Source Code

To fetch the source code we simply need to connect to GNU's FTP site and navigate to the appropriate package directory.

When we get to the directory for textutils there are several versions available. There is also a note informing us that the package has been renamed to coreutils. The same message about coreutils appears in the fileutils and sh-utils directories as well. So instead of downloading three separate packages we can get everything in one convenient bundle in the coreutils directory.

3. Construction

Rather than copying files directly to the ramdisk, we can make things easier by setting up a staging area. The staging area will give us room to work without worrying about the space constraints of the ramdisk. It will also provide a way to save our work and make it easier to enhance the rootdisk in later phases of the project.

The staging procedure will work like this:

  1. Create a directory structure as defined in the FHS.

  2. Copy in the files from phase 2's root disk.

  3. Build the new package from source code.

  4. Install files into the correct FHS directories.

  5. Strip the binaries to save space.

  6. Check library dependencies.

  7. Copy to the whole directory structure to the ramdisk.

  8. Compress the ramdisk and write it out to floppy.

3.1. Create a staging area

bash# mkdir ~/staging
bash# cd ~/staging
bash# mkdir bin boot dev etc home lib mnt opt proc root sbin tmp usr var
bash# mkdir var/log var/run

3.2. Copy contents of phase 2 rootdisk

bash# dd if=~/phase2-image.gz | gunzip -c > /dev/ram7
bash# mount /dev/ram7 /mnt
bash# cp -dpR /mnt/* ~/staging
bash# umount /dev/ram7
bash# rmdir ~/staging/lost+found

3.3. Install binaries from GNU coreutils

Download a recent version of coreutils from ftp://ftp.gnu.org/gnu/coreutils/

bash# cd /usr/src/coreutils-5.2.1
bash# export CC="gcc -mcpu=i386"
bash# ./configure --host=i386-pc-linux-gnu
bash# make
bash# cd src
bash# cp cat chgrp chmod chown cp date dd df ~/staging/bin
bash# cp hostname ln ls mkdir mkfifo mknod ~/staging/bin
bash# cp mv rm rmdir stty su sync uname ~/staging/bin

3.4. Copy additional libraries

Check library requirements by using ldd on some of the new binaries.

bash# ldd ~/staging/bin/cat
bash# ldd ~/staging/bin/ls
bash# ldd ~/staging/bin/su
bash# ls ~/staging/lib

Note the differences in the required libraries, as shown by the ldd command, and the libraries present in the staging area, as shown by the ls command, then copy any missing libraries to the staging area.

bash# cp /lib/librt.so.1 ~/staging/lib
bash# cp /lib/libpthread.so.0 ~/staging/lib
bash# cp /lib/libcrypt.so.1 ~/staging/lib

3.5. Strip binaries and libraries

bash# strip ~/staging/bin/*
bash# strip --strip-unneeded ~/staging/lib/*

3.6. Create a compressed 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=~/phase3-image bs=1k count=4096
bash# gzip -9 ~/phase3-image

Note

The process for creating the compressed root disk image will change very little throughout the remaining chapters. Writing a small script to handle this function can be a great time saver.

3.7. Write the root disk image to floppy

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

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

4. Implementation

We will need to have a read-write filesystem in order for some of the commands to work. The kernel's normal behavior is to mount root as read-only, but we can change this using a kernel option. By passing the kernel the rw option before init=/bin/sh we will get a read-write root filesystem.

4.1. System startup

Follow these steps to get the system running.

  • Boot the PC from using the GRUB boot disk.

  • At the grub> prompt, type kernel (fd0)/boot/vmlinuz rw init=/bin/sh root=/dev/fd0 load_ramdisk=1 prompt_ramdisk=1.

  • Verify that you remembered to add the rw parameter and press Enter.

  • Type boot and press Enter.

  • Insert the recently created root disk when prompted.

The terminal display should look similar to the example below.

GNU GRUB version 0.95

grub> kernel (fd0)/boot/vmlinuz rw init=/bin/sh root=/dev/fd0 load_ramdisk=1 prompt_ramdisk=1
   [Linux-bzImage, setup=0xc00, size=0xce29b]

grub> 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) read-write.
Freeing unused kernel memory: 178k freed
# _

4.2. Testing new commands

Now that the system is up and running, try using some of the new commands.

bash# uname -a
bash# ls /etc
bash# echo "PocketLinux" > /etc/hostname
bash# hostname $(cat /etc/hostname)
bash# uname -n
bash# mkdir /home/stuff
bash# cd /home/stuff

If everything goes well the commands like cat, ls and hostname should work now. Even mkdir should work since the root filesystem is mounted read-write. Of course since we are using a ramdisk, any changes will be lost once the PC is reset.

4.3. System shutdown

Remove the diskette from fd0 and restart the system using CTRL-ALT-DELETE.