wiki:Linux/Ubuntu/UserModeLinux/AutomatedImageBuild

UML Automated Image Build

This is a shell script for automating the creation of disk images for User Mode Linux installations. It is controlled by environment variables that can be set prior to the script running for custom choices. If a variable isn't set the script adopts a sensible default.

If necessary it will clone the Ubuntu kernel git repository and build the UML kernel before creating the file-system image. A custom kernel configuration file can be included to over-ride the default kernel config that is selected based on architecture. When creating the file-system image(s) it can be set to create separate images for /, /home, /var and /swap. The installed language is by default the same as the current user's settings in the environment variable LANG. Timezone can be set using, e.g. UML_TZ="Europe/London".

At the end it reports the UML boot arguments required to start with the file-system image(s) and includes parameters for using virtual ethernet devices via a vde_switch tun/tap interface, in this case kvm0. It makes testing UML installations much easier and faster.

Because the script does so much it is best to read the comments to determine if you need to alter the defaults. Of note is that you can create files with different configurations and have them read when the script starts by setting UML_PRESEED. For example:

UML_PRESEED="uml/configs/custom01.cfg"
uml-create-fs

This makes it trivial to test differing build settings and reuse them easily.

File: uml-create-fs

#!/bin/bash
# uml-create-fs version 0.5-experimental
# © Copyright November 2007, TJ <ubuntu@tjworld.net>
# Licensed on the terms of the General Public License Version 3 (GPLv3).
# If you haven't read it, do so now.
#
# This script automates the creation of User Mode Linux file-system images for Ubuntu.
# Later versions will use preseeded debian installer scripts to recreate the
# same install as using an Ubuntu installer ISO image or CD. 

# don't echo the commands as they are performed
set -x
echo "============ Environment =============="
env | sort
echo "======================================="
# easy-to-use common values
MB=$((1024 * 1024))
GB=$((MB * 1024))

# include pre-seeded values
[ ! -z "$UML_PRESEED" -a -f "$UML_PRESEED" ] && source $UML_PRESEED

# set this to 'yes' or 'no'. Use 'no' if you've already built UML and are
# creating new images
[ -z "$BUILD_KERNEL" ] && BUILD_KERNEL="yes"

# set to 'yes' or 'no'. Use 'yes' to have apt-get install the distro package.
[ -z "$INSTALL_DISTRO" ] && INSTALL_DISTRO="yes"

# the distro-package to install. e.g. ubuntu-minimal, ubuntu-standard, ubuntu-server, ubuntu-desktop
[ -z "$INSTALL_DISTRO_PACKAGE" ] && INSTALL_DISTRO_PACKAGE="${INSTALL_DISTRO_PACKAGE-ubuntu-minimal}"

# location of the Ubuntu kernel source
# must be from Ubuntu git or linux-source package because the script relies on knowing
# the location of the flavour-specific kernel .config file fragments in copyKernelConfig()
[ -z "$KERNEL_SOURCE_DIR" ] && KERNEL_SOURCE_DIR="${KERNEL_SOURCE_DIR-$(pwd)/uml/src}"

# where to create the binary files. This ensures the source-code tree doesn't get messed
# up with UML binaries, especially if you use the kernel source tree for development
[ -z "$BUILD_DIR" ] && BUILD_DIR="${BUILD_DIR-$(pwd)/uml/build}"

# where to create the disk images that contain the file-systems
[ -z "$IMAGE_DIR" ] && IMAGE_DIR="${IMAGE_DIR-$(pwd)/uml}"

# the default UML kernel config settings needed for a successful build
# expected to be found in this text file
[ -z "$KERNEL_CONFIG_UML" ] && KERNEL_CONFIG_UML="${KERNEL_CONFIG_UML-$(pwd)/uml-config}"

# name of file containing custom kernel config options
# if this exists it will be used to modify the default kernel configuration
[ -z "$KERNEL_CONFIG_CUSTOM" ] && KERNEL_CONFIG_CUSTOM="${KERNEL_CONFIG_CUSTOM-$(pwd)/config-custom}"

