+error_handler() {
+ last_exit_code="$?"
+ last_bash_command="$BASH_COMMAND"
+ if [ "$REPORT_TRAP_ERR" = "yes" ]; then
+ echo "Unexpected non-zero exit code $last_exit_code in ${BASH_SOURCE[*]} at line ${BASH_LINENO[*]} detected!
+last bash command: $last_bash_command"
+ fi
+ if [ ! "$FAIL_TRAP_ERR" = "yes" ]; then
+ return
+ fi
+ ## Check if "bailout" function is available.
+ ## This is not the case in chroot-script.
+ if command -v bailout >/dev/null 2>&1; then
+ bailout 1
+ else
+ echo 'FAIL_TRAP_ERR is set to "yes", exit 1.'
+ exit 1
+ fi
+}
+
+if [ "$REPORT_TRAP_ERR" = "yes" ] || [ "$FAIL_TRAP_ERR" = "yes" ]; then
+ set -E
+ set -o pipefail
+ trap "error_handler" ERR
+ export -f "error_handler"
+fi
+# }}}
+
+# variables {{{
+PN="$(basename "$0")"
+if [[ -d "$(dirname "$(command -v "$0")")"/.git ]]; then
+ VERSION="$(git describe | sed 's|^v||')"
+else
+ VERSION="$(dpkg-query --show --showformat='${Version}' "$PN")"
+fi
+VERSION="${VERSION:-unknown}"
+MNTPOINT="/mnt/debootstrap.$$"
+
+# defaults
+[ -n "$CHROOT_SCRIPTS" ] || CHROOT_SCRIPTS='yes'
+[ -n "$CONFFILES" ] || CONFFILES='/etc/debootstrap'
+[ -n "$DEBCONF" ] || DEBCONF='yes'
+[ -n "$DEBIAN_FRONTEND" ] || DEBIAN_FRONTEND='noninteractive'
+[ -n "$DEBOOTSTRAP" ] || DEBOOTSTRAP='debootstrap'
+[ -n "$DEFAULT_LANGUAGE" ] || DEFAULT_LANGUAGE='en_US:en'
+[ -n "$DEFAULT_LOCALES" ] || DEFAULT_LOCALES='en_US.UTF-8'
+[ -n "$DISK_IDENTIFIER" ] || DISK_IDENTIFIER='26ada0c0-1165-4098-884d-aafd2220c2c6'
+[ -n "$EXTRAPACKAGES" ] || EXTRAPACKAGES='yes'
+[ -n "$FALLBACK_MIRROR" ] || FALLBACK_MIRROR='http://deb.debian.org/debian'
+[ -n "$FIXED_DISK_IDENTIFIERS" ] || FIXED_DISK_IDENTIFIERS="no"
+[ -n "$FORCE" ] || FORCE=''
+[ -n "$HOSTNAME" ] || HOSTNAME='grml'
+[ -n "$INITRD" ] || INITRD='yes'
+[ -n "$INSTALL_NOTES" ] || INSTALL_NOTES='/etc/debootstrap/install_notes'
+[ -n "$LOCALES" ] || LOCALES='yes'
+[ -n "$MIRROR" ] || MIRROR="$FALLBACK_MIRROR"
+[ -n "$MKFS" ] || MKFS='mkfs.ext4'
+[ -n "$MKFS_OPTS" ] || MKFS_OPTS=''
+[ -n "$PACKAGES" ] || PACKAGES='yes'
+[ -n "$POST_SCRIPTS" ] || POST_SCRIPTS='yes'
+[ -n "$PRE_SCRIPTS" ] || PRE_SCRIPTS='yes'
+[ -n "$RECONFIGURE" ] || RECONFIGURE='console-data'
+[ -n "$RELEASE" ] || RELEASE='buster'
+[ -n "$RM_APTCACHE" ] || RM_APTCACHE='yes'
+[ -n "$SCRIPTS" ] || SCRIPTS='no' # deprecated, replaced by POST_SCRIPTS
+[ -n "$SECURE" ] || SECURE='yes'
+[ -n "$TIMEZONE" ] || TIMEZONE='Europe/Vienna'
+[ -n "$TUNE2FS" ] || TUNE2FS='tune2fs -c0 -i0'
+[ -n "$UPGRADE_SYSTEM" ] || UPGRADE_SYSTEM='yes'
+[ -n "$VMSIZE" ] || VMSIZE="2G"
+[ -n "$GRUB_INSTALL" ] || GRUB_INSTALL='yes'
+
+# inside the chroot system locales might not be available, so use minimum:
+export LANG=C
+export LC_ALL=C
+export LANGUAGE=C
+
+# make sure interactive mode is only executed when
+# using an empty configuration file or option --interactive
+INTERACTIVE=''
+# }}}
+
+# help text {{{
+usage() {
+ echo "$PN - wrapper around debootstrap for installing Debian
+
+Usage: $PN [options]
+
+Bootstrap options:
+
+ -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: buster).
+ -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,
+ has no effect if -t is given and represents a directory.
+ --debopt <params> Extra parameters passed to the debootstrap command.
+ --interactive Use interactive mode (frontend).
+ --nodebootstrap Skip debootstrap, only do configuration to the target.
+ --grub <device> Target for grub installation. Usage example: /dev/sda
+ --efi <device> Target for EFI installation. Usage example: /dev/sda1
+ --arch <arch> Set target architecture, use for installing i386 on amd64.
+ --filesystem <fs> Filesystem that should be used when target is a partition
+ or Virtual Machine (see --vmfile).
+ --force Do not prompt for user acknowledgement.
+
+Options for Virtual Machine deployment:
+
+ --vm Set up a Virtual Machine on an existing block device
+ instead of plainly installing to a partition or
+ directory. Needs to be combined with --target.
+ Example: --vm --target /dev/mapper/your-vm-disk
+ --vmfile Like --vm, but install into a regular file (created by
+ 'qemu-img create -f raw ...') instead.
+ Example: --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:
+
+ -c, --config <file> Use specified configuration file, defaults to
+ /etc/debootstrap/config
+ -d, --confdir <path> Place of config files for debootstrap, defaults
+ to /etc/debootstrap
+ --packages <file> Install packages defined in specified list file
+ instead of using /etc/debootstrap/packages.
+ --nopackages Skip installation of packages defined in
+ /etc/debootstrap/packages
+ --nokernel Skip installation of default kernel images.
+ --nointerfaces Do not copy /etc/network/interfaces from host system
+ to target system.
+ (This option is automatically enabled when using --vmfile.)
+ --defaultinterfaces Install a default /etc/network/interfaces file (enabling
+ DHCP for eth0) instead of taking over config from host system.
+ --debconf <file> Pre-seed packages using specified pre-seed db file.
+ --grmlrepos Enable Grml's Debian repository (deb.grml.org).
+ --backportrepos Enable Debian's backports repository (backports.debian.org).
+ --keep_src_list Do not overwrite user provided apt sources.list.
+ --contrib Enable 'contrib' in COMPONENTS (defaults to 'main' only).
+ --non-free Enable non-free in COMPONENTS (defaults to 'main' only).
+ --hostname <name> Hostname of Debian system.
+ --nopassword Do not prompt for the root password.
+ --password <pwd> Use specified password as password for user root.
+ --sshcopyid Use locally available public keys to authorise root login on the target system.
+ --bootappend <line> Add specified appendline to kernel whilst booting.
+ --chroot-scripts <d> Execute chroot scripts from specified directory.
+ --pre-scripts <dir> Execute scripts from specified directory (before chroot-scripts).
+ --scripts <dir> Execute scripts from specified directory (after chroot-scripts).
+ --remove-configs Delete grml-debootstrap configuration files from installed system.
+
+Other options:
+
+ -v, --verbose Increase verbosity.
+ --debug Execute in very verbose way.
+ -h, --help Print this usage information and exit.
+ -V, --version Show summary of options and exit.
+
+Usage examples can be found in the grml-debootstrap manpage.
+Send bugreports to the grml-team: bugs (at) grml.org || https://grml.org/bugs/
+"
+}
+
+if [ "$1" = '-h' ] || [ "$1" = '-help' ] || [ "$1" = "--help" ] ; then
+ usage
+ echo 'Please notice that this script requires root permissions!'
+ exit 0
+fi
+# }}}
+
+# early helper functions {{{
+GOOD='\e[32;01m'
+BAD='\e[31;01m'
+WARN='\e[33;01m'
+NORMAL='\e[0m'
+
+einfo() {
+ einfon "$1\\n"
+ return 0
+}
+
+einfon() {
+ [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
+ printf " %s*%s $*" "${GOOD}" "${NORMAL}"
+ LAST_E_CMD=einfon
+ return 0
+}
+
+ewarn() {
+ printf " %s*%s $*\\n" "${WARN}" "${NORMAL}"
+ return 0
+}
+
+eerror() {
+ [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
+ printf " %s*%s $*\\n" "${BAD}" "${NORMAL}" >&2
+ LAST_E_CMD=eerror
+ return 0
+}
+
+eend() {
+ local retval="${1:-0}"
+ shift
+ if [ "$retval" -gt 0 ]; then
+ printf " %s-> Failed (rc=%s)%s\\n" "${BAD}" "${retval}" "${NORMAL}"
+ fi
+ return "$retval"
+}
+
+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
+ command -v "$arg" >/dev/null 2>&1 || RC="$arg"
+ done
+ if [ -n "$RC" ] ; then
+ echo "$RC not installed"
+ return 1
+ fi
+}
+# }}}
+
+# helper functions {{{
+cleanup() {
+ if [ -n "$CHROOT_VARIABLES" ] ; then
+ einfo "Removing ${CHROOT_VARIABLES}" ; rm "$CHROOT_VARIABLES" ; eend $?
+ fi
+
+ if [ -n "$STAGES" ] ; then
+ einfo "Removing ${STAGES}" ; rmdir "$STAGES" ; eend $?
+ fi
+
+ # Remove temporary mountpoint again
+ if echo "$MNTPOINT" | grep -q '/mnt/debootstrap\.' ; then
+ rmdir "$MNTPOINT" 2>/dev/null
+ fi
+
+ # make sure $TARGET is not mounted when exiting grml-debootstrap
+ if [ -n "$MNTPOINT" ] ; then
+ if grep -q "$MNTPOINT" /proc/mounts ; then
+ # make sure nothing is left inside chroot so we can unmount it
+ for service in ssh mdadm ; do
+ if [ -x "${MNTPOINT}/etc/init.d/${service}" ] ; then
+ chroot "$MNTPOINT" "/etc/init.d/${service}" stop
+ fi
+ done
+
+ [ -x "$MNTPOINT"/bin/umount ] && chroot "$MNTPOINT" umount -a >/dev/null 2>&1
+
+ # ugly, but make sure we really don't leave anything (/proc /proc and
+ # /dev /dev are intended, trying to work around timing issues, see #657023)
+ for ARG in /run/udev /sys /proc /proc /dev/pts /dev/pts /dev /dev ; do
+ [ -x "$MNTPOINT"/bin/umount ] && chroot "$MNTPOINT" umount $ARG >/dev/null 2>&1
+ umount "$MNTPOINT"/$ARG >/dev/null 2>&1
+ done
+
+ if [ -n "$ISODIR" ] ; then
+ [ -d "$MNTPOINT/$ISODIR" ] && umount "$MNTPOINT/$ISODIR" >/dev/null 2>&1
+ fi
+
+ if [ -n "$DIRECTORY" ] ; then
+ einfo "Not unmounting $MNTPOINT as you requested me to install into a directory of your own choice." ; eend 0
+ else
+ einfo "Unmounting $MNTPOINT"
+ umount "$MNTPOINT"
+ eend $?
+ fi
+
+ if [ -n "$STAGES" ] ; then
+ echo -n "Removing stages directory ${STAGES}: "
+ rm -rf "$STAGES" && echo 'done'
+ fi
+
+ # remove directory only if we used the default with process id inside the name
+ if echo "$MNTPOINT" | grep -q '/mnt/debootstrap\.' ; then
+ einfo "Removing directory ${MNTPOINT}"
+ rmdir "$MNTPOINT"
+ eend $?
+ fi
+ fi
+ fi
+
+ if [ -n "${ORIG_TARGET}" ] ; then
+ einfo "Removing loopback mount of file ${ORIG_TARGET}."
+ kpartx -d "${ORIG_TARGET}"
+ # Workaround for a bug in kpartx which doesn't clean up properly,
+ # see Debian Bug #891077 and Github-PR grml/grml-debootstrap#112
+ if dmsetup ls | grep -q "^${LOOP_PART} "; then
+ kpartx -d "/dev/${LOOP_DISK}" >/dev/null
+ fi
+ eend $?
+ fi
+}
+
+# we want to exit smoothly and clean:
+bailout(){
+
+ cleanup
+
+ [ -n "$1" ] && EXIT="$1" || EXIT="1"
+ [ -n "$2" ] && einfo "Notice: remove $STAGES/$2 to reexecute the stage"
+
+ exit "$EXIT"
+}
+trap bailout HUP INT QUIT TERM
+
+# we want to execute all the functions only once, simple check for it:
+stage() {
+ if [ -n "$2" ] ; then
+ echo "$2" > "${STAGES}/${1}"
+ 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
+ ewarn " To reexecute it clean up the according directory inside $STAGES" ; eend 0
+ return 1
+ fi
+}
+# }}}
+
+# make sure we have what we need {{{
+check4progs "${DEBOOTSTRAP}" || bailout 1
+# }}}
+
+# source main configuration file {{{
+if [ -r /etc/debootstrap/config ] ; then
+ # shellcheck disable=SC1091
+ . /etc/debootstrap/config
+fi
+# }}}
+
+# cmdline handling {{{
+CMDLINE_OPTS=mirror:,iso:,release:,target:,mntpoint:,debopt:,defaultinterfaces,interactive,nodebootstrap,nointerfaces,nokernel,nopackages,filesystem:,config:,confdir:,packages:,chroot-scripts:,scripts:,post-scripts:,pre-scripts:,debconf:,vm,vmfile,vmsize:,keep_src_list,hostname:,password:,nopassword,grmlrepos,backportrepos,bootappend:,grub:,efi:,arch:,insecure,verbose,help,version,force,debug,contrib,non-free,remove-configs,sshcopyid
+
+_opt_temp=$(getopt --name grml-debootstrap -o +m:i:r:t:p:c:d:vhV --long \
+ $CMDLINE_OPTS -- "$@")
+
+if [ $? != 0 ]; then
+ eerror "Try 'grml-debootstrap --help' for more information."; eend 1; exit 1
+fi
+eval set -- "$_opt_temp"
+
+while :; do
+ case "$1" in
+
+ # == Bootstrap options
+ --mirror|-m) # Mirror which should be used for apt-get/aptitude
+ shift; _opt_mirror="$1"
+ ;;
+ --iso|-i) # Mountpoint where a Debian ISO is mounted to
+ shift; _opt_iso="$1"
+ ;;
+ --release|-r) # Release of new Debian system
+ shift; _opt_release="$1"
+ ;;
+ --target|-t) # Target partition (/dev/...) or directory
+ shift; _opt_target="$1"
+ ;;
+ --vm) # Virtual machine image (no file)
+ _opt_vm="T"
+ ;;
+ --vmfile) # Virtual machine file
+ _opt_vmfile="T"
+ ;;
+ --vmsize) # size of Virtual machine file
+ shift; _opt_vmsize="$1"
+ ;;
+ --mntpoint|-p) # Mountpoint used for mounting the target system
+ shift; _opt_mntpoint="$1"
+ ;;
+ --debopt) # Extra parameters passed to the debootstrap command
+ shift; _opt_debopt="$1"
+ ;;
+ --filesystem) # Filesystem that should be used
+ shift; _opt_filesystem="$1"
+ ;;
+ --interactive) # Use interactive mode (frontend)
+ _opt_interactive=T
+ ;;
+ --nodebootstrap) # Skip debootstrap, only do configuration to the target
+ _opt_nodebootstrap=T
+ ;;
+ --nopackages) # Skip installation of packages defined in /etc/debootstrap/packages
+ _opt_nopackages=T
+ ;;
+ --arch) # Target architecutre
+ shift; _opt_arch="$1"
+ ;;
+ # just for backwards compatibility
+ --insecure)
+ _opt_insecure=T
+ ;;
+ #
+
+ # == Configuration options
+ --config|-c) # Use specified configuration file, defaults to /etc/debootstrap
+ shift; _opt_config="$1"
+ ;;
+ --confdir|-d) # Place of config files for debootstrap, defaults to /etc/debootstrap
+ shift; _opt_confdir="$1"
+ ;;
+ --packages) # Install packages defined in specified file
+ shift; _opt_packages="$1"
+ _opt_packages_set=T
+ ;;
+ --debconf) # Pre-seed packages using specified file
+ shift; _opt_debconf="$1"
+ _opt_debconf_set=T
+ ;;
+ --pre-scripts) # Execute scripts from specified directory (before chroot-scripts).
+ shift; _opt_pre_scripts="$1"
+ _opt_pre_scripts_set=T
+ ;;
+ --scripts) # Execute scripts from specified directory [NOTE: deprecated, replaced via --post-scripts]
+ shift; _opt_scripts="$1"
+ _opt_scripts_set=T
+ ;;
+ --post-scripts) # Execute scripts from specified directory
+ shift; _opt_post_scripts="$1"
+ _opt_post_scripts_set=T
+ ;;
+ --chroot-scripts) # Execute chroot scripts from specified directory
+ shift; _opt_chroot_scripts="$1"
+ _opt_chroot_scripts_set=T
+ ;;
+ --keep_src_list) # Do not overwrite user provided apt sources.list
+ _opt_keep_src_list=T
+ ;;
+ --hostname) # Hostname of Debian system
+ shift; _opt_hostname="$1"
+ ;;
+ --password) # Use specified password as password for user root
+ shift; _opt_password="$1"
+ ;;
+ --defaultinterfaces) # Install default /etc/network/interfaces
+ _opt_defaultinterfaces=T
+ ;;
+ --nointerfaces) # Skip installation of /etc/network/interfaces
+ _opt_nointerfaces=T
+ ;;
+ --nokernel) # Skip installation of default kernel images
+ _opt_nokernel=T
+ ;;
+ --nopassword) # Skip password dialog
+ _opt_nopassword=T
+ ;;
+ --sshcopyid) # Use locally available public keys to authorise root login on the target system
+ _opt_sshcopyid=T
+ ;;
+ --grmlrepos) # Enable Grml repository
+ _opt_grmlrepos=T
+ ;;
+ --backportrepos) # Enable Debian backports repository
+ _opt_backportrepos=T
+ ;;
+ --bootappend) # Add specified appendline to kernel whilst booting
+ shift; _opt_bootappend="$1"
+ ;;
+ --grub) # Target for grub installation. Use grub syntax for specifying
+ shift; _opt_grub="$1"
+ ;;
+ --efi) # Target for EFI boot installation
+ shift; _opt_efi="$1"
+ ;;
+ --contrib) # Add 'contrib' to list of components
+ _opt_contrib=T
+ ;;
+ --non-free) # Add 'non-free' to list of components
+ _opt_non_free=T
+ ;;
+ --remove-configs) # Drop config files from installed system
+ _opt_remove_configs=T
+ ;;
+
+ # == Other options
+ --verbose|-v) # Increase verbosity
+ if [ "$_opt_verbose" ]; then
+ _opt_verbose=$( _opt_verbose + 1 )
+ else
+ _opt_verbose=1
+ fi
+ ;;
+ --debug) # Execute in debug mode
+ _opt_debug=T
+ ;;
+ --help|-h) # Print usage information and exit
+ _opt_help=T
+ ;;
+ --version|-V) # Show version information and exit
+ _opt_version=T
+ ;;
+ --force) # Do not prompt for user input
+ _opt_force=T
+ ;;
+ --)
+ shift; break
+ ;;
+ *)
+ eerror "Internal getopt error!"; eend 1 ; exit 1
+ ;;
+ esac
+ shift
+done
+
+# == business-logic of command line parameter-processing
+
+# source configuration file in <confdir> if supplied. {{{
+[ "$_opt_confdir" ] && {
+ CONFFILES=$_opt_confdir
+ einfo "Using config files under $CONFFILES/."
+ if ! [ -r "$CONFFILES/config" ] ; then
+ eerror "Error: config file $CONFFILES/config not found."; eend 1; bailout 1
+ fi
+ # shellcheck disable=SC1091 source=config
+ if ! . "$CONFFILES/config" ; then
+ eerror "Error reading config file $CONFFILES/config" ; eend 1 ; bailout 1
+ fi
+ # restore the command line parameter value
+ CONFFILES=$_opt_confdir
+}
+# }}}