SHA256
1
0
forked from pool/xen
xen/mk-xen-rescue-img.sh

279 lines
8.6 KiB
Bash
Raw Normal View History

#!/bin/bash
# Shell script to prepare a root FS image based on the Novell/SUSE rescue
# image source. You must have a xen kernel installed for this to work.
# (c) Kurt Garloff <garloff@suse.de>, 2005-01-24, GNU GPL
# Maintained by Charles Coffing <ccoffing@novell.com>
#
# TODO:
# - trap SIGINT and clean up
# - can't know that /sbin/depmod will work with this rescue image
# - support domUloader
# - check for disk full in exchange_kernel_modules
MB_DEFAULT=88
usage()
{
echo "Usage:"
echo " mk-xen-rescue-img.sh source destination [MB [kernelver]]"
echo "Purpose:"
echo " Creates a root filesystem and an associated config file for a Xen-compatible"
echo " Linux virtual machine."
echo "Arguments:"
echo " * 'source' is the source from which to copy files. Normally, this is"
echo " the SUSE rescue image, such as /media/cdrom/boot/x86_64/rescue,"
echo " but it could also be an already-mounted root filesystem."
echo " * 'destination' is the pathname of a disk image to be created, based on"
echo " 'source'."
echo " * 'MB' is the size of disk image (default $MB_DEFAULT)."
echo " * 'kernelver' is the version of an installed Xen-compatible Linux kernel"
echo " (from the kernel-xen package) to install in the disk image. If not"
echo " specified, the newest of those currently installed will be selected."
exit 2
}
usage_error()
{
echo "Error: $@"
echo ""
usage
}
error()
{
echo "Error: $@"
if [ ! -z "$DST_MNT" ]; then
umount "$DST_MNT"
rmdir "$DST_MNT"
fi
exit 1
}
cp_error()
{
error "Failed to copy files to '$DST'."
}
# Determine Xen kernel version
get_xen_kernel()
{
if [ -z "$KVER" ]; then
KVER="`cd /lib/modules && ls -td *-xen/kernel | head -n1 | sed 's@/kernel@@'`"
else
if [ ! -d /lib/modules/$KVER/kernel ]; then
error "/lib/modules/$KVER/kernel does not exist."
fi
fi
if [ -z "$KVER" ]; then
error "You need to have a 'kernel-xen' package installed."
fi
}
cp_rescue()
{
local LSRC=$1
local LDST=$2
# The rescue image has empty directories all hard-linked to the same
# thing, probably to conserve inodes. This gives 'cp' heartburn.
# I want hard linked directories to be created separately (i.e.,
# dereferenced), but I don't want to dereference soft links.
# 'tar' handles this nicely.
(cd "$LSRC" && tar --atime-preserve --one-file-system -cf - *) | \
(cd "$LDST" && tar -xmf -)
}
# Create FS and copy rescue FS
create_basis_and_mount()
{
echo "Creating disk image within '$DST'..."
dd if=/dev/zero of="$DST" bs=4096 count=1 2>/dev/null >/dev/null 2>&1
dd if=/dev/zero of="$DST" bs=1048576 count=0 seek=$MB >/dev/null 2>&1
/sbin/mke2fs -b 1024 -i 2048 -L xen_rescue -F "$DST" >/dev/null 2>&1
DST_MNT="$DST".mnt
mkdir -p "$DST_MNT"
mount -o loop "$DST" "$DST_MNT"
if [ $? -ne 0 ]; then
error "Failed to mount destination disk image via loopback."
fi
echo "Copying files from '$SRC'..."
if test -d "$SRC"; then
if [ ! -d "$SRC"/dev ] || [ ! -d "$SRC"/sbin ]; then
error "'$SRC' does not look like a valid root filesystem."
fi
cp_rescue "$SRC" "$DST_MNT"
if [ $? -ne 0 ]; then
cp_error
fi
else
mkdir -p "$DST".src
if test ! -z "`file $SRC | grep gzip`"; then
cp -p "$SRC" "$DST".stage.gz
gunzip -f "$DST".stage.gz || rm -f "$DST".stage.gz
mount -o loop "$DST".stage "$DST".src
if [ $? -ne 0 ]; then
rm "$DST".stage
rmdir "$DST".src
error "Failed to mount the source via loopback."
fi
cp_rescue "$DST".src "$DST_MNT"
if [ $? -ne 0 ]; then
umount "$DST".src
rm "$DST".stage
rmdir "$DST".src
cp_error
fi
umount "$DST".src
rm "$DST".stage
else
mount -o loop "$SRC" "$DST".src
if [ $? -ne 0 ]; then
rmdir "$DST".src
error "Failed to mount the source via loopback."
fi
cp_rescue "$DST".src "$DST_MNT"
if [ $? -ne 0 ]; then
umount "$DST".src
rmdir "$DST".src
cp_error
fi
umount "$DST".src
fi
rmdir "$DST".src
fi
}
# Save some inodes
remove_some_files()
{
# these consume an excessive amount of inodes
rm -f "$DST_MNT"/dev/sd[c-z][a-z][0-9]*
# hwclock does not work
rm -f "$DST_MNT"/etc/init.d/boot.d/*boot.clock
}
xenify_image()
{
# Xen doesn't yet support virtualizing USB
sed -i "s/^usbfs/#usbfs/" "$DST_MNT"/etc/fstab
}
# Copy extra files to rescue image
copy_extra_files()
{
test ! -e "$DST_MNT"/sbin/depmod && cp -p /sbin/depmod "$DST_MNT"/sbin/
cp -p /usr/share/doc/packages/xen/boot.local.xenU "$DST_MNT"/etc/init.d/boot.local
}
# Remove kernel modules and replace by ours
exchange_kernel_modules()
{
echo "Updating kernel within '$DST'..."
KMODDIR=/lib/modules/$KVER/kernel
MNTKVER="`cd "$DST_MNT"/lib/modules && ls -td */kernel 2>/dev/null | sed 's@/kernel@@' 2>/dev/null`"
for dir in $MNTKVER; do
if test "$MNTKVER" != "$KVER"; then
rm -rf "$DST_MNT"/lib/modules/$MNTKVER
fi
done
mkdir -p "$DST_MNT"$KMODDIR
# complete trees
for dir in arch crypto lib net security; do
cp -ax $KMODDIR/$dir "$DST_MNT"$KMODDIR/
done
mkdir -p "$DST_MNT"$KMODDIR/fs
cp -p $KMODDIR/fs/*.ko "$DST_MNT"$KMODDIR/fs/
# a selection of FS
for fs in afs autofs autofs4 cifs exportfs ext3 fat jbd jfs msdos ncpfs nfsd nls ntfs reiser4 reiserfs smbfs subfs sysv udf ufs vfat xfs; do
if test -e $KMODDIR/fs/$fs; then
cp -ax $KMODDIR/fs/$fs "$DST_MNT"$KMODDIR/fs/
fi
done
# some drivers
mkdir -p "$DST_MNT"$KMODDIR/drivers/char
for name in lp.ko n_hdlc.ko raw.ko; do
cp -p $KMODDIR/drivers/char/$name "$DST_MNT"$KMODDIR/drivers/char/
done
mkdir -p "$DST_MNT"$KMODDIR/drivers/block
for name in umem.ko nbd.ko loop.ko loop_fish2.ko cryptoloop.ko; do
cp -p $KMODDIR/drivers/block/$name "$DST_MNT"$KMODDIR/drivers/block/
done
mkdir -p "$DST_MNT"$KMODDIR/drivers/base
cp -p $KMODDIR/drivers/base/firmware_class.ko "$DST_MNT"$KMODDIR/drivers/base/
mkdir -p "$DST_MNT"$KMODDIR/drivers/md
cp -p $KMODDIR/drivers/md/*.ko "$DST_MNT"$KMODDIR/drivers/md/
mkdir -p "$DST_MNT"$KMODDIR/drivers/xen
for dir in $KMODDIR/drivers/xen/*front; do
cp -ax $dir "$DST_MNT"$KMODDIR/drivers/xen/
done
if test -e $KMODDIR/kernel; then
mkdir -p "$DST_MNT"$KMODDIR/kernel
cp -ax $KMODDIR/kernel/* "$DST_MNT"$KMODDIR/kernel/
fi
# Kernel image + System.map
mkdir -p "$DST_MNT"/boot
rm -f "$DST_MNT"/boot/vmlinuz-* "$DST_MNT"/boot/System.map-* "$DST_MNT"/boot/initrd-*
cp -p /boot/vmlinuz-$KVER "$DST_MNT"/boot/
if test -e /boot/initrd-$KVER-domU; then
cp -p /boot/initrd-$KVER-domU "$DST_MNT"/boot/initrd-$KVER
else
cp -p /boot/initrd-$KVER "$DST_MNT"/boot/
fi
cp -p /boot/System.map-$KVER "$DST_MNT"/boot/
depmod -a $KVER -b "$DST_MNT" -F "$DST_MNT"/boot/System.map-$KVER
}
# umount and display message
umount_and_msg()
{
umount "$DST_MNT"
rmdir "$DST_MNT"
DST_MNT=
echo "'$DST' has been prepared successfully."
CFGFILE=/etc/xen/vm/${DST##*/}
if test -e $CFGFILE; then
mv -b $CFGFILE $CFGFILE.save
fi
if test "${DST:0:1}" != "/"; then
DST="`pwd`/$DST"
fi
cp -p /etc/xen/examples/xmexample.rescue $CFGFILE
sed -i "/^disk/s@^.*\$@disk = [ \'file:$DST,hda1,w\' ]@" $CFGFILE
# These next two lines are only applicable if not using domUloader,
# but try anyway.
sed -i "/^kernel/s@^.*\$@kernel = \"/boot/vmlinuz-$KVER\"@" $CFGFILE
sed -i "/^ramdisk/s@^.*\$@ramdisk = \"/boot/initrd-$KVER\"@" $CFGFILE
echo ""
echo "Config file '$CFGFILE' has been created. Please review!"
echo "You may also want to add an IP address to the config file."
echo "Start the domain with 'xm create -c $CFGFILE'."
}
if test -z "$1" -o -z "$2"; then
usage
fi
SRC=$1
if [ ! -e "$SRC" ]; then
usage_error "'$SRC' does not exist."
fi
DST=$2
if [ -e "$DST" ]; then
error "'$DST' already exists."
fi
MB=$MB_DEFAULT
[ ! -z "$3" ] && MB=$3
KVER=$4
if [ `id -u` -ne 0 ]; then
usage_error "Please run this script as root."
fi
get_xen_kernel
create_basis_and_mount
remove_some_files
copy_extra_files
xenify_image
exchange_kernel_modules
umount_and_msg