# a text file containing the path/names of any kernel patches to apply
[ -z "$KERNEL_PATCH_DIR" ] && KERNEL_PATCH_DIR="${KERNEL_PATCH_DIR-$(pwd)}"
[ -z "$KERNEL_PATCHLIST" ] && KERNEL_PATCHLIST="${KERNEL_PATCHLIST-$KERNEL_PATCH_DIR/uml-patches}"
# set to 'yes' or 'no'. Use 'yes' to have patches applied
[ -z "$KERNEL_PATCH" ] && KERNEL_PATCH="${KERNEL_PATCH-no}"

# how many concurrent processes make should use when building the kernel and modules
[ -z "$CONCURRENCY" ] && CONCURRENCY="1"

# the UML machine architecture to build for
[ -z "$SUBARCH" ] && SUBARCH="${SUBARCH-}"

# The distribution. Used by git in building the repository name
[ -z "$DISTRO" ] && DISTRO="${DISTRO-ubuntu}"

# the Ubuntu release to install in the root file-system
[ -z "$RELEASE" ] && RELEASE="${RELEASE-$(lsb_release -sc)}"

# set this to 'yes' or 'no' to control whether git clones the kernel source repository
[ -z "$GET_KERNEL_SOURCE" ] && GET_KERNEL_SOURCE="yes"

# the URL of the git repository for the kernel source
[ -z "$KERNEL_SOURCE_REPO" ] && KERNEL_SOURCE_REPO="${KERNEL_SOURCE_REPO-git://kernel.ubuntu.com/${DISTRO}/${DISTRO}-${RELEASE}.git}"

# where deboostrap should get packages from
[ -z "$ARCHIVE" ] && ARCHIVE="${ARCHIVE-http://archive.ubuntu.com/ubuntu/}"

# file-system images to be created
[ -z "$UML_ROOT_CREATE"   ] && UML_ROOT_CREATE="yes"
[ -z "$UML_ROOT_FILE"     ] && UML_ROOT_FILE="uml_root_fs.bin"
[ -z "$UML_ROOT_TYPE"     ] && UML_ROOT_TYPE="ext3"
[ -z "$UML_ROOT_SIZE"     ] && UML_ROOT_SIZE="$((4 * GB))"
[ -z "$UML_ROOT_NAME"     ] && UML_ROOT_NAME="uml-root"
[ -z "$UML_ROOT_LOOP_DEV" ] && UML_ROOT_LOOP_DEV="/dev/loop0"

[ -z "$UML_HOME_CREATE"   ] && UML_HOME_CREATE="yes"
[ -z "$UML_HOME_FILE"     ] && UML_HOME_FILE="uml_home_fs.bin"
[ -z "$UML_HOME_TYPE"     ] && UML_HOME_TYPE="ext3"
[ -z "$UML_HOME_SIZE"     ] && UML_HOME_SIZE="$((4 * GB))"
[ -z "$UML_HOME_NAME"     ] && UML_HOME_NAME="uml-home"
[ -z "$UML_HOME_LOOP_DEV" ] && UML_HOME_LOOP_DEV="/dev/loop1"

[ -z "$UML_VAR_CREATE"   ] && UML_VAR_CREATE="no"
[ -z "$UML_VAR_FILE"     ] && UML_VAR_FILE="uml_var_fs.bin"
[ -z "$UML_VAR_TYPE"     ] && UML_VAR_TYPE="ext3"
[ -z "$UML_VAR_SIZE"     ] && UML_VAR_SIZE="$((2 * GB))"
[ -z "$UML_VAR_NAME"     ] && UML_VAR_NAME="uml-var"
[ -z "$UML_VAR_LOOP_DEV" ] && UML_VAR_LOOP_DEV="/dev/loop2"

[ -z "$UML_SWAP_CREATE"   ] && UML_SWAP_CREATE="yes"
[ -z "$UML_SWAP_FILE"     ] && UML_SWAP_FILE="uml_swap_fs.bin"
[ -z "$UML_SWAP_SIZE"     ] && UML_SWAP_SIZE="$((256 * MB))"
[ -z "$UML_SWAP_NAME"     ] && UML_SWAP_NAME="swap"
[ -z "$UML_SWAP_LOOP_DEV" ] && UML_SWAP_LOOP_DEV="/dev/loop3"

