Creating the root filesystem involves selecting files necessary for the system to run. In this section we describe how to build a compressed root filesystem. A less common option is to build an uncompressed filesystem on a diskette that is directly mounted as root; this alternative is described in section Non-ramdisk Root Filesystem.
A root filesystem must contain everything needed to support a full Linux system. To be able to do this, the disk must include the minimum requirements for a Linux system:
/dev, /proc, /bin, /etc, /lib, /usr,
/tmp
,sh, ls, cp, mv
, etc.,rc, inittab, fstab
, etc.,/dev/hd*, /dev/tty*, /dev/fd0
, etc.,Of course, any system only becomes useful when you can run something on it, and a root diskette usually only becomes useful when you can do something like:
fsck
on your original root drive while it is not
mounted.
cpio, tar, gzip
and ftape
.
We will describe how to build a compressed filesystem, so called because it is compressed on disk and, when booted, is uncompressed onto a ramdisk. With a compressed filesystem you can fit many files (approximately six megabytes) onto a standard 1440K diskette. Because the filesystem is much larger than a diskette, it cannot be built on the diskette. We have to build it elsewhere, compress it, then copy it to the diskette.
In order to build such a root filesystem, you need a spare device that is large enough to hold all the files before compression. You will need a device capable of holding about four megabytes. There are several choices:
RAMDISK_SIZE = nnnwhich determines how much RAM will be allocated. The default is 4096K, which should be sufficient. You should probably not try to use such a ramdisk on a machine with less than 8MB of RAM. Check to make sure you have a device like /dev/ram0, /dev/ram or /dev/ramdisk. If not, create /dev/ram0 with
mknod
(major number 1, minor 0).
mount
and
unmount
programs. You can find these in the directory:
ftp://ftp.win.tue.nl:/pub/linux/util/mount/
If you do not have a loop device (/dev/loop0,
/dev/loop1, etc.) on your system, you will have to create
one with ``mknod /dev/loop0 b 7 0
''. One you've installed these
special mount
and umount
binaries, create a temporary file
on a hard disk with enough capacity (eg, /tmp/fsfile).
You can use a command like
dd if=/dev/zero of=/tmp/fsfile bs=1k count=nnn
to create an nnn-block file.
Use the file name in place of DEVICE below. When you issue a mount
command you must include the option ``-o loop
'' to tell mount
to use a loopback device.
For example:
mount -o loop -t ext2 /tmp/fsfile /mnt
will mount /tmp/fsfile (via a loopback device) at the mount
point /mnt
. A df
will confirm this.
After you've chosen one of these options, prepare the DEVICE with:
dd if=/dev/zero of=DEVICE bs=1k count=3000
This command zeroes out the device. This step is important because the filesystem on the device will be compressed later, so all unused portions should be filled with zeroes to achieve maximum compression.
Next, create the filesystem. The Linux kernel recognizes two file system
types for root disks to be automatically copied to ramdisk. These are minix
and ext2, of which ext2 is the preferred file system. If using ext2, you may
find it useful to use the -i
option to specify more inodes than the
default; -i 2000
is suggested so that you don't run out of inodes.
Alternatively, you can save on inodes by removing lots of unnecessary
/dev
files. mke2fs
will by default create 360 inodes on a
1.44Mb diskette. I find that 120 inodes is ample on my current rescue root
diskette, but if you include all the devices in the /dev
directory
then you will easily exceed 360. Using a compressed root filesystem allows a
larger filesystem, and hence more inodes by default, but you may still need to
either reduce the number of files or increase the number of inodes.
So the command you use will look like:
mke2fs -m 0 -i 2000 DEVICE
(If you're using a loopback device, the disk file you're using should be
supplied in place of this DEVICE.
In this case,
mke2fs
will ask if you really want to do this; say yes.)
The mke2fs
command will automatically detect the space available and
configure itself accordingly. The -m 0
parameter prevents it
from reserving space for root, and hence provides more usable space on
the disk.
Next, mount the device:
mount -t ext2 DEVICE /mnt
(You must create a mount point /mnt
if it does not already exist.)
In the remaining sections, all destination directory names are assumed
to be relative to /mnt
.
Here is a reasonable minimum set of directories for your root filesystem:
/dev
-- Devices, required to perform I/O /proc
-- Directory stub required by the proc filesystem/etc
-- System configuration files/sbin
-- Critical system binaries /bin
-- Basic binaries considered part of the system /lib
-- Shared libraries to provide run-time support/mnt
-- A mount point for maintenance on other disks/usr
-- Additional utilities and applications(The directory structure presented here is for root diskette use only. Real Linux systems have a more complex and disciplined set of policies, called the File System Standard, for determining where files should go.)
Three of these directories will be empty on the root filesystem, so they
only need to be created with mkdir
. The /proc
directory is
basically a stub under which the proc filesystem is placed. The
directories /mnt
and /usr
are only mount points for use
after the boot/root system is running. Hence again, these directories only
need to be created.
The remaining four directories are described in the following sections.
A /dev
directory containing a special file for all devices to be
used by the system is mandatory for any Linux system. The directory itself
is a normal directory, and can be created with mkdir
in the normal
way. The device special files, however, must be created in a special way,
using the mknod
command.
There is a shortcut, though -- copy your existing /dev
directory
contents, and delete the ones you don't want. The only requirement is that
you copy the device special files using -R
option. This will copy the
directory without attempting to copy the contents of the files. Be sure
to use an upper case R. If you use the lower case switch -r
, you
will probably end up copying the entire contents of all of your hard disks
-- or at least as much of them as will fit on a diskette! Therefore,
take care, and use the command:
cp -dpR /dev /mnt
assuming that the diskette is mounted at /mnt
. The dp
switches
ensure that symbolic links are copied as links, rather than using the
target file, and that the original file attributes are preserved, thus
preserving ownership information.
Alternatively, you can use the cpio
program with the -p
option, because cpio
handles device special files correctly, and
will not try to copy the contents. For example, the commands:
cd /dev
find . -print | cpio -pmd /mnt/dev
will copy all device special files from /dev
to
/mnt/dev. In fact it will copy all files in the directory
tree starting at /dev
, and will create any required subdirectories
in the target directory tree.
If you want to do it the hard way, use ls -l
to display the major
and minor device numbers for the devices you want, and create
them on the diskette using mknod
.
However the devices are copied, it is worth checking that any special
devices you need have been placed on the rescue diskette. For example,
ftape
uses tape devices, so you will need to copy all of
these if you intend to access your floppy tape drive from the bootdisk.
Note that one inode is required for each device special file, and
inodes can at times be a scarce resource, especially on diskette
filesystems. It therefore makes sense to remove any device special files
that you don't need from the diskette /dev
directory. Many
devices are obviously unnecessary on specific systems. For example, if you
do not have SCSI disks you can safely remove all the device files starting
with sd
. Similarly, if you don't intend to use your serial port
then all device files starting with cua
can go.
Be sure to include the following files from this directory:
console, kmem, mem, null, ram, tty1
.
This directory must contain a number of configuration files. On most systems, these can be divided into three groups:
rc, fstab, passwd
.
Files which are not essential can be identified with the command:
ls -ltru
This lists files in reverse order of date last accessed, so if any files are not being accessed, they can be omitted from a root diskette.
On my root diskettes, I have the number of config files down to 15. This reduces my work to dealing with three sets of files:
rc.d/*
-- system startup and run level change scriptsfstab
-- list of file systems to be mounted inittab
-- parameters for the init
process, the
first process started at boot time.
passwd
-- list of users, home directories, etc.group
-- user groups.
shadow
-- passwords of users. You may not have this.
passwd
and shadow
should be pruned to
avoid copying user passwords off the system, and so that when you boot from
diskette, unwanted logins are rejected. However, there is a reason not
to prune passwd
and group
. tar
(and probably other archivers)
stores user and group names with files. If you restore files to your hard
disk from tape, the files will be restored with their original names. If
these names do not exist in passwd
/group
when they are restored, the
UIDs/GIDs will not be correct.
Be sure that passwd
contains at least root
. If you
intend other users to login, be sure their home directories and shells
exist.
Out of this, I only really have to configure two files, and what they should contain is surprisingly small.
rc
should contain:
#!/bin/sh /bin/mount -av /bin/hostname KangarooBe sure the directories are right. You don't really need to run
hostname
-- it just looks nicer if you do.
fstab
should contain at least:
/dev/ram0 / ext2 defaults /dev/fd0 / ext2 defaults /proc /proc proc defaultsYou can copy entries from your existing
fstab
, but you should not
automatically mount any of your hard disk partitions; use the noauto
keyword with them. Your hard disk may be damaged or dead when the bootdisk is
used.
Your inittab
should be changed so that its
sysinit
line runs rc
or whatever basic boot script
will be used. Also, if you want to ensure that users on serial ports
cannot login, comment out all the entries for getty
which include a
ttys
or ttyS
device at the end of the line. Leave in the
tty
ports so that you can login at the console.
A minimal inittab
file looks like this:
id:2:initdefault: si::sysinit:/etc/rc 1:2345:respawn:/sbin/getty 9600 tty1 2:23:respawn:/sbin/getty 9600 tty2
The inittab
file defines what the system will run in various
states including startup, move to multi-user mode, etc. A point to be
careful of here is to carefully check that the commands entered in
inittab
refer to programs which are present and to the correct
directory. If you place your command files on your rescue disk using
Section
Sample rootdisk directory listings as
a guide, and then copy your inittab
to your rescue disk without
checking it, the probability of failure will be quite high because half of
the inittab
entries will refer to missing programs or to the wrong
directory.
Note that some programs cannot be moved elsewhere because other programs
have hardcoded their locations. For example on my system,
/etc/shutdown has hardcoded in it /etc/reboot.
If I move reboot
to /bin/reboot, and then issue a
shutdown
command, it will fail because it cannot find the reboot
file.
For the rest, just copy all the text files in your /etc
directory,
plus all the executables in your /etc
directory that you cannot be
sure you do not need. As a guide, consult the sample listing in Section
Sample rootdisk directory listings. Probably it will
suffice to copy only those files, but systems differ a great deal, so you
cannot be sure that the same set of files on your system is equivalent to the
files in the list. The only sure method is to start with inittab
and
work out what is required.
Most systems now use an /etc/rc.d/ directory containing shell
scripts for different run levels. The minimum is a single rc
script,
but it may be simpler just to copy inittab
and the
/etc/rc.d directory from your existing system, and prune the shell
scripts in the rc.d
directory to remove processing not relevent to a
diskette system environment.
The /bin
directory is a convenient place for extra utilities you need
to perform basic operations, utilities such as ls
, mv
, cat
and
dd
. See Appendix
Sample rootdisk directory listings for an example list of files that go in a /bin
and
/sbin
directories. It does not include any of the utilities required
to restore from backup, such as cpio
, tar
and gzip
. That is
because I place these on a separate utility diskette, to save space on the
boot/root diskette. Once the boot/root diskette is booted, it is copied to
the ramdisk leaving the diskette drive free to mount another diskette, the
utility diskette. I usually mount this as /usr
.
Creation of a utility diskette is described below in the section Section Building a utility disk. It is probably desirable to maintain a copy of the same version of backup utilities used to write the backups so you don't waste time trying to install versions that cannot read your backup tapes.
Make sure you include the following programs: init
, getty
or equivalent, login
, mount
, some shell capable of running your rc
scripts, a link from sh
to the shell.
In /lib
you place necessary shared libraries and loaders. If the
necessary libraries are not found in your /lib
directory then the
system will be unable to boot. If you're lucky you may see an error
message telling you why.
Nearly every program requires at least the libc
library,
libc.so.N
, where N is the current version number. Check
your /lib
directory. libc.so.5
is usually a symlink
to a filename with a complete version number:
% ls -l /lib/libc.so*
lrwxrwxrwx 1 root root 14 Nov 1 20:34 /lib/libc.so.5 -> libc.so.5.4.33*
-rwxr-xr-x 1 root root 573176 Jun 12 02:05 /lib/libc.so.5.4.33*
In this case, you want libc.so.5.4.33
. To find other libraries you
should go through all the binaries you plan to include and check their
dependencies with the ldd
command. For example:
% ldd /sbin/mke2fs libext2fs.so.2 => /lib/libext2fs.so.2 libcom_err.so.2 => /lib/libcom_err.so.2 libuuid.so.1 => /lib/libuuid.so.1 libc.so.5 => /lib/libc.so.5
Each file on the right-hand side is required. Keep in mind that the libraries listed may be symbolic links.
In /lib
you must also include a loader for the libraries.
The loader will be either ld.so
(for a.out libraries)
or ld-linux.so
(for ELF libraries).
If you're
not sure which you need, run the file
command on the library. For
example:
% file /lib/libc.so.5.4.33 /lib/libc.so.4.7.2 /lib/libc.so.4.7.2: Linux/i386 demand-paged executable (QMAGIC), stripped /lib/libc.so.5.4.33: ELF 32-bit LSB shared object, Intel 386, version 1, stripped
The QMAGIC
indicates that 4.7.2
is for a.out libraries, and
ELF
indicates that 5.4.33
is for ELF.
Copy the specific loader(s) you need to the root filesystem you're building. Libraries and loaders should be checked carefully against the included binaries. If the kernel cannot load a necessary library, the kernel will usually hang with no error message.
Your system may require dynamically loaded libraries that are not visible to ldd.
If your system uses PAM (Pluggable Authentication Modules), you must make some provision for it on your bootdisk or you will not be able to login. PAM, briefly, is a sophisticated modular method for authenticating users and controlling their access to services. An easy way to determine if your system uses PAM is to check your hard disks's /etc directory for a file pam.conf or a pam.d directory; if either exists, you must provide some minimal PAM support. (Alternatively, run ldd on your login executable; if the output includes libpam.so, you need PAM.)
Fortunately, security is usually of no concern with bootdisks, since anyone who has physical access to a machine can usually do anything they want anyway. Therefore, you can essentially disable PAM by creating a simple /etc/pam.conf file in your root filesystem that looks like this:
OTHER auth optional /lib/security/pam_permit.so OTHER account optional /lib/security/pam_permit.so OTHER password optional /lib/security/pam_permit.so OTHER session optional /lib/security/pam_permit.so
Also copy the file /lib/security/pam_permit.so
to your root
filesystem. This library is only about 8K so it imposes minimal overhead.
Note that this configuration allows anyone complete access to the files and services on your machine. If you care about security on your bootdisk for some reason, you'll have to copy some or all of your hard disk's PAM setup to your root filesystem. Be sure to read the PAM documentation carefully, and copy any libraries needed in /lib/security onto your root filesystem.
You must also include /lib/libpam.so on your bootdisk. But you already know this since you ran ldd on /bin/login, which showed this dependency.
If you are using glibc (aka libc6), you will have to make provisions for name services or you will not be able to log in. The file /etc/nsswitch.conf controls database lookups for various servies. If you don't plan to access services from the network (eg, DNS or NIS lookups), you need only prepare a simple nsswitch.conf file that looks like this:
passwd: files shadow: files group: files hosts: files services: files networks: files protocols: files rpc: files ethers: files netmasks: files bootparams: files automount: files aliases: files netgroup: files publickey: files
This specifies that every service be provided only by local files. You
will also need to include /lib/libnss_files.so.1
, which will
be loaded dynamically to handle the file lookups.
If you plan to access the network from your bootdisk, you may want to
create a more elaborate nsswitch.conf file. See the
nsswitch man page for details. Keep in mind that you must
include a file /lib/libnss_
service.so.1
for each service you specify.
If you have a modular kernel, you must consider which modules you may want to
load from your bootdisk after booting. You might want to include ftape
and zftape
modules if your backup tapes are on floppy tape, modules for
SCSI devices if you have them, and possibly modules for PPP or SLIP support if
you want to access the net in an emergency.
These modules may be placed in /lib/modules. You should also
include insmod
, rmmod
and lsmod
. Depending on whether you
want to load modules automatically, you might also include modprobe
,
depmod
and swapout
. If you use kerneld
, include it along
with /etc/conf.modules.
However, the main advantage to using modules is that you can move non-critical modules to a utility disk and load them when needed, thus using less space on your root disk. If you may have to deal with many different devices, this approach is preferable to building one huge kernel with many drivers built in.
Note that in order to boot a compressed ext2 filesystem, you must have ramdisk and ext2 support built-in. They cannot be supplied as modules.
Some system programs, such as login
, complain if the file
/var/run/utmp and the directory /var/log do not
exist.
So:
mkdir -p /mnt/var/{log,run} touch /mnt/var/run/utmp
Finally, after you have set up all the libraries you need, run
ldconfig
to remake /etc/ld.so.cache on the root
filesystem. The cache tells the loader where to find the libraries. To
remake ld.so.cache
, issue the following
commands:
chdir /mnt; chroot /mnt /sbin/ldconfig
The chroot
is necessary because ldconfig
always remakes the
cache for the root filesystem.
Once you have finished constructing the root filesystem, unmount it, copy it to a file and compress it:
umount /mnt dd if=DEVICE bs=1k | gzip -v9 > rootfs.gz
When this finishes you will have a file rootfs.gz
that is your
compressed root filesystem. You should check its size to make sure it will
fit on a diskette; if it doesn't you'll have to go back and remove some
files. Section
Reducing root filesystem size
has some hints for reducing the size of the root filesystem.