Creating a root filesystem with rootstrap
One day, I needed a
Debian Sarge root filesystem to be used with
User Mode Linux, because the official website of UML only provided Debian Woody images. This short document explains how you can create your own root filesystem and run it through UML.
In the document, host is the computer on which you're working, and the target is the system we're trying to build.
Package installation
In order to do everything properly, you need the rootstrap package (which contains the tool that creates the root filesystem), and user-mode-linux (which is a kernel patched for UML).
# apt-get install rootstrap user-mode-linux
Root filesystem building
First of all, you have to tune the
/etc/rootstrap/rootstrap.conf file. The file is self documented, by I will list here the parameter that are really interesting.
- In the global section
- initialsize : the initial size of the root filesystem (I've tested with 512)
- freespace : at the end of the building process, the root filesystem can be shrinked to leave only the number of megabytes given by this paramater as free space. If 0, the root filesystem will not be shrinked
- In the network section (I've used the TUN/TAP stuff to link the host and the target)
- interface=eth0 : create the eth0 interface in the target
- transport=tuntap : use the TUN/TAP stuff
- host=192.168.2.1 : IP of the host machine
- uml=192.168.2.2 : IP of the target machine (will be the IP of eth0 on the target)
- netmask=255.255.255.0 : network mask
- host_if=tap0 : create the tap0 interface on the host with the host IP
- gateway=192.168.2.1 : make the host be the default gateway in the target
- nameserver=xxx.yyy.zzz.aaa : your DNS IP address
- In the debian section
That's it !
If the Debian mirror you gave in
mirror is on the Internet, you have to allow the target system to access the Internet. That is, you must enable NAT (Network Address Translation) on your host machine on the tap0 interface. I will suppose that your host kernel is properly compiled, and just say that running the following command is enough :
# iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE
The user under which your will be logged to run
rootstrap and more generally the UML kernel
must be in the
uml-net group.
Now, as an user, you can run :
Which will start the UML kernel, and start the installation process. First of all the
Package file is downloaded, then the packages themselves, and then the packages are installed.
Root filesystem tuning
WIth Debian Sarge, if you boot your root filesystem right now, it won't start, it will stop after :
fsck 1.35 (28-Feb-2004)
/dev/ubd0: clean, 13822/26624 files, 87754/101951 blocks
We need to tune some files inside the root filesystem to allow it to work correctly. So let's mount the root filesystem using the loop device :
# mount -t ext2 -o loop root_fs /mnt
Now, I can tell you that it's the
hwclock initialization process that locks the kernel (see
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=272529). This problem only appears with 2.4.x kernels used as target. If you compile a 2.6.9 UML kernel by yourself (see below), then you don't need this ugly fix. Let's say you don't want to compile a new kernel, so we need to remove everything related to hwclock in the root filesystem :
# cd /mnt/etc
# rm ./rc0.d/K25hwclock.sh ./rc6.d/K25hwclock.sh ./rcS.d/S50hwclock.sh ./rcS.d/S18hwclockfirst.sh
The following applies to both 2.4.x and 2.6.x target kernels.
We will also edit the
/etc/inittab file, to replace the following lines :
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6
With
1:2345:respawn:/sbin/getty 38400 tty0
2:23:respawn:/sbin/getty 38400 tty1
3:23:respawn:/sbin/getty 38400 tty2
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
The
tty0 terminal will be the console that launched the UML kernel, and
tty1 and
tty2 will be two small xterm automatically opened when the kernel boots. If you want more xterms, of course you can add
tty3,
tty4, etc. Note that this assume that you're using a 2.4.x kernel without devfs. With devfs, terminal device files are named differently.
I suggest you also edit the
/etc/securetty file, to allow root to log in on
tty0. To do that, just add
tty0 in that file.
Testing
Now, your root filesystem is ready, you can boot on it. This will suppose that the root filesystem image is the
root_fs file of the current directory. If it's not, pass the
ubd0=/path/to/root/filesystem option.
$ linux eth0=tuntap,,,192.168.2.1
Then the kernel should start. If it hangs at "Configuring network devices ...", it's because you forgot to specify
eth0=tuntap,,,192.168.2.1. This problem is also registered on the Debian Bug Tracking System at
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=274259.
If everything went well, you have 3 terminal emulators : the one in which you launched the kernel, and two other small xterms. Each of them allows you to login to the UML system. Simply login as root, it won't prompt you for any password.
As our system was installed using
rootstrap, Debian packages have not been configured. It's time to do it now (inside the target system) :
Important : the reconfiguring step of package
util-linux reinstalled the various links in /etc/rc.d that starts the hwclock program. So before rebooting the system, remove these symbolic links again ! If you forget to do it, you won't be able to halt the system properly. If you really forgot, kill the UML-related processes on the host, then mount the root filesystem using the loop device. Of course, this is only important is you're running a 2.4.x kernel as the target kernel. With 2.6.9, it works perfectly.
That's it !
Compile a new kernel for UML
Compiling a new kernel is not mandatory, do it only if you want to try a more recent version of the kernel.
As UML support has been integrated in the mainstream kernel, it is not quite easy to compile an UML kernel because there's no need to patch anything. Take a recent version of the kernel. I tried with 2.6.9 (2.6.8.1 doesn't compile for the UML architecture) :
$ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.9.tar.bz2
$ tar xvjf linux-2.6.9.tar.bz2
$ cd linux-2.6.9
$ make menuconfig ARCH=um
This launches the usual configuration tool, but for the UML architecture. On my system, I only disabled the compilation of
devfs in
File Systems - Pseudo filesystems - /dev filesystem support. Of course, you can use the devfs filesystem, but it's obselete, and it doesn't work with the inittab provided above. Now, the real compilation can start :
Once the compilation is finished, you get a
vmlinux executable (the UML kernel), which is fairly large (23M on my system). A simple strip allows to reduce its size to 2.3M.
By default in 2.6.9, module support is disabled, so we don't have to take care of the modules. Otherwise, you would have to do:
$ make modules ARCH=um
$ mount -t ext2 -o loop root_fs /mnt
$ make modules_install INSTALL_MOD_PATH=/mnt ARCH=um
This compiles the module, mounts the target root filesystem with the loop device and install the modules inside the target root filesystem. See
http://user-mode-linux.sourceforge.net/compile.html for more informations.
Troubleshooting
If your newly kernel doesn't work, here are some solutions I found to the various problems I faced :
- If when initializing the network interfaces ("Configuring network interfaces..."), the kernel says "read_output - read of data failed", it's because it can't find the uml_net binary on the host. On a Debian, this binary is in the /usr/lib/uml/ directory, which is not by default in the PATH. The solution is either to add /usr/lib/uml/ to the PATH, or to edit the arch/um/os-Linux/drivers/tuntap_user.c and change "uml_net" by "/usr/lib/uml/uml_net". If you're using ethertap, make the same changes to ethertap_user.c in the same directory. You also have to change the arch/um/drivers/net_user.c file, and change "uml_net" by "/usr/lib/uml/uml_net".
- If the kernel exits during initialization after Initializing stdio console driver, it's because you forgot to compile virtual tty and console support in the UML kernel.
Links