# default to installing the user's locale setting
[ -z "$UML_LANG" ] && UML_LANG="${LANG}"
# symlinked to /etc/localtime (from /usr/share/zoneinfo/)
[ -z "$UML_TZ" ] && UML_TZ="Europe/London"

# path in host file-system to mount the UML loop device
[ -z "$MOUNT_ROOT" ] && MOUNT_ROOT="${IMAGE_DIR}/root"

# string to add to language pack names, default extracted from user's locale setting
[ -z "$INSTALL_LANG" ] && INSTALL_LANG="$(expr $LANG : '\(.*\)_.*')"
[ -z "$DEBOOTSTRAP_LANG_PACKAGES" ] && DEBOOTSTRAP_LANG_PACKAGES="language-pack-${INSTALL_LANG},language-pack-${INSTALL_LANG}-base"
[ -z "$DEBOOTSTRAP_PACKAGES" ] && DEBOOTSTRAP_PACKAGES=""

# network hostname
[ -z "$UML_HOSTNAME" ] && UML_HOSTNAME="usermodelinux"

# contents of UML resolv.conf
[ -z "$UML_RESOLV_CONF" ] && RESOLV_CONF="nameserver 10.0.0.254\n"

# content of UML /etc/network/interfaces
[ -z "$UML_NET_INTERFACES" ] && UML_NET_INTERFACES="auto lo eth0\niface lo inet loopback\niface eth0 inet dhcp\n"


#####################################
#
# Do not edit beyond this point
#
#####################################

# Create the source directory
function setKernelSourceDir() {
 mkdir -p ${KERNEL_SOURCE_DIR}
}

# Enter the kernel source tree
function cdKernelSource() {
 cd ${KERNEL_SOURCE_DIR}
}

# Create an out-of-tree build directory
function setBuildDir() {
 mkdir -p ${BUILD_DIR}
}

# Enter the build tree
function cdBuildDir() {
 OLDPWD=$(pwd)
 cd ${BUILD_DIR}
}

# Enter the image directory
function cdImageDir() {
 cd ${IMAGE_DIR}
}

function installGit() {
 # if git isn't installed already, install it
 dpkg-query -l git 2>&1 >/dev/null
 [ $? -ne 0 ] && sudo apt-get install git
}

function getKernelSource() {
 if [ "$GET_KERNEL_SOURCE" = "yes" ]; then
  local oldpwd=$(pwd)
  cdKernelSource
  # default operation is clone from remote repository
  local GIT_OPERATION="clone"
  local GIT_REPO="${KERNEL_SOURCE_REPO}"
  local GIT_LOCAL="${KERNEL_SOURCE_DIR}"
  # if the local repository exists just pull the latest head
  [ -d ${GIT_LOCAL}/.git ] && GIT_OPERATION="pull" && GIT_REPO="" && GIT_LOCAL=""
  git ${GIT_OPERATION} ${GIT_REPO} ${GIT_LOCAL}
  cd $oldpwd
 fi
}

# Copy the configuration files for the kernel
function defaultKernelConfig() {
 make O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} defconfig
}

