I believe a bootable linux system should not be too difficult to build. I don't need a perfect system anyway. The point is making it able to boot, and has stand alone tools just to make some recoveries when something goes wrong with our computer system.
In fact we have almost everything inside initrd file. A busybox package is almost perfect. Simply copying it along with its kernel version is enough to give you a 'panic' shell interface. On Debian system, one may try also passing break=mount, to break the booting process right before initrd mounting filesystems.
Now, to make a bootable flashdisk we can simply create a partition inside it, format it as ext2 filesystem, and then install grub on its MBR. We do this from our running system without downloading anything from the net.
I use this variable in this process:
rootflash=/mnt/buildboot
drive=/dev/sdb1
1) partinion the drive (/dev/sdb1, 83, bootable)
fdisk /dev/sdb
2) format as ext2:
mkfs.ext2 $drive
e2label $drive ROSBOOT
We need to give a label to our disk, because we are working with a removable disk. It is unsure in which device node the usb storage will be referred. Using label we can easily point to as /dev/disk/by-label/ROSBOOT. We need a small change on init script in order to make it possible.
3) mount usb drive and copy kernel
mount $drive $rootflash
mkdir $rootflash/boot
cp /boot/vmlinuz-2.6.18-4-686 $rootflash/boot/vmlinuz
cp /boot/initrd.img-2.6.18-4-686 $rootflash/boot/initrd
4) install grub on the mbr of our usb storage and create grub menu.
grub-install --root-directory $rootflash /dev/sdb
cat > $rootflash/boot/grub/menu.lst << endt
title Debian Tumb
root (hd0,0)
kernel /boot/vmlinuz root=/dev/ram0 vga=794
initrd /initrd
boot
Until this point the usb drive can boot and gives busybox. What else do you want?
It is now a totally imperfect booting system. But at least busybox gives us a lot of useful basic command. We can now mount something from nfs to boot if we want. The better idea is maybe creating Debian bootstrap:
debootstrap --arch i386 etch $rootflash
and change one corresponding line in menu.lst to
kernel /boot/vmlinuz root=LABEL=ROSBOOT ROOTDELAY=5 vga=791
Than we will use at least 150Mb for nothing. I haven't tried that, but anyway, I don't want to. My first idea is to have an imperfect rescue system. For which I only need to add some administration applications and change init script to make it
imperfect.
5) Modify initrd
We can extract our working initrd and put it somewhere. Here are the commands:
cd /tmp; mkdir work-initrd; cd work-initrd
gzip -dc /boot/initrd.img-2.6.18-4-686 | cpio -id
Now we put some missing good applications, modules and libraries.
install /sbin/fdisk sbin/
install /lib/libext2fs.so.2* lib/
install /lib/modules/2.6.18-4-686/kernel/drivers/usb/input/usbkbd.ko lib/modules/2.6.18-4-686/kernel/drivers/usb/input/
install /lib/modules/2.6.18-4-686/kernel/drivers/usb/input/usbmouse.ko lib/modules/2.6.18-4-686/kernel/drivers/usb/input/
Now it is time for us to make modifications on init file. It is a normal shell script. My hand feels at home.
joe init
and do our blablablas there! I put my
imperfect init script as a tail to this blog. We need to modify the modules file as well:
cat > conf/modules << endt
unix
usbcore
usbhid
usb-storage
ext2
i8042
atkbd
usbhid
usbkbd
usbmouse
Finished with modifications? now repack initrd!
find ./ | cpio -H newc -o > /tmp/initrd.cpio
gzip /tmp/initrd.cpio
mv /tmp/initrd.cpio.gz $rootflash/boot/initrd
Now for me everything is OK. It boots well in my notebook, but an old computer in the corner can not boot from it, even though it has capability for it. Maybe the bios is imperfect! Don't care.
The size of my booting flashdisk system is now 7.6Mb. Maybe I can have it smaller by recompiling the kernel and throw out some unused drivers.
Next idea is to put directories inside the flash disk and make a link to it inside the initram like usr directory, etc, so we don't have to change the initrd afterward.
6) Tail: imperfect init script
I modified the init script from initrd of Debian etch. With this modification I intend to call /disk/etc/rc.d file in the real usb drive storage. We do not need to touch this init rd anymore, and control everything there.
#!/bin/sh
echo "Loading, please wait..."
[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir --mode=0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs none /sys
mount -t proc none /proc
## increase tmpfs size to 20M ###
tmpfs_size="20M"
#################################
if [ -e /etc/udev/udev.conf ]; then
. /etc/udev/udev.conf
fi
mount -t tmpfs -o size=$tmpfs_size,mode=0755 udev /dev
[ -e /dev/console ] || mknod /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3
> /dev/.initramfs-tools
mkdir /dev/.initramfs
export DPKG_ARCH=
. /conf/arch.conf
export ROOT=
. /conf/initramfs.conf
for i in conf/conf.d/*; do
[ -f ${i} ] && . ${i}
done
. /scripts/functions
export break=
export init=/sbin/init
export quiet=n
export readonly=y
export rootmnt=/root
export debug=
export cryptopts=${CRYPTOPTS}
export panic=
## give default ROOTDELAY to 5 seconds #
# this gives time to udev to make usb disk online #
export ROOTDELAY=5
####################################################
# no need to parse complete command line options
for x in $(cat /proc/cmdline); do
case $x in
break=*)
break=${x#break=} ;;
break)
break=premount ;;
esac
done
if [ -z "${NORESUME}" ]; then
export resume=${RESUME}
fi
depmod -a
maybe_break top
run_scripts /scripts/init-top
maybe_break modules
log_begin_msg "Loading essential drivers..."
load_modules
log_end_msg
maybe_break premount
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"
run_scripts /scripts/init-premount
[ "$quiet" != "y" ] && log_end_msg
####### cut debian's init script here #########
echo "mounting flash filesystem"
echo "if this fails, we run without it"
mkdir /disk
mount -t ext2 /dev/disk/by-label/ROSBOOT /disk
RCRET=255
# if exist /disk/etc/rc.d then give control to it
if [ -x /disk/usr/rc.d ]; then
/disk/usr/rc.d
RCRET=$?
fi
# if rc.d returns 255 run shell
[ $RCRET -eq 255 ] && PS1='ROSBOOT$ ' /bin/sh -i /dev/console 2>&1
echo "Unmounting file systems...."
umount /disk
sleep 5
echo "Quits rosboot.... REBOOTING...."
sleep 1
reboot
Remember! imperfectness is perfectness it self.