################################################################################
# http://www.debian.org/releases/stable/i386/index.html.en
-set -e # exit on any error
-
# variables {{{
PN="$(basename $0)"
VERSION="$(dpkg --list $PN 2>/dev/null| awk '/^i/ {print $3}')"
VERSION="${VERSION:-unknown}"
MNTPOINT="/mnt/debootstrap.$$"
+# defaults
+VMSIZE="2G"
+FORCE=''
+
# inside the chroot system locales might not be available, so use minimum:
export LANG=C
export LC_ALL=C
INTERACTIVE=''
# }}}
-# source core functions {{{
-. /etc/grml/lsb-functions
-. /etc/grml/script-functions
-# }}}
-
# help text {{{
usage() {
echo "$PN - wrapper around debootstrap for installing Debian
-m, --mirror <URL> Mirror which should be used for apt-get/aptitude.
-i, --iso <mnt> Mountpoint where a Debian ISO is mounted to, for use
- instead of fetching packages from a mirror.
- -r, --release <name> Release of new Debian system (default: lenny).
+ instead of fetching packages from a mirror.
+ -r, --release <name> Release of new Debian system (default: squeeze).
-t, --target <target> Target partition (/dev/...) or directory where the
system should be installed to.
-p, --mntpoint <mnt> Mountpoint used for mounting the target system,
--nodebootstrap Skip debootstrap, only do configuration to the target.
--grub <device> Target for grub installation. Usage example: /dev/sda
--arch <arch> Architecture to use. Currently only i386 is supported.
- --filesystem <fs> Filesystem that should be used when target is a partition.
+ --filesystem <fs> Filesystem that should be used when target is a partition
+ or Virtual Machine (see --vmfile).
--insecure Do not download and check Release file signatures.
+ --force Do not prompt for user acknowledgement.
+
+Options for Virtual Machine deployment:
+
+ --vmfile Set up a Virtual Machine instead of installing to
+ a partition or directory, to be combined with --target,
+ like: --vmfile --target /mnt/sda1/qemu.img
+ --vmsize <size> Use specified size for size of VM file (default: 2G).
+ Syntax as supported by qemu-img, like: --vmsize 3G
Configuration options:
fi
# }}}
+# {{{
+GOOD='\e[32;01m'
+WARN='\e[33;01m'
+BAD='\e[31;01m'
+NORMAL='\e[0m'
+HILITE='\e[36;01m'
+BRACKET='\e[34;01m'
+
+einfo() {
+ einfon "$1\n"
+ return 0
+}
+
+einfon() {
+ [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
+ printf " ${GOOD}*${NORMAL} $*"
+ LAST_E_CMD=einfon
+ return 0
+}
+
+eerror() {
+ [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
+ printf " ${BAD}*${NORMAL} $*\n"
+ LAST_E_CMD=eerror
+ return 0
+}
+
+eend() {
+ local retval="${1:-0}"
+ shift
+ if [ $retval -gt 0 ]; then
+ printf " ${BAD}-> Failed (rc=${retval})${NORMAL}\n"
+ fi
+}
+
+check4root(){
+ if [ "$(id -u 2>/dev/null)" != 0 ] ; then
+ echo 1>&2 "Error: please run this script with uid 0 (root)." ; return 1
+ fi
+}
+
+check4progs(){
+ local RC=''
+ for arg in $* ; do
+ which $arg >/dev/null 2>&1 || RC="$arg"
+ done
+ if [ -n "$RC" ] ; then
+ echo "$RC not installed"
+ return 1
+ fi
+}
+
+# }}}
+
# make sure we have what we need {{{
check4progs debootstrap dialog || exit 1
# }}}
elif [ -r /usr/share/grml-debootstrap/functions/cmdlineopts.clp ] ; then
. /usr/share/grml-debootstrap/functions/cmdlineopts.clp
else
- echo "Error: cmdline function file not found, exiting.">&2
+ eerror "Error: cmdline function file not found, exiting."
+ eend 1
exit 1
fi
[ "$_opt_iso" ] && ISO=$_opt_iso
[ "$_opt_release" ] && RELEASE=$_opt_release
[ "$_opt_target" ] && TARGET=$_opt_target
+[ "$_opt_vmfile" ] && VIRTUAL=1
+[ "$_opt_vmsize" ] && VMSIZE=$_opt_vmsize
[ "$_opt_mntpoint" ] && MNTPOINT=$_opt_mntpoint
[ "$_opt_debopt" ] && DEBOOTSTRAP_OPT=$_opt_debopt
[ "$_opt_interactive" ] && INTERACTIVE=1
[ "$_opt_grub" ] && GRUB=$_opt_grub
[ "$_opt_arch" ] && ARCH=$_opt_arch
[ "$_opt_insecure" ] && SECURE='false'
+[ "$_opt_force" ] && FORCE=$_opt_force
[ "$_opt_verbose" ] && VERBOSE="-v"
[ "$_opt_help" ] && {
fi
# }}}
+# make sure we have what we need {{{
+if [ -n "$VIRTUAL" ] ; then
+ check4progs kpartx mksh qemu-img || exit 1
+fi
+# }}}
+
# source specified configuration file {{{
if [ -n "$CONFIGFILE" ] ; then
einfo "Reading specified config file $CONFIGFILE."
# backwards compability checks {{{
if [ -n "$GROOT" ] ; then
- echo "Error: you seem to have \$GROOT configured." >&2
- echo "This variable is no longer supported, please visit the" >&2
- echo "grml-debootstrap documentation for details." >&2
+ eerror "Error: you seem to have \$GROOT configured."
+ eerror "This variable is no longer supported, please visit the"
+ eerror "grml-debootstrap documentation for details."
+ eend 1
exit 1
fi
if echo "$GRUB" | grep -q '^hd' ; then
- echo "Error: this syntax for the grub configuration variable is no longer supported." >&2
- echo "Please do not use hd... any longer but /dev/sdX instead." >&2
+ eerror "Error: this syntax for the grub configuration variable is no longer supported."
+ eerror "Please do not use hd... any longer but /dev/sdX instead."
+ eend 1
exit 1
fi
# }}}
fi
ERRORFILE=$(mktemp)
-set +e
-# TODO: better error handling?
yes | mdadm --create "${TARGET}" --level="${RAIDLEVEL}" \
--raid-devices="${NUM_PARTITIONS}" ${METADATA_VERSION} ${SELECTED_PARTITIONS} >/dev/null 2>$ERRORFILE
RC=$?
-set -e
-
if [ "$RC" = 0 ] ; then
dialog --title "$PN" --msgbox \
"Creating $TARGET was successful." 0 0
# do not display if MNTPOINT is the default one
case "$MNTPOINT" in /mnt/debootstrap*) ;; *) echo " Mount point: $MNTPOINT" ;; esac
- [ -n "$GRUB" ] && echo " Install grub: $GRUB" || echo " Install grub: no"
+ if [ -n "$VIRTUAL" ] ; then
+ echo " Install grub: yes"
+ else
+ [ -n "$GRUB" ] && echo " Install grub: $GRUB" || echo " Install grub: no"
+ fi
+
[ -n "$RELEASE" ] && echo " Using release: $RELEASE"
[ -n "$MIRROR" ] && echo " Using mirror: $MIRROR"
[ -n "$HOSTNAME" ] && echo " Using hostname: $HOSTNAME"
[ -n "$ISO" ] && echo " Using ISO: $ISO"
+ if [ -n "$VIRTUAL" ] ; then
+ echo " Deploying as Virtual Machine."
+ [ -n "$VMSIZE" ] && echo " Using Virtual Disk file with size of ${VMSIZE}."
+ fi
+ echo
echo " Important! Continuing will delete all data from ${TARGET}!"
- echo
- einfon "Is this ok for you? [y/N] "
- read a
- if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
- eerror "Exiting as requested." ; eend 1
- exit 1
+ if [ -n "$FORCE" ] ; then
+ einfo "Skip user acknowledgement as requested via --force option."
+ else
+ echo
+ einfon "Is this ok for you? [y/N] "
+ read a
+ if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
+ eerror "Exiting as requested." ; eend 1
+ exit 1
+ fi
fi
fi
}
TARGET="$(readlink -f $TARGET)"
}
-if [ -b "$TARGET" ] ; then
+if [ -b "$TARGET" ] || [ -n "$VIRTUAL" ] ; then
PARTITION=1
else
set_target_directory
fi
fi
+ if [ -n "${ORIG_TARGET}" ] ; then
+ einfo "Removing loopback mount of file ${ORIG_TARGET}."
+ kpartx -d "${ORIG_TARGET}" ; eend $?
+ fi
+
[ -n "$1" ] && EXIT="$1" || EXIT="1"
[ -n "$3" ] && einfo "Notice: just remove $STAGES/$3 to reexecute the stage"
return 0
elif grep -q done "${STAGES}/${1}" 2>/dev/null ; then
ewarn "Notice: stage $1 has been executed already, skipping execution therefore." ; eend 0
- eindent
- ewarn "To reexecute it clean up the according directory inside $STAGES" ; eend 0
- eoutdent
+ ewarn " To reexecute it clean up the according directory inside $STAGES" ; eend 0
return 1
fi
}
# will fail to detect the uuid in the chroot
if echo "$TARGET" | grep -q "/dev/md" ; then
blockdev --rereadpt "${TARGET}"
- else
+ elif ! [ -n "$VIRTUAL" ] ; then
blockdev --rereadpt "${TARGET%%[0-9]*}"
fi
# give the system 2 seconds, otherwise we might run into
if grep -q $TARGET /proc/mounts ; then
ewarn "$TARGET already mounted, continuing anyway." ; eend 0
else
- [ -d "$MNTPOINT" ] || mkdir -p "$MNTPOINT"
+ if ! [ -d "${MNTPOINT}" ] ; then
+ [ -n "$VIRTUAL" ] || mkdir -p "${MNTPOINT}"
+ fi
einfo "Mounting $TARGET to $MNTPOINT"
+ mkdir -p "$MNTPOINT"
mount -o rw,suid,dev $TARGET $MNTPOINT
eend $?
fi
}
# }}}
+# prepare VM image for usage with debootstrap {{{
+prepare_vm() {
+ if [ -z "$VIRTUAL" ] ; then
+ return 0 # be quite by intention
+ fi
+
+ if [ -b "$TARGET" ] ; then
+ eerror "Error: specified virtual disk target ($TARGET) is an existing block device."
+ eend 1
+ exit 1
+ fi
+
+ ORIG_TARGET="$TARGET" # store for later reuse
+
+ qemu-img create -f raw "${TARGET}" "${VMSIZE}"
+ echo 4 66 | mksh /usr/share/grml-debootstrap/bootgrub.mksh -A | dd of="$TARGET" conv=notrunc
+ dd if=/dev/zero bs=1 conv=notrunc count=64 seek=446 of="$TARGET"
+ parted -s "${TARGET}" 'mkpart primary ext3 2M -1'
+
+ DEVINFO=$(kpartx -av $TARGET) # 'add map loop1p1 (253:0): 0 6289408 linear /dev/loop1 2048'
+ if [ -z "${DEVINFO}" ] ; then
+ eerror "Error setting up loopback device." ; eend 1
+ exit 1
+ fi
+
+ # hopefully this always works as expected
+ LOOP=$(echo ${DEVINFO} | sed 's/.* linear //; s/ [[:digit:]]*//') # '/dev/loop1'
+ BLOCKDEV=$(echo "${DEVINFO}" | sed -e 's/.* (\(.*:.*\)).*/\1/') # '253:0'
+ LOOP_PART="$(echo ${DEVINFO##add map } | sed 's/ .*//')" # '/dev/loop1p1'
+ export TARGET="/dev/mapper/$LOOP_PART" # '/dev/mapper/loop1p1'
+
+ blockdev --rereadpt "${LOOP}"
+
+ if [ -z "$TARGET" ] ; then
+ eerror "Error: target could not be set to according /dev/mapper/* device." ; eend 1
+ exit 1
+ fi
+}
+# }}}
+
+# make VM image bootable and unmount it {{{
+finalize_vm() {
+ if [ -z "${VIRTUAL}" ] ; then
+ return 0
+ fi
+
+ if ! mount "${TARGET}" "${MNTPOINT}" ; then
+ eerror "Error: Mounting ${TARGET} failed, can not continue." ; eend 1
+ exit 1
+ fi
+
+ einfo "Installing Grub as bootloader."
+ mount -t proc none "${MNTPOINT}"/proc
+ mount -t sysfs none "${MNTPOINT}"/sys
+ mount --bind /dev "${MNTPOINT}"/dev
+
+ mkdir -p "${MNTPOINT}/boot/grub"
+ if ! [ -d "${MNTPOINT}"/usr/lib/grub/i386-pc/ ] ; then
+ eerror "Error: grub not installed inside Virtual Machine. Can not install bootloader." ; eend 1
+ exit 1
+ fi
+
+ cp "${MNTPOINT}"/usr/lib/grub/i386-pc/* "${MNTPOINT}/boot/grub/"
+ chroot "${MNTPOINT}" grub-mkimage -O i386-pc -p "(hd0,msdos1)/boot/grub" -o /tmp/core.img biosdisk part_msdos ext2
+ dd if="${MNTPOINT}/tmp/core.img" of="${ORIG_TARGET}" conv=notrunc seek=4
+ rm -f "${MNTPOINT}/tmp/core.img"
+
+ einfo "Updating grub configuration file."
+ chroot "${MNTPOINT}" update-grub
+
+ umount "${MNTPOINT}"/proc
+ umount "${MNTPOINT}"/sys
+ umount "${MNTPOINT}"/dev
+
+ einfo "Adjusting grub.cfg for successful boot sequence."
+ # ugly but needed to boot grub acordingly
+ sed -i "s;set root=.*;set root='(hd0,msdos1)';" "${MNTPOINT}"/boot/grub/grub.cfg
+ sed -i "s; root=/dev/.*; root=/dev/sda1;" "${MNTPOINT}"/boot/grub/grub.cfg
+
+ umount "${MNTPOINT}"
+ kpartx -d "${ORIG_TARGET}" >/dev/null
+}
+# }}}
+
# install main chroot {{{
debootstrap_system() {
if [ "$_opt_nodebootstrap" ]; then
# }}}
# now execute all the functions {{{
-for i in mkfs tunefs mount_target debootstrap_system preparechroot \
- execute_pre_scripts chrootscript execute_scripts umount_chroot \
- fscktool ; do
+for i in prepare_vm mkfs tunefs mount_target debootstrap_system \
+ preparechroot execute_pre_scripts chrootscript execute_scripts \
+ umount_chroot finalize_vm fscktool ; do
if stage "${i}" ; then
$i && ( stage "${i}" done && rm -f "${STAGES}/${i}" ) || bailout 2 "i"
fi