# Correct some kernel configurations for UML. The root file-system must be built in.
# Add other kernel built-ins (CONFIG_XXX=y) from the required 'KERNEL_CONFIG_UML' (that ensures
# the UML-specific build configuration is avaiable) and the optional 'KERNEL_CONFIG_CUSTOM' files
function customKernelConfig() {

 # update .config entries
 function update_config() {
  local KEY=$1
  local VALUE=$2
  local config=$3
  if [ "${VALUE}" != "N" ]; then
   # enable an entry
   if grep "${KEY}[= ]" $config; then
    # existing key so change it
    if grep "^${KEY}=" $config; then
 	 # replace the existing setting
	 sed -i "s/\(${KEY}\)=.*/\1=${VALUE}/" $config
    else
 	 # enable the setting - replace the commented-out key
	 sed -i "s/# \(${KEY}\).*/\1=${VALUE}/" $config
    fi
   else
    # key doesn't exist so add it
    echo "${KEY}=${VALUE}" >>$config
   fi
  else
   # comment it out
   if grep "${KEY}[= ]" $config; then
    # existing key so change it
     if grep "^${KEY}=" $config; then
	 # replace the existing setting with a comment
	 sed -i "s/.*\(${KEY}\)=.*/# \1 is not set/" $config
    fi
   else
    # key doesn't exist so add it as a comment
    
    echo "# ${KEY} is not set" >>$config
   fi
  fi
 }

 # read a list of preseeded config values
 function readCustomKernelConfig() {
  local customConfig=$1
  local config=$2
  local key
  local value
  while read line; do
   if [ ! -z "$line" ]; then
    # extract CONFIG_* keys from comments and active lines
    key=$(expr "$line" : '[# ]*\(CONFIG_[0-9A-Z_]\+\)[= ]')
    value=$(expr "$line" : '.*=\(.*\)')
    # if '=value' was not found it must be a comment so indicate that to update_config()
    [ -z "$value" ] && value="N"
    [ ! -z "$key" ] && update_config "$key" "$value" ${BUILD_DIR}/$config
   fi
  done <$customConfig
 }

 local config="${BUILD_DIR}/.config"

 # create a backup of the default config
 cp ${config} ${config}.bak

 # These values needed to over-ride default settings from the Ubuntu flavours

 # convert file-system type to UPPER case for use in kernel config
 local fs_type=$(echo $UML_ROOT_TYPE | tr [:lower:] [:upper:])
 
 # read the default UML preseed values
 [ ! -z "${KERNEL_CONFIG_UML}" -a -f ${KERNEL_CONFIG_UML} ] && readCustomKernelConfig ${KERNEL_CONFIG_UML} $config
 # include any custom config options declared
 [ ! -z "${KERNEL_CONFIG_CUSTOM}" -a -f ${KERNEL_CONFIG_CUSTOM} ] && readCustomKernelConfig ${KERNEL_CONFIG_CUSTOM} $config

 # ensure the root file-systems block driver is built in
 update_config "CONFIG_${fs_type}_FS" "y" $config
 update_config "CONFIG_${fs_type}_FS_XATTR" "y" $config
 update_config "CONFIG_${fs_type}_FS_POSIX_ACL" "y" $config
 update_config "CONFIG_${fs_type}_FS_SECURITY" "y" $config

}

# Clean the build tree (just in case it has been built before with different options)
function cleanBuildDir() {
 local oldpwd=$(pwd) 
 # make sure to be in the **build** directory (in KERNEL_SRC_DIR this will remove the ./debian
 cdKernelSource
 make O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} mrproper
 cd $oldpwd
}

# Build the config file. Accept default answers for all questions related to UML.
function makeKernelConfig() {
 local oldpwd=$(pwd) 
 # make sure to be in the source directory
 cdKernelSource
 make O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} oldconfig
 cd $oldpwd
}

# Apply essentional patches to the kernel tree. A list of patch files is
# contained in the file passed in as parameter 1. Each patch name is read
# and applied in turn. Patch is run in the kernel source directory and
# assumes -p1 for all patches.
# This means the patch will have the first component of the path removed, e.g:
# diff -Nrua 2.6.22.orig/drivers/net/driver.c 2.6.22/drivers/net/driver.c >patch01.diff
# patch -p1 <patch01.diff
# will strip the first path component ('2.6.22/') and use 'drivers/net/driver.c'
function applyKernelPatches() {
 if [ "${KERNEL_PATCH}" = "yes" ]; then
  if [ ! -z "${KERNEL_PATCHLIST}" -a -f ${KERNEL_PATCHLIST} ]; then
   local oldpwd=$(pwd)
   cdKernelSource
   while read patchname; do
    # if there is no path, prefix the defined KERNEL_PATCH_DIR
    if ! echo "$patchname" | grep '/'; then
     patchname="${KERNEL_PATCH_DIR}/$patchname"
    fi 
    [ ! -z "$patchname" ] && patch -N -p1 < $patchname
   done <${KERNEL_PATCHLIST}
   cd $oldpwd
  fi
 fi
}

# Build the UML kernel (the -jX is the number of concurrent processes - speeds things up if you've
# got a multi-proccesor SMP host).
function buildUMLKernel() {
 local oldpwd=$(pwd) 
 # make sure to be in the source directory
 cdKernelSource
 make -j${CONCURRENCY} O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} linux
 cd $oldpwd
}

