Chapter 3. Saving Space

Table of Contents

1. Analysis
2. Design
2.1. Shared Libraries
2.2. Stripped Binaries
2.3. Compressed Root Filesystem
3. Construction
3.1. Create a ramdisk
3.2. Rebuild the BASH shell
3.3. Determine which libraries are required
3.4. Copy BASH and its libraries to the ramdisk
3.5. Create a console device
3.6. Compress the ramdisk image
3.7. Copy the compressed image to diskette
4. Implementation
4.1. System startup
4.2. Verify results
4.3. System shutdown

1. Analysis

One of the drawbacks in the prototype phase of the project was that the diskset was not all that useful. The only commands that worked were the ones built into the BASH shell. We could improve our root disk by installing commands like cat, ls, mv, rm and so on. Unfortunately, we are short on space. The current root disk has no shared libraries so each utility would have to be statically-linked just like the BASH shell. A lot of big binaries together with a static shell will rapidly exceed the tiny 1.44M of available disk space. So our main goal in this phase should be to maximize space savings on the root disk and pave the way for expanded functionality in the next phase.

2. Design

Take another look at the Bootdisk-HOWTO and notice how many utilities can be squeezed onto a 1.44M floppy. There are three things that make this possible. One is the use of shared libraries. The second is stripped binaries. And the third is the use of a compressed filesystem. We can use all of these techniques to save space on our root disk.

2.1. Shared Libraries

First, in order to use shared libraries we will need to rebuild the BASH shell. This time we will configure it without using the --enable-static-link option. Once BASH is rebuilt we need to figure out which libraries it is linked with and be sure to include them on the root disk. The ldd command makes this job easy. By typing ldd bash on the command-line we can see a list of all the shared libraries that BASH uses. As long as all these libraries are copied to the root disk, the new BASH build should work fine.

2.2. Stripped Binaries

Next, we should strip any binaries that get copied to the root disk. The manpage for strip does not give much description of what it does other than to say, "strip discards all symbols from the object files." It seems like removing pieces of a binary would render it useless, but this is not the case. The reason it works is because a large number of these discarded symbols are used for debugging. While debugging symbols are very helpful to programmers working to improve the code, they do not do much for the average end-user other than take up more disk space. And since space is at a premium, we should definitely remove as many symbols as possible from BASH and any other binaries before we copy over them to the ramdisk.

The process of stripping files to save space also works with shared library files. But when stripping libraries it is important to use the --strip-unneeded option so as not to break them. Using --strip-unneeded shrinks the file size, but leaves the symbols needed for relocation intact which is something that shared libraries need to function properly.

2.3. Compressed Root Filesystem

Finally, we can tackle the problem of how to build a compressed root filesystem. The Bootdisk-HOWTO suggests three ways of constructing a compressed root filesystem using either a ramdisk, a spare hard drive partition or a loopback device. This project will concentrate on using the ramdisk approach. It seems logical that if the root filesystem is going to be run from a ramdisk, it may as well be built on a ramdisk. All we have to do is create a second extended filesystem on a ramdisk device, mount it and copy files to it. Once the filesystem is populated with all the files that the root disk needs, we simply unmount it, compress it and write it out to floppy.

Note

For this to work, we need to make sure the system used for building has ramdisk support. If ramdisk is not available it is also possible to use a loopback device. See the Bootdisk-HOWTO for more information on using loopback devices.

3. Construction

This section is written using ramdisk seven (/dev/ram7) to build the root image. There is nothing particularly special about ramdisk seven and it is possible to use any of the other available ramdisks provided they are not already in use.

3.1. Create a ramdisk

bash# dd if=/dev/zero of=/dev/ram7 bs=1k count=4096
bash# mke2fs -m0 /dev/ram7 4096
bash# mount /dev/ram7 /mnt

3.2. Rebuild the BASH shell

bash# cd /usr/src/bash-3.0
bash# make distclean
bash# export CC="gcc -mcpu=i386"
bash# ./configure --enable-minimal-config --host=i386-pc-linux-gnu
bash# make
bash# strip bash

3.3. Determine which libraries are required

bash# ldd bash

View the output from the ldd command. It should look similar to the example below.

bash# ldd bash
  libdl.so.2 => /lib/libdl.so.2 (0x4001d000)
  libc.so.6 => /lib/libc.so.6 (0x40020000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Note

Some systems may have a slightly different library set up. For example, you may see libc.so.6 => /lib/tls/libc.so.6 rather than libc.so.6 => /lib/libc.so.6 as shown in the example. If your ldd output does not match the example then use the path given by your ldd command when completing the next step.

3.4. Copy BASH and its libraries to the ramdisk

bash# mkdir /mnt/bin
bash# cp bash /mnt/bin
bash# ln -s bash /mnt/bin/sh
bash# mkdir /mnt/lib
bash# strip --strip-unneeded -o /mnt/lib/libdl.so.2 /lib/libdl.so.2
bash# strip --strip-unneeded -o /mnt/lib/libc.so.6 /lib/libc.so.6
bash# strip --strip-unneeded -o /mnt/lib/ld-linux.so.2 /lib/ld-linux.so.2
bash# chmod +x /mnt/lib/ld-linux.so.2

Note

Using strip -o might seem an odd way to copy library files from the development system to the ramdisk. What it does is strip the symbols while the file is in transit from the source location to the destination. This has the effect of stripping symbols from the library on the ramdisk without altering the libraries on the development system. Unfortunately file permissions are lost when copying libraries this way which is why the chmod +x command is then used to set the execute flag for the rootdisk's dynamic loader.

3.5. Create a console device

bash# mkdir /mnt/dev
bash# mknod /mnt/dev/console c 5 1

3.6. Compress the ramdisk image

bash# cd /
bash# umount /dev/ram7
bash# dd if=/dev/ram7 of=~/phase2-image bs=1k count=4096
bash# gzip -9 ~/phase2-image

3.7. Copy the compressed image to diskette

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

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

4. Implementation

Successful implementation of this phase is probably the most difficult part of the Pocket Linux Guide. If you need help getting things to work please visit the Pocket Linux Guide Resource Site to browse the troubleshooting forum and subscribe to the mailing list.

4.1. System startup

Follow these steps to boot:

  • Restart the PC using the boot disk from the previous chapter.

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

  • Type boot at the grub> prompt and press Enter.

  • Insert the new, compressed root disk when prompted.

The screen output should be similar to the following example:

GNU GRUB version 0.95

grub> kernel (fd0)/boot/vmlinuz 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) readonly.
Freeing unused kernel memory: 178k freed
# _

4.2. Verify results

If the implementation was successful, this new root disk should behave exactly like the root disk from the previous chapter. The key difference is that this compressed root disk has much more room to grow and we will put this extra space to good use in the next phase of the project.

4.3. System shutdown

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