UML (User Mode Linux) is sort of like an emulator. It's a tiny little self-contained Linux system that runs as a normal user process.
UML is a standard Linux kernel configured to run as a normal user process. Instead of booting up and talking directly to hardware, it runs as a process and its device drivers use the C library and standard system calls to ask the parent system for anything (memory, network, disk I/O) it needs. (The UML process then hands out memory and timeslices to any child processes it starts, and handles all their system calls.)
UML gives a normal user the ability to run programs with simulated root access, and in the virtual environment perform loopback mounts, chroot, create device nodes, change file ownership, and so on. This can be used as a more powerful replacement for packages like "fakeroot", as a way to experiment with system administration without screwing up your real system, as a security measure further isolating different users' processes from each other on a common server, as an administrator tool grouping different processes at different "nice" levels and allowing hard limits on physical memory usage...
UML lets kernel developers test changes to the Linux kernel without rebooting all the time. Just build a UML, run it, and try out the change. UML has its own process scheduler, I/O scheduler, page tables, filesystems, network stack, virtual memory, software suspend, and so on. You can even stick "printf" calls into this kernel to see what it's doing, just as with any other user space program. (It's not quite as good for debugging device drivers: configuring a UML instance to talk directly to the hardware is possible, but is an advanced feature we won't talk about here.)
UML also has features such as "copy on write" partitions. In addition to the ability to treat any normal file on the host system as a block device using the User Block Device (UBD) driver, UML can be configured to save any changes made to a given block device into a separate file, allowing several UML instances to share the same block device while keeping their changes to it (if any) separate.
For normal users, UML is extremely easy to get started with. If you can compile a kernel, you can run UML.
The following creates a fairly minimalistic User Mode Linux kernel, builds it, and runs it. It gives you a shell prompt where the shell process is running inside UML.
The easy way to run UML is to mounts the existing Linux filesystem to be the User Mode Linux system's root filesystem as well. (This way we don't have to set up a special root directory to try out hostfs, we just borrow the existing one from the host system.)
Configure the kernel. For the quickstart we're going to cheat slightly, by starting with allnoconfig and switching on just the symbols we want to enable (a technique known as "miniconfig"):
cat > mini.config << EOF && CONFIG_BINFMT_ELF=y CONFIG_HOSTFS=y CONFIG_LBD=y CONFIG_BLK_DEV=y CONFIG_BLK_DEV_LOOP=y CONFIG_STDERR_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_EXT2_FS=y EOF make ARCH=um allnoconfig KCONFIG_ALLCONFIG=mini.config
Note the "ARCH=um". This is what tells the kernel we're building User Mode Linux instead of a normal Linux kernel. You can configure your UML kernel with menuconfig as long as you remember to supply "ARCH=um", which needs to be specified for both configure and build phases.
Be sure to "make distclean" if you built a normal kernel in this source directory or want to build a normal kernel afterwards, otherwise the build will break because of things like the wrong include/asm symlink. (You need to do a distclean any time the value of ARCH changes.)
Build it. This produces a runnable "vmlinux" executable (also hardlinked to the name "linux").
Run it. Here's a short command line that should get you a command prompt inside the UML instance, by running /bin/sh as the init process (PID 1). UML understands the kernel command line parameters documented in Documentation/kernel-parameters.txt, plus a few of its own. To see the UML specific command line parameters, run ./linux --help
The three command line arguments tell UML to use the "hostfs" driver
for the root filesystem (which makes a parent directory show up within
UML, a bit like an NFS mount, and defaults to mounting the parent's "/"
directory unless told otherwise), specifies this root mount should be
writeable (the default is read only for historical reasons), and specifies that
UML's initial process (PID 1 within the UML instance) should exec "/bin/bash".
./linux rootfstype=hostfs rw init=/bin/bash
To confirm that you're running in UML, do the following:
mount -t procfs /proc /proc cat /proc/cpuinfo
You can also try "ps ax" to see that UML has its own process list, and so on. Note that this UML kernel booted without any init scripts, so it doesn't have devpts or sysfs mounted. (You may see filesystems in /sys and /dev/pts, but those are exported from the host system and don't match what UML is doing unless you mount the right filesystems on them. A tmpfs on /dev/shm is a good idea too.)
If you want an init script, you can point the init= command line argument of UML at a shell script (although this script needs to exec /bin/bash at the end if you still want a shell prompt). Note that if your shell script has a period in its name, such as "/home/me/uml-init.sh", a bug in the kernel's command line processing logic will discard it (and thus UML will try to run the default init at /sbin/init, which probably isn't what you want). here's a patch that fixes that.
When you want to exit UML, just type:
Don't worry about the panic message, Linux kernels always panic when PID 1 tries to exit (which should never happen during normal operation), and after printing a panic message the UML process exits. (If you want to exit more gracefully, try "halt -f" but make sure you're typing that in UML, not on your host system.)
Also don't worry about a UML crash leaving hostfs in a "dirty" state: it doesn't work that way. It works more like NFS; the host you're exporting files from doesn't care if the client goes away suddenly.
Here's a much longer command line that specifies a directory other than / to mount hostfs from, how much "physical" memory the UML kernel should allocate from the host system (the default is 32 megs), sets some environment variables for the "init" program (PID 1) that UML spawns, and tells the kernel boot process not to show most of its boot messages.
./linux rootfstype=hostfs rootflags=/home/me/uml/ rw mem=48M init=/bin/uml-init.sh TERM=linux PATH=/tools/bin:/bin quiet
Note that the init argument must be an absolute path relative to the directory mounted by hostfs, so in this case the parent system must have a file named "/home/me/uml/bin/uml-init.sh". If this is a shell script, it must start with "#!/bin/bash" or similar, and that file must also exist within the /home/me/uml directory (and if that shell isn't statically linked it needs all its shared libraries and library loader, plus both the init program and the shell must be executable... Borrowing the parent system's root filesystem is much easier than setting up your own.)
Feel free to switch on more features and rebuild. "make ARCH=um menuconfig" works. The above configuration includes loopback mount and EXT2 support, which gives you some fully writeable space. (Note if you run UML as a normal user, you can't do anything to the hostfs mount you couldn't do as the user running UML, so things like chown will give you an error even as root. The hostfs mount is more like a network mount with restricted permissions than normal fully writeable space. Inside a loopback mount, you have normal fully writeable space to play with.
The UBD driver is another way to get fully writeable space, associating a host file with a UML block device (/dev/ubda is major 98 minor 0, see www.lanana.org for details). If you use UBD as your root device then you may not need hostfs at all (and since a UBD is not a loopback device, you can stick a swap partition on it if you enable swap in menuconfig). This lets you play with software suspend, and yes you can then save the resulting kernel, UBD file, and swap partition and resume from them at will later.
Note: if you run UML as root and share the existing Linux system's rootfs via hostfs, it will be normal fully writeable space. This can cause problems. For example, if your host system uses an old version of the mount command that maintains an mtab file (instead of the modern way, where /etc/mtab is a symlink to /proc/mounts), then running mount inside UML will modify /etc/mtab for the host system as well. You probably don't want to do this.