# Build the kernel modules.  Later, after creating the file-system images files, you'll be
# able to install them directly into the root file-system.
function buildUMLKernelModules() {
 local oldpwd=$(pwd) 
 # make sure to be in the source directory
 cdKernelSource
 make -j${CONCURRENCY} O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} modules
 cd $oldpwd
}

# Strip the kernel debug symbols
function stripKernelDebugSymbols() {
 strip -S ${BUILD_DIR}/linux
}


# Create a swap-disk image
function createSwapImage() {
 [ "${UML_SWAP_CREATE}" = "yes" ] && dd if=/dev/zero of=${IMAGE_DIR}/${UML_SWAP_FILE} bs=1024 count=$((UML_SWAP_SIZE / 1024))
}

# Create / sparse disk image
function createRootImage() {
 [ "${UML_ROOT_CREATE}" = "yes" ] && dd if=/dev/zero of=${IMAGE_DIR}/${UML_ROOT_FILE} bs=1024 count=0 seek=$((UML_ROOT_SIZE / 1024))
}

# Create /home sparse disk image
function createHomeImage() {
 [ "${UML_HOME_CREATE}" = "yes" ] && dd if=/dev/zero of=${IMAGE_DIR}/${UML_HOME_FILE} bs=1024 count=0 seek=$((UML_HOME_SIZE / 1024))
}

# Create /var sparse disk image
function createVarImage() {
 [ "${UML_VAR_CREATE}" = "yes" ] && dd if=/dev/zero of=${IMAGE_DIR}/${UML_VAR_FILE} bs=1024 count=0 seek=$((UML_VAR_SIZE / 1024))
}


# attach the virtual disk devices (if you are a member of the 'disk' group you can do this without sudo)
function attachImageDevices() {
 sudo modprobe loop
 [ -e ${IMAGE_DIR}/${UML_ROOT_FILE} -a "${UML_ROOT_CREATE}" = "yes" ] && losetup ${UML_ROOT_LOOP_DEV} ${IMAGE_DIR}/${UML_ROOT_FILE}
 [ -e ${IMAGE_DIR}/${UML_HOME_FILE} -a "${UML_HOME_CREATE}" = "yes" ] && losetup ${UML_HOME_LOOP_DEV} ${IMAGE_DIR}/${UML_HOME_FILE}
 [ -e ${IMAGE_DIR}/${UML_VAR_FILE}  -a "${UML_VAR_CREATE}"  = "yes" ] && losetup ${UML_VAR_LOOP_DEV} ${IMAGE_DIR}/${UML_VAR_FILE}
 [ -e ${IMAGE_DIR}/${UML_SWAP_FILE} -a "${UML_SWAP_CREATE}" = "yes" ] && losetup ${UML_SWAP_LOOP_DEV} ${IMAGE_DIR}/${UML_SWAP_FILE}
}

# Create file-systems and swap
function createFileSystems() {
 [ "${UML_ROOT_CREATE}" = "yes" ] && mkfs -t ${UML_ROOT_TYPE} -L ${UML_ROOT_NAME} ${UML_ROOT_LOOP_DEV}
 [ "${UML_HOME_CREATE}" = "yes" ] && mkfs -t ${UML_HOME_TYPE} -L ${UML_HOME_NAME} ${UML_HOME_LOOP_DEV}
 [ "${UML_VAR_CREATE}"  = "yes" ] && mkfs -t ${UML_VAR_TYPE} -L ${UML_VAR_NAME} ${UML_VAR_LOOP_DEV}
 [ "${UML_SWAP_CREATE}" = "yes" ] && mkswap -L ${UML_SWAP_NAME} ${UML_SWAP_LOOP_DEV}
}

# Check file-systems are okay
function checkFileSystems() {
 # -y option required for non-interactive repairs (assumes Yes to all questions)
 [ "${UML_ROOT_CREATE}" = "yes" ] && fsck -y ${UML_ROOT_LOOP_DEV}
 [ "${UML_HOME_CREATE}" = "yes" ] && fsck -y ${UML_HOME_LOOP_DEV}
 [ "${UML_VAR_CREATE}"  = "yes" ] && fsck -y ${UML_VAR_LOOP_DEV}
}

