Building a Minimal Linux System
Introduction
The application the Netwinders are to be used in specifies no hard
drive and no network connection. So, since we have to boot our system
out of flash, we need to determine the minimum amount of Linux
required to actually do something useful. This is broken up in to
several stages which can be added or ignored depending on your
needs.
This system is based on RedHat version 5.2 as the .rpm files
are readily available on ftp.netwinder.org.
I'm sure that other distributions will work just as well but I am more
familiar with RedHat. I've found that I've learnt a bit about how
Linux works by doing this and I hope other people can derive something
useful out of it.
Thanks to Mike Montour for his NFS Rescue Package for
lots of tips on getting started and having a working system to play
with.
Table of Contents
Using RPM to locate and extract files
The best tool for setting up a system like this is the rpm
program. Using the -qf options we can determine which
package files belong to (this requires a running system
unfortunately. Once we have the name of the RPM package, use
rpm2cpio rpmfile.rpm | cpio -vid to extract all the files.
Copy out the ones required. Note there may be a problem with any
post-install scripts that are normally run when you install the RPM
file. Not sure how to handle this at the moment.
Creating devices
Extract the MAKEDEV script from the MAKEDEV rpm into
the /dev/ directory of your new installation. Note that
since MAKEDEV creates new device nodes using mknod,
this script is required to be run as root. Use MAKEDEV in
turn with the arguments below to create the appropriate device files.
std | Creates "standard" devices including
core, full, mem, null,
port, ram, tty, and
zero |
pty | Creates master and slave pty devices |
console | Creates virtual console devices |
fd | Symbolic links for fd and stdio
devices (not to be confused with floppy disk device files) |
Other devices which may be of use, but not in my particular
application are as follows.
ttyS0, ttyS1 | Serial port devices |
hda | First IDE hard disk device files |
audio | Sound driver devices |
Note that due to the way MAKEDEV calculates the major numbers
for devices, the kernel running the script needs to have those options
compiled in to it. For example, you can't create the device files for
the loopback or audio devices without having loopback or audio support
compiled in to the currently running kernel, respectively.
A Bourne shell
Extract a version of your favourite shell into the /bin
directory. If you're feeling lucky (punk) then extract a dynamically
linked version. If you just want to muck around before getting the
dynamic linker working then use a statically linked version. I
recommend /bin/ash.static from the ash rpm package.
Writing /sbin/init
Now, the very last thing the Linux kernel does is try and execute
/sbin/init which is the very first process run in user-land.
From init/main.c from the kernel source code:
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command)
execve(execute_command,argv_init,envp_init);
execve("/sbin/init",argv_init,envp_init);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
execve("/bin/sh",argv_init,envp_init);
panic("No init found. Try passing init= option to kernel.");
Normally the version of init installed on a Linux system, in
the case of the RedHat distribution, is the SysVinit
package. This is a fairly complicated series of shell scripts in
/etc/init.d involving runlevels and such. For a minimal
Linux system I consider this overkill and the whole arrangement can
consist of a simple shell script.
An simple example of an init script is below.
#!/bin/ash
echo Welcome to nano-linux
/bin/ash
This will present you with a (single) console shell logged in as
root. Note that if you log out of it your system basically hangs. I
think the kernel is still runing and scheduling processes but you may
have no way of logging in. What is needed is to run ash as a
login shell. According to the manual page for ash,
If the first character of argument zero to the shell is
``-'', the shell is assumed to be a login shell, and the
files /etc/profile and .profile are read if they exist.
I'm not sure how you do this from a shell script. A C program may be
able to do this by fiddling with the arguments to execv().
Running dynamically linked executables
Through trial and error, I've discovered the minimum number of files
required to run dynamically linked executables. The following files
are required.
- glibc
- /lib/ld-2.0.*.so
- /lib/libc-2.0-*.so
Make the following symbolic links.
# ln -s /lib/ld-2.0.*.so /lib/ld-linux.so.2
# ln -s /lib/libc-2.0.*.so /lib/libc.so.6
# ln -s /lib/ld-linux.so.2 /usr/lib/ld.so.1
The glibc RPM also contains the math library, /libm
and many others which may be needed by other applications.
The /proc filesystem
Copy mount and umount from their RPM.
Add the following lines to your /sbin/init script to mount
the proc filesystem.
echo >/etc/mtab
mount /proc /proc -t proc
File and text utilities
I consider the following programs to be fairly essential in being able
to get something useful done.
- fileutils
- chgrp, chmod, chown,
cp, dd, df, ln,
ls, mkdir, mknod, mv,
rm, rmdir, sync, touch
- textutils
Networking
Presently, running ping on the minimal linux system produces
the error "no such protocol: icmp" which would imply some problem in
the getprotobyname() library call. I've copied across the
following files but it still doesn't work.
- netkit-base
- setup
- /etc/protocols
- /etc/services
I suspect there may be some other configuration files needed (perhaps
some entries in /etc/resolv.conf or
/etc/nsswitch.conf plus associated libraries out of the
glibc rpm to get protocol resolution working correctly.
Going over the source for the getprotobyname() function will
probably be instructive.
To get some more useful network things happening, the following
binaries may be needed. This information can probably be retrieved or
set from the /proc directory.
- net-tools
- /bin/{host,domain}name
- /sbin/ifconfig
- /sbin/route
- /bin/netstat
Virtual consoles
How to get virtual consoles working. Dunno.
Other useful packages
Other programs considered to be standard UNIX functions which you may
want to add to your minimal linux system are:
- cron and at
- Various daemons run out of inetd which can be configured to run
standalone:
- telnet
- ftp
- rsh and rlogin
Scripts
Need to write some scripts to extract files from RPMs as it would be
nice to be able to copy across updated versions of RPMs and use
make to rebuild the image. Doing it by hand is a bit
annoying.
Other resources
Some other resources on building a minimal linux distribution include:
Notes/Ideas/TODO
- The dynamic library for libc.6 is rather large. It's
6MB uncompressed and 1MB compressed. On a netwinder with 4MB of
flash, this takes up a quarter of the total available space
- Look at building a stripped down version of libc with all
the unused sumbols removed. Need to work out compiler
flags and such to link with modified libc.
- How to upgrade/distribute dynamically linked objects in
the field. Perhaps statically link objects that are not
present in the modified libc.
- Pinch ideas from the Linux Router
Project (-:
- Investigate post-install scripts in the RPM file
- Figure out how to run ash as a login shell
- Write utilities as small shell scripts by reading/writing from
the /proc directory
Tim Potter <tpot@acsys.anu.edu.au>
Last modified: Fri Feb 26 14:04:00 EST 1999