The UML Root Filesystem
The installation of a Linux system always requires the creation of a consistent filesystem (called root filesystem) that contains a standard directories tree. Because I did not use any standard installation procedure, I needed to create this filesystem separately. A lot of programs are available for this task; the Debian one, debootstrap, works perfectly when used with an Internet connection. Ubuntu is derived from Debian, so it allows the use of the same package manager and offers the same software packages.
I enclosed the entire filesystem in a 4GB file (uml1-root or uml2-root), and created a clean one on the host machine as root user:
dd if=/dev/zero of=uml1-root bs=4096 seek=1M count=1
I then formatted this as ext3 filesystem:
Next, I made it available via a loopback device by mounting it under /mnt as a loopback filesystem:
mount -o loop uml1-root /mnt
Next, I installed the debootstrap application and used it to install a complete root filesystem for Ubuntu 7.10 (Gutsy Gibbon) under /mnt:
apt-get install debootstrap
debootstrap --arch i386 gutsy /mnt http://us.archive.ubuntu.com/ubuntu
After that, I had a basic but complete Linux filesystem. Before booting uml1, however, I had to customize it to provide a better start.
UML runs as a normal user process of the Linux host system, so it doesn't talk directly to hardware as a normal Linux system does. Instead, it talks with the hardware presented by the Linux host system. One great advantage of this is that you can run UML on whatever virtual hardware configuration, regardless of the real one.
I accomplished the virtual device assignment in the command line by associating a variable switch. For example, UML block devices are defined by the ubd variables (i.e., ubd0 for the first block device, ubd1 for the second one, and so on). With the assignment ubd0=uml1-root in the command line, I associated the loopback filesystem containing the root filesystem and the first UML block device; so I needed to edit /mnt/etc/fstab in this way:
/dev/ubd0 / ext3 defaults 0 1
proc / proc proc defaults 0 0
And then create the device with the right permissions:
mknod --mode=660 ubd0 b 98 0
chown root:disk ubd0
For the machine name, I put the name of the machine in the file /mnt/etc/hostname and created a plain vanilla file /mnt/etc/hosts with only this line:
Ubuntu, like Debian, uses the ifupdown package to configure and deconfigure network interfaces. So I could edit the file /mnt/etc/networking/interfaces to have the UML eth0 device automatically up at boot time. For uml1:
iface lo inet loopback
iface eth0 inet static
I had to configure tty0 to be a UML terminal allowed to login as root and erase the other ones:
echo "tty0" >> /mnt/etc/securetty
echo "ttys/0" >> /mnt/etc/securetty
By the way, there is a little difference between standard Debian and Ubuntu here. Ubuntu replaced the famous init daemon with the new upstart framework, and you have to edit files under the /etc/event.d directory instead of modifying the file /etc/inittab.
I needed to erase the standard rule of the udev framework that recreates a new ethX device every time the system boots:
When the umount /mnt filesystem has assigned the rights to host-user, that will boot UML instances.