# Create a mount point and mount the loop device(s) into the existing file system
function mountFileSystems() {
 if [ "${UML_ROOT_CREATE}" = "yes" ]; then
  mkdir -p ${MOUNT_ROOT}
  sudo mount -t ${UML_ROOT_TYPE} ${UML_ROOT_LOOP_DEV} ${MOUNT_ROOT} -o defaults
  # potential work-around to prevent chroot preventing umount after it exits
  # losetup -d ${UML_ROOT_LOOP_DEV}
  # sudo mount -t ${UML_ROOT_TYPE} ${IMAGE_DIR}/${UML_ROOT_FILE} ${MOUNT_ROOT} -o defaults,loop

  if [ "${UML_VAR_CREATE}" = "yes" ]; then
   sudo mkdir -p ${MOUNT_ROOT}/var
   sudo mount -t ${UML_VAR_TYPE} ${UML_VAR_LOOP_DEV} ${MOUNT_ROOT}/var -o defaults
  fi
  if [ "${UML_HOME_CREATE}" = "yes" ]; then
   sudo mkdir -p ${MOUNT_ROOT}/home
   sudo mount -t ${UML_HOME_TYPE} ${UML_HOME_LOOP_DEV} ${MOUNT_ROOT}/home -o defaults
  fi
 fi
}

# Install OS into the root. To determine which language packs you want, you can see the entire list by
# doing a package search:
# http://packages.ubuntu.com/cgi-bin/search_packages.pl?keywords=language-pack-&searchon=names&subword=1&version=gutsy&release=all
#
# This will also configure the guest's apt sources.list to use components main and universe
function installOS() {
 local arch;
 [ ! -z "$SUBARCH" ] && arch="--arch $SUBARCH"
 [ "$UML_ROOT_CREATE" = "yes" ] && sudo debootstrap --variant=buildd --components="main,universe" ${arch} --include="${DEBOOTSTRAP_LANG_PACKAGES} ${DEBOOTSTRAP_PACKAGES}" ${RELEASE} ${MOUNT_ROOT} ${ARCHIVE}
}

# Set a default hostname
function setHostname() {
 [ "$UML_ROOT_CREATE" = "yes" -a ! -z "$UML_HOSTNAME" ] && sudo sh -c "echo '${UML_HOSTNAME}' >${MOUNT_ROOT}/etc/hostname"
}

# Set the default DNS name-server(s). The value from your host was set by deboostrap. Change it
# if the UML instance will use different DNS server(s). These values are *examples* only!
function setResolvers() {
 [ "$UML_ROOT_CREATE" = "yes" -a ! -z "$UML_RESOLV_CONF" ] && sudo sh -c "echo '${UML_RESOLV_CONF}' >${MOUNT_ROOT}/etc/resolv.conf"
}

# set the default network configuration
function setNetworkInterfaces() {
 [ ! -z "$UML_NET_INTERFACES" ] && sudo sh -c "echo '$UML_NET_INTERFACES' >${MOUNT_ROOT}/etc/network/interfaces"
}

# Set the default system locale and time
function setLocale() {
 [ ! -z "$UML_LANG" ] && sudo sh -c "echo 'LANG=${UML_LANG}' >>${MOUNT_ROOT}/etc/environment"
 [ ! -z "$UML_TZ" ] && sudo rm /etc/localtime && sudo ln -s /usr/share/zoneinfo/${UML_TZ} /etc/localtime
}

