Running a rootfs from usb (Home Media)

From NAS-Central Iomega Wiki
Jump to: navigation, search

Introduction

In some circumstances it could be nice to run a rootfs from usbstick, for instance when you want to try to install and configure some packages, but you don't want to mess up the main fs. There are several ways to do that.

Method 1

The commandline for the kernel is

elevator=cfq panic=20 root=/dev/sda1 console=ttyS0,115200 init=/linuxrc mem=64M poweoutage=yes

So it will run /linuxrc from sda1. /linuxrc is a script, so we can change it to our needs. Using pivot_root we can switch to another root, if available. In our case we want to mount an usb device, so we'll have to load the necessary modules, wait for the stick to settle, mount it, switch root, and pass the execution to this rootfs. A sample script:

#!/bin/sh
# This file is created by /csb/product/hmed/scratch/mods/init/linuxrc.sh !! DO NOT edit !!

# Unset variable exported by sh.
unset PWD

# Try the same paths as the kernel would.
PATH=/sbin:/etc:/bin:/usr/bin:/usr/sbin

# Load the necessary modules and do the mounts to be able to mount an usb stick
mount -t proc proc /proc
modprobe usb_storage
modprobe usbcore
modprobe ehci_hcd
mount -t usbfs usb /proc/bus/usb

# Wait for the stick to 'come up'
sleep 10

# Mount usb stick:
mknod /dev/sdb1 b 8 17
mkdir -p /mnt/sdb1
if mount -t ext3 /dev/sdb1 /mnt/sdb1 ; then
	if [ -x /mnt/sdb1/sbin/init ] ; then
                mount --move /proc /mnt/sdb1/proc

		# Pivot
		cd /mnt/sdb1
                mkdir -p oldroot
		pivot_root . oldroot
		
		# Pass execution to new rootfs
                exec /sbin/init
	fi
	# else: no /sbin/init on the stick
fi
# else no stick to be mounted

# Pass execution to the original rootfs
exec /sbin/init

Creating a suitable rootfs

NIC

For us it's important to bring up the network, being the only interface to the box (Unless you've got serial access). So we need to load the driver module gmac.ko. This module needs a userspace helper to pass the NIC's firmware (/lib/firmware/gmac_copro_firmware). Further this module expects the macaddress as a parameter during load. Fortunately Debian can do this out-of-the-box. In /etc/modules you can specify modules to load, and add load parameters. Further the package 'udev' will handle the request for firmware. By default udev will be started before the modules in /etc/modules will be loaded.

Fancontrol

There is a kernel module thermAndFan.ko which handles this. Add it to /etc/modules to start it automatically.

Squeeze

Unfortunately the udev from squeeze doesn't work on kernels older than 2.6.27. So when running squeeze you'll have to provide your own helper program for the NIC firmware, or use a newer kernel than the stock one (2.6.24.4)

Enough talked

Creating a filesystem:

su
# install cdebootstrap
apt-get update
apt-get install cdebootstrap
# prepare stick
mke2fs -j /dev/sdb1
mount /dev/sdb1 /media
# get a clean lenny
cdebootstrap lenny /media http://ftp.us.debian.org/debian

# chroot the new rootfs
mount proc /media/proc -t proc
mount --bind /var /media/var
chroot /media /bin/sh
# set a root password
passwd
# install udev and dropbear
# (you could also use openssh or telnetd instead of dropbear,
# but dropbear is 700k, and the other are several MB's)
apt-get update
apt-get install dropbear udev

# leave chroot 
exit
umount /media/proc
umount /media/var

# copy some config files
cp /etc/inittab /media/etc/
cp /etc/network/interfaces /media/etc/network/
cat /etc/modules >>/media/etc/modules
cp /etc/resolv.conf /media/etc/

# copy modules and firmware
cp -r /lib/modules/* /media/lib/modules/
mkdir /media/lib/firmware
cp -r /lib/firmware/* /media/lib/firmware/

This rootfs should be able to get booted by /linuxrc above

Method 2

Usage of reloaded.ko. This is a kernelmodule which gives you the possibility to load runtime another kernel, pass an initrd and a commandline, and boot it. In our case we could use the stock kernel, create an initrd which loads the necessary modules for usb devices, and let it mount the stick and switch_root to it. The other way is to use a kernel with usb possibilities build in, and just provide a cmdline which tells this kernel to boot from the stick. I compiled a kernel with usb support build in, and with a bunch of modules which Iomega forgot to supply (usbv6, nfs, usb sound, ...). You can download it here. When you extract reload-kernel.tgz to the builded rootfs, it will install both the kernel modules and reloaded.ko, and a reload script. You can reload the kernel by

su
cd /mountpoint/of/usbdevice/boot
./reload.sh

The box will reboot instantaneously, so make sure it was not doing something important.