# Prepare the file-system table (including /proc)
function setFstab() {
 # conditionally add entries to the UML fstab
 sudo sh -c "echo 'proc\t/proc\tproc\tdefaults\t0\t0\n' > ${MOUNT_ROOT}/etc/fstab"
 [ "${UML_ROOT_CREATE}" = "yes" ] && export UML_ROOT_UUID="$(blkid -s UUID -o value ${UML_ROOT_LOOP_DEV})" && \
  sudo sh -c "echo 'UUID=${UML_ROOT_UUID}\t/\t${UML_ROOT_TYPE}\tdefaults,errors=remount-ro\t0\t1\n' >> ${MOUNT_ROOT}/etc/fstab"
 [ "${UML_VAR_CREATE}" = "yes" ] && export UML_VAR_UUID="$(blkid -s UUID -o value ${UML_VAR_LOOP_DEV})" && \
  sudo sh -c "echo 'UUID=${UML_VAR_UUID}\t/var\t${UML_VAR_TYPE}\tdefaults,errors=remount-ro\t0\t1\n' >> ${MOUNT_ROOT}/etc/fstab"
 [ "${UML_HOME_CREATE}" = "yes" ] && export UML_HOME_UUID="$(blkid -s UUID -o value ${UML_HOME_LOOP_DEV})" && \
  sudo sh -c "echo 'UUID=${UML_HOME_UUID}\t/home\t${UML_HOME_TYPE}\tdefaults\t0\t2\n' >> ${MOUNT_ROOT}/etc/fstab"
 [ "${UML_SWAP_CREATE}" = "yes" ] && export UML_SWAP_UUID="$(blkid -s UUID -o value ${UML_SWAP_LOOP_DEV})" && \
  sudo sh -c "echo 'UUID=${UML_SWAP_UUID}\tnone\tswap\tsw\t0\t0\n' >> ${MOUNT_ROOT}/etc/fstab"
}

# Install the kernel modules into the loop-mounted root file-system
function installKernelModules() {
 if [ "${UML_ROOT_CREATE}" = "yes" ]; then
  local oldpwd="$(pwd)"
  cd ${KERNEL_SOURCE_DIR}
  sudo make O=${BUILD_DIR} ARCH=um SUBARCH=${SUBARCH} INSTALL_MOD_PATH=${MOUNT_ROOT} modules_install 
  cd ${oldpwd}
 fi
}

# Reconfigure console support
function setConsoles() {
 if [ "${UML_ROOT_CREATE}" = "yes" ]; then
  # Prevent the boot-time messages "Couldnt get a file descriptor referring to the console"
  sed -i 's/\(ACTIVE_CONSOLES=\).*/\1""/' ${MOUNT_ROOT}/etc/default/console-setup

  # need to ensure a console login is possible
  # determine if upstart is being used instead of sysvinit (or another init process)
  local init="$(sudo chroot ${MOUNT_ROOT} /bin/bash -c 'dpkg-query -S /sbin/init' )"
  # init will contain something along the lines of "upstart: /sbin/init"
  if [ "$(expr "$init" : '\(.*\):/*')" = "upstart" ]; then
   # add tty0 to the list of terminals root is allowed to use if it isn't in the list already
   grep 'tty0' ${MOUNT_ROOT}/etc/securetty || sudo sed -i '/# Standard consoles/ a tty0' ${MOUNT_ROOT}/etc/securetty
   # add an upstart event for tty0 (copies and modifies /etc/event.d/tty1)
   sudo sh -c "sed -e 's/\(start on runlevel\) 2/\1 1\n\1 2/' -e 's/^stop on runlevel 1/stop on shutdown/' -e 's/tty1/tty0/' ${MOUNT_ROOT}/etc/event.d/tty1 > ${MOUNT_ROOT}/etc/event.d/tty0"
    
   # remove tty1-6 because they aren't usable anyhow. No point having unusable processes 
   sudo sh -c "rm ${MOUNT_ROOT}/etc/event.d/tty[123456]"
  else
   if [ -e ${MOUNT_ROOT}/etc/inittab ]; then
   # sysvinit /etc/inittab used
    echo "FIXME: inittab"
   fi
  fi
 fi
}

# Configure basic settings using a chroot environment
function configUMLbasic() {
}

# attach /proc and /dev so chroot has access to ptys
function attachHostProcDev() {
 sudo mount -o bind /proc ${MOUNT_ROOT}/proc
 sudo mount -o bind /dev ${MOUNT_ROOT}/dev
}

# stop the daemon processes started in the chroot as a result of installing
# packages
function stopChrootProcesses() {
 [ -e "${MOUNT_ROOT}/etc/init.d/sysklogd" ] && sudo chroot ${MOUNT_ROOT} /bin/bash -c "/etc/init.d/sysklogd stop"
 [ -e "${MOUNT_ROOT}/etc/init.d/klogd" ] && sudo chroot ${MOUNT_ROOT} /bin/bash -c "/etc/init.d/klogd stop"
}

# detach /proc and /dev
function detachHostProcDev() {
 sudo umount ${MOUNT_ROOT}/dev
 sudo umount ${MOUNT_ROOT}/proc
}

# Install the distro
function installMinimalPackages() {
 # using --force-yes to overcome missing package signing keys
 [ "${INSTALL_DISTRO}" = "yes" ]  && sudo chroot ${MOUNT_ROOT} /bin/bash -c "apt-get -y --force-yes install ${INSTALL_DISTRO_PACKAGE}"
}

# Unmount and detach the loop devices
function detachUMLdevices() {
 [ "${UML_HOME_CREATE}" = "yes" ] && sudo umount ${UML_HOME_LOOP_DEV}
 [ "${UML_VAR_CREATE}"  = "yes" ] && sudo umount ${UML_VAR_LOOP_DEV}
 [ "${UML_ROOT_CREATE}" = "yes" ] && sudo umount ${UML_ROOT_LOOP_DEV}
 # if the unmount failed, adding a trailing / seems to work
 [ $? -ne 0 ] && sudo umount ${UML_ROOT_LOOP_DEV}/

 [ "${UML_ROOT_CREATE}" = "yes" -a -e ${IMAGE_DIR}/${UML_ROOT_FILE} ] && losetup -d ${UML_ROOT_LOOP_DEV}
 [ "${UML_HOME_CREATE}" = "yes" -a -e ${IMAGE_DIR}/${UML_HOME_FILE} ] && losetup -d ${UML_HOME_LOOP_DEV}
 [ "${UML_VAR_CREATE}"  = "yes" -a -e ${IMAGE_DIR}/${UML_VAR_FILE}  ] && losetup -d ${UML_VAR_LOOP_DEV}
 [ "${UML_SWAP_CREATE}" = "yes" -a -e ${IMAGE_DIR}/${UML_SWAP_FILE} ] && losetup -d ${UML_SWAP_LOOP_DEV}

 echo "Remaining loop devices:"
 losetup -a
}



#### Execution begins here
setBuildDir
cdBuildDir

if [ "x$1" = "x" ]; then
 if [ "${BUILD_KERNEL}" = "yes" ]; then
	installGit
    getKernelSource
    setKernelSourceDir
	cdKernelSource
	setBuildDir
	cleanBuildDir
	# apply patches before copying config in case patches apply to config files
	applyKernelPatches
	defaultKernelConfig
	customKernelConfig
	makeKernelConfig
	buildUMLKernel
	buildUMLKernelModules
	stripKernelDebugSymbols
	cdBuildDir
 fi
 # Finished building kernel

 # create file-system image files
 createSwapImage
 createRootImage
 createHomeImage
 createVarImage
 attachImageDevices
 createFileSystems
 checkFileSystems
 mountFileSystems

 # install base packages and kernel modules
 installOS
 installKernelModules
 # configure the new installation
 setHostname
 setResolvers
 # must do this before installing additional packages, especially 'ifupdown'
 setNetworkInterfaces
 setLocale
 setFstab

 # prepare for chroot
 attachHostProcDev
 # install and configure a minimal setup
 installMinimalPackages

 stopChrootProcesses
 detachHostProcDev
 # finished with chroot

 setConsoles
 configUMLbasic

 detachUMLdevices
else
 # execute a singe stage
 echo "Executing stage $1"
 $1
fi

cdImageDir

echo "Finished"
echo "To use the new UML file-system do:"
echo "./linux mem=256M ubda=${UML_ROOT_FILE} ubdb=${UML_VAR_FILE} ubdc=${UML_HOME_FILE} ubdd=${UML_SWAP_FILE} ubde=/dev/cdrom root=/dev/ubda eth0=tuntap,kvm0,fe:f0:00:00:00:01,10.254.1.11 con=null con0=fd:0,fd:1"

Attachments

  • uml-create-fs Download (22.7 KB) - added by tj 10 years ago. Shell Script to automate building User Mode Linux and file systems