Release new version 0.108 master v0.108
authorMichael Prokop <mika@grml.org>
Sat, 24 Feb 2024 09:55:45 +0000 (10:55 +0100)
committerMichael Prokop <mika@grml.org>
Sat, 24 Feb 2024 09:55:45 +0000 (10:55 +0100)
38 files changed:
.github/workflows/pr-review.yml [new file with mode: 0644]
.github/workflows/test-build.yml [new file with mode: 0644]
.gitignore
.travis.yml [deleted file]
Makefile
README.md
chroot-script
config
debian/changelog
debian/control
debian/copyright
debian/grml-debootstrap.maintscript
debian/rules
devices.tar.gz [deleted file]
docker/Dockerfile
grml-debootstrap
grml-debootstrap.8.txt
packages
packages-arm64 [new file with mode: 0644]
packer/Makefile
packer/debian64.bats
packer/debian64.json
packer/debian64_provision.sh
packer/fake-uname.c
releasetable.txt
tests/build-vm-and-test.sh [new file with mode: 0755]
tests/docker-build-deb.sh [new file with mode: 0755]
tests/docker-build-vm.sh [new file with mode: 0755]
tests/docker-install-deb.sh [new file with mode: 0755]
tests/gha-build-deb.sh [new file with mode: 0755]
tests/goss.yaml [moved from travis/goss.yaml with 67% similarity]
tests/run_tests.sh [deleted file]
tests/serial-console-connection [new file with mode: 0755]
tests/shellcheck-stub-debootstrap-variables [new file with mode: 0644]
tests/test-vm.sh [new file with mode: 0755]
travis/build-vm.sh [deleted file]
travis/execute.sh [deleted file]
travis/serial-console-connection [deleted file]

diff --git a/.github/workflows/pr-review.yml b/.github/workflows/pr-review.yml
new file mode 100644 (file)
index 0000000..686de9d
--- /dev/null
@@ -0,0 +1,40 @@
+# PR Review workflows.
+# The intention is for these to only find *new* issues.
+
+name: pr-review
+on:
+  pull_request:
+jobs:
+
+  shellcheck-code:
+    name: shellcheck grml-debootstrap
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: shellcheck
+        uses: reviewdog/action-shellcheck@v1
+        with:
+          github_token: ${{ secrets.github_token }}
+          reporter: github-pr-review
+          path: "."
+          pattern: |
+            chroot-script
+            grml-debootstrap
+            config
+            tests/shellcheck-stub-debootstrap-variables
+          check_all_files_with_shebangs: "false"
+
+  shellcheck-tests:
+    name: shellcheck test scripts
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - name: shellcheck
+        uses: reviewdog/action-shellcheck@v1
+        with:
+          github_token: ${{ secrets.github_token }}
+          reporter: github-pr-review
+          path: tests
+          pattern: |
+            *
+          check_all_files_with_shebangs: "false"
diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml
new file mode 100644 (file)
index 0000000..e22fec4
--- /dev/null
@@ -0,0 +1,104 @@
+name: test-build
+on:
+  pull_request:
+  push:
+  schedule:
+    - cron: '30 3 * * 2'
+
+concurrency:
+  group: "${{ github.ref }}"
+  cancel-in-progress: true
+jobs:
+  build-debian:
+    strategy:
+      # Keep other matrix jobs running, even if one fails.
+      fail-fast: false
+      matrix:
+        host_release:
+        - unstable
+        - trixie
+        - bookworm
+        - bullseye
+
+    # We want a working shell, qemu, python and docker. Specific version should not matter (much).
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - run: ./tests/gha-build-deb.sh
+      name: "Build .deb for ${{matrix.host_release}}"
+      env:
+        HOST_RELEASE: ${{matrix.host_release}}
+
+    - name: Archive built .deb
+      uses: actions/upload-artifact@v3
+      with:
+        name: deb-${{matrix.host_release}}
+        if-no-files-found: error
+        path: |
+          *.deb
+
+  test-debian:
+    needs: build-debian
+    strategy:
+      # Keep other matrix jobs running, even if one fails.
+      fail-fast: false
+      matrix:
+        host_release:
+        - unstable
+        - trixie
+        - bookworm
+        - bullseye
+
+        release:
+        - trixie
+        - bookworm
+        - bullseye
+        - buster
+        - stretch
+
+        debootstrap:
+        - ''
+        - mmdebstrap
+
+        exclude:
+          # debootstrap in bullseye is too old.
+          - host_release: bullseye
+            release: trixie
+          # unclear how to pass --no-check-gpg to mmdebstrap
+          - release: stretch
+            debootstrap: mmdebstrap
+
+    # We want a working shell, qemu, python and docker. Specific version should not matter (much).
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Download built deb
+      uses: actions/download-artifact@v3
+      with:
+        name: deb-${{matrix.host_release}}
+
+    - run: ./tests/build-vm-and-test.sh setup
+      name: "Setup test environment"
+
+    - run: ./tests/build-vm-and-test.sh run
+      name: "Build VM image using grml-debootstrap on host ${{matrix.host_release}} for ${{matrix.release}} using debootstrap=${{matrix.debootstrap}}"
+      env:
+        HOST_RELEASE: ${{matrix.host_release}}
+        RELEASE: ${{matrix.release}}
+        DEBOOTSTRAP: ${{matrix.debootstrap}}
+
+    - run: ./tests/build-vm-and-test.sh test
+      name: "Test built VM image for ${{matrix.release}}"
+      env:
+        RELEASE: ${{matrix.release}}
+
+    - name: Archive VM test results
+      uses: actions/upload-artifact@v3
+      with:
+        name: vm-results-${{matrix.host_release}}-${{matrix.release}}-${{matrix.debootstrap}}
+        if-no-files-found: error
+        path: tests/results/
index 74c16de..06e1213 100644 (file)
@@ -1,3 +1,6 @@
 *.box
 packer_cache
 *_output
+qemu.img
+tests/dgoss
+tests/goss
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644 (file)
index 98b0e4b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-language: generic
-sudo: required
-
-services:
-  - docker
-
-env:
-  - TRAVIS_DEBIAN_DISTRIBUTION=buster
-  - TRAVIS_DEBIAN_DISTRIBUTION=unstable TRAVIS_DEBIAN_INCREMENT_VERSION_NUMBER=true
-
-script:
-  - ./travis/execute.sh
-
-matrix:
-  fast_finish: true
index f4bd866..20e533b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -40,9 +40,9 @@ install:
        mkdir -p $(DESTDIR)/usr/sbin/
        mkdir -p $(DESTDIR)/usr/share/zsh/vendor-completions
        install -m 644 config           $(DESTDIR)/etc/debootstrap/
-       install -m 644 devices.tar.gz   $(DESTDIR)/etc/debootstrap/
        install -m 644 locale.gen       $(DESTDIR)/etc/debootstrap/
        install -m 644 packages         $(DESTDIR)/etc/debootstrap/
+       install -m 644 packages-arm64   $(DESTDIR)/etc/debootstrap/
        install -m 755 chroot-script    $(DESTDIR)/etc/debootstrap/
        install -m 755 grml-debootstrap $(DESTDIR)/usr/sbin/
        install -m 644 zsh-completion   $(DESTDIR)/usr/share/zsh/vendor-completions/_grml-debootstrap
index b8e9359..25bcde4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 grml-debootstrap
 ================
 
-[![Build Status](https://travis-ci.org/grml/grml-debootstrap.svg?branch=master)](https://travis-ci.org/grml/grml-debootstrap)
+[![test-build](https://github.com/grml/grml-debootstrap/actions/workflows/test-build.yml/badge.svg)](https://github.com/grml/grml-debootstrap/actions/workflows/test-build.yml)
 
 This tool is a wrapper suite around debootstrap and cdebootstrap
 to ease installation of a pure [Debian](https://debian.org/) system.
index a5f92c4..c356bc8 100755 (executable)
@@ -8,18 +8,20 @@
 # GRML_CHROOT_SCRIPT_MARKER - do not remove this line unless you want to keep
 # this script as /bin/chroot-script on your new installed system
 ################################################################################
+# shellcheck disable=SC2317  # shellcheck has trouble understanding the code flow in this file
 
 # error_handler {{{
-if [ "$REPORT_TRAP_ERR" = "yes" ] || [ "$FAIL_TRAP_ERR" = "yes" ]; then
-   set -E
-   set -o pipefail
-   trap "error_handler" ERR
-fi
+set -e
+set -E
+set -o pipefail
+trap "error_handler" ERR
 # }}}
 
-# shellcheck disable=SC1091
+bash -n /etc/debootstrap/config
+# shellcheck source=config
 . /etc/debootstrap/config    || exit 1
-# shellcheck disable=SC1091
+bash -n /etc/debootstrap/variables
+# shellcheck source=tests/shellcheck-stub-debootstrap-variables
 . /etc/debootstrap/variables || exit 1
 
 [ -r /proc/1 ] || mount -t proc none /proc
@@ -75,8 +77,8 @@ askpass() {
 
 # define chroot mirror {{{
 chrootmirror() {
-  if [ -n "$KEEP_SRC_LIST" ] ; then
-    echo "KEEP_SRC_LIST has been set, skipping chrootmirror stage."
+  if [ "$KEEP_SRC_LIST" = "yes" ] ; then
+    echo "KEEP_SRC_LIST has been enabled, skipping chrootmirror stage."
     return
   fi
 
@@ -100,20 +102,10 @@ chrootmirror() {
     fi
   fi
 
-  # LTS support
-  case "$RELEASE" in
-    squeeze)
-      if [ -n "$MIRROR" ] ; then
-        echo "Release matching $RELEASE - enabling LTS support in sources.list"
-        echo "deb $MIRROR ${RELEASE}-lts $COMPONENTS" >> /etc/apt/sources.list
-      fi
-      ;;
-  esac
-
   # add security.debian.org:
   case "$RELEASE" in
-    unstable|sid|lenny) ;;  # no security pool available
-    squeeze|wheezy|jessie|stretch|buster)
+    unstable|sid|stretch) ;;  # no security pool available
+    jessie|buster)
       echo "Adding security.debian.org to sources.list."
       echo "deb http://security.debian.org ${RELEASE}/updates $COMPONENTS" >> /etc/apt/sources.list
       ;;
@@ -129,8 +121,8 @@ chrootmirror() {
 
 # remove local chroot mirror {{{
 remove_chrootmirror() {
-  if [ -n "$KEEP_SRC_LIST" ] ; then
-    echo "KEEP_SRC_LIST has been set, skipping remove_chrootmirror stage."
+  if [ "$KEEP_SRC_LIST" = "yes" ] ; then
+    echo "KEEP_SRC_LIST has been enabled, skipping remove_chrootmirror stage."
     return
   fi
 
@@ -152,48 +144,46 @@ remove_chrootmirror() {
 
 # set up grml repository {{{
 grmlrepos() {
-  if [ -n "$GRMLREPOS" ] ; then
-     # user might have provided their own apt sources.list
-     if ! grep -q grml /etc/apt/sources.list.d/grml.list 2>/dev/null ; then
-        cat >> /etc/apt/sources.list.d/grml.list << EOF
+  if [ -z "$GRMLREPOS" ] ; then
+    return 0
+  fi
+
+  # user might have provided their own apt sources configuration
+  if [ -r /etc/apt/sources.list.d/grml.list ] ; then
+    echo "File /etc/apt/sources.list.d/grml.list exists already, not modifying."
+  else
+    echo "Setting up /etc/apt/sources.list.d/grml.list."
+    cat > /etc/apt/sources.list.d/grml.list << EOF
 # grml: stable repository:
-  deb     http://deb.grml.org/ grml-stable  main
-  deb-src http://deb.grml.org/ grml-stable  main
+  deb     [signed-by=/usr/share/keyrings/grml-archive-keyring.gpg] http://deb.grml.org/ grml-stable main
+  deb-src [signed-by=/usr/share/keyrings/grml-archive-keyring.gpg] http://deb.grml.org/ grml-stable main
 
 # grml: testing/development repository:
-  deb     http://deb.grml.org/ grml-testing main
-  deb-src http://deb.grml.org/ grml-testing main
+  deb     [signed-by=/usr/share/keyrings/grml-archive-keyring.gpg] http://deb.grml.org/ grml-testing main
+  deb-src [signed-by=/usr/share/keyrings/grml-archive-keyring.gpg] http://deb.grml.org/ grml-testing main
 EOF
-     fi
-
-     # shellcheck disable=SC2086
-     if apt-get update $DPKG_OPTIONS; then
-       # shellcheck disable=SC2086
-       apt-get -y --allow-unauthenticated install grml-debian-keyring $DPKG_OPTIONS
-       # shellcheck disable=SC2086
-       apt-get update $DPKG_OPTIONS
-     else
-       # make sure we have the keys available for aptitude
-       gpg --keyserver subkeys.pgp.net --recv-keys 709BCE51568573EBC160E590F61E2E7CECDEA787
-       gpg --export 709BCE51568573EBC160E590F61E2E7CECDEA787 | apt-key add - || true # not yet sure
-       # why it's necessary, sometimes we get an error even though it works [mika]
-     fi
-
-     # make sure we install packages from Grml's pool only if not available
-     # from Debian!
-     if ! grep -q grml /etc/apt/preferences 2>/dev/null ; then
-        cat >> /etc/apt/preferences << EOF
-// debian pool (default):
-Package: *
-Pin: release o=Debian
-Pin-Priority: 996
+  fi
 
-// main grml-repository:
+  # make sure we install packages from Grml's pool only if not available from Debian
+  if [ -r /etc/apt/preferences.d/grml.pref ] ; then
+    echo "File /etc/apt/preferences.d/grml.pref exists already, not modifying."
+  else
+    echo "Setting up /etc/apt/preferences.d/grml.pref."
+    cat > /etc/apt/preferences.d/grml.pref << EOF
+Explanation: use Grml repository only after Debian ones
 Package: *
 Pin: origin deb.grml.org
-Pin-Priority: 991
+Pin-Priority: 100
 EOF
-     fi
+  fi
+
+  apt-get update -o Acquire::AllowInsecureRepositories=1
+  apt-get -y --allow-unauthenticated install grml-debian-keyring
+  apt-get update
+
+  if [ "$(dpkg-query -f "\${db:Status-Status} \${db:Status-Eflag}" -W grml-debian-keyring 2>/dev/null)" != 'installed ok' ]; then
+    echo "Error: installation of grml-debian-keyring failed." >&2
+    exit 1
   fi
 }
 # }}}
@@ -271,14 +261,21 @@ packages() {
   }
 
   if [ "$PACKAGES" = 'yes' ] ; then
-     if ! [ -r /etc/debootstrap/packages ] ; then
-       echo "Error: /etc/debootstrap/packages (inside chroot) not found, exiting." >&2
-       exit 1
-     else
-       $APTUPDATE
-       # shellcheck disable=SC2086,SC2046
-       DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL $(grep -v '^#' /etc/debootstrap/packages) $GRMLPACKAGES
-     fi
+    PACKAGES_FILE="/etc/debootstrap/packages"
+
+    if [ "$ARCH" = 'arm64' ]; then
+      PACKAGES_FILE="/etc/debootstrap/packages-arm64"
+    fi
+
+    if ! [ -r "${PACKAGES_FILE}" ] ; then
+      echo "Error: ${PACKAGES_FILE} (inside chroot) not found, exiting." >&2
+      exit 1
+    else
+      $APTUPDATE
+
+      # shellcheck disable=SC2086,SC2046
+      DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL $(grep -v '^#' "${PACKAGES_FILE}") $GRMLPACKAGES
+    fi
   fi
 }
 # }}}
@@ -318,28 +315,28 @@ get_kernel_version() {
   # shellcheck disable=SC2153
   case "$ARCH" in
     i386)
-      case "$RELEASE" in
-        lenny|squeeze|wheezy) KARCH='686' ;;
-        # since jessie the linux-image-686 image doesn't exist any longer
-        *) KARCH='686-pae' ;;
-      esac
+      KARCH='686-pae'
       ;;
     amd64)
       KARCH='amd64'
       ;;
+    arm64)
+      KARCH='arm64'
+      ;;
     *)
-      echo "Only i386 and amd64 are currently supported" >&2
+      echo "Only i386, amd64 and arm64 are currently supported" >&2
       return 1
   esac
 
-  for KPREFIX in "" "2.6-" ; do  # iterate through the kernel prefixes,
-                                 # currently "" and "2.6-"
-    if package_exists linux-image-${KPREFIX}${KARCH} ; then
-      echo ${KPREFIX}${KARCH}
-      return 0
-    fi
+  local KPACKAGE
+  KPACKAGE=linux-image-"${KPREFIX}${KARCH}"
+  if package_exists "$KPACKAGE"; then
+    echo "${KPREFIX}${KARCH}"
+    return 0
+  fi
 
-  done
+  echo "Expected kernel package $KPACKAGE not found" >&2
+  return 1
 }
 
 # install kernel packages {{{
@@ -352,8 +349,14 @@ kernel() {
   $APTUPDATE
   KVER=$(get_kernel_version)
   if [ -n "$KVER" ] ; then
-     # note: install busybox to be able to debug initramfs
-     KERNELPACKAGES="linux-image-$KVER linux-headers-$KVER busybox firmware-linux-free"
+    case "$RELEASE" in
+      stretch)
+        echo "Installing busybox on Debian/$RELEASE as it's essential for the initramfs"
+        DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL busybox
+        ;;
+    esac
+
+     KERNELPACKAGES="linux-image-$KVER linux-headers-$KVER firmware-linux-free $INITRD_GENERATOR"
      # only add firmware-linux if we have non-free as a component
      if expr "$COMPONENTS" : '.*non-free' >/dev/null ; then
        KERNELPACKAGES="$KERNELPACKAGES firmware-linux"
@@ -387,15 +390,13 @@ passwords()
     return 0
   fi
 
-  echo "Activating shadow passwords."
-  shadowconfig on
-
   CHPASSWD_OPTION=
   if chpasswd --help 2>&1 | grep -q -- '-m,' ; then
      CHPASSWD_OPTION='-m'
   fi
 
   if [ -n "$ROOTPASSWORD" ] ; then
+     # shellcheck disable=SC2086
      echo root:"$ROOTPASSWORD" | chpasswd $CHPASSWD_OPTION
      export ROOTPASSWORD=''
   else
@@ -418,6 +419,7 @@ passwords()
          a='1'
          b='2'
        else
+         # shellcheck disable=SC2086
          echo root:"$a" | chpasswd $CHPASSWD_OPTION
          unset a
          unset b
@@ -481,14 +483,27 @@ createfstab(){
 EOF
 
   if [ -n "$TARGET_UUID" ] ; then
-    echo "/dev/disk/by-uuid/${TARGET_UUID} /  auto    defaults,errors=remount-ro 0   1" >> /etc/fstab
+    local rootfs_mount_options=""
+
+    if [ -z "${FILESYSTEM}" ] ; then
+      FILESYSTEM="$(blkid -o value -s TYPE /dev/disk/by-uuid/"${TARGET_UUID}")" || true
+    fi
+
+    case "${FILESYSTEM}" in
+      # errors=remount-ro is supported only by a few file systems
+      ext*|exfat|fat|jfs|nilfs2|vfat)
+        rootfs_mount_options=",errors=remount-ro"
+        ;;
+    esac
+
+    echo "/dev/disk/by-uuid/${TARGET_UUID} /  auto    defaults${rootfs_mount_options} 0   1" >> /etc/fstab
   else
     echo "Warning: couldn't identify target UUID for rootfs, your /etc/fstab might be incomplete."
   fi
 
 if [ -n "$EFI" ] ; then
-  # shellcheck disable=SC2086
-  echo "UUID=$(blkid -o value -s UUID $EFI)  /boot/efi       vfat    umask=0077      0       1" >> /etc/fstab
+  UUID_EFI="$(blkid -o value -s UUID "$EFI")"
+  echo "UUID=$UUID_EFI  /boot/efi       vfat    umask=0077      0       1" >> /etc/fstab
 fi
 
 cat >> /etc/fstab << EOF
@@ -519,6 +534,28 @@ fstab() {
 }
 # }}}
 
+# ensure we have according filesystem tools available {{{
+install_fs_tools() {
+  local pkg=""
+
+  # note: this is supposed to be coming either via command lines'
+  # $_opt_filesystem or via createfstab()
+  case "${FILESYSTEM}" in
+    jfs)
+      pkg="jfsutils"
+      ;;
+    xfs)
+      pkg="xfsprogs"
+      ;;
+  esac
+
+  if [ -n "${pkg:-}" ] && ! dpkg --list "${pkg}" 2>/dev/null | grep -q '^ii' ; then
+    echo "Filesystem package ${pkg} not present, installing now"
+    DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL "${pkg}"
+  fi
+}
+# }}}
+
 # set up hostname {{{
 hostname() {
   if [ -n "$HOSTNAME" ] ; then
@@ -568,7 +605,13 @@ initrd() {
   # generate initrd
   if [ -n "$INITRD" ] ; then
      echo "Generating initrd."
-     update-initramfs -c -t -k "$KERNELVER"
+     if [ "$INITRD_GENERATOR" = 'dracut' ] ; then
+         # shellcheck disable=SC2086
+         dracut --no-hostonly --kver "$KERNELVER" --fstab --add-fstab /etc/fstab --force --reproducible $INITRD_GENERATOR_OPTS
+     else
+         # shellcheck disable=SC2086
+         update-initramfs -c -t -k "$KERNELVER" $INITRD_GENERATOR_OPTS
+     fi
   fi
 }
 # }}}
@@ -585,13 +628,56 @@ efi_setup() {
 
   mkdir -p /boot/efi
   echo "Mounting $EFI on /boot/efi"
-  mount "$EFI" /boot/efi || return 1
+  mount "$EFI" /boot/efi
+
+  # if efivarfs kernel module is loaded, but efivars isn't,
+  # then we need to mount efivarfs for efibootmgr usage
+  if ! ls /sys/firmware/efi/efivars/* &>/dev/null ; then
+    echo "Mounting efivarfs on /sys/firmware/efi/efivars"
+    mount -t efivarfs efivarfs /sys/firmware/efi/efivars
+  fi
 
   echo "Invoking efibootmgr"
-  efibootmgr || return 1
+  efibootmgr
 }
 
 # grub configuration/installation {{{
+
+# helper function to get relevant /dev/disk/by-id/* entries,
+# based on GRUB's postinst script
+available_ids() {
+  local path ids
+
+  [ -d /dev/disk/by-id ] || return
+  ids="$(
+    for path in /dev/disk/by-id/*; do
+      [ -e "${path}" ] || continue
+      printf '%s %s\n' "${path}" "$(readlink -f "${path}")"
+    done | sort -k2 -s -u | cut -d' ' -f1
+  )"
+  echo "${ids}"
+}
+
+# helper function to report corresponding /dev/disk/by-id/ for a given device name,
+# based on GRUB's postinst script
+device_to_id() {
+  local id
+
+  for id in $(available_ids); do
+    if [ "$(readlink -f "${id}")" = "$(readlink -f "$1")" ]; then
+      echo "${id}"
+      return 0
+    fi
+  done
+
+  # Fall back to the plain device name if there's no by-id link for it.
+  if [ -e "$1" ]; then
+    echo "$1"
+    return 0
+  fi
+  return 1
+}
+
 grub_install() {
 
   if [ -z "$GRUB" ] ; then
@@ -599,7 +685,7 @@ grub_install() {
     return 0
   fi
 
-  efi_setup || return 1
+  efi_setup
 
   if [ -n "$EFI" ] ; then
     GRUB_PACKAGE=grub-efi-amd64
@@ -609,18 +695,29 @@ grub_install() {
 
   # make sure this is pre-defined so we have sane settings for automated
   # upgrades, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=711019
+  local grub_device
+  grub_device=$(device_to_id "${GRUB}")
+  if [ -z "${grub_device:-}" ] ; then
+     echo "Warning: Could not identify /dev/disk/by-id/... for '${GRUB}', falling back to '${GRUB}'"
+     grub_device="${GRUB}"
+  fi
+
   echo "Setting ${GRUB_PACKAGE} debconf configuration for install device to $GRUB"
-  echo "${GRUB_PACKAGE} ${GRUB_PACKAGE}/install_devices multiselect $GRUB" | debconf-set-selections
+  echo "${GRUB_PACKAGE} ${GRUB_PACKAGE}/install_devices multiselect ${grub_device}" | debconf-set-selections
 
-  if ! dpkg --list ${GRUB_PACKAGE} 2>/dev/null | grep -q '^ii' ; then
+  if ! dpkg --list "${GRUB_PACKAGE}" 2>/dev/null | grep -q '^ii' ; then
     echo "Notice: grub option set but no ${GRUB_PACKAGE} package, installing it therefore."
-    DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL ${GRUB_PACKAGE}
+    DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL "${GRUB_PACKAGE}"
   fi
 
   if ! [ -x "$(command -v grub-install)" ] ; then
      echo "Error: grub-install not available. (Error while installing grub package?)" >&2
      return 1
   fi
+  if ! [ -x "$(command -v update-grub)" ] ; then
+     echo "Error: update-grub not available. (Error while installing grub package?)" >&2
+     return 1
+  fi
 
   if [ -n "$SELECTED_PARTITIONS" ] ; then # using sw-raid
      for device in $SELECTED_PARTITIONS ; do
@@ -634,40 +731,17 @@ grub_install() {
      done
      rm -f /boot/grub/device.map
   else
-     echo "Installing grub on ${GRUB}:"
-     case "$RELEASE" in
-       lenny|squeeze|wheezy)
-         local grub_dev
-         grub_dev="$(readlink -f "${GRUB}")"
-         if ! grub-install --no-floppy "${grub_dev}" ; then
-           echo "Error: failed to execute 'grub-install --no-floppy ${grub_dev}'." >&2
-           exit 1
-         fi
-         rm -f /boot/grub/device.map
-         ;;
-       *)
-         echo "(hd0) ${GRUB}" > /boot/grub/device.map
-         if ! grub-install "(hd0)" ; then
-           echo "Error: failed to execute 'grub-install (hd0)'." >&2
-           exit 1
-         fi
-         rm /boot/grub/device.map
-         ;;
-     esac
+    echo "Installing grub on ${GRUB}:"
+    echo "(hd0) ${GRUB}" > /boot/grub/device.map
+    if ! grub-install "(hd0)" ; then
+      echo "Error: failed to execute 'grub-install (hd0)'." >&2
+      exit 1
+    fi
+    rm /boot/grub/device.map
   fi
 
   echo "Adjusting grub configuration for use on ${GRUB}."
 
-  # finally install grub
-  if [ -x /usr/sbin/update-grub ] ; then
-     UPDATEGRUB='/usr/sbin/update-grub'
-  elif [ -x /sbin/update-grub ] ; then
-     UPDATEGRUB='/sbin/update-grub'
-  else
-    echo "Error: update-grub not available, can not execute it." >&2
-    return 1
-  fi
-
   if [ -n "${BOOT_APPEND}" ] ; then
     echo "Adding BOOT_APPEND configuration ['${BOOT_APPEND}'] to /etc/default/grub."
     sed -i "/GRUB_CMDLINE_LINUX_DEFAULT/ s#\"\$# ${BOOT_APPEND}\"#" /etc/default/grub
@@ -675,7 +749,8 @@ grub_install() {
 
   mountpoint /boot/efi &>/dev/null && umount /boot/efi
 
-  $UPDATEGRUB
+  # finally install grub. Existence of update-grub is checked above.
+  update-grub
 }
 # }}}
 
@@ -707,6 +782,8 @@ finalize() {
 
   [ -n "$POLICYRCD" ] && rm -f /usr/sbin/policy-rc.d
 
+  umount /sys/firmware/efi/efivars &>/dev/null || true
+
   umount /sys >/dev/null 2>/dev/null || true
   umount /proc >/dev/null 2>/dev/null || true
 }
@@ -731,11 +808,13 @@ trap signal_handler HUP INT QUIT TERM
 
  for i in chrootmirror grmlrepos backportrepos kernelimg_conf \
      kernel packages extrapackages reconfigure hosts \
-     default_locales timezone fstab hostname initrd grub_install passwords \
+     default_locales timezone fstab install_fs_tools hostname \
+     initrd grub_install passwords \
      custom_scripts upgrade_system remove_apt_cache services \
      remove_chrootmirror; do
-     if stage $i ; then
-       $i && stage $i 'done' || exit 1
+     if stage "$i" ; then
+       "$i"
+       stage "$i" 'done'
      fi
   done
   # always execute the finalize stage:
diff --git a/config b/config
index 6477acf..cd562e9 100644 (file)
--- a/config
+++ b/config
@@ -4,6 +4,7 @@
 # Bug-Reports:   see https://grml.org/bugs/
 # License:       This file is licensed under the GPL v2 or any later version.
 ################################################################################
+# shellcheck shell=sh
 
 ################################################################################
 # Important: adjust this file if you want to execute grml-debootstrap
@@ -16,7 +17,7 @@
 # If you specify a string *without* /dev/ in the beginning, grml-debootstrap
 # assumes you want to install Debian into a directory. MKFS, TUNE2FS, GRUB and
 # FSCK will be ignored.
-# Make sure the TARGET-directory points to a filesystem which has the dev, exec
+# Make sure the TARGET-directory points to a filesystem which has the dev, exec
 # options enabled.
 # Default: no default.
 # Usage examples:
@@ -72,9 +73,9 @@
 # BACKPORTREPOS='yes'
 
 # Debian release that should be installed.
-# Supported values: lenny, squeeze, wheezy, jessie, stretch, buster, bullseye, sid
-# Default: 'buster'
-# RELEASE='buster'
+# Supported values: jessie, stretch, buster, bullseye, sid
+# Default: 'bullseye'
+# RELEASE='bullseye'
 
 # Define components that should be used within sources.list.
 # Default: 'main'
@@ -82,7 +83,7 @@
 
 # Set target architecture.
 # Only useful when installing i386 while running an amd64 kernel.
-# Default: current architecture. (From 'dpkg â€”print-architecture'.)
+# Default: current architecture. (From 'dpkg --print-architecture'.)
 # ARCH='amd64'
 
 # Hostname of new system.
 # Default: 'yes' (if file exists)
 # DEBCONF='no'
 
-# Run scripts from /etc/debootstrap/pre-scripts/ before creating the chroot.
+# Run scripts from /etc/debootstrap/pre-scripts/ before creating the chroot.
 # Default: 'yes'
 # PRE_SCRIPTS='no'
 
 # Default: 'yes'
 # UPGRADE_SYSTEM='no'
 
-# Explicit generation of initrd via update-initramfs.
+# Explicit generation of initrd via selected initrd generator.
 # Default: 'yes'
 # INITRD='no'
 
+# Which generator to use for initrd creation.
+# Supported values: 'dracut', 'initramfs-tools'
+# Default: 'initramfs-tools'
+# INITRD_GENERATOR='initramfs-tools'
+
+# Pass extra options to the selected initrd generator
+# Default: no default
+# INITRD_GENERATOR_OPTS='-v'
+
 # If the specified file exists its content will be displayed at the end of the
 # installation process.
 # Useful for checking for errors and display warning message.
index 3b8b099..98227ec 100644 (file)
@@ -1,3 +1,230 @@
+grml-debootstrap (0.108) unstable; urgency=medium
+
+  [ Darshaka Pathirana ]
+  * [811c294] Move try_umount above cleanup()
+
+ -- Michael Prokop <mika@grml.org>  Sat, 24 Feb 2024 10:55:23 +0100
+
+grml-debootstrap (0.107) unstable; urgency=medium
+
+  [ Antoine Beaupré ]
+  * [cfa1651] fix debootstrap error handler
+
+ -- Michael Prokop <mika@grml.org>  Fri, 02 Feb 2024 12:31:41 +0100
+
+grml-debootstrap (0.106) unstable; urgency=medium
+
+  [ Patrick Schleizer ]
+  - [1a229d0..cc891df] Improve error handling (PR #255)
+  * [81d7587] consistently use ESP label for the EFI system partition
+  * [9706bd9] improved error handling, removed RC=$? noops
+  * [48f3096] remove noops "eend $RC"
+  * [cbd20a0] consistently use same code path for umounting
+
+  [ Michael Prokop ]
+  * [19dc059] coding style: use '[' instead of 'test'
+  * [325a888] Install busybox On Debian/stretch as it's required for
+    initramfs. Thanks to Patrick Schleizer <adrelanos@whonix.org> for
+    spotting and reporting
+
+  [ Chris Hofstaedtler ]
+  * [090612a] ci: enable test-build on pushes to branches and periodic
+
+ -- Michael Prokop <mika@grml.org>  Sat, 23 Dec 2023 20:00:42 +0100
+
+grml-debootstrap (0.105) unstable; urgency=medium
+
+  The "farewell lenny, squeeze + wheezy; hello arm64" release
+
+  [ Michael Prokop ]
+  * [4405248] packer: update to Grml 2022.11 ISO
+  * [2708f44] Don't install busybox any longer by default.
+    Thanks to Patrick Schleizer + Chris Hofstaedtler
+
+  [ Daniel Winzen ]
+  * [f4d3906] Add EFI support for VMs
+  * [39685c7] Add support for legacy BIOS boot to efi VM images
+
+  [ Patrick Schleizer ]
+  * [ef3019b] add mmdebstrap as alternative to (c)debootstrap
+  * [c1d92f2] remove unnecessary unicode from config
+  * [438ca09] remove unnecessary unicode from chroot-script
+  * [e8494a4] disable prompt/wait by tune2fs
+  * [1e27d8e] improve error handling
+  * [256bdb7] debian: add dosfstools to Depends for EFI use case
+  * [dcccf11] code simplification: drop NOP usage of eend 0
+  * [b9035f6] Avoid intermediary installation of initramfs-tools when
+    using INITRD_GENERATOR=dracut.
+
+  [ GavinPacini ]
+  * [670035b] Initial arm64 support
+
+  [ Chris Hofstaedtler ]
+  * [7f5e351] grml-debootstrap: support BOOT_APPEND in --vm mode
+  * [e53df19] GitHub Actions: build and test grml-debootstrap in PRs
+  * [46d50de] README: replace build status badge
+  * [dc0052a] kernel selection: drop pre-jessie code
+  * [f01e4a2] kernel selection: drop 2.6 specific kernel image support
+  * [94b63ad] grub_install: remove pre-jessie code
+  * [3bcafe4] grub_install: use same method for checking grub-install and
+    update-grub
+  * [0a759e7] d/control: record (actual) minimum debootstrap version
+  * [ce80d13] chrootmirror: remove pre-jessie code
+  * [0cf7d8e] swraid: remove code for lenny
+  * [ac6c869] packer: remove pre-jessie code
+  * [ed7ad07] Drop support for installing releases before jessie
+  * [1f6141f] Stop using sed when creating CHROOT_VARIABLES
+  * [045542c] Skip EFI support check if --vm is given
+  * [511ca11] shellcheck: fix some warnings
+  * [dbfbaac] GitHub Actions: add shellcheck to PR workflow
+  * [bd7e57f] shellcheck: ignore SC2001,SC2181
+  * [8671b4a] Remove manual setup of /dev contents
+  * [64f1f16] Remove shadowconfig call
+  * [2f15cb7] Remove empty shell-based test suite
+  * [84a613c] ci: disable progress output from apt-get
+  * [ebcba7a] ci: fix shellcheck for test scripts
+
+ -- Michael Prokop <mika@grml.org>  Thu, 07 Dec 2023 18:15:09 +0100
+
+grml-debootstrap (0.104) unstable; urgency=medium
+
+  [ Michael Prokop ]
+  * [b379e24] GRUB: use persistent device names under /dev/disk/by-id/ for
+    install_devices
+
+  [ Giovanni Rosa ]
+  * [64d4081] Fix for Dockerfile smell DL3059
+
+ -- Michael Prokop <mika@grml.org>  Fri, 08 Sep 2023 13:14:50 +0200
+
+grml-debootstrap (0.103) unstable; urgency=medium
+
+  * [bbb2ea0] Disable ext4 metadata_csum_seed for Debian releases older
+    than bookworm (Closes: #1031416)
+
+ -- Michael Prokop <mika@grml.org>  Mon, 20 Feb 2023 11:40:07 +0100
+
+grml-debootstrap (0.102) unstable; urgency=medium
+
+  The "¡hola bookworm!" release
+
+  * [97308cd] Support new non-free repository component for Debian
+    bookworm and newer
+  * [4a2a0b2] Use bookworm as new default release + update release list
+  * [d839c3c] Update copyright information
+  * [df8c043] Update Vcs-* headers + copyright source to use github.com
+  * [3a8d2b7] packer: clone git repository from github.com
+  * [594d9d1] docker: retrieve vimrc + zshrc from github
+  * [d71aaf4] Bump Standards-Version to 4.6.2
+
+ -- Michael Prokop <mika@grml.org>  Mon, 06 Feb 2023 18:32:46 +0100
+
+grml-debootstrap (0.101) unstable; urgency=medium
+
+  [ Daniel Winzen ]
+  * [d60b372] Add dracut support
+  * [4deb6e8] Add option to pass extra options to initrd generator
+  * [79f5f42] Make dracut images reproducible and use long form of --no-
+    hostonly
+
+  [ Michael Prokop ]
+  * [78eb32c] packer: add support for Debian/bookworm
+  * [8b44fbb] packer: update Grml ISO to 2022.11-rc1
+  * [4c49de9] Ensure to have filesystem tools installed. Thanks to Chris
+    Hofstaedtler for the bug report
+  * [befae5a] Use "errors=remount-ro" fstab option only within supported
+    filesystems. Thanks to Chris Hofstaedtler for the bug report
+
+ -- Michael Prokop <mika@grml.org>  Fri, 25 Nov 2022 17:12:51 +0100
+
+grml-debootstrap (0.100) unstable; urgency=medium
+
+  * [43ea7e2] Drop leftover KEYRING code
+  * [ea978f6] Fix Grml repository usage. Thanks to Karl Voit for the bug
+    report
+  * [7b2b4c8] VMs: create partition with alignment starting at 4MiB +
+    ending at 100%. Thanks to David Gnedt for the bug report and analysis,
+    Darshaka Pathirana and Chris Hofstaedtler for further information and
+    feedback
+
+ -- Michael Prokop <mika@grml.org>  Mon, 24 Jan 2022 17:17:29 +0100
+
+grml-debootstrap (0.99) unstable; urgency=medium
+
+  * [0d4c089] packer: update VBoxGuestAdditions to v6.1.22 + Grml ISO to
+    latest stable release (2021.07)
+  * [86f83aa] Install dbus by default
+  * [1ca3ec5] EFI support: fix for grub-install usage with efivarfs
+  * [b45ae94] Bump Standards-Version to 4.6.0
+
+ -- Michael Prokop <mika@grml.org>  Mon, 23 Aug 2021 16:21:44 +0200
+
+grml-debootstrap (0.98) unstable; urgency=medium
+
+  [ Paul Menzel ]
+  * [1c4b3b0] Correct indentation in switch statement
+  * [8995409] Support XFS in VMs by including xfs driver in grub-mkimage
+  * [f6d7aac] Remove *os-prober* from shipped packages list
+  * [457e3e4] config: Replace em dash â€” by `--` for switch in comment
+
+  [ Michael Prokop ]
+  * [b047071] Fix git version detection when executing in foreign git
+    repository. Thanks to Paul Menzel for the bugreport
+
+ -- Michael Prokop <mika@grml.org>  Fri, 09 Jul 2021 09:08:45 +0200
+
+grml-debootstrap (0.97) unstable; urgency=medium
+
+  * [72ce6b6] packer: update VBoxGuestAdditions to v6.1.20
+  * [4d625ea] fake-uname: fix gcc argument order and improve preloaded
+    shared library. Thanks to Guillem Jover
+  * [360e057] Bail out if architecture isn't set nor can be identified
+    automatically
+  * [9ae6b12] Avoid installation of os-proper in VM environments
+  * [d91d9f3] EFI support: check + mount efivarfs to support Debian
+    kernels >=5.10
+
+ -- Michael Prokop <mika@grml.org>  Tue, 01 Jun 2021 07:44:46 +0200
+
+grml-debootstrap (0.96) unstable; urgency=medium
+
+  * [181ec9a] Use shorter fs label for EFI partition to not break with
+    recent dosfstools (Closes: #987014)
+
+ -- Michael Prokop <mika@grml.org>  Mon, 19 Apr 2021 16:36:17 +0200
+
+grml-debootstrap (0.95) unstable; urgency=medium
+
+  * [3f28b11] Properly handle KEEP_SRC_LIST option when set to 'no'
+  * [fa2ce1b] Do not enable escape characters on dumb terminals
+  * [01b5b0f] Support F2FS in VMs by including f2fs driver in grub-
+    mkimage. Thanks to Paul Menzel for bugreport and bugfix
+  * [1537613] F2FS filesystem doesn't support errors=remount-ro mount
+    option
+
+ -- Michael Prokop <mika@grml.org>  Fri, 22 Jan 2021 11:56:34 +0100
+
+grml-debootstrap (0.94) unstable; urgency=medium
+
+  The "waiting for bullseye, 2021 + vaccinations" release
+
+  [ Chris Hofstaedtler ]
+  * [5c7f7fa] d/control: Set Rules-Requires-Root: no
+  * [2617a47] d/control: fix Vcs-Git field name
+  * [2e6b03e] d/rules: remove dh_make template header
+
+  [ Michael Prokop ]
+  * [8f673fa] Fix shellcheck issue SC2174
+  * [622ca58] Improve EFI detection by checking for /sys/firmware/efi.
+    Thanks to Darshaka Pathirana for reporting and feedback
+  * [1475b08] packer: make template compatible with recent packer
+    versions. Thanks to Darshaka Pathirana for reporting
+  * [208a600] packer: use latest VBoxGuestAdditions (6.1.16) + Grml stable
+    release (2020.06)
+  * [9506ba5] Use bullseye as default Debian release
+
+ -- Michael Prokop <mika@grml.org>  Wed, 23 Dec 2020 17:34:26 +0100
+
 grml-debootstrap (0.93) unstable; urgency=medium
 
   * New release (without code changes) to fix Debian policy issue
@@ -1347,4 +1574,3 @@ grml-debootstrap (0.1) unstable; urgency=low
   * Initial release.
 
  -- Michael Prokop <mika@grml.org>  Fri,  3 Nov 2006 01:10:52 +0100
-
index 2909fb1..15e4ce0 100644 (file)
@@ -5,25 +5,28 @@ Maintainer: Grml Team <team@grml.org>
 Uploaders:
  Michael Prokop <mika@debian.org>,
  Alexander Wirt <formorer@debian.org>,
- Christian Hofstaedtler <zeha@debian.org>,
+ Chris Hofstaedtler <zeha@debian.org>,
  Ulrich Dangel <mru@spamt.net>,
 Build-Depends:
- debhelper-compat (= 12),
+ debhelper-compat (= 13),
 Build-Depends-Indep:
  asciidoc,
  docbook-xsl,
  shunit2,
  xsltproc,
-Standards-Version: 4.5.0
+Standards-Version: 4.6.2
+Rules-Requires-Root: no
 Homepage: https://grml.org/grml-debootstrap/
-Vcs-git: git://git.grml.org/grml-debootstrap.git
-Vcs-Browser: https://git.grml.org/?p=grml-debootstrap.git
+Vcs-Git: https://github.com/grml/grml-debootstrap.git
+Vcs-Browser: https://github.com/grml/grml-debootstrap
 
 Package: grml-debootstrap
 Architecture: all
 Depends:
+ bash (>= 4.3-11+deb8u2),
  debian-archive-keyring,
- debootstrap (>= 0.3.3.3) | cdebootstrap (>= 0.3.16),
+ debootstrap (>= 1.0.65) | cdebootstrap (>= 0.3.16) | mmdebstrap,
+ dosfstools,
  e2fsprogs,
  fdisk | util-linux (<< 2.29.2-3~),
  gawk,
@@ -36,7 +39,7 @@ Recommends:
  parted,
  qemu-utils,
 Description: wrapper around debootstrap for installing pure Debian
- Provides a wrapper suite around debootstrap and cdebootstrap
+ Provides a wrapper suite around debootstrap, cdebootstrap, mmdebstrap
  to ease installation of a pure Debian system.
  .
  Configuration can be done on the command line, in a dialog frontend
index 723046d..da2e2f2 100644 (file)
@@ -1,10 +1,10 @@
 Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: grml-debootstrap
 Upstream-Contact: Michael Prokop <mika@grml.org>
-Source: https://git.grml.org/?p=grml-debootstrap.git;a=summary
+Source: https://github.com/grml/grml-debootstrap
 
 Files: *
-Copyright: 2006-2019, Michael Prokop <mika@grml.org>
+Copyright: 2006-2023, Michael Prokop <mika@grml.org>
            2014, 2015, Sebastian Pipping <sebastian@pipping.org>
            2014, Patrick Schleizer <adrelanos@riseup.net>
            2013, 2014, Markus Rekkenbeil <mre@mobi4friends.de>
index a60be94..936057b 100644 (file)
@@ -1 +1,2 @@
+rm_conffile /etc/debootstrap/devices.tar.gz 0.105~
 rm_conffile /etc/zsh/completion.d/_grml-debootstrap 0.86~
index 17ee334..5571e03 100755 (executable)
@@ -1,10 +1,5 @@
 #!/usr/bin/make -f
 # -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
 
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
@@ -14,6 +9,5 @@
 
 ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS)))
 override_dh_auto_test:
-       (cd tests && ./run_tests.sh)
        make shellcheck
 endif
diff --git a/devices.tar.gz b/devices.tar.gz
deleted file mode 100644 (file)
index 0d02e40..0000000
Binary files a/devices.tar.gz and /dev/null differ
index 5439785..5c405b2 100644 (file)
@@ -12,8 +12,8 @@ RUN apt-get install -y grml-debootstrap bats eatmydata
 RUN apt-get install -y curl less vim wget zsh
 
 # grml config
-RUN wget -O /root/.vimrc http://git.grml.org/f/grml-etc-core/etc/vim/vimrc
-RUN wget -O /root/.zshrc http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
+RUN wget -O /root/.vimrc https://raw.githubusercontent.com/grml/grml-etc-core/master/etc/vim/vimrc \
+    && wget -O /root/.zshrc https://raw.githubusercontent.com/grml/grml-etc-core/master/etc/zsh/zshrc
 
 # nice defaults
 ENV LANG C.UTF-8
@@ -23,7 +23,7 @@ ENV TERM xterm-256color
 RUN echo 'APT::Get::Show-Versions "1";' > /etc/apt/apt.conf.d/verbose
 
 # cleanup
-RUN apt-get clean
-RUN rm -rf /var/lib/apt/lists/*
+RUN apt-get clean \
+    && rm -rf /var/lib/apt/lists/*
 
 ENTRYPOINT ["/bin/zsh"]
index 823d876..97dc26b 100755 (executable)
@@ -5,43 +5,40 @@
 # Bug-Reports:   see https://grml.org/bugs/
 # License:       This file is licensed under the GPL v2+
 ################################################################################
+# shellcheck disable=SC2001,SC2181
 
 # error_handler {{{
-[ -n "$REPORT_TRAP_ERR" ] || REPORT_TRAP_ERR='no'
-[ -n "$FAIL_TRAP_ERR" ] || FAIL_TRAP_ERR='no'
-
 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!
+   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
+   if [ -r "$MNTPOINT/debootstrap/debootstrap.log" ] && \
+          [ -s "$MNTPOINT/debootstrap/debootstrap.log" ] ; then
+       einfo "Presenting last ten lines of debootstrap.log:"
+       tail -10 "${MNTPOINT}"/debootstrap/debootstrap.log
+       einfo "End of debootstrap.log"
    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
+set -e
+set -E
+set -o pipefail
+trap "error_handler" ERR
+export -f "error_handler"
 # }}}
 
 # variables {{{
 PN="$(basename "$0")"
 if [[ -d "$(dirname "$(command -v "$0")")"/.git ]]; then
-  VERSION="$(git describe | sed 's|^v||')"
+  VERSION="$(git --git-dir "$(dirname "$(command -v "$0")")"/.git describe | sed 's|^v||')"
 else
   VERSION="$(dpkg-query --show --showformat='${Version}' "$PN")"
 fi
@@ -63,6 +60,8 @@ MNTPOINT="/mnt/debootstrap.$$"
 [ -n "$FORCE" ] || FORCE=''
 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
 [ -n "$INITRD" ] || INITRD='yes'
+[ -n "$INITRD_GENERATOR" ] || INITRD_GENERATOR='initramfs-tools'
+[ -n "$INITRD_GENERATOR_OPTS" ] || INITRD_GENERATOR_OPTS=''
 [ -n "$INSTALL_NOTES" ] || INSTALL_NOTES='/etc/debootstrap/install_notes'
 [ -n "$LOCALES" ] || LOCALES='yes'
 [ -n "$MIRROR" ] || MIRROR="$FALLBACK_MIRROR"
@@ -72,7 +71,7 @@ MNTPOINT="/mnt/debootstrap.$$"
 [ -n "$POST_SCRIPTS" ] || POST_SCRIPTS='yes'
 [ -n "$PRE_SCRIPTS" ] || PRE_SCRIPTS='yes'
 [ -n "$RECONFIGURE" ] || RECONFIGURE='console-data'
-[ -n "$RELEASE" ] || RELEASE='buster'
+[ -n "$RELEASE" ] || RELEASE='bookworm'
 [ -n "$RM_APTCACHE" ] || RM_APTCACHE='yes'
 [ -n "$SCRIPTS" ] || SCRIPTS='no' # deprecated, replaced by POST_SCRIPTS
 [ -n "$SECURE" ] || SECURE='yes'
@@ -103,7 +102,7 @@ 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).
+  -r, --release <name>   Release of new Debian system (default: bullseye).
   -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,
@@ -129,6 +128,7 @@ Options for Virtual Machine deployment:
                          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
+      --vmefi            Create an EFI boot partition for the VM.
 
 Configuration options:
 
@@ -151,7 +151,7 @@ Configuration options:
       --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).
+      --non-free           Enable non-free / non-free-firmware 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.
@@ -183,10 +183,18 @@ fi
 # }}}
 
 # early helper functions {{{
-GOOD='\e[32;01m'
-BAD='\e[31;01m'
-WARN='\e[33;01m'
-NORMAL='\e[0m'
+# skip colors when running within a dumb terminal
+if [ "${TERM}" = "dumb" ] ; then
+  GOOD=
+  BAD=
+  WARN=
+  NORMAL=
+else
+  GOOD='\e[32;01m'
+  BAD='\e[31;01m'
+  WARN='\e[33;01m'
+  NORMAL='\e[0m'
+fi
 
 einfo() {
   einfon "$1\\n"
@@ -239,19 +247,49 @@ check4progs(){
 }
 # }}}
 
+# unmount mountpoint {{{
+try_umount() {
+  local tries=$1
+  local mountpoint="$2"
+
+  if ! mountpoint "$mountpoint" &>/dev/null ; then
+    return 0
+  fi
+
+  for (( try=1; try<=tries; try++ )); do
+    if [[ ${try} -eq ${tries} ]]; then
+      # Last time, show errors this time
+      umount "${mountpoint}" && return 0
+    else
+      # Not last time, hide errors until fatal
+      if umount "${mountpoint}" 2>/dev/null ; then
+        return 0
+      else
+        sleep 1
+      fi
+    fi
+  done
+  return 1  # Tried enough
+}
+# }}}
+
 # helper functions {{{
 cleanup() {
   if [ -n "$CHROOT_VARIABLES" ] ; then
-    einfo "Removing ${CHROOT_VARIABLES}" ; rm "$CHROOT_VARIABLES" ; eend $?
+    einfo "Removing ${CHROOT_VARIABLES}" ; rm "$CHROOT_VARIABLES" || eend $?
   fi
 
   if [ -n "$STAGES" ] ; then
-    einfo "Removing ${STAGES}" ; rmdir "$STAGES" ; eend $?
+    einfo "Removing ${STAGES}" ; rmdir "$STAGES" || eend $?
   fi
 
+  try_umount 3 "${MNTPOINT}"/boot/efi
+
   # Remove temporary mountpoint again
   if echo "$MNTPOINT" | grep -q '/mnt/debootstrap\.' ; then
-    rmdir "$MNTPOINT" 2>/dev/null
+    if [ -d "$MNTPOINT" ] ; then
+      rmdir "$MNTPOINT" || true
+    fi
   fi
 
   # make sure $TARGET is not mounted when exiting grml-debootstrap
@@ -264,25 +302,24 @@ cleanup() {
         fi
       done
 
-      [ -x "$MNTPOINT"/bin/umount ] && chroot "$MNTPOINT" umount -a >/dev/null 2>&1
+      [ -x "$MNTPOINT"/bin/umount ] && chroot "$MNTPOINT" umount -a >/dev/null 2>&1 || true
 
       # 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
+        [ -x "$MNTPOINT"/bin/umount ] && chroot "$MNTPOINT" umount $ARG >/dev/null 2>&1 || true
+        umount "$MNTPOINT"/$ARG >/dev/null 2>&1 || true
       done
 
       if [ -n "$ISODIR" ] ; then
-        [ -d "$MNTPOINT/$ISODIR" ] && umount "$MNTPOINT/$ISODIR" >/dev/null 2>&1
+        try_umount 3 "$MNTPOINT/$ISODIR" >/dev/null 2>&1 || true
       fi
 
       if [ -n "$DIRECTORY" ] ; then
-        einfo "Not unmounting $MNTPOINT as you requested me to install into a directory of your own choice." ; eend 0
+        einfo "Not unmounting $MNTPOINT as you requested me to install into a directory of your own choice."
       else
         einfo "Unmounting $MNTPOINT"
-        umount "$MNTPOINT"
-        eend $?
+        try_umount 3 "$MNTPOINT"
       fi
 
       if [ -n "$STAGES" ] ; then
@@ -292,27 +329,28 @@ cleanup() {
 
       # 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 $?
+        if [ -d "$MNTPOINT" ] ; then
+          einfo "Removing directory ${MNTPOINT}"
+          rmdir "$MNTPOINT" || eend $?
+        fi
       fi
     fi
   fi
 
   if [ -n "${ORIG_TARGET}" ] ; then
     einfo "Removing loopback mount of file ${ORIG_TARGET}."
-    kpartx -d "${ORIG_TARGET}"
+    kpartx -d "${ORIG_TARGET}" || eend $?
     # 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
+      kpartx -d "/dev/${LOOP_DISK}" >/dev/null || eend $?
     fi
-    eend $?
   fi
 }
 
 # we want to exit smoothly and clean:
 bailout(){
+  eend "$1" || true
 
   cleanup
 
@@ -329,8 +367,8 @@ stage() {
      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
+     ewarn "Notice: stage $1 has been executed already, skipping execution therefore."
+     ewarn "  To reexecute it clean up the according directory inside $STAGES"
      return 1
   fi
 }
@@ -338,19 +376,19 @@ stage() {
 
 # source main configuration file {{{
 if [ -r /etc/debootstrap/config ] ; then
+  bash -n /etc/debootstrap/config
   # 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,sshcopyauth
-
-_opt_temp=$(getopt --name grml-debootstrap -o +m:i:r:t:p:c:d:vhV --long \
-  $CMDLINE_OPTS -- "$@")
+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:,vmefi,keep_src_list,hostname:,password:,nopassword,grmlrepos,backportrepos,bootappend:,grub:,efi:,arch:,insecure,verbose,help,version,force,debug,contrib,non-free,remove-configs,sshcopyid,sshcopyauth
 
-if [ $? != 0 ]; then
-  eerror "Try 'grml-debootstrap --help' for more information."; eend 1; exit 1
+if ! _opt_temp=$(getopt --name grml-debootstrap -o +m:i:r:t:p:c:d:vhV --long \
+  $CMDLINE_OPTS -- "$@"); then
+  eerror "Try 'grml-debootstrap --help' for more information."
+  bailout 1
 fi
 eval set -- "$_opt_temp"
 
@@ -379,6 +417,9 @@ while :; do
   --vmsize)            # size of Virtual machine file
     shift; _opt_vmsize="$1"
     ;;
+  --vmefi)            # Create an EFI boot partition for the VM
+    _opt_vmefi="T"
+    ;;
   --mntpoint|-p)       # Mountpoint used for mounting the target system
     shift; _opt_mntpoint="$1"
     ;;
@@ -386,7 +427,7 @@ while :; do
     shift; _opt_debopt="$1"
     ;;
   --filesystem)        # Filesystem that should be used
-    shift; _opt_filesystem="$1"
+    shift; _opt_filesystem="$1" ; FILESYSTEM="${_opt_filesystem}"
     ;;
   --interactive)       # Use interactive mode (frontend)
     _opt_interactive=T
@@ -526,11 +567,11 @@ done
   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
+    eerror "Error: config file $CONFFILES/config not found."; bailout 1
   fi
   # shellcheck disable=SC1091 source=config
   if ! . "$CONFFILES/config" ; then
-    eerror "Error reading config file $CONFFILES/config" ; eend 1 ; bailout 1
+    eerror "Error reading config file $CONFFILES/config" ; bailout 1
   fi
   # restore the command line parameter value
   CONFFILES=$_opt_confdir
@@ -544,6 +585,7 @@ done
 [ "$_opt_vm" ]                  && VIRTUAL=1
 [ "$_opt_vmfile" ]              && VMFILE=1 && VIRTUAL=1
 [ "$_opt_vmsize" ]              && VMSIZE=$_opt_vmsize
+[ "$_opt_vmefi" ]               && VMEFI=1
 [ "$_opt_mntpoint" ]            && MNTPOINT=$_opt_mntpoint
 [ "$_opt_debopt" ]              && DEBOOTSTRAP_OPT=$_opt_debopt
 [ "$_opt_interactive" ]         && INTERACTIVE=1
@@ -579,7 +621,15 @@ done
 # make sure main is always included
 [ -z "$COMPONENTS" ]            && COMPONENTS="main"
 [ "$_opt_contrib" ]             && COMPONENTS="$COMPONENTS contrib"
-[ "$_opt_non_free" ]            && COMPONENTS="$COMPONENTS non-free"
+
+case "${RELEASE}" in
+  jessie|stretch|buster|bullseye)
+    [ "$_opt_non_free" ] && COMPONENTS="$COMPONENTS non-free"
+    ;;
+  *)
+    [ "$_opt_non_free" ] && COMPONENTS="$COMPONENTS non-free-firmware non-free"
+    ;;
+esac
 
 # command line option checks
 if [ "$_opt_scripts_set" ] ; then
@@ -589,21 +639,18 @@ fi
 
 if [ "$_opt_grub" ] && [ "$_opt_vmfile" ] ; then
   eerror "The --grub option is incompatible with --vmfile, please drop it from your command line."
-  eerror "The --grub option is unneeded as GRUB will be installed automatically."
-  eend 1
+  eerror "The --grub option is unneeded as GRUB will be installed automatically (unless GRUB_INSTALL='no')."
   bailout 1
 fi
 
 if [ "${_opt_sshcopyid}" ] && [ "${_opt_sshcopyauth}" ] ; then
   eerror "The --sshcopyid option is incompatible with --sshcopyauth, please drop either of them from your command line."
-  eend 1
   bailout 1
 fi
 
 if [ -n "$ISO" ] && [[ "$DEBOOTSTRAP" =~ mmdebstrap$ ]] ; then
   eerror "The ISO option is incompatible with usage of mmdebstrap for bootstrapping."
   eerror "Either drop the --iso ... option or use plain debootstrap instead."
-  eend 1
   bailout 1
 fi
 
@@ -612,15 +659,13 @@ if [ "$DEBUG" = "true" ] ; then
 fi
 
 [ "$_opt_help" ] && {
-  usage ; eend 0
-  eend 0
+  usage
   exit 0
 }
 
 [ "$_opt_version" ] && {
   einfo "$PN - version $VERSION"
   einfo "Report bugs via https://github.com/grml/grml-debootstrap/ or https://grml.org/bugs/"
-  eend 0
   exit 0
 }
 # }}}
@@ -643,9 +688,10 @@ fi
 # source specified configuration file {{{
 if [ -n "$CONFIGFILE" ] ; then
   einfo "Reading specified config file $CONFIGFILE."
+  bash -n "$CONFIGFILE"
   # shellcheck disable=SC1091 source=config
   if ! . "$CONFIGFILE" ; then
-    eerror "Error reading config file $CONFIGFILE" ; eend 1 ; bailout 1
+    eerror "Error reading config file $CONFIGFILE" ; bailout 1
   fi
 fi
 # }}}
@@ -655,14 +701,12 @@ if [ -n "$GROOT" ] ; then
    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
    bailout 1
 fi
 
 if echo "$GRUB" | grep -q '^hd' ; then
    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
    bailout 1
 fi
 # }}}
@@ -687,8 +731,7 @@ prompt_for_target()
      dialog --title "$PN" --trim \
      --msgbox "Sorry, no partitions found. Please configure your
      harddisks (see /proc/partitions) using a tool like fdisk,
-     cfdisk, gpart, gparted,..." 0 0
-     bailout 1
+     cfdisk, gpart, gparted,..." 0 0 || bailout 1
   fi
 
   PARTITION_LIST=$(for i in $AVAILABLE_PARTITIONS ; do
@@ -701,8 +744,7 @@ prompt_for_target()
   # shellcheck disable=SC2086
   TARGET=$(dialog --title "$PN" --single-quoted --stdout \
          --menu "Please select the target partition:" 0 0 0 \
-         $PARTITION_LIST)
-  [ $? -eq 0 ] || bailout 1
+         $PARTITION_LIST) || bailout 1
 }
 # }}}
 
@@ -750,8 +792,7 @@ prompt_for_bootmanager()
           --menu "Where do you want to install the bootmanager grub?" 0 0 0 \
             mbr       "install bootmanager into $MBRPART" \
             nowhere   "do not install bootmanager at all" \
-          ${ADDITIONAL_PARAMS})
-  [ $? -eq 0 ] || bailout 3
+          ${ADDITIONAL_PARAMS}) || bailout 3
   IFS="$OIFS"
 
   case "$GETMBR" in
@@ -779,19 +820,15 @@ prompt_for_bootmanager()
 # ask for Debian release {{{
 prompt_for_release()
 {
-  [ -n "$RELEASE" ] && DEFAULT_RELEASE="$RELEASE" || DEFAULT_RELEASE='buster'
+  [ -n "$RELEASE" ] && DEFAULT_RELEASE="$RELEASE" || DEFAULT_RELEASE='bullseye'
   RELEASE="$(dialog --stdout --title "${PN}" --default-item $DEFAULT_RELEASE --menu \
             "Please enter the Debian release you would like to use for installation:" \
             0 50 8 \
-            lenny    Debian/5.0 \
-            squeeze  Debian/6.0 \
-            wheezy   Debian/7.0 \
-            jessie   Debian/8.0 \
-            stretch  Debian/9.0 \
-            buster   Debian/10.0 \
-            bullseye Debian/11.0 \
-            sid      Debian/unstable)"
-  [ $? -eq 0 ] || bailout
+            buster   Debian/10 \
+            bullseye Debian/11 \
+            bookworm Debian/12 \
+            sid      Debian/unstable)" \
+            || bailout
 }
 # }}}
 
@@ -800,8 +837,7 @@ prompt_for_hostname()
 {
   HOSTNAME="$(dialog --stdout --title "${PN}" --inputbox \
             "Please enter the hostname you would like to use for installation:" \
-            0 0 "$HOSTNAME")"
-  [ $? -eq 0 ] || bailout
+            0 0 "$HOSTNAME")" || bailout
 }
 # }}}
 
@@ -817,13 +853,11 @@ prompt_for_password()
   ROOTPW2='PW2'
   while [ "$ROOTPW1" != "$ROOTPW2" ]; do
     ROOTPW1=$(dialog --insecure --stdout --title "${PN}" --passwordbox \
-    "Please enter the password for the root account:" 10 60)
-    [ $? -eq 0 ] || bailout
+    "Please enter the password for the root account:" 10 60) || bailout
 
     ROOTPW2=$(dialog --insecure --stdout --title "${PN}" --passwordbox \
     "Please enter the password for the root account again for \
-    confirmation:" 10 60)
-    [ $? -eq 0 ] || bailout
+    confirmation:" 10 60) || bailout
 
     if [ "$ROOTPW1" != "$ROOTPW2" ]; then
       dialog --stdout --title "${PN}" --ok-label \
@@ -844,20 +878,18 @@ prompt_for_mirror()
             net   "install via network (downloading from mirror)" \
             local "install from local directory/mirror"
           )
-  [ $? -eq 0 ] || bailout
 
   if [ "$CHOOSE_MIRROR" = 'net' ] ; then
      [ -n "$MIRROR" ] || MIRROR='http://deb.debian.org/debian'
      MIRROR="$(dialog --stdout --title "${PN}" --inputbox \
                "Please enter Debian mirror you would like to use for installing packages." \
-               0 0 $MIRROR)"
-     [ $? -eq 0 ] || bailout
+               0 0 $MIRROR)" || bailout
+
   else # CHOOSE_MIRROR == local
      [ -n "$ISO" ] || ISO='/mnt/mirror'
      ISO="$(dialog --stdout --title "${PN}" --inputbox \
                "Please enter directory name you would like to use for installing packages." \
-               0 0 $ISO)"
-     [ $? -eq 0 ] || bailout
+               0 0 $ISO)" || bailout
   fi
 }
 # }}}
@@ -880,8 +912,7 @@ TARGET=$(dialog --stdout --title "$PN" --default-item /dev/md0 \
 --menu "Which device do you want to use for ${RAIDLEVEL}?
 
 Notice: activated devices will not be listed for security reasons. Anyway, please make sure the selected device is not in use already!" 0 0 0 \
-$MD_LIST)
-[ $? -eq 0 ] || bailout 20
+$MD_LIST) || bailout 20
 
 AVAILABLE_PARTITIONS=$(LANG=C fdisk -l 2>/dev/null | \
              sed 's/*//' | \
@@ -895,8 +926,8 @@ PARTITION_LIST=$(for i in $AVAILABLE_PARTITIONS ; do
 # shellcheck disable=SC2086
 dialog --title "$PN" --separate-output \
        --checklist "Please select the partitions you would like to use for your $RAIDLEVEL on ${TARGET}:" 0 0 0 \
-       $PARTITION_LIST 2>"$TMPFILE"
-[ $? -eq 0 ] || bailout
+       $PARTITION_LIST 2>"$TMPFILE" || bailout
+
 SELECTED_PARTITIONS="$(cat "$TMPFILE")"
 
 NUM_PARTITIONS=0
@@ -904,17 +935,13 @@ while IFS= read -r i; do
   NUM_PARTITIONS=$(( NUM_PARTITIONS + 1 ))
 done < "$TMPFILE"
 
-# force metadata version 0.90 for lenny so old grub can boot from this array.
-METADATA_VERSION=""
-if [ "$RELEASE" = "lenny" ]; then
-   METADATA_VERSION="-e0"
-fi
-
 ERRORFILE=$(mktemp)
+
+local RC=0
 # shellcheck disable=SC2086
 yes | mdadm --create "${TARGET}" --level="${RAIDLEVEL}" \
-      --raid-devices="${NUM_PARTITIONS}" ${METADATA_VERSION} ${SELECTED_PARTITIONS} >/dev/null 2>$ERRORFILE
-RC=$?
+      --raid-devices="${NUM_PARTITIONS}" ${SELECTED_PARTITIONS} >/dev/null 2>$ERRORFILE || RC=$?
+
 if [ "$RC" = 0 ] ; then
    dialog --title "$PN" --msgbox \
    "Creating $TARGET was successful." 0 0
@@ -969,16 +996,11 @@ format_efi_partition() {
   fi
 
   if fsck.vfat -bn "$EFI" >/dev/null; then
-    einfo "EFI partition $EFI seems to have a FAT filesystem, not modifying." ; eend 0
+    einfo "EFI partition $EFI seems to have a FAT filesystem, not modifying."
   else
     einfo "EFI partition $EFI doesn't seem to be formatted, creating filesystem."
-    mkfs.fat -F32 -n "EFI System Partition" "$EFI"
-    RC=$?
-    if [ $RC -eq 0 ] ; then
-      eend 0
-    else
+    if ! mkfs.fat -F32 -n "EFI" "$EFI" ; then
       eerror "Error while creating filesystem on ${EFI}."
-      eend 1
       bailout 1
     fi
   fi
@@ -987,16 +1009,25 @@ format_efi_partition() {
 
 # check for EFI support or try to enable it {{{
 efi_support() {
-  if lsmod | grep -q efivars ; then
-    einfo "EFI support detected." ; eend 0
-    return 0
+  local efivars_loaded=false
+  # this is for kernels versions before v3.10, which didn't provide efivarfs yet
+  if modprobe efivars &>/dev/null ; then
+    efivars_loaded=true
+  fi
+  # kernel versions v3.10 and newer usually provide efivarfs
+  if modprobe efivarfs &>/dev/null ; then
+    efivars_loaded=true
   fi
 
-  if modprobe efivars &>/dev/null ; then
-    einfo "EFI support enabled now." ; eend 0
+  if [ -d /sys/firmware/efi ] ; then
+    einfo "EFI support detected."
     return 0
   fi
 
+  if ! [ -d /sys/firmware/efi ] && [ "${efivars_loaded:-}" = "true" ] ; then
+    einfo "EFI support detected, but system seems to be running in BIOS mode."
+  fi
+
   return 1
 }
 # }}}
@@ -1005,20 +1036,22 @@ efi_support() {
 checkconfiguration()
 {
 
-if efi_support ; then
-  if [ -z "$_opt_efi" ] ; then
-    ewarn "EFI support detected but no --efi option given, please consider enabling it." ; eend 0
-  fi
-else
-  if [ -n "$_opt_efi" ] ; then
-     eerror "EFI option used but no EFI support detected." ; eend 0
-     bailout 1
+if [ -z "$VIRTUAL" ] ; then
+  if efi_support ; then
+    if [ -z "$_opt_efi" ] ; then
+      ewarn "EFI support detected but no --efi option given, please consider enabling it."
+    fi
+  else
+    if [ -n "$_opt_efi" ] ; then
+      eerror "EFI option used but no EFI support detected."
+      bailout 1
+    fi
   fi
 fi
 
 if [ -n "$AUTOINSTALL" ] ; then
    if checkforrun ; then
-      eerror "Exiting as requested" ; eend 0
+      eerror "Exiting as requested"
       bailout 1
    fi
 elif [ -n "$INTERACTIVE" ] ; then
@@ -1049,8 +1082,7 @@ elif [ -n "$INTERACTIVE" ] ; then
 Is this ok for you? Notice: selecting 'No' will exit ${PN}."
 
    dialog --title "$PN" --no-collapse \
-          --yesno "$INFOTEXT" 0 0
-   [ $? -eq 0 ] || bailout 0
+          --yesno "$INFOTEXT" 0 0 || bailout 0
 
 else # if not running automatic installation display configuration and prompt for execution:
    einfo "$PN [${VERSION}] - Please recheck configuration before execution:"
@@ -1060,8 +1092,9 @@ else # if not running automatic installation display configuration and prompt fo
    # do not display if MNTPOINT is the default one
    case "$MNTPOINT" in /mnt/debootstrap*) ;; *) echo "   Mount point:     $MNTPOINT" ;; esac
 
-   if [ -n "$VIRTUAL" ] ; then
+   if [ -n "$VIRTUAL" ] && [ "$GRUB_INSTALL" = 'yes' ] ; then
       echo "   Install grub:    yes"
+      [ -n "$VMEFI" ]   && echo "   Install efi:     yes"   || echo "   Install efi:     no"
    else
      [ -n "$GRUB" ]     && echo "   Install grub:    $GRUB" || echo "   Install grub:    no"
      [ -n "$EFI" ]      && echo "   Install efi:     $EFI"  || echo "   Install efi:     no"
@@ -1096,7 +1129,7 @@ else # if not running automatic installation display configuration and prompt fo
      einfon "Is this ok for you? [y/N] "
      read -r a
      if ! [ "$a" = 'y' ] || [ "$a" = 'Y' ] ; then
-        eerror "Exiting as requested." ; eend 1
+        eerror "Exiting as requested."
         bailout 1
      fi
    fi
@@ -1143,13 +1176,19 @@ else
    ARCHCMD="--arch $ARCH"
    ARCHINFO=" (${ARCH})"
 fi
+
+if [ -z "${ARCH:-}" ] ; then
+  eerror 'Architecture neither set (environment variable ARCH), nor could be automatically identified (using dpkg).'
+  eerror 'Consider setting the --arch ... option.'
+  bailout 1
+fi
 # }}}
 
 # It is not possible to build amd64 on i686. {{{
 CURRENT_ARCH="$(uname -m)"
 if [ "$CURRENT_ARCH" != "x86_64" ] ; then
    if [ "$ARCH" = "amd64" ] ; then
-      eerror "It is not possible to build amd64 on $CURRENT_ARCH. Consider installing and booting the 'linux-image-amd64' kernel or using '--arch i386' instead." ; eend 1
+      eerror "It is not possible to build amd64 on $CURRENT_ARCH. Consider installing and booting the 'linux-image-amd64' kernel or using '--arch i386' instead."
       bailout 1
    fi
 fi
@@ -1158,7 +1197,7 @@ fi
 # Support for generic release codenames is unavailable. {{{
 if [ "$RELEASE" = "stable" ] || [ "$RELEASE" = "testing" ] ; then
    eerror "Generic release codenames (stable, testing) are unsupported. \
-Please use specific codenames such as stretch or buster." ; eend 1
+Please use specific codenames such as bullseye or bookworm."
    bailout 1
 fi
 # }}}
@@ -1170,7 +1209,7 @@ if [ -n "$TARGET" ] ; then
    SHORT_TARGET="${TARGET##*/}"
 else
    eerror "Please adjust $CONFFILES/config or..."
-   eerror "... use the interactive version for configuration before running ${0}" ; eend 1
+   eerror "... use the interactive version for configuration before running ${0}"
    bailout 1
 fi
 # }}}
@@ -1184,7 +1223,7 @@ fi
 if [ -r "$STAGES"/grml-debootstrap ] ; then
    if grep -q 'done' "${STAGES}/grml-debootstrap" ; then
       eerror "Error: grml-debootstrap has been executed already, won't continue therefore."
-      eerror "If you want to re-execute grml-debootstrap just manually remove ${STAGES}" ; eend 1
+      eerror "If you want to re-execute grml-debootstrap just manually remove ${STAGES}"
    fi
 fi
 # }}}
@@ -1212,7 +1251,7 @@ else
     # $TARGET was not detected as block device, but we do not want to create target directory in /dev/
     if [[ $TARGET == "/dev/"* ]]; then
       eerror "Error: Will not create target directory $TARGET in /dev."
-      eerror "  Please check the partition(s) of the blockdevice."; eend 1
+      eerror "  Please check the partition(s) of the blockdevice."
       bailout 1
     fi
     set_target_directory
@@ -1247,7 +1286,7 @@ mkfs() {
   fi
 
   if grep -q "$TARGET" /proc/mounts ; then
-    eerror "$TARGET already mounted, exiting to avoid possible damage. (Manually unmount $TARGET)" ; eend 1
+    eerror "$TARGET already mounted, exiting to avoid possible damage. (Manually unmount $TARGET)"
     bailout 1
   fi
 
@@ -1258,8 +1297,6 @@ mkfs() {
       mkfs.ext*)
         einfo "Enabling force option (-F) for mkfs.ext* tool as requested via --force switch."
         MKFS_OPTS="$MKFS_OPTS -F"
-        eend 0
-
         ;;
     esac
   fi
@@ -1269,36 +1306,62 @@ mkfs() {
   # so disable this feature for older Debian releases where it's known to be unsupported
   if [ -n "$MKFS" ] && [ "$MKFS" = "mkfs.ext4" ] ; then
     case "$RELEASE" in
-      lenny|squeeze|wheezy|jessie)
+      jessie)
         # assume a more recent version if we can't identify the version via dpkg-query
         local e2fsprogs_version
         e2fsprogs_version="$(dpkg-query --show --showformat='${Version}' e2fsprogs 2>/dev/null || echo 1.44)"
         if [ -n "$e2fsprogs_version" ] && dpkg --compare-versions "$e2fsprogs_version" ge '1.43~WIP.2015.05.18-1' ; then
           einfo "Disabling metadata_csum feature for $MKFS as $RELEASE doesn't support it."
           MKFS_OPTS="$MKFS_OPTS -O ^metadata_csum"
-          eend 0
+        fi
+        ;;
+    esac
+  fi
+
+  # starting with e2fsprogs v1.47.0 mkfs.ext4 enables the metadata_csum_seed feature
+  # by default, which requires Linux kernel >=4.4, e2fsprogs >=1.43, according GRUB etc.
+  # Disable this feature for Debian releases older than bookworm
+  if [ -n "$MKFS" ] && [ "$MKFS" = "mkfs.ext4" ] ; then
+    case "$RELEASE" in
+      jessie|stretch|buster|bullseye)
+        local e2fsprogs_version
+        # assume a more recent version if we can't identify the version via dpkg-query
+        e2fsprogs_version="$(dpkg-query --show --showformat='${Version}' e2fsprogs 2>/dev/null || echo 1.47)"
+        if [ -n "$e2fsprogs_version" ] && dpkg --compare-versions "$e2fsprogs_version" ge '1.43' ; then
+          einfo "Disabling metadata_csum_seed feature for $MKFS as $RELEASE doesn't support it."
+          MKFS_OPTS="$MKFS_OPTS -O ^metadata_csum_seed"
         fi
         ;;
     esac
   fi
 
   if [ -n "$MKFS" ] ; then
+
+    if [ -n "${ARM_EFI_TARGET}" ] ; then
+      einfo "Running mkfs.fat $MKFS_OPTS on $ARM_EFI_TARGET"
+      mkfs.fat -n "EFI" "$ARM_EFI_TARGET"
+      MKFS_OPTS="$MKFS_OPTS -L LINUX"
+    fi
+
     einfo "Running $MKFS $MKFS_OPTS on $TARGET"
     # shellcheck disable=SC2086
-    "$MKFS" $MKFS_OPTS "$TARGET" ; RC=$?
+    "$MKFS" $MKFS_OPTS "$TARGET"
 
     if [ "$FIXED_DISK_IDENTIFIERS" = "yes" ] ; then
       if ! echo "$MKFS" | grep -q "mkfs.ext" ; then
         eerror "Not changing disk uuid for $TARGET because $MKFS doesn't seem to match for ext{2,3,4} file system"
-        eend 1
         bailout 1
       else
         einfo "Changing disk uuid for $TARGET to fixed (non-random) value $DISK_IDENTIFIER using tune2fs"
-        tune2fs "$TARGET" -U "$DISK_IDENTIFIER"
-        eend $?
+        tune2fs "$TARGET" -U "$DISK_IDENTIFIER" </dev/null
       fi
     fi
 
+    if [ -n "$VIRTUAL" ] && [ -n "$EFI_TARGET" ]; then
+      einfo "Creating FAT filesystem on $EFI_TARGET"
+      mkfs.fat -F32 -n "EFI" "$EFI_TARGET"
+    fi
+
     # make sure /dev/disk/by-uuid/... is up2date, otherwise grub
     # will fail to detect the uuid in the chroot
     if [ -n "$VIRTUAL" ] ; then
@@ -1319,7 +1382,6 @@ mkfs() {
     # race conditions :-/
     sleep 2
 
-    eend $RC
   fi
 }
 # }}}
@@ -1373,8 +1435,7 @@ mountpoint_to_blockdevice() {
 tunefs() {
   if [ -n "$TUNE2FS" ] && echo "$MKFS" | grep -q "mkfs.ext" ; then
      einfo "Disabling automatic filesystem check on $TARGET via tune2fs"
-     $TUNE2FS "$TARGET"
-     eend $?
+     $TUNE2FS "$TARGET" </dev/null
   fi
 }
 # }}}
@@ -1385,7 +1446,7 @@ mount_target() {
      einfo "Running grml-debootstrap on a directory, nothing to mount."
   else
      if grep -q "$TARGET" /proc/mounts ; then
-        ewarn "$TARGET already mounted, continuing anyway." ; eend 0
+        ewarn "$TARGET already mounted, continuing anyway."
      else
        if ! [ -d "${MNTPOINT}" ] ; then
           [ -n "$VIRTUAL" ] || mkdir -p "${MNTPOINT}"
@@ -1393,14 +1454,12 @@ mount_target() {
        einfo "Mounting $TARGET to $MNTPOINT"
        mkdir -p "$MNTPOINT"
        mount -o rw,suid,dev "$TARGET" "$MNTPOINT"
-       eend $?
      fi
   fi
   if [ -n "$ISODIR" ] ; then
      einfo "Mounting Debian image loopback to $MNTPOINT/$ISODIR."
      mkdir -p "$MNTPOINT/$ISODIR"
      mount --bind "$ISODIR" "$MNTPOINT/$ISODIR"
-     eend $?
   fi
 }
 # }}}
@@ -1413,27 +1472,25 @@ prepare_vm() {
 
   if [ -b "$TARGET" ] && [ -n "$VMFILE" ] ; then
      eerror "Error: specified virtual disk target ($TARGET) is an existing block device."
-     eend 1
      bailout 1
   fi
   if [ ! -b "$TARGET" ] && [ -z "$VMFILE" ] ; then
      eerror "Error: specified virtual disk target ($TARGET) does not exist yet."
-     eend 1
      bailout 1
   fi
 
   # make sure loop module is present and a usable loop device exists
-  modprobe -q loop
+  modprobe loop || true
   if ! losetup -f >/dev/null 2>&1; then
-    eerror "Error finding usable loop device" ; eend 1
+    eerror "Error finding usable loop device"
     bailout 1
   fi
 
   # if dm-mod isn't available then kpartx will fail with
   # "Is device-mapper driver missing from kernel? [...]"
-  modprobe -q dm-mod
+  modprobe dm-mod || true
   if ! grep -q 'device-mapper' /proc/misc >/dev/null 2>&1 ; then
-    eerror "Device-mapper support missing in kernel." ; eend 1
+    eerror "Device-mapper support missing in kernel."
     bailout 1
   fi
 
@@ -1442,32 +1499,63 @@ prepare_vm() {
   if [ -n "$VMFILE" ]; then
     qemu-img create -f raw "${TARGET}" "${VMSIZE}"
   fi
-  parted -s "${TARGET}" 'mklabel msdos'
-  if [ "$FIXED_DISK_IDENTIFIERS" = "yes" ] ; then
-    einfo "Adjusting disk signature to a fixed (non-random) value"
-    MBRTMPFILE=$(mktemp)
-    dd if="${TARGET}" of="${MBRTMPFILE}" bs=512 count=1
-    echo -en "\\x41\\x41\\x41\\x41" | dd of="${MBRTMPFILE}" conv=notrunc seek=440 bs=1
-    dd if="${MBRTMPFILE}" of="${TARGET}" conv=notrunc
-    eend $?
+  if [ -n "$VMEFI" ]; then
+    parted -s "${TARGET}" 'mklabel gpt'
+    parted -s "${TARGET}" 'mkpart ESP fat32 1MiB 101MiB'
+    parted -s "${TARGET}" 'set 1 boot on'
+    parted -s "${TARGET}" 'mkpart bios_grub 101MiB 102MiB'
+    parted -s "${TARGET}" 'set 2 bios_grub on'
+    parted -s "${TARGET}" 'mkpart primary ext4 102MiB 100%'
+
+  else
+    # arm64 support largely only exists for GPT
+    if [ "$ARCH" = 'arm64' ]; then
+      einfo "Setting up GPT partitions for arm64"
+      parted -s "${TARGET}" 'mklabel gpt'
+      parted -s "${TARGET}" 'mkpart ESP fat32 1MiB 10MiB'
+      parted -s "${TARGET}" 'set 1 boot on'
+      parted -s "${TARGET}" 'mkpart LINUX ext4 10MiB 100%'
+    else
+      parted -s "${TARGET}" 'mklabel msdos'
+      if [ "$FIXED_DISK_IDENTIFIERS" = "yes" ] ; then
+        einfo "Adjusting disk signature to a fixed (non-random) value"
+        MBRTMPFILE=$(mktemp)
+        dd if="${TARGET}" of="${MBRTMPFILE}" bs=512 count=1
+        echo -en "\\x41\\x41\\x41\\x41" | dd of="${MBRTMPFILE}" conv=notrunc seek=440 bs=1
+        dd if="${MBRTMPFILE}" of="${TARGET}" conv=notrunc
+      fi
+      parted -s "${TARGET}" 'mkpart primary ext4 4MiB 100%'
+      parted -s "${TARGET}" 'set 1 boot on'
+    fi
   fi
-  parted -s "${TARGET}" 'mkpart primary ext4 2M -1'
-  parted -s "${TARGET}" 'set 1 boot on'
 
-  DEVINFO=$(kpartx -asv "$TARGET") # e.g. 'add map loop0p1 (254:5): 0 20477 linear 7:0 3'
+  DEVINFO=$(kpartx -asv "$TARGET") # e.g. 'add map loop0p1 (254:5): 0 20477 linear 7:0 3' - will be multi-line for arm64
   if [ -z "${DEVINFO}" ] ; then
-    eerror "Error setting up loopback device." ; eend 1
+    eerror "Error setting up loopback device."
     bailout 1
   fi
 
+  # if we're building for arm64, we operate on the first line of $DEVINFO which is the EFI partition
+  if [ "$ARCH" = 'arm64' ]; then
+    LOOP_PART="${DEVINFO##add map }" # 'loop0p1 (254:5): 0 20477 linear 7:0 3'
+    LOOP_PART="${LOOP_PART// */}"    # 'loop0p1'
+    LOOP_DISK="${LOOP_PART%p*}"      # 'loop0'
+    export ARM_EFI_TARGET="/dev/mapper/$LOOP_PART"
+    DEVINFO=${DEVINFO##*$'\n'} # now set $DEVINFO to the last line which is the OS partition
+  fi
+
   # hopefully this always works as expected
   LOOP_PART="${DEVINFO##add map }" # 'loop0p1 (254:5): 0 20477 linear 7:0 3'
   LOOP_PART="${LOOP_PART// */}"    # 'loop0p1'
+  if [ -n "$VMEFI" ]; then
+    export EFI_TARGET="/dev/mapper/$LOOP_PART" # '/dev/mapper/loop0p1'
+    LOOP_PART="${LOOP_PART%p1}p3"
+  fi
   LOOP_DISK="${LOOP_PART%p*}"      # 'loop0'
-  export TARGET="/dev/mapper/$LOOP_PART" # '/dev/mapper/loop1p1'
+  export TARGET="/dev/mapper/$LOOP_PART" # '/dev/mapper/loop0p1'
 
   if [ -z "$TARGET" ] ; then
-     eerror "Error: target could not be set to according /dev/mapper/* device." ; eend 1
+     eerror "Error: target could not be set to according /dev/mapper/* device."
      bailout 1
   fi
 }
@@ -1484,45 +1572,99 @@ grub_install() {
   fi
 
   if ! mount "${TARGET}" "${MNTPOINT}" ; then
-    eerror "Error: Mounting ${TARGET} failed, can not continue." ; eend 1
+    eerror "Error: Mounting ${TARGET} failed, can not continue."
     bailout 1
   fi
 
+  if [ -n "${ARM_EFI_TARGET}" ]; then
+    mkdir -p "${MNTPOINT}"/boot/efi
+    if ! mount "${ARM_EFI_TARGET}" "${MNTPOINT}"/boot/efi ; then
+      eerror "Error: Mounting ${ARM_EFI_TARGET} failed, can not continue."
+      bailout 1
+    fi
+  fi
+
   mount -t proc none "${MNTPOINT}"/proc
   mount -t sysfs none "${MNTPOINT}"/sys
   mount -t devtmpfs udev "${MNTPOINT}"/dev
   mount -t devpts devpts "${MNTPOINT}"/dev/pts
 
-# Has chroot-script installed GRUB to MBR using grub-install (successfully), already?
-# chroot-script skips installation for unset ${GRUB}
-if [[ -z "${GRUB}" ]] || ! dd if="${GRUB}" bs=512 count=1 2>/dev/null | cat -v | grep -Fq GRUB; then
-  einfo "Installing Grub as bootloader."
+  if [ -n "$ARM_EFI_TARGET" ]; then
+    einfo "Installing Grub as bootloader into EFI."
 
-  if ! chroot "${MNTPOINT}" dpkg --list grub-pc 2>/dev/null | grep -q '^ii' ; then
-    echo "Notice: grub-pc package not present yet, installing it therefore."
-    # shellcheck disable=SC2086
-    DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y install $DPKG_OPTIONS grub-pc
-  fi
+    chroot "${MNTPOINT}" grub-install --target=arm64-efi --efi-directory=/boot/efi --bootloader-id=debian --recheck --no-nvram --removable
+  # Has chroot-script installed GRUB to MBR using grub-install (successfully), already?
+  # chroot-script skips installation for unset ${GRUB}
+  elif [[ -z "${GRUB}" ]] || ! dd if="${GRUB}" bs=512 count=1 2>/dev/null | cat -v | grep -Fq GRUB; then
+    einfo "Installing Grub as bootloader."
 
-  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
-     bailout 1
-  fi
+    if ! chroot "${MNTPOINT}" dpkg --list grub-pc 2>/dev/null | grep -q '^ii' ; then
+      echo "Notice: grub-pc package not present yet, installing it therefore."
+      # shellcheck disable=SC2086
+      DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y --no-install-recommends install $DPKG_OPTIONS grub-pc
+    fi
 
-  case "$RELEASE" in
-    lenny|squeeze|wheezy)
-      cp "${MNTPOINT}"/usr/lib/grub/i386-pc/* "${MNTPOINT}/boot/grub/"
-      ;;
-    *)
-      cp -a "${MNTPOINT}"/usr/lib/grub/i386-pc "${MNTPOINT}/boot/grub/"
-      ;;
-  esac
-  dd if="${MNTPOINT}/usr/lib/grub/i386-pc/boot.img" of="${ORIG_TARGET}" conv=notrunc bs=440 count=1
-  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=1
-  rm -f "${MNTPOINT}/tmp/core.img"
-fi
+    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."
+      bailout 1
+    fi
+    cp -a "${MNTPOINT}"/usr/lib/grub/i386-pc "${MNTPOINT}/boot/grub/"
+
+    if [ -n "$VMEFI" ]; then
+
+      mkdir -p "${MNTPOINT}"/boot/efi
+      mount -t vfat "${EFI_TARGET}" "${MNTPOINT}"/boot/efi
+
+      if ! chroot "${MNTPOINT}" dpkg --list shim-signed 2>/dev/null | grep -q '^ii' ; then
+        echo "Notice: shim-signed package not present yet, installing it therefore."
+        # shellcheck disable=SC2086
+        DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y --no-install-recommends install $DPKG_OPTIONS shim-signed
+      fi
+
+      if [ "$(dpkg --print-architecture)" = "arm64" ]; then
+        if ! chroot "${MNTPOINT}" dpkg --list grub-efi-arm64-signed 2>/dev/null | grep -q '^ii' ; then
+          echo "Notice: grub-efi-arm64-signed package not present yet, installing it therefore."
+          # shellcheck disable=SC2086
+          DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y --no-install-recommends install $DPKG_OPTIONS grub-efi-arm64-bin grub-efi-arm64-signed
+        fi
+        chroot "$MNTPOINT" grub-install --target=arm64-efi --efi-directory=/boot/efi --uefi-secure-boot --removable "/dev/$LOOP_DISK"
+      elif [ "$(dpkg --print-architecture)" = "i386" ]; then
+        if ! chroot "${MNTPOINT}" dpkg --list grub-efi-ia32-signed 2>/dev/null | grep -q '^ii' ; then
+          echo "Notice: grub-efi-ia32-signed package not present yet, installing it therefore."
+          # shellcheck disable=SC2086
+          DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y --no-install-recommends install $DPKG_OPTIONS grub-efi-ia32-bin grub-efi-ia32-signed
+        fi
+        chroot "$MNTPOINT" grub-install --target=i386-efi --efi-directory=/boot/efi --uefi-secure-boot --removable "/dev/$LOOP_DISK"
+        chroot "$MNTPOINT" grub-install --target=i386-pc "/dev/$LOOP_DISK"
+      else
+        if ! chroot "${MNTPOINT}" dpkg --list grub-efi-amd64-signed 2>/dev/null | grep -q '^ii' ; then
+          echo "Notice: grub-efi-amd64-signed package not present yet, installing it therefore."
+          # shellcheck disable=SC2086
+          DEBIAN_FRONTEND=$DEBIAN_FRONTEND chroot "$MNTPOINT" apt-get -y --no-install-recommends install $DPKG_OPTIONS grub-efi-amd64-bin grub-efi-amd64-signed
+        fi
+        chroot "$MNTPOINT" grub-install --target=x86_64-efi --efi-directory=/boot/efi --uefi-secure-boot --removable "/dev/$LOOP_DISK"
+        chroot "$MNTPOINT" grub-install --target=i386-pc "/dev/$LOOP_DISK"
+      fi
+    else
+      dd if="${MNTPOINT}/usr/lib/grub/i386-pc/boot.img" of="${ORIG_TARGET}" conv=notrunc bs=440 count=1
+      case "${_opt_filesystem}" in
+        f2fs)
+          chroot "${MNTPOINT}" grub-mkimage -O i386-pc -p "(hd0,msdos1)/boot/grub" -o /tmp/core.img biosdisk part_msdos f2fs
+          ;;
+        xfs)
+          chroot "${MNTPOINT}" grub-mkimage -O i386-pc -p "(hd0,msdos1)/boot/grub" -o /tmp/core.img biosdisk part_msdos xfs
+          ;;
+        # NOTE - we might need to distinguish between further filesystems
+        *)
+          chroot "${MNTPOINT}" grub-mkimage -O i386-pc -p "(hd0,msdos1)/boot/grub" -o /tmp/core.img biosdisk part_msdos ext2
+          ;;
+      esac
+
+      dd if="${MNTPOINT}/tmp/core.img" of="${ORIG_TARGET}" conv=notrunc seek=1
+      rm -f "${MNTPOINT}/tmp/core.img"
+    fi
+  fi
 
   # workaround for Debian bug #918590 with lvm + udev:
   # WARNING: Device /dev/... not initialized in udev database even after waiting 10000000 microseconds
@@ -1530,11 +1672,16 @@ fi
     einfo "Setting up bind-mount /run/udev"
     mkdir -p "${MNTPOINT}"/run/udev
     mount --bind /run/udev "${MNTPOINT}"/run/udev
-    eend $?
+  fi
+
+  if [ -n "${BOOT_APPEND}" ] ; then
+    echo "Adding BOOT_APPEND configuration ['${BOOT_APPEND}'] to /etc/default/grub."
+    sed -i "/GRUB_CMDLINE_LINUX_DEFAULT/ s#\"\$# ${BOOT_APPEND}\"#" "${MNTPOINT}/etc/default/grub"
   fi
 
   einfo "Updating grub configuration file."
   chroot "${MNTPOINT}" update-grub
+  chroot "${MNTPOINT}" sync
 
   case "$RELEASE" in
     jessie)
@@ -1547,24 +1694,22 @@ fi
   if grep -q '^GRUB_DISABLE_LINUX_UUID=.*true' "${MNTPOINT}"/etc/default/grub 2>/dev/null ; then
     ewarn "GRUB_DISABLE_LINUX_UUID is set to true in /etc/default/grub, not adjusting root= in grub.cfg."
     ewarn "Please note that your system might NOT be able to properly boot."
-  else
+  elif [ -z "$ARM_EFI_TARGET" ]; then
     einfo "Adjusting grub.cfg for successful boot sequence."
     sed -i "s;root=[^ ]\\+;root=UUID=$TARGET_UUID;" "${MNTPOINT}"/boot/grub/grub.cfg
   fi
 
   # workaround for Debian bug #918590 with lvm + udev:
   # WARNING: Device /dev/... not initialized in udev database even after waiting 10000000 microseconds
-  if mountpoint "${MNTPOINT}"/run/udev &>/dev/null ; then
-    einfo "Unmounting bind-mount /run/udev"
-    umount "${MNTPOINT}"/run/udev
-    eend $?
-  fi
+  try_umount 3 "${MNTPOINT}"/run/udev
 
-  umount "${MNTPOINT}"/proc
-  umount "${MNTPOINT}"/sys
-  umount "${MNTPOINT}"/dev/pts
+  try_umount 3 "${MNTPOINT}"/proc
+  try_umount 3 "${MNTPOINT}"/sys
+  try_umount 3 "${MNTPOINT}"/dev/pts
   try_umount 3 "${MNTPOINT}"/dev
 
+  try_umount 3 "${MNTPOINT}"/boot/efi
+
 }
 # }}}
 
@@ -1574,7 +1719,9 @@ umount_target() {
      return 0
   fi
 
-  umount "${MNTPOINT}"
+  try_umount 3 "${MNTPOINT}"/boot/efi
+
+  try_umount 3 "${MNTPOINT}"
   kpartx -d "${ORIG_TARGET}" >/dev/null
   # Workaround for a bug in kpartx which doesn't clean up properly,
   # see Debian Bug #891077 and Github-PR grml/grml-debootstrap#112
@@ -1600,28 +1747,15 @@ debootstrap_system() {
 
   if [ -n "$ISO" ] ; then
     einfo "Running $DEBOOTSTRAP $DEBOOTSTRAP_OPT for release ${RELEASE}${ARCHINFO} using ${ISO}"
-    einfo "Executing: $DEBOOTSTRAP $ARCHCMD $KEYRING $DEBOOTSTRAP_OPT $RELEASE $MNTPOINT $ISO"
+    einfo "Executing: $DEBOOTSTRAP $ARCHCMD $DEBOOTSTRAP_OPT $RELEASE $MNTPOINT $ISO"
     # shellcheck disable=SC2086
-    "$DEBOOTSTRAP" $ARCHCMD $KEYRING $DEBOOTSTRAP_OPT "$RELEASE" "$MNTPOINT" "$ISO"
-    RC=$?
+    "$DEBOOTSTRAP" $ARCHCMD $DEBOOTSTRAP_OPT "$RELEASE" "$MNTPOINT" "$ISO"
   else
     einfo "Running $DEBOOTSTRAP $DEBOOTSTRAP_OPT for release ${RELEASE}${ARCHINFO} using ${MIRROR}"
-    einfo "Executing: $DEBOOTSTRAP $ARCHCMD $KEYRING $DEBOOTSTRAP_OPT $RELEASE $MNTPOINT $MIRROR"
+    einfo "Executing: $DEBOOTSTRAP $ARCHCMD $DEBOOTSTRAP_OPT $RELEASE $MNTPOINT $MIRROR"
     # shellcheck disable=SC2086
-    "$DEBOOTSTRAP" $ARCHCMD $KEYRING $DEBOOTSTRAP_OPT "$RELEASE" "$MNTPOINT" "$MIRROR"
-    RC=$?
+    "$DEBOOTSTRAP" $ARCHCMD $DEBOOTSTRAP_OPT "$RELEASE" "$MNTPOINT" "$MIRROR"
   fi
-
-  if [ $RC -ne 0 ] ; then
-    if [ -r "$MNTPOINT/debootstrap/debootstrap.log" ] && \
-      [ -s "$MNTPOINT/debootstrap/debootstrap.log" ] ; then
-      einfo "Presenting last ten lines of debootstrap.log:"
-      tail -10 "${MNTPOINT}"/debootstrap/debootstrap.log
-      einfo "End of debootstrap.log"
-    fi
-  fi
-
-  eend $RC
 }
 # }}}
 
@@ -1634,52 +1768,53 @@ preparechroot() {
   touch "$CHROOT_VARIABLES"
   chmod 600 "$CHROOT_VARIABLES" # make sure nobody except root can read it
   echo "# Configuration of ${PN}"                                                                                   > "$CHROOT_VARIABLES"
-  # Resorting to sed(1) for escaping since "VAR='${VAR//\'/\'\\\'\'}'" does not work with all versions of Bash,
-  #   e.g. not with 4.2.37(1)-release (a.k.a 4.2+dfsg-0.1+deb7u3) of Debian wheezy
-  [ -n "$ARCH" ]                && echo "ARCH='$(sed "s,','\\\\'',g" <<<"${ARCH}")'"                               >> "$CHROOT_VARIABLES"
-  [ -n "$BACKPORTREPOS" ]       && echo "BACKPORTREPOS='$(sed "s,','\\\\'',g" <<<"${BACKPORTREPOS}")'"             >> "$CHROOT_VARIABLES"
-  [ -n "$BOOT_APPEND" ]         && echo "BOOT_APPEND='$(sed "s,','\\\\'',g" <<<"${BOOT_APPEND}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$CHROOT_SCRIPTS" ]      && echo "CHROOT_SCRIPTS='$(sed "s,','\\\\'',g" <<<"${CHROOT_SCRIPTS}")'"           >> "$CHROOT_VARIABLES"
-  [ -n "$COMPONENTS" ]          && echo "COMPONENTS='$(sed "s,','\\\\'',g" <<<"${COMPONENTS}")'"                   >> "$CHROOT_VARIABLES"
-  [ -n "$CONFFILES" ]           && echo "CONFFILES='$(sed "s,','\\\\'',g" <<<"${CONFFILES}")'"                     >> "$CHROOT_VARIABLES"
-  [ -n "$DEBCONF" ]             && echo "DEBCONF='$(sed "s,','\\\\'',g" <<<"${DEBCONF}")'"                         >> "$CHROOT_VARIABLES"
-  [ -n "$DEBIAN_FRONTEND" ]     && echo "DEBIAN_FRONTEND='$(sed "s,','\\\\'',g" <<<"${DEBIAN_FRONTEND}")'"         >> "$CHROOT_VARIABLES"
-  [ -n "$DEBOOTSTRAP" ]         && echo "DEBOOTSTRAP='$(sed "s,','\\\\'',g" <<<"${DEBOOTSTRAP}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$DEFAULT_LOCALES" ]     && echo "DEFAULT_LOCALES='$(sed "s,','\\\\'',g" <<<"${DEFAULT_LOCALES}")'"         >> "$CHROOT_VARIABLES"
-  [ -n "$DEFAULT_LANGUAGE" ]    && echo "DEFAULT_LANGUAGE='$(sed "s,','\\\\'',g" <<<"${DEFAULT_LANGUAGE}")'"       >> "$CHROOT_VARIABLES"
-  [ -n "$EXTRAPACKAGES" ]       && echo "EXTRAPACKAGES='$(sed "s,','\\\\'',g" <<<"${EXTRAPACKAGES}")'"             >> "$CHROOT_VARIABLES"
-  [ -n "$EFI" ]                 && echo "EFI='$(sed "s,','\\\\'',g" <<<"${EFI}")'"                                 >> "$CHROOT_VARIABLES"
-  [ -n "$FALLBACK_MIRROR" ]     && echo "FALLBACK_MIRROR='$(sed "s,','\\\\'',g" <<<"${FALLBACK_MIRROR}")'"         >> "$CHROOT_VARIABLES"
-  [ -n "$FORCE" ]               && echo "FORCE='$(sed "s,','\\\\'',g" <<<"${FORCE}")'"                             >> "$CHROOT_VARIABLES"
-  [ -n "$GRMLREPOS" ]           && echo "GRMLREPOS='$(sed "s,','\\\\'',g" <<<"${GRMLREPOS}")'"                     >> "$CHROOT_VARIABLES"
-  [ -n "$GRUB" ]                && echo "GRUB='$(sed "s,','\\\\'',g" <<<"${GRUB}")'"                               >> "$CHROOT_VARIABLES"
-  [ -n "$HOSTNAME" ]            && echo "HOSTNAME='$(sed "s,','\\\\'',g" <<<"${HOSTNAME}")'"                       >> "$CHROOT_VARIABLES"
-  [ -n "$INITRD" ]              && echo "INITRD='$(sed "s,','\\\\'',g" <<<"${INITRD}")'"                           >> "$CHROOT_VARIABLES"
-  [ -n "$INSTALL_NOTES" ]       && echo "INSTALL_NOTES='$(sed "s,','\\\\'',g" <<<"${INSTALL_NOTES}")'"             >> "$CHROOT_VARIABLES"
-  [ -n "$ISODIR" ]              && echo "ISODIR='$(sed "s,','\\\\'',g" <<<"${ISO}")'"                              >> "$CHROOT_VARIABLES"
-  [ -n "$ISO" ]                 && echo "ISO='$(sed "s,','\\\\'',g" <<<"${ISO}")'"                                 >> "$CHROOT_VARIABLES"
-  [ -n "$KEEP_SRC_LIST" ]       && echo "KEEP_SRC_LIST='$(sed "s,','\\\\'',g" <<<"${KEEP_SRC_LIST}")'"             >> "$CHROOT_VARIABLES"
-  [ -n "$LOCALES" ]             && echo "LOCALES='$(sed "s,','\\\\'',g" <<<"${LOCALES}")'"                         >> "$CHROOT_VARIABLES"
-  [ -n "$MIRROR" ]              && echo "MIRROR='$(sed "s,','\\\\'',g" <<<"${MIRROR}")'"                           >> "$CHROOT_VARIABLES"
-  [ -n "$MKFS" ]                && echo "MKFS='$(sed "s,','\\\\'',g" <<<"${MKFS}")'"                               >> "$CHROOT_VARIABLES"
-  [ -n "$NOPASSWORD" ]          && echo "NOPASSWORD=\"true\""                                                      >> "$CHROOT_VARIABLES"
-  [ -n "$NOKERNEL" ]            && echo "NOKERNEL=\"true\""                                                        >> "$CHROOT_VARIABLES"
-  [ -n "$PACKAGES" ]            && echo "PACKAGES='$(sed "s,','\\\\'',g" <<<"${PACKAGES}")'"                       >> "$CHROOT_VARIABLES"
-  [ -n "$POST_SCRIPTS" ]        && echo "POST_SCRIPTS='$(sed "s,','\\\\'',g" <<<"${POST_SCRIPTS}")'"               >> "$CHROOT_VARIABLES"
-  [ -n "$PRE_SCRIPTS" ]         && echo "PRE_SCRIPTS='$(sed "s,','\\\\'',g" <<<"${PRE_SCRIPTS}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$RECONFIGURE" ]         && echo "RECONFIGURE='$(sed "s,','\\\\'',g" <<<"${RECONFIGURE}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$RELEASE" ]             && echo "RELEASE='$(sed "s,','\\\\'',g" <<<"${RELEASE}")'"                         >> "$CHROOT_VARIABLES"
-  [ -n "$RM_APTCACHE" ]         && echo "RM_APTCACHE='$(sed "s,','\\\\'',g" <<<"${RM_APTCACHE}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$ROOTPASSWORD" ]        && echo "ROOTPASSWORD='$(sed "s,','\\\\'',g" <<<"${ROOTPASSWORD}")'"               >> "$CHROOT_VARIABLES"
-  [ -n "$SCRIPTS" ]             && echo "SCRIPTS='$(sed "s,','\\\\'',g" <<<"${SCRIPTS}")'"                         >> "$CHROOT_VARIABLES"
-  [ -n "$SECURE" ]              && echo "SECURE='$(sed "s,','\\\\'',g" <<<"${SECURE}")'"                           >> "$CHROOT_VARIABLES"
-  [ -n "$SELECTED_PARTITIONS" ] && echo "SELECTED_PARTITIONS='$(sed "s,','\\\\'',g" <<<"${SELECTED_PARTITIONS}")'" >> "$CHROOT_VARIABLES"
-  [ -n "$TARGET" ]              && echo "TARGET='$(sed "s,','\\\\'',g" <<<"${TARGET}")'"                           >> "$CHROOT_VARIABLES"
-  [ -n "$UPGRADE_SYSTEM" ]      && echo "UPGRADE_SYSTEM='$(sed "s,','\\\\'',g" <<<"${UPGRADE_SYSTEM}")'"           >> "$CHROOT_VARIABLES"
-  [ -n "$TARGET_UUID" ]         && echo "TARGET_UUID='$(sed "s,','\\\\'',g" <<<"${TARGET_UUID}")'"                 >> "$CHROOT_VARIABLES"
-  [ -n "$TIMEZONE" ]            && echo "TIMEZONE='$(sed "s,','\\\\'',g" <<<"${TIMEZONE}")'"                       >> "$CHROOT_VARIABLES"
-  [ -n "$TUNE2FS" ]             && echo "TUNE2FS='$(sed "s,','\\\\'',g" <<<"${TUNE2FS}")'"                         >> "$CHROOT_VARIABLES"
-  [ -n "$VMSIZE" ]              && echo "VMSIZE='$(sed "s,','\\\\'',g" <<<"${VMSIZE}")'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$ARCH" ]                      && echo "ARCH='${ARCH//\'/\'\\\'\'}'"                                         >> "$CHROOT_VARIABLES"
+  [ -n "$BACKPORTREPOS" ]             && echo "BACKPORTREPOS='${BACKPORTREPOS//\'/\'\\\'\'}'"                       >> "$CHROOT_VARIABLES"
+  [ -n "$BOOT_APPEND" ]               && echo "BOOT_APPEND='${BOOT_APPEND//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$CHROOT_SCRIPTS" ]            && echo "CHROOT_SCRIPTS='${CHROOT_SCRIPTS//\'/\'\\\'\'}'"                     >> "$CHROOT_VARIABLES"
+  [ -n "$COMPONENTS" ]                && echo "COMPONENTS='${COMPONENTS//\'/\'\\\'\'}'"                             >> "$CHROOT_VARIABLES"
+  [ -n "$CONFFILES" ]                 && echo "CONFFILES='${CONFFILES//\'/\'\\\'\'}'"                               >> "$CHROOT_VARIABLES"
+  [ -n "$DEBCONF" ]                   && echo "DEBCONF='${DEBCONF//\'/\'\\\'\'}'"                                   >> "$CHROOT_VARIABLES"
+  [ -n "$DEBIAN_FRONTEND" ]           && echo "DEBIAN_FRONTEND='${DEBIAN_FRONTEND//\'/\'\\\'\'}'"                   >> "$CHROOT_VARIABLES"
+  [ -n "$DEBOOTSTRAP" ]               && echo "DEBOOTSTRAP='${DEBOOTSTRAP//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$DEFAULT_LOCALES" ]           && echo "DEFAULT_LOCALES='${DEFAULT_LOCALES//\'/\'\\\'\'}'"                   >> "$CHROOT_VARIABLES"
+  [ -n "$DEFAULT_LANGUAGE" ]          && echo "DEFAULT_LANGUAGE='${DEFAULT_LANGUAGE//\'/\'\\\'\'}'"                 >> "$CHROOT_VARIABLES"
+  [ -n "$EXTRAPACKAGES" ]             && echo "EXTRAPACKAGES='${EXTRAPACKAGES//\'/\'\\\'\'}'"                       >> "$CHROOT_VARIABLES"
+  [ -n "$EFI" ]                       && echo "EFI='${EFI//\'/\'\\\'\'}'"                                           >> "$CHROOT_VARIABLES"
+  [ -n "$FALLBACK_MIRROR" ]           && echo "FALLBACK_MIRROR='${FALLBACK_MIRROR//\'/\'\\\'\'}'"                   >> "$CHROOT_VARIABLES"
+  [ -n "$FILESYSTEM" ]                && echo "FILESYSTEM='${FILESYSTEM//\'/\'\\\'\'}'"                             >> "$CHROOT_VARIABLES"
+  [ -n "$FORCE" ]                     && echo "FORCE='${FORCE//\'/\'\\\'\'}'"                                       >> "$CHROOT_VARIABLES"
+  [ -n "$GRMLREPOS" ]                 && echo "GRMLREPOS='${GRMLREPOS//\'/\'\\\'\'}'"                               >> "$CHROOT_VARIABLES"
+  [ -n "$GRUB" ]                      && echo "GRUB='${GRUB//\'/\'\\\'\'}'"                                         >> "$CHROOT_VARIABLES"
+  [ -n "$HOSTNAME" ]                  && echo "HOSTNAME='${HOSTNAME//\'/\'\\\'\'}'"                                 >> "$CHROOT_VARIABLES"
+  [ -n "$INITRD" ]                    && echo "INITRD='${INITRD//\'/\'\\\'\'}'"                                     >> "$CHROOT_VARIABLES"
+  [ -n "$INITRD_GENERATOR" ]          && echo "INITRD_GENERATOR='${INITRD_GENERATOR//\'/\'\\\'\'}'"                 >> "$CHROOT_VARIABLES"
+  [ -n "$INITRD_GENERATOR_OPTS" ]     && echo "INITRD_GENERATOR_OPTS='${INITRD_GENERATOR_OPTS//\'/\'\\\'\'}'"       >> "$CHROOT_VARIABLES"
+  [ -n "$INSTALL_NOTES" ]             && echo "INSTALL_NOTES='${INSTALL_NOTES//\'/\'\\\'\'}'"                       >> "$CHROOT_VARIABLES"
+  [ -n "$ISODIR" ]                    && echo "ISODIR='${ISO//\'/\'\\\'\'}'"                                        >> "$CHROOT_VARIABLES"
+  [ -n "$ISO" ]                       && echo "ISO='${ISO//\'/\'\\\'\'}'"                                           >> "$CHROOT_VARIABLES"
+  [ -n "$KEEP_SRC_LIST" ]             && echo "KEEP_SRC_LIST='${KEEP_SRC_LIST//\'/\'\\\'\'}'"                       >> "$CHROOT_VARIABLES"
+  [ -n "$LOCALES" ]                   && echo "LOCALES='${LOCALES//\'/\'\\\'\'}'"                                   >> "$CHROOT_VARIABLES"
+  [ -n "$MIRROR" ]                    && echo "MIRROR='${MIRROR//\'/\'\\\'\'}'"                                     >> "$CHROOT_VARIABLES"
+  [ -n "$MKFS" ]                      && echo "MKFS='${MKFS//\'/\'\\\'\'}'"                                         >> "$CHROOT_VARIABLES"
+  [ -n "$NOPASSWORD" ]                && echo "NOPASSWORD=\"true\""                                                 >> "$CHROOT_VARIABLES"
+  [ -n "$NOKERNEL" ]                  && echo "NOKERNEL=\"true\""                                                   >> "$CHROOT_VARIABLES"
+  [ -n "$PACKAGES" ]                  && echo "PACKAGES='${PACKAGES//\'/\'\\\'\'}'"                                 >> "$CHROOT_VARIABLES"
+  [ -n "$POST_SCRIPTS" ]              && echo "POST_SCRIPTS='${POST_SCRIPTS//\'/\'\\\'\'}'"                         >> "$CHROOT_VARIABLES"
+  [ -n "$PRE_SCRIPTS" ]               && echo "PRE_SCRIPTS='${PRE_SCRIPTS//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$RECONFIGURE" ]               && echo "RECONFIGURE='${RECONFIGURE//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$RELEASE" ]                   && echo "RELEASE='${RELEASE//\'/\'\\\'\'}'"                                   >> "$CHROOT_VARIABLES"
+  [ -n "$RM_APTCACHE" ]               && echo "RM_APTCACHE='${RM_APTCACHE//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$ROOTPASSWORD" ]              && echo "ROOTPASSWORD='${ROOTPASSWORD//\'/\'\\\'\'}'"                         >> "$CHROOT_VARIABLES"
+  [ -n "$SCRIPTS" ]                   && echo "SCRIPTS='${SCRIPTS//\'/\'\\\'\'}'"                                   >> "$CHROOT_VARIABLES"
+  [ -n "$SECURE" ]                    && echo "SECURE='${SECURE//\'/\'\\\'\'}'"                                     >> "$CHROOT_VARIABLES"
+  [ -n "$SELECTED_PARTITIONS" ]       && echo "SELECTED_PARTITIONS='${SELECTED_PARTITIONS//\'/\'\\\'\'}'"           >> "$CHROOT_VARIABLES"
+  [ -n "$TARGET" ]                    && echo "TARGET='${TARGET//\'/\'\\\'\'}'"                                     >> "$CHROOT_VARIABLES"
+  [ -n "$UPGRADE_SYSTEM" ]            && echo "UPGRADE_SYSTEM='${UPGRADE_SYSTEM//\'/\'\\\'\'}'"                     >> "$CHROOT_VARIABLES"
+  [ -n "$TARGET_UUID" ]               && echo "TARGET_UUID='${TARGET_UUID//\'/\'\\\'\'}'"                           >> "$CHROOT_VARIABLES"
+  [ -n "$TIMEZONE" ]                  && echo "TIMEZONE='${TIMEZONE//\'/\'\\\'\'}'"                                 >> "$CHROOT_VARIABLES"
+  [ -n "$TUNE2FS" ]                   && echo "TUNE2FS='${TUNE2FS//\'/\'\\\'\'}'"                                   >> "$CHROOT_VARIABLES"
+  [ -n "$VMSIZE" ]                    && echo "VMSIZE='${VMSIZE//\'/\'\\\'\'}'"                                     >> "$CHROOT_VARIABLES"
 
   cp $VERBOSE "${CONFFILES}"/chroot-script "${MNTPOINT}"/bin/chroot-script
   chmod 755 "${MNTPOINT}"/bin/chroot-script
@@ -1699,8 +1834,14 @@ preparechroot() {
 
   # package selection:
   if [ "$PACKAGES" = 'yes' ] ; then
-    cp $VERBOSE "${_opt_packages:-$CONFFILES/packages}" \
-      "${MNTPOINT}"/etc/debootstrap/packages
+    PACKAGES_FILE="packages"
+
+    if [ "$ARCH" = 'arm64' ]; then
+      PACKAGES_FILE="packages-arm64"
+    fi
+
+    cp $VERBOSE "${_opt_packages:-$CONFFILES/$PACKAGES_FILE}" \
+      "${MNTPOINT}/etc/debootstrap/${PACKAGES_FILE}"
   fi
 
   # debconf preseeding:
@@ -1726,9 +1867,6 @@ preparechroot() {
   # setup default locales
   [ -n "$LOCALES" ] && cp $VERBOSE "${CONFFILES}"/locale.gen "${MNTPOINT}"/etc/locale.gen
 
-  # MAKEDEV is just a forking bomb crap, let's do it on our own instead :)
-  ( cd "${MNTPOINT}"/dev && tar zxf /etc/debootstrap/devices.tar.gz )
-
   # copy any existing files to chroot
   [ -d "${CONFFILES}"/bin   ] && cp $VERBOSE -a -L "${CONFFILES}"/bin/*   "${MNTPOINT}"/bin/
   [ -d "${CONFFILES}"/boot  ] && cp $VERBOSE -a -L "${CONFFILES}"/boot/*  "${MNTPOINT}"/boot/
@@ -1779,27 +1917,23 @@ iface ${interface} inet dhcp
   fi
 
   if [ -n "$NOINTERFACES" ] ; then
-    einfo "Not installing /etc/network/interfaces as requested via --nointerfaces option" ; eend 0
+    einfo "Not installing /etc/network/interfaces as requested via --nointerfaces option"
   elif [ -n "$USE_DEFAULT_INTERFACES" ] ; then
     einfo "Installing default /etc/network/interfaces as requested via --defaultinterfaces options."
     mkdir -p "${MNTPOINT}/etc/network"
     echo "$DEFAULT_INTERFACES" > "${MNTPOINT}/etc/network/interfaces"
-    eend $?
   elif [ -n "$VIRTUAL" ] ; then
     einfo "Setting up Virtual Machine, installing default /etc/network/interfaces"
     mkdir -p "${MNTPOINT}/etc/network"
     echo "$DEFAULT_INTERFACES" > "${MNTPOINT}/etc/network/interfaces"
-    eend $?
   elif [ -r /etc/network/interfaces ] ; then
     einfo "Copying /etc/network/interfaces from host to target system"
     mkdir -p "${MNTPOINT}/etc/network"
     cp $VERBOSE /etc/network/interfaces "${MNTPOINT}/etc/network/interfaces"
-    eend $?
   else
     ewarn "Couldn't read /etc/network/interfaces, installing default /etc/network/interfaces"
     mkdir -p "${MNTPOINT}/etc/network"
     echo "$DEFAULT_INTERFACES" > "${MNTPOINT}/etc/network/interfaces"
-    eend $?
   fi
 
   # install config file providing some example entries
@@ -1815,27 +1949,20 @@ iface ${interface} inet dhcp
       einfo "Use locally available public keys to authorise root login on the target system as requested via --sshcopyid option."
       mkdir -p "${MNTPOINT}"/root/.ssh
       chmod 0700 "${MNTPOINT}"/root/.ssh
-      if ssh-add -L >> "${MNTPOINT}"/root/.ssh/authorized_keys ; then
-        eend 0
-      else
+      if ! ssh-add -L >> "${MNTPOINT}"/root/.ssh/authorized_keys ; then
         eerror "Error: executing 'ssh-add -L' failed."
-        eend 1
         bailout 1
       fi
     elif [ -f "$AUTHORIZED_KEYS_SOURCE" ]; then
       einfo "copying '$AUTHORIZED_KEYS_SOURCE' to '$AUTHORIZED_KEYS_TARGET' as requested via --sshcopyid option."
       mkdir -p "$AUTHORIZED_KEYS_TARGET"
       chmod 0700 "$AUTHORIZED_KEYS_TARGET"
-      if cp "$AUTHORIZED_KEYS_SOURCE" "$AUTHORIZED_KEYS_TARGET" ; then
-        eend 0
-      else
+      if ! cp "$AUTHORIZED_KEYS_SOURCE" "$AUTHORIZED_KEYS_TARGET" ; then
         eerror "Error: copying '$AUTHORIZED_KEYS_SOURCE' to '$AUTHORIZED_KEYS_TARGET' failed"
-        eend 1
         bailout 1
       fi
     else
       eerror "Error: Could not open a connection to your authentication agent or the agent has no identities."
-      eend 1
       bailout 1
     fi
   fi
@@ -1845,18 +1972,15 @@ iface ${interface} inet dhcp
 
     if ! [ -f "${AUTHORIZED_KEYS_SOURCE}" ]; then
       eerror "Error: could not read '${AUTHORIZED_KEYS_SOURCE}' for setting up SSH key login."
-      eend 1
       bailout 1
     fi
 
     AUTHORIZED_KEYS_TARGET="${MNTPOINT}/root/.ssh/"
     einfo "Copying '${AUTHORIZED_KEYS_SOURCE}' to '${AUTHORIZED_KEYS_TARGET}' as requested via --sshcopyauth option."
-    mkdir -m 0700 -p "${AUTHORIZED_KEYS_TARGET}"
-    if cp "${AUTHORIZED_KEYS_SOURCE}" "${AUTHORIZED_KEYS_TARGET}" ; then
-      eend 0
-    else
+    mkdir -p "${AUTHORIZED_KEYS_TARGET}"
+    chmod 0700 "${AUTHORIZED_KEYS_TARGET}"
+    if ! cp "${AUTHORIZED_KEYS_SOURCE}" "${AUTHORIZED_KEYS_TARGET}" ; then
       eerror "Error: copying '${AUTHORIZED_KEYS_SOURCE}' to '${AUTHORIZED_KEYS_TARGET}' failed."
-      eend 1
       bailout 1
     fi
   fi
@@ -1865,10 +1989,7 @@ iface ${interface} inet dhcp
     einfo "Setting up bind-mount /run/udev"
     mkdir -p "${MNTPOINT}"/run/udev
     mount --bind /run/udev "${MNTPOINT}"/run/udev
-    eend $?
   fi
-
-  eend 0
 }
 # }}}
 
@@ -1885,7 +2006,7 @@ execute_pre_scripts() {
     for script in "${pre_scripts}"/* ; do
       if [ -x "$script" ] ; then
         einfo "Executing pre-script $script"
-        "$script" ; eend $?
+        "$script"
       fi
     done
   fi
@@ -1910,35 +2031,13 @@ execute_post_scripts() {
     for script in "${post_scripts}"/* ; do
       if [ -x "$script" ] ; then
         einfo "Executing post-script $script"
-        "$script" ; eend $?
+        "$script"
       fi
     done
   fi
 }
 # }}}
 
-# unmount mountpoint {{{
-try_umount() {
-  local tries=$1
-  local mountpoint="$2"
-
-  for (( try=1; try<=tries; try++ )); do
-    if [[ ${try} -eq ${tries} ]]; then
-      # Last time, show errors this time
-      umount "${mountpoint}" && return 0
-    else
-      # Not last time, hide errors until fatal
-      if umount "${mountpoint}" 2>/dev/null ; then
-        return 0
-      else
-        sleep 1
-      fi
-    fi
-  done
-  return 1  # Tried enough
-}
-# }}}
-
 # execute chroot-script {{{
 chrootscript() {
   if ! [ -r "$MNTPOINT/bin/chroot-script" ] ; then
@@ -1953,13 +2052,12 @@ chrootscript() {
     mount -t devtmpfs udev "${MNTPOINT}"/dev
     mount -t devpts devpts "${MNTPOINT}"/dev/pts
     if [ "$DEBUG" = "true" ] ; then
-      chroot "$MNTPOINT" /bin/bash -x /bin/chroot-script ; RC=$?
+      chroot "$MNTPOINT" /bin/bash -x /bin/chroot-script
     else
-      chroot "$MNTPOINT" /bin/chroot-script ; RC=$?
+      chroot "$MNTPOINT" /bin/chroot-script
     fi
     try_umount 3 "$MNTPOINT"/dev/pts
     try_umount 3 "$MNTPOINT"/dev
-    eend $RC
   fi
 
   # finally get rid of chroot-script again, there's no good reason to
@@ -1967,10 +2065,8 @@ chrootscript() {
   if grep -q GRML_CHROOT_SCRIPT_MARKER "${MNTPOINT}/bin/chroot-script" ; then
     einfo "Removing chroot-script again"
     rm -f "${MNTPOINT}/bin/chroot-script"
-    eend $?
   else
     einfo "Keeping chroot-script as string GRML_CHROOT_SCRIPT_MARKER could not be found"
-    eend 0
   fi
 }
 # }}}
@@ -1984,25 +2080,14 @@ umount_chroot() {
   fi
 
   if [ -n "$ISODIR" ] ; then
-     if grep -q "$ISODIR" /proc/mounts ; then
-        einfo "Unmount $MNTPOINT/$ISODIR"
-        umount "$MNTPOINT/$ISODIR"
-        eend $?
-     fi
+     einfo "Unmount $MNTPOINT/$ISODIR"
+     try_umount 3 "$MNTPOINT/$ISODIR"
   fi
 
-  if grep -q "$MNTPOINT" /proc/mounts ; then
-    if mountpoint "${MNTPOINT}"/run/udev &>/dev/null ; then
-      einfo "Unmounting bind-mount /run/udev"
-      umount "${MNTPOINT}"/run/udev
-      eend $?
-    fi
+  try_umount 3 "${MNTPOINT}"/run/udev
 
-     if [ -n "$PARTITION" ] ; then
-        einfo "Unmount $MNTPOINT"
-        umount "$MNTPOINT"
-        eend $?
-     fi
+  if [ -n "$PARTITION" ] ; then
+     try_umount 3 "$MNTPOINT"
   fi
 }
 # }}}
@@ -2018,7 +2103,6 @@ fscktool() {
    [ -n "$FSCKTOOL" ] || FSCKTOOL="fsck.${MKFS#mkfs.}"
    einfo "Checking filesystem on $TARGET using $FSCKTOOL"
    "$FSCKTOOL" "$TARGET"
-   eend $?
  fi
 }
 # }}}
@@ -2030,13 +2114,12 @@ remove_configs() {
   fi
 
   if ! mountpoint "${MNTPOINT}" >/dev/null 2>&1 ; then
-    ewarn "Target ${MNTPOINT} doesn't seem to be mounted, can't remove configuration files." ; eend 0
+    ewarn "Target ${MNTPOINT} doesn't seem to be mounted, can't remove configuration files."
     return 0
   fi
 
   einfo "Removing configuration files from installed system as requested via --remove-configs / REMOVE_CONFIGS."
   rm -rf "${MNTPOINT}"/etc/debootstrap/
-  eend $?
 }
 # }}}
 
@@ -2046,11 +2129,9 @@ for i in format_efi_partition prepare_vm mkfs tunefs \
          preparechroot execute_pre_scripts chrootscript execute_post_scripts \
          remove_configs umount_chroot grub_install umount_target fscktool ; do
     if stage "${i}" ; then
-      if "$i" ; then
-        stage "${i}" 'done' && rm -f "${STAGES}/${i}"
-      else
-        bailout 2 "$i"
-      fi
+      "$i"
+      stage "${i}" 'done'
+      rm -f "${STAGES}/${i}"
     fi
 done
 
@@ -2066,7 +2147,7 @@ Choose Cancel to skip rebooting." 10 60 10 ; then
      noeject noprompt reboot
   fi
 else
-   einfo "Finished execution of ${PN}. Enjoy your Debian system." ; eend 0
+   einfo "Finished execution of ${PN}. Enjoy your Debian system."
 fi
 # }}}
 
index 111ca97..457d4b4 100644 (file)
@@ -168,8 +168,9 @@ Options and environment variables
 
 *--non-free*::
 
-    Enable the 'non-free' repository in COMPONENTS. By default only
-    the 'main' repository is enabled.
+    Enable the 'non-free' repository in COMPONENTS.
+    For bookworm and newer Debian releases also the 'non-free-firmware' repository gets enabled.
+    By default only the 'main' repository is enabled.
 
 *--nopackages*::
 
@@ -217,9 +218,9 @@ Options and environment variables
 
 *-r*, *--release* _releasename_::
 
-    Specify release of new Debian system. Supported releases names: lenny,
-    squeeze, wheezy, jessie, stretch, buster, bullseye and sid. Corresponding with configuration
-    variable RELEASE. Default release: buster
+    Specify release of new Debian system. Supported releases names:
+    jessie, stretch, buster, bullseye, bookworm and sid.
+    Corresponding with configuration variable RELEASE. Default release: bookworm
 
 *--remove-configs*::
 
@@ -274,6 +275,10 @@ Options and environment variables
    qemu-img(1) for details.
    Usage example: --vmsize 3G
 
+*--vmefi*::
+
+   Create an EFI boot partition for the VM.
+
 *-V*, *--version*::
 
     Show version of program and exit.
@@ -294,7 +299,7 @@ Usage examples
 
   grml-debootstrap --target /dev/sda1 --grub /dev/sda
 
-Install default Debian release (buster) on /dev/sda1 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
+Install default Debian release (bookworm) on /dev/sda1 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
 
   grml-debootstrap --release stretch --target /dev/sda1 --grub /dev/sda --hostname debian01 --password changeme
 
@@ -307,32 +312,32 @@ Install Debian unstable/sid on /dev/sda6 and install bootmanager GRUB in MBR (ma
 
   DEBOOTSTRAP=mmdebstrap grml-debootstrap --target /dev/sda1 --grub /dev/sda
 
-Install default Debian release (buster) on /dev/sda1 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
+Install default Debian release (bookworm) on /dev/sda1 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
 Use mmdebstrap instead of default debootstrap tool for bootstrapping.
 
   grml-debootstrap --target /dev/mapper/vg0-rootfs --grub /dev/sda
 
-Install default Debian release (buster) on LVM device /dev/mapper/vg0-rootfs and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
+Install default Debian release (bookworm) on LVM device /dev/mapper/vg0-rootfs and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
 
   grml-debootstrap --efi /dev/sda1 --target /dev/sda2 --grub /dev/sda
 
-Install default Debian release (buster) on /dev/sda2 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
+Install default Debian release (bookworm) on /dev/sda2 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
 Use /dev/sda1 as EFI partition (requires EFI support in booted system).
 
   mount /dev/sda1 /data/chroot
   grml-debootstrap --target /data/chroot
 
-Install default Debian release (buster) in directory /data/chroot (without any bootloader).
+Install default Debian release (bookworm) in directory /data/chroot (without any bootloader).
 
   grml-debootstrap --target /dev/sda3 --grub /dev/sda  --mirror ftp://ftp.tugraz.at/mirror/debian
 
-Install default Debian release (buster) on /dev/sda3 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
+Install default Debian release (bookworm) on /dev/sda3 and install bootmanager GRUB in MBR (master boot record) of /dev/sda.
 Use specified mirror instead of the default (http://deb.debian.org/debian) one.
 
   mount /dev/sda1 /mnt/sda1
   grml-debootstrap --vmfile --vmsize 3G --target /mnt/sda1/qemu.img
 
-Install default debian release (buster) in a Virtual Machine file with 3GB disk size (including GRUB as bootmanager in MBR of the virtual disk file):
+Install default debian release (bookworm) in a Virtual Machine file with 3GB disk size (including GRUB as bootmanager in MBR of the virtual disk file):
 
   mount -o loop ./debian-CD-1.iso /media/cdrom
   grml-debootstrap --target /dev/sda1 --grub /dev/sda --iso /media/cdrom
@@ -404,8 +409,9 @@ Where do you want to install grub to? Usage example: grub=/dev/sda
 
   release=...
 
-Specify release of new Debian system. Defaults to Debian buster. Supported
-releases: lenny, squeeze, wheezy, jessie, stretch, buster, bullseye and sid. Usage example: release=stretch
+Specify release of new Debian system. Defaults to Debian bookworm.
+Supported releases: jessie, stretch, buster, bullseye, bookworm and sid.
+Usage example: release=bullseye
 
   mirror=...
 
@@ -439,18 +445,17 @@ Supported Releases
 include::releasetable.txt[]
 
 [NOTE]
-.lenny/squeeze/wheezy release
+.jessie/stretch/buster release
 ================================================================================
-[1] Please notice that releases like lenny, squeeze and wheezy are unsupported releases within Debian nowadays.
-grml-debootstrap can handle the releases but you really should not use them
-anymore unless you really know what you are doing.
+[1] Please notice that releases like jessie, stretch and buster are unsupported releases within Debian nowadays.
+grml-debootstrap can handle the releases but you really should not use them anymore unless you really know what you are doing.
+Even older versions are also entirely unsupported by grml-debootstrap.
+
 Choose the current Debian stable version instead.
 See https://wiki.debian.org/DebianReleases for the list of supported releases.
 
-Notice that you need to specify a mirror providing the lenny and squeeze releases, the
-default (http://deb.debian.org/debian) doesn't provide it any longer nowadays.
-Set the mirror to e.g. http://archive.debian.org/debian/ if you don't have
-your own lenny/squeeze mirror.
+Notice that you need to specify a specific mirror providing old releases, the default (http://deb.debian.org/debian) doesn't provide them any longer.
+Set the mirror to e.g. http://archive.debian.org/debian/ if you don't have your own Debian mirror.
 
 Older releases might also fail to install when running on top of recent kernel versions,
 throwing segfaults during debootstrap. This can be identified by the following messages inside kernel log (check with 'dmesg'):
@@ -459,26 +464,6 @@ throwing segfaults during debootstrap. This can be identified by the following m
    dpkg[...]: segfault at [...]
 
 To work around this issue boot your system with the kernel boot option 'vsyscall=emulate'.
-
-You also need to specify a filesystem that's supported by lenny, e.g.
-'--filesystem ext3' since grml-debootstrap's current default (ext4) isn't
-supported by lenny.
-
-Also when debootstrapping lenny on a live system with a kernel version
-like "3.16-1-grml-amd64" lenny's libc will fail to install with:
-
-   [...]
-   /var/lib/dpkg/tmp.ci/preinst: line 265: [: 3.16-1-grml-amd64: integery expression expected
-   /var/lib/dpkg/tmp.ci/preinst: line 231: 3.16-1-grml-amd64: syntax error: invalid arithemtic operator (error token is ".16-1-grml-amd64")
-   dpkg: error processing /var/cache/apt/archives/libc6_2.7-18lenny7_amd64.deb (--install):
-   [....]
-
-To workaround this either debootstrap from a system with an according
-kernel version or use the "fake uname" workaround (just google for it).
-
-When installing lenny to a new mdraid, grml-debootstrap will use md metadata
-format version 0.90. This limits the device to a maximum size of 2TB, but has
-the advantage of grub-legacy actually being able to boot from it.
 ================================================================================
 
 [NOTE]
index 6a06f85..c961a81 100644 (file)
--- a/packages
+++ b/packages
@@ -4,10 +4,10 @@ bzip2
 console-common
 console-data
 cryptsetup
+dbus
 file
 grub-pc
 ifenslave
-initramfs-tools
 isc-dhcp-client
 less
 locales
@@ -16,7 +16,6 @@ lsof
 lvm2
 mdadm
 most
-os-prober
 pciutils
 postfix
 resolvconf
diff --git a/packages-arm64 b/packages-arm64
new file mode 100644 (file)
index 0000000..f69c849
--- /dev/null
@@ -0,0 +1,31 @@
+acpi-support-base
+bridge-utils
+bzip2
+console-common
+console-data
+cryptsetup
+dbus
+file
+grub2-common
+grub-efi-arm64
+ifenslave
+isc-dhcp-client
+less
+locales
+lsb-release
+lsof
+lvm2
+mdadm
+most
+pciutils
+postfix
+resolvconf
+rsync
+screen
+ssh
+strace
+usbutils
+vim
+vlan
+w3m
+zsh
index 6a94be0..8a79a1e 100644 (file)
@@ -1,43 +1,49 @@
 GRML_DEBOOTSTRAP_VERSION=latest
 GRML_DEBOOTSTRAP_LOCAL_PATH=$(shell pwd)/local_dir
 
-compile: fake-uname.so
+CFLAGS ?= -ggdb -O2 -Wall -Wextra -Wno-unused-parameter
+CFLAGS += -fPIC -fvisibility=hidden
+LDLIBS ?=
+LDLIBS += -ldl
+
+PLUGIN = fake-uname.so
+
+$(PLUGIN): fake-uname.c
+       $(CC) $(CFLAGS) $(LDFLAGS) $< $(LDLIBS) -o $@ -shared
+
+UNAME_CHECK = LD_PRELOAD="$(CURDIR)/$(PLUGIN)" uname
+
+check: $(PLUGIN)
+       echo "$(UNAME_CHECK)"
+       test "0.0.0" = "$(shell $(UNAME_CHECK) -r)"
+       test "1.2.3" = "$(shell UTS_RELEASE="1.2.3" $(UNAME_CHECK) -r)"
 
 install:
        cd .. && make DESTDIR=packer/local_dir install
 
 clean:
+       $(RM) *.o *.so
        rm -rf local_dir
 
-fake-uname.so:
-       gcc -shared -fPIC -ldl fake-uname.c -o fake-uname.so
+# Debian 12
+bookworm: clean fake-uname.so install
+       packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 11
-bullseye: fake-uname.so clean install
+bullseye: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 10
-buster: fake-uname.so clean install
+buster: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 9
-stretch: fake-uname.so clean install
+stretch: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
 # Debian 8
-jessie: fake-uname.so clean install
-       packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
-
-# Debian 7
-wheezy: fake-uname.so clean install
-       packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
-
-# Debian 6.0
-squeeze: fake-uname.so clean install
-       packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
-
-# Debian 5.0
-lenny: fake-uname.so clean install
+jessie: clean fake-uname.so install
        packer build -var debian_version=$@ -var grml_debootstrap_version=$(GRML_DEBOOTSTRAP_VERSION) -var grml_debootstrap_local_path=$(GRML_DEBOOTSTRAP_LOCAL_PATH) debian64.json
 
-.PHONY: compile bullseye buster stretch jessie wheezy squeeze lenny
+.PHONY: compile bullseye buster stretch jessie
+.NOTPARALLEL:
index d5aca59..3e5818c 100644 (file)
@@ -17,7 +17,7 @@ teardown() {
 @test "debian_version exists and is valid version" {
   run cat "${mountpath}/etc/debian_version"
   [ "$status" -eq 0 ]
-  [[ "$output" == [0-9]*.[0-9]* ]] || [[ "$output" == 'bullseye/sid' ]]
+  [[ "$output" == [0-9]*.[0-9]* ]] || [[ "$output" == 'bookworm/sid' ]]
 }
 
 @test "kernel exists" {
@@ -75,7 +75,7 @@ teardown() {
   [ "$status" -eq 0 ]
 }
 
-@test "home directory for user vagrant" {
+@test "ssh key for user vagrant" {
   run grep -q ssh-rsa "$mountpath"/home/vagrant/.ssh/authorized_keys
   [ "$status" -eq 0 ]
 }
index 1e684a1..007b8d4 100644 (file)
@@ -1,78 +1,82 @@
 {
-  "variables": {
-    "grml_type": "grml64-full",
-    "grml_version": "2020.06-rc1",
-    "grml_iso_checksum": "b28b54e55fc5fe1569e0201e918da49be0885646",
-    "debian_version": "buster",
-    "grml_debootstrap_version": "latest",
-    "grml_debootstrap_local_path": "doesnotexist"
-  },
-
   "builders": [
-  {
-    "type": "virtualbox-iso",
-    "vm_name": "{{ user `grml_type` }}_{{ user `grml_version` }}",
-    "guest_os_type": "Debian_64",
-    "hard_drive_interface": "sata",
-    "iso_url": "http://download.grml.org/devel/{{ user `grml_type` }}_{{ user `grml_version` }}.iso",
-    "iso_checksum": "{{ user `grml_iso_checksum` }}",
-    "iso_checksum_type": "sha1",
-    "ssh_wait_timeout": "20m",
-    "ssh_username": "root",
-    "ssh_password": "grml",
-    "output_directory": "{{ user `grml_type` }}_output",
-    "headless": false,
-    "boot_wait": "5s",
-    "boot_command": [
-      "<tab> ssh=grml <enter>"
-    ],
-    "shutdown_command": "shutdown -h now",
-    "guest_additions_url": "https://download.virtualbox.org/virtualbox/6.1.10/VBoxGuestAdditions_6.1.10.iso",
-    "guest_additions_sha256": "62a0c6715bee164817a6f58858dec1d60f01fd0ae00a377a75bbf885ddbd0a61",
-    "vboxmanage": [
-      ["modifyvm", "{{.Name}}", "--memory", "1024"]
-    ]
-  }
+    {
+      "boot_command": [
+        "<tab> ssh=grml <enter>"
+      ],
+      "boot_wait": "5s",
+      "guest_additions_sha256": "bffc316a7b8d5ed56d830e9f6aef02b4e5ffc28674032142e96ffbedd905f8c9",
+      "guest_additions_url": "https://download.virtualbox.org/virtualbox/6.1.22/VBoxGuestAdditions_6.1.22.iso",
+      "guest_os_type": "Debian_64",
+      "hard_drive_interface": "sata",
+      "headless": false,
+      "iso_checksum": "sha1:{{ user `grml_iso_checksum` }}",
+      "iso_url": "http://download.grml.org/{{ user `grml_type` }}_{{ user `grml_version` }}.iso",
+      "output_directory": "{{ user `grml_type` }}_output",
+      "shutdown_command": "shutdown -h now",
+      "ssh_password": "grml",
+      "ssh_timeout": "20m",
+      "ssh_username": "root",
+      "type": "virtualbox-iso",
+      "vboxmanage": [
+        [
+          "modifyvm",
+          "{{.Name}}",
+          "--memory",
+          "1024"
+        ]
+      ],
+      "vm_name": "{{ user `grml_type` }}_{{ user `grml_version` }}"
+    }
+  ],
+  "post-processors": [
+    {
+      "override": {
+        "virtualbox": {
+          "output": "debian64_{{ user `debian_version` }}.box"
+        }
+      },
+      "type": "vagrant"
+    }
   ],
-    "provisioners": [
+  "provisioners": [
     {
-      "type": "file",
+      "destination": "/tmp/fake-uname.so",
       "source": "fake-uname.so",
-      "destination": "/tmp/fake-uname.so"
+      "type": "file"
     },
     {
-      "type": "file",
+      "destination": "/tmp/debian64.bats",
       "source": "debian64.bats",
-      "destination": "/tmp/debian64.bats"
+      "type": "file"
     },
     {
-      "type": "shell",
-      "inline": "mkdir -vp /tmp/grml-debootstrap/"
+      "inline": "mkdir -vp /tmp/grml-debootstrap/",
+      "type": "shell"
     },
     {
-      "type": "file",
+      "destination": "/tmp/grml-debootstrap/",
       "source": "{{ user `grml_debootstrap_local_path` }}/",
-      "destination": "/tmp/grml-debootstrap/"
+      "type": "file"
     },
     {
-      "type": "shell",
       "environment_vars": [
-       "GRML_DEBOOTSTRAP_VERSION={{ user `grml_debootstrap_version` }}",
-       "DEBIAN_VERSION={{ user `debian_version` }}"
+        "GRML_DEBOOTSTRAP_VERSION={{ user `grml_debootstrap_version` }}",
+        "DEBIAN_VERSION={{ user `debian_version` }}"
       ],
       "scripts": [
         "debian64_provision.sh"
-        ]
+      ],
+      "type": "shell"
     }
   ],
-    "post-processors": [
-    {
-      "type": "vagrant",
-      "override": {
-        "virtualbox": {
-          "output": "debian64_{{ user `debian_version` }}.box"
-        }
-      }
-    }
-  ]
+  "variables": {
+    "debian_version": "bookworm",
+    "grml_debootstrap_local_path": "doesnotexist",
+    "grml_debootstrap_version": "latest",
+    "grml_iso_checksum": "ac071ab44592568b05635ccdd881da4f2a90c3a8",
+    "grml_type": "grml64-full",
+    "grml_version": "2022.11"
+  }
 }
+
index 2a416de..480df1c 100644 (file)
@@ -32,13 +32,6 @@ trap 'bailout ${LINENO} $?' ERR
 
 ## helper functions
 virtualbox_setup() {
-  case "$DEBIAN_VERSION" in
-    lenny)
-      echo "* Debian lenny doesn't support Virtualbox Guest Additions, skipping."
-      return 0
-      ;;
-  esac
-
   if ! mountpoint "${TARGET}" &>/dev/null ; then
     echo "* Mounting target system"
     mount "${INSTALL_TARGET}" "${TARGET}"
@@ -115,12 +108,8 @@ vagrant_setup() {
   chroot ${TARGET} chown vagrant:vagrant /home/vagrant/.ssh /home/vagrant/.ssh/authorized_keys
 
   echo "* Setting up sudo configuration for user vagrant"
-  if ! [ -d "${TARGET}/etc/sudoers.d" ] ; then # lenny:
-    echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> "${TARGET}/etc/sudoers"
-  else # wheezy and newer:
-    echo "vagrant ALL=(ALL) NOPASSWD: ALL" > "${TARGET}/etc/sudoers.d/vagrant"
-    chmod 0440 "${TARGET}/etc/sudoers.d/vagrant"
-  fi
+  echo "vagrant ALL=(ALL) NOPASSWD: ALL" > "${TARGET}/etc/sudoers.d/vagrant"
+  chmod 0440 "${TARGET}/etc/sudoers.d/vagrant"
 
   host="$(cat ${TARGET}/etc/hostname)"
   if ! grep -q "${host}$" "${TARGET}"/etc/hosts ; then
@@ -188,7 +177,7 @@ EOF
   elif [ "$GRML_DEBOOTSTRAP_VERSION" = "git" ] ; then
     echo "** GRML_DEBOOTSTRAP_VERSION is set to '$GRML_DEBOOTSTRAP_VERSION'"
     echo "** Using grml-debootstrap from Git repository"
-    git clone git://git.grml.org/grml-debootstrap.git
+    git clone https://github.com/grml/grml-debootstrap.git
     cd grml-debootstrap
     GRML_DEBOOTSTRAP="CONFFILES=$(pwd) $(pwd)/grml-debootstrap"
   elif [ "$GRML_DEBOOTSTRAP_VERSION" = "local" ] ; then
@@ -203,30 +192,9 @@ EOF
   fi
 }
 
-verify_debootstrap_version() {
-  local required_version=1.0.65
-  local present_version=$(dpkg-query --show --showformat='${Version}' debootstrap)
-
-  if dpkg --compare-versions $present_version lt $required_version ; then
-    echo "** debootstrap version $present_version is older than minimum required version $required_version - upgrading."
-    apt-get update
-    apt-get -y install debootstrap
-  fi
-}
-
 grml_debootstrap_execution() {
   echo "* Installing Debian"
 
-  # release specific stuff
-  case "$DEBIAN_VERSION" in
-    lenny)
-      GRML_DEB_OPTIONS="--mirror http://archive.debian.org/debian/ --filesystem ext3"
-      ;;
-    stretch)
-      verify_debootstrap_version
-      ;;
-  esac
-
   echo "** Executing: $GRML_DEBOOTSTRAP --hostname $DEBIAN_VERSION --release $DEBIAN_VERSION --target ${INSTALL_TARGET} --grub ${GRUB_TARGET} --password grml --force $GRML_DEB_OPTIONS" | tee -a /tmp/grml-debootstrap.log
   $GRML_DEBOOTSTRAP --hostname "${DEBIAN_VERSION}" --release "${DEBIAN_VERSION}" --target "${INSTALL_TARGET}" --grub "${GRUB_TARGET}" --password grml --force $GRML_DEB_OPTIONS 2>&1 | tee -a /tmp/grml-debootstrap.log
 }
@@ -234,7 +202,7 @@ grml_debootstrap_execution() {
 apply_nic_workaround() {
   # release specific stuff
   case "$DEBIAN_VERSION" in
-    stretch|buster|bullseye|unstable|sid)
+    stretch|buster|bullseye|bookworm|unstable|sid)
       ;;
     *)
       echo "* Debian $DEBIAN_VERSION doesn't require NIC workaround"
index 7bbcb24..d71a4f4 100644 (file)
 #define RTLD_NEXT      ((void *) -1l)
 #endif
 
-typedef int (*uname_t) (struct utsname * buf);
+#define SYMBOL_EXPORT __attribute__((visibility("default")))
+
+typedef int uname_func(struct utsname *buf);
 
 static void *get_libc_func(const char *funcname)
 {
   void *func;
   char *error;
 
+  /* Clear any previous errors. */
+  dlerror();
   func = dlsym(RTLD_NEXT, funcname);
-  if ((error = dlerror()) != NULL) {
-    fprintf(stderr, "Can't locate libc function `%s' error: %s", funcname, error);
+  error = dlerror();
+  if (error != NULL) {
+    fprintf(stderr, "Cannot locate libc function '%s' error: %s",
+            funcname, error);
     _exit(EXIT_FAILURE);
   }
   return func;
 }
 
-int uname(struct utsname *buf)
+int SYMBOL_EXPORT uname(struct utsname *buf)
 {
+  static uname_func *real_uname;
+  const char *release;
   int ret;
-  char *env = NULL;
-  uname_t real_uname = (uname_t) get_libc_func("uname");
 
-  ret = real_uname((struct utsname *) buf);
-  strncpy(buf->release, ((env = getenv("UTS_RELEASE")) == NULL) ? UTS_RELEASE : env, 65);
+  if (real_uname == NULL)
+    real_uname = (uname_func *)get_libc_func("uname");
+
+  ret = real_uname(buf);
+  if (ret < 0)
+    return ret;
+
+  release = getenv("UTS_RELEASE");
+  if (release == NULL)
+    release = UTS_RELEASE;
+  strncpy(buf->release, release, sizeof(buf->release) - 1);
+  buf->release[sizeof(buf->release) - 1] = '\0';
+
   return ret;
 }
index d3f0316..d085c86 100644 (file)
@@ -2,12 +2,10 @@
 [width="40%",frame="topbot",options="header"]
 |======================
 |Release  |Status
-|lenny    |works[1]
-|squeeze  |works[1]
-|wheezy   |works[1]
-|jessie   |works
-|stretch  |works
-|buster   |works
-|bullseye |works[2]
+|jessie   |works[1]
+|stretch  |works[1]
+|buster   |works[1]
+|bullseye |works
+|bookworm |works
 |sid      |works[2]
 |======================
diff --git a/tests/build-vm-and-test.sh b/tests/build-vm-and-test.sh
new file mode 100755 (executable)
index 0000000..53076ac
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Install an already built grml-debootstrap.deb in docker and use it to
+# build a test VM image. Then run this VM image in qemu and check if it
+# boots.
+
+set -eu -o pipefail
+
+usage() {
+  echo "Usage: $0 setup"
+  echo " then: $0 run"
+  echo " then: $0 test"
+  echo "WARNING: $0 is potentially dangerous and may destroy the host system and/or any data."
+  exit 0
+}
+
+if [ "${1:-}" == "--help" ] || [ "${1:-}" == "help" ]; then
+  usage
+fi
+
+if [ -z "${1:-}" ]; then
+  echo "$0: unknown parameters, see --help" >&2
+  exit 1
+fi
+
+set -x
+
+if [ ! -d ./tests ]; then
+  echo "$0: Started from incorrect working directory" >&2
+  exit 1
+fi
+
+if [ "$1" == "setup" ]; then
+  [ -x ./tests/goss ] || curl -fsSL https://goss.rocks/install | GOSS_DST="$(pwd)/tests" sh
+  sudo apt-get update
+  sudo apt-get -qq -y install qemu-system-x86 kpartx python3-pexpect python3-serial
+  # TODO: docker.io
+  exit 0
+fi
+
+# Debian version to install using grml-debootstrap
+RELEASE="${RELEASE:-bookworm}"
+
+TARGET="${TARGET:-qemu.img}"
+
+# debootstrap to use, default empty (let grml-debootstrap decide)
+DEBOOTSTRAP="${DEBOOTSTRAP:-}"
+
+if [ "$1" == "run" ]; then
+  # Debian version on which grml-debootstrap will *run*
+  HOST_RELEASE="${HOST_RELEASE:-bookworm}"
+
+  DEB_NAME=$(ls ./grml-debootstrap*.deb || true)
+  if [ -z "$DEB_NAME" ]; then
+    echo "$0: No grml-debootstrap*.deb found, aborting" >&2
+    exit 1
+  fi
+
+  # we need to run in privileged mode to be able to use loop devices
+  exec docker run --privileged --rm -i \
+    -v "$(pwd)":/code \
+    -e TERM="$TERM" \
+    -e DEBOOTSTRAP="$DEBOOTSTRAP" \
+    -w /code \
+    debian:"$HOST_RELEASE" \
+    bash -c './tests/docker-install-deb.sh '"$DEB_NAME"' && ./tests/docker-build-vm.sh '"$(id -u)"' '"/code/$TARGET"' '"$RELEASE"
+
+elif [ "$1" == "test" ]; then
+  # run tests from inside Debian system
+  exec ./tests/test-vm.sh "$PWD/$TARGET" "$RELEASE"
+
+else
+  echo "$0: unknown parameters, see --help" >&2
+  exit 1
+fi
+
+# EOF
diff --git a/tests/docker-build-deb.sh b/tests/docker-build-deb.sh
new file mode 100755 (executable)
index 0000000..4320c82
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Build a grml-debootstrap.deb.
+# To be run inside docker, as this script assumes it can modify the running OS.
+
+set -eu -o pipefail
+set -x
+
+if [ "${1:-}" != "--autobuild" ]; then
+  echo "$0: Only intended for CI scenarios, will destroy source files and modify running OS." >&2
+  exit 1
+fi
+BUILD_NUMBER="${2:-}"
+if [ -z "$BUILD_NUMBER" ]; then
+  echo "$0: missing build number in arguments" >&2
+  exit 1
+fi
+
+apt-get update
+apt-get install -qq -y --no-install-recommends build-essential devscripts equivs
+
+SOURCEDIR=$PWD
+
+cd /tmp
+mk-build-deps -ir -t 'apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y' "$SOURCEDIR"/debian/control
+
+dpkg-source -b "$SOURCEDIR"
+dpkg-source -x ./*.dsc builddir
+cd builddir
+
+OLD_VERSION=$(dpkg-parsechangelog -SVersion)
+
+cat > debian/changelog <<EOT
+grml-debootstrap (${OLD_VERSION}+autobuild${BUILD_NUMBER}) UNRELEASED; urgency=medium
+
+  * Automated Build
+
+ -- Automated Build <builder@localhost>  $(date -R)
+EOT
+
+dpkg-buildpackage -b --no-sign
+
+mv ../*deb "$SOURCEDIR"/
diff --git a/tests/docker-build-vm.sh b/tests/docker-build-vm.sh
new file mode 100755 (executable)
index 0000000..4b73dbc
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Use an already installed grml-debootstrap to build a VM image, then
+# run it in qemu. Installs goss inside the VM.
+
+set -eu -o pipefail
+
+if [ "$#" -ne 3 ]; then
+  echo "$0: Invalid arguments" >&2
+  echo "Expect: $0 HOST_UID TARGET RELEASE" >&2
+  exit 1
+fi
+HOST_UID="$1"
+TARGET="$2"
+RELEASE="$3"
+
+if [ -n "${DEBOOTSTRAP:-}" ] && [ "${DEBOOTSTRAP:-}" != "debootstrap" ]; then
+  apt-get install -qq -y "${DEBOOTSTRAP}"
+fi
+
+set -x
+
+case "${RELEASE:-}" in
+  stretch)
+    MIRROR='http://archive.debian.org/debian'
+    EXTRAOPT=--debopt=--no-check-gpg
+  ;;
+  *)
+    MIRROR='http://deb.debian.org/debian'
+    EXTRAOPT=''
+  ;;
+esac
+
+
+echo " ****************************************************************** "
+echo " * Running grml-debootstrap"
+
+grml-debootstrap \
+  --debug \
+  --force \
+  --vmfile \
+  --vmsize 3G \
+  --target "$TARGET" \
+  --bootappend "console=ttyS0,115200 console=tty0 vga=791" \
+  --password grml \
+  --release  "$RELEASE" \
+  --hostname "$RELEASE" \
+  --mirror "$MIRROR" \
+  $EXTRAOPT
+
+chown "$HOST_UID" "$TARGET"
diff --git a/tests/docker-install-deb.sh b/tests/docker-install-deb.sh
new file mode 100755 (executable)
index 0000000..b056952
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Install an already built grml-debootstrap.deb.
+# Wrapper around apt-get install for usage inside docker.
+
+set -eu -o pipefail
+
+if [ "$#" -ne 1 ]; then
+  echo "$0: Invalid arguments" >&2
+  echo "Expect: $0 DEB_NAME" >&2
+  exit 1
+fi
+DEB_NAME="$1"
+
+apt-get update
+# docker images can be relatively old, especially for unstable.
+apt-get upgrade -qq -y
+apt-get install -qq -y "$DEB_NAME"
diff --git a/tests/gha-build-deb.sh b/tests/gha-build-deb.sh
new file mode 100755 (executable)
index 0000000..a031c96
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Entrypoint for GitHub Actions to build a grml-debootstrap.deb.
+
+set -eu -o pipefail
+set -x
+
+if [ -z "${CI:-}" ] || [ -z "${GITHUB_RUN_NUMBER:-}" ]; then
+  echo "Running outside of CI pipeline." >&2
+  exit 1
+fi
+
+docker run --privileged -v "$(pwd)":/code --rm -i debian:"$HOST_RELEASE" \
+    bash -c 'TERM='"$TERM"' cd /code && ./tests/docker-build-deb.sh --autobuild '"$GITHUB_RUN_NUMBER"
similarity index 67%
rename from travis/goss.yaml
rename to tests/goss.yaml
index 97b75d8..fdf8316 100644 (file)
@@ -1,6 +1,7 @@
 process:
   sshd:
     running: true
+
 file:
   /etc/timezone:
     exists: true
@@ -9,3 +10,9 @@ file:
     filetype: symlink
     exists: true
     linked-to: /usr/share/zoneinfo/Europe/Vienna
+
+  # shadow passwords are enabled.
+  /etc/shadow:
+    exists: true
+  /etc/gshadow:
+    exists: true
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
deleted file mode 100755 (executable)
index 570291c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-# Filename:      run_tests
-# Purpose:       run unit tests for grml-autoconfig
-# Authors:       grml-team (grml.org), (c) Ulrich Dangel <mru@grml.org>
-# Bug-Reports:   see https://grml.org/bugs/
-# License:       This file is licensed under the GPL v2.
-################################################################################
-
-
-GLOBRETVAL=0
-
-for FILE in test_*.sh ; do
-  if [ -x "${FILE}" ] ; then
-     pretty_name="${FILE##test_}"
-     pretty_name="${pretty_name/.sh/}"
-
-     echo "Running test for: ${pretty_name}"
-
-     ./"${FILE}"
-     RETVAL=$?
-
-     [ "$RETVAL" -ne 0 ] && GLOBRETVAL=$RETVAL
-  fi
-done
-
-exit $GLOBRETVAL
-
-## END OF FILE #################################################################
-# vim:foldmethod=marker expandtab ai ft=zsh shiftwidth=2
diff --git a/tests/serial-console-connection b/tests/serial-console-connection
new file mode 100755 (executable)
index 0000000..97c623b
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+import argparse
+import pexpect
+import serial
+import sys
+import time
+from pexpect import fdpexpect, TIMEOUT
+
+parser = argparse.ArgumentParser(description='Connect to serial console ' +
+                                 'to execute stuff')
+parser.add_argument('--port', required=True,
+                    help='serial console device to connect ' +
+                    'to (e.g. /dev/pts/X)')
+parser.add_argument('--hostname', default="buster",
+                    help='hostname of the system for login process ' +
+                    '(default: buster)')
+parser.add_argument('--user', default="root",
+                    help='user name to use for login (default: root)')
+parser.add_argument('--password', default="grml",
+                    help='password for login (default: grml)')
+parser.add_argument('--tries', default="12", type=int,
+                    help='Number of retries for finding the login prompt')
+parser.add_argument('--poweroff', action="store_true", default=False,
+                    help='send "poweroff" command after all other commands')
+parser.add_argument('command', nargs='+',
+                    help='command to execute after logging in')
+
+
+
+def print_ser_lines(ser):
+    for line in ser.readlines():
+        print("<<", line)  # line will be a binary string
+
+
+def write_ser_line(ser, text):
+    print(">>", text)
+    ser.write(("%s\n" % text).encode())
+    ser.flush()
+
+
+def login(ser, hostname, user, password, timeout=5):
+
+    child = fdpexpect.fdspawn(ser.fileno())
+    child.sendline("\n")
+
+    try:
+        child.expect("%s@%s" % (user, hostname), timeout=timeout)
+        return
+    except:
+        pass
+
+    print("Waiting for login prompt...")
+    child.expect("%s login:" % hostname, timeout=timeout)
+    print("Logging in...")
+    write_ser_line(ser, user)
+    time.sleep(1)
+    write_ser_line(ser, password)
+    time.sleep(1)
+
+    print("Waiting for shell prompt...")
+    child.expect("%s@%s" % (user, hostname), timeout=timeout)
+
+
+def main():
+    args = parser.parse_args()
+    hostname = args.hostname
+    password = args.password
+    port = args.port
+    user = args.user
+    commands = args.command
+
+    ser = serial.Serial(port, 115200)
+    ser.flushInput()
+    ser.flushOutput()
+
+    success = False
+    for i in range(args.tries):
+        try:
+            print("Logging into %s via serial console [try %s]" % (port, i))
+            login(ser, hostname, user, password)
+            success = True
+            break
+        except Exception as except_inst:
+            print("Login failure (try %s):" % (i, ), except_inst, file=sys.stderr)
+            time.sleep(5)
+
+    if success:
+        write_ser_line(ser, "")
+        ser.timeout = 5
+        print_ser_lines(ser)
+        print("Running commands...")
+        for command in commands:
+            write_ser_line(ser, command)
+            print_ser_lines(ser)
+        if args.poweroff:
+            print("Sending final poweroff command...")
+            write_ser_line(ser, "poweroff")
+            ser.flush()
+            # after poweroff, the serial device will probably vanish. do not attempt reading from it anymore.
+
+    if not success:
+        sys.exit(1)
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/shellcheck-stub-debootstrap-variables b/tests/shellcheck-stub-debootstrap-variables
new file mode 100644 (file)
index 0000000..8fd7606
--- /dev/null
@@ -0,0 +1,7 @@
+# Stub data file for shellcheck runs.
+# shellcheck shell=sh
+# shellcheck disable=SC2034  # The point of our whole existence is to conflict with SC2034.
+
+# ARCH is defaulted in grml-debootstrap, so it is never empty.
+ARCH=amd64
+
diff --git a/tests/test-vm.sh b/tests/test-vm.sh
new file mode 100755 (executable)
index 0000000..85e46c5
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Run previously built VM image in qemu and check if it boots.
+# Requires virtiofs support in VM.
+
+set -eu -o pipefail
+
+if [ "$#" -ne 2 ]; then
+  echo "$0: Invalid arguments" >&2
+  echo "Expect: $0 VM_IMAGE VM_HOSTNAME" >&2
+  exit 1
+fi
+set -x
+
+VM_IMAGE="$1"
+VM_HOSTNAME="$2"
+
+TEST_PWD="$PWD"
+TEST_TMPDIR=$(mktemp -d)
+TESTS_RESULTSDIR="$PWD/tests/results"
+echo "Working in $TEST_TMPDIR, writing results to $TESTS_RESULTSDIR"
+mkdir -p "$TESTS_RESULTSDIR"
+
+bailout() {
+  if [ -n "${QEMU_PID:-}" ] ; then
+    # shellcheck disable=SC2009
+    ps --pid="${QEMU_PID}" -o pid= | grep -q '.' && kill "${QEMU_PID:-}"
+  fi
+
+  rm -rf "${TEST_TMPDIR}"
+
+  [ -n "${1:-}" ] && EXIT_CODE="$1" || EXIT_CODE=1
+  exit "$EXIT_CODE"
+}
+trap bailout 1 2 3 6 14 15
+
+# Setup test runner
+cp ./tests/goss "$TEST_TMPDIR"/
+cp ./tests/goss.yaml "$TEST_TMPDIR"/
+cat <<EOT > "$TEST_TMPDIR"/testrunner
+#!/bin/bash
+# Do not set -eu, we want to continue even if individual commands fail.
+set -x
+echo "INSIDE_VM $0 running"
+mkdir results
+
+# Collect information from VM first
+lsb_release -a > results/lsb_release.txt
+uname -a > results/uname-a.txt
+systemctl list-units > results/systemctl_list-units.txt
+systemctl status > results/systemctl_status.txt
+fdisk -l > results/fdisk-l.txt
+hostname -f > results/hostname-f.txt 2>&1
+journalctl -b > results/journalctl-b.txt
+dpkg -l > results/dpkg-l.txt
+
+# Run tests
+./goss --gossfile goss.yaml validate --format tap > results/goss.tap
+# Detection of testrunner success hinges on goss.exitcode file.
+echo \$? > results/goss.exitcode
+
+echo "INSIDE_VM $0 finished"
+EOT
+chmod a+rx "$TEST_TMPDIR"/testrunner
+
+cd "$TEST_TMPDIR"
+
+MOUNT_TAG=host0
+qemu-system-x86_64 -hda "${VM_IMAGE}" -m 2048 \
+                   -display none -vnc :0 \
+                   -virtfs local,path="$TEST_TMPDIR",mount_tag="$MOUNT_TAG",security_model=none,id=host0 \
+                   -serial pty &>qemu.log &
+QEMU_PID="$!"
+
+timeout=30
+success=0
+while [ "$timeout" -gt 0 ] ; do
+  ((timeout--))
+  if grep -q 'char device redirected to ' qemu.log ; then
+    success=1
+    sleep 1
+    break
+  else
+    echo "No serial console from Qemu found yet [$timeout retries left]"
+    sleep 1
+  fi
+done
+
+if [ "$success" = "1" ] ; then
+  serial_port=$(awk '/char device redirected/ {print $5}' qemu.log)
+else
+  echo "Error: Failed to identify serial console port." >&2
+  cat qemu.log
+  exit 1
+fi
+
+timeout=30
+success=0
+while [ "$timeout" -gt 0 ] ; do
+  ((timeout--))
+  if [ -c "$serial_port" ] ; then
+    success=1
+    sleep 1
+    break
+  else
+    echo "No block device for serial console found yet [$timeout retries left]"
+    sleep 1
+  fi
+done
+
+if [ "$success" = "0" ] ; then
+  echo "Error: can't access serial console block device." >&2
+  exit 1
+fi
+
+"$TEST_PWD"/tests/serial-console-connection \
+  --tries 180 \
+  --port "$serial_port" \
+  --hostname "$VM_HOSTNAME" \
+  --poweroff \
+  "mount -t 9p -o trans=virtio,version=9p2000.L,rw $MOUNT_TAG /mnt && cd /mnt && ./testrunner"
+
+if [ ! -d results ] || [ ! -f ./results/goss.tap ] || [ ! -f ./results/goss.exitcode ]; then
+  echo "Running tests inside VM failed for unknown reason" >&2
+  RC=1
+else
+  RC=$(cat results/goss.exitcode)
+  echo "goss exitcode: $RC"
+
+  cat results/goss.tap
+fi
+
+echo "Finished serial console connection [timeout=${timeout}]."
+
+mv results/* "$TESTS_RESULTSDIR/"
+
+bailout $RC
+
+# EOF
diff --git a/travis/build-vm.sh b/travis/build-vm.sh
deleted file mode 100755 (executable)
index 217813b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-set -eu -o pipefail
-
-TARGET="${TARGET:-/code/qemu.img}"
-RELEASE="${RELEASE:-buster}"
-
-cd "$(dirname "$TARGET")"
-apt update
-apt -y install ./grml-debootstrap*.deb
-
-grml-debootstrap \
-  --force \
-  --vmfile \
-  --vmsize 3G \
-  --target "$TARGET" \
-  --bootappend "console=ttyS0,115200 console=tty0 vga=791" \
-  --password grml \
-  --release  "$RELEASE" \
-  --hostname "$RELEASE" \
-  # EOF
diff --git a/travis/execute.sh b/travis/execute.sh
deleted file mode 100755 (executable)
index 5b4f47a..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/bin/bash
-
-set -eu -o pipefail
-set -x
-
-if [ -z "${TRAVIS:-}" ] ; then
-  echo "Running outside of Travis."
-
-  if [ "$#" -ne 1 ] ; then
-    echo "Usage: $(basename "$0") ./grml-debootstrap*.deb" >&2
-    exit 1
-  else
-    GRML_DEBOOTSTRAP_DEB="$1"
-    if [ "$(dirname "$(realpath "$GRML_DEBOOTSTRAP_DEB")")" != "$(pwd)" ] ; then
-      echo "Error: the grml-debootstrap*.deb needs to be inside $(pwd) to be shared with docker container." >&2
-      exit 1
-    fi
-  fi
-fi
-
-RELEASE="${RELEASE:-buster}"
-export RELEASE
-
-TARGET="${TARGET:-qemu.img}"
-
-bailout() {
-  if [ -n "${QEMU_PID:-}" ] ; then
-    # shellcheck disable=SC2009
-    ps --pid="${QEMU_PID}" -o pid= | grep -q '.' && kill "${QEMU_PID:-}"
-  fi
-
-  if [ -f "${TARGET:-}" ] ; then
-    sudo kpartx -dv "$(realpath "${TARGET}")"
-  fi
-
-  if [ -n "${LOOP_DISK:-}" ] ; then
-    if sudo dmsetup ls | grep -q "${LOOP_DISK}"; then
-      sudo kpartx -d "/dev/${LOOP_DISK}"
-    fi
-  fi
-
-  local loopmount
-  loopmount="$(sudo losetup -a | grep "$(realpath "${TARGET}")" | cut -f1 -d: || true)"
-
-  if [ -n "${loopmount:-}" ] ; then
-    sudo losetup -d "${loopmount}"
-  fi
-
-  [ -n "${1:-}" ] && EXIT_CODE="$1" || EXIT_CODE=1
-  exit "$EXIT_CODE"
-}
-trap bailout 1 2 3 6 14 15
-
-# run shellcheck tests
-docker run koalaman/shellcheck:stable --version
-docker run --rm -v "$(pwd)":/code koalaman/shellcheck:stable -e SC2181 -e SC2001 /code/chroot-script /code/grml-debootstrap
-
-# build Debian package
-if [ -z "${TRAVIS:-}" ] ; then
-  echo "Not running under Travis, installing local grml-debootstrap package ${GRML_DEBOOTSTRAP_DEB}."
-else
-  if ! [ "${TRAVIS_DEBIAN_DISTRIBUTION:-}" = "unstable" ] ; then
-    echo "TRAVIS_DEBIAN_DISTRIBUTION is $TRAVIS_DEBIAN_DISTRIBUTION and not unstable, skipping VM build tests."
-    exit 0
-  fi
-  wget -O- https://travis.debian.net/script.sh | sh -
-  # copy only the binary from the TRAVIS_DEBIAN_INCREMENT_VERSION_NUMBER=true build
-  cp ../grml-debootstrap_*travis*deb .
-fi
-
-# we need to run in privileged mode to be able to use loop devices
-docker run --privileged -v "$(pwd)":/code --rm -i -t debian:buster /code/travis/build-vm.sh
-
-[ -x ./goss ] || curl -fsSL https://goss.rocks/install | GOSS_DST="$(pwd)" sh
-
-# Ubuntu trusty (14.04LTS) doesn't have realpath in coreutils yet
-if ! command -v realpath &>/dev/null ; then
-  REALPATH_PACKAGE=realpath
-fi
-
-sudo apt-get update
-sudo apt-get -y install qemu-system-x86 kpartx python-pexpect python-serial ${REALPATH_PACKAGE:-}
-
-# run tests from inside Debian system
-DEVINFO=$(sudo kpartx -asv "${TARGET}")
-LOOP_PART="${DEVINFO##add map }"
-LOOP_PART="${LOOP_PART// */}"
-LOOP_DISK="${LOOP_PART%p*}"
-IMG_FILE="/dev/mapper/$LOOP_PART"
-
-MNTPOINT="$(mktemp -d)"
-sudo mount "$IMG_FILE" "${MNTPOINT}"
-
-sudo cp ./goss "${MNTPOINT}"/usr/local/bin/goss
-sudo cp ./travis/goss.yaml "${MNTPOINT}"/root/goss.yaml
-
-sudo umount "${MNTPOINT}"
-sudo kpartx -dv "$(realpath "${TARGET}")"
-if sudo dmsetup ls | grep -q "${LOOP_DISK}"; then
-  sudo kpartx -d "/dev/${LOOP_DISK}"
-fi
-
-rmdir "$MNTPOINT"
-
-sudo chown "$(id -un)" qemu.img
-rm -f ./serial0
-mkfifo ./serial0
-qemu-system-x86_64 -hda qemu.img -display none -vnc :0 \
-                   -device virtio-serial-pci \
-                   -chardev pipe,id=ch0,path=./serial0 \
-                   -device virtserialport,chardev=ch0,name=serial0 \
-                   -serial pty &>qemu.log &
-QEMU_PID="$!"
-
-timeout=30
-success=0
-while [ "$timeout" -gt 0 ] ; do
-  ((timeout--))
-  if grep -q 'char device redirected to ' qemu.log ; then
-    success=1
-    sleep 1
-    break
-  else
-    echo "No serial console from Qemu found yet [$timeout retries left]"
-    sleep 1
-  fi
-done
-
-if [ "$success" = "1" ] ; then
-  serial_port=$(awk '/char device redirected/ {print $5}' qemu.log)
-else
-  echo "Error: Failed to identify serial console port." >&2
-  exit 1
-fi
-
-timeout=30
-success=0
-while [ "$timeout" -gt 0 ] ; do
-  ((timeout--))
-  if [ -c "$serial_port" ] ; then
-    success=1
-    sleep 1
-    break
-  else
-    echo "No block device for serial console found yet [$timeout retries left]"
-    sleep 1
-  fi
-done
-
-if [ "$success" = "0" ] ; then
-  echo "Error: can't access serial console block device." >&2
-  exit 1
-fi
-
-sudo chown "$(id -un)" "$serial_port"
-./travis/serial-console-connection --port "$serial_port" --hostname "$RELEASE" --pipefile "serial0" --vmoutput "vm-output.txt"
-
-cat vm-output.txt
-
-RC=0
-if grep -q '^failure_exit' vm-output.txt ; then
-  echo "We noticed failing tests."
-  RC=1
-else
-  echo "All tests passed."
-fi
-
-echo "Finished serial console connection [timeout=${timeout}]."
-
-bailout $RC
-
-# EOF
diff --git a/travis/serial-console-connection b/travis/serial-console-connection
deleted file mode 100755 (executable)
index ff3fbd0..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-import argparse
-import pexpect
-import serial
-import sys
-import time
-from pexpect import fdpexpect
-
-parser = argparse.ArgumentParser(description='Connect to serial console ' +
-                                 'to execute stuff')
-parser.add_argument('--port', required=True,
-                    help='serial console device to connect ' +
-                    'to (e.g. /dev/pts/X)')
-parser.add_argument('--hostname', default="buster",
-                    help='hostname of the system for login process ' +
-                    '(default: buster)')
-parser.add_argument('--pipefile', default="./serial0",
-                    help='file name for named pipe file (for ' +
-                    'interacting between host + VM via QEMU ' +
-                    '(default: ./serial0)')
-parser.add_argument('--vmoutput', default="vm-output.log",
-                    help='filename for VM output (default: vm-output.log)')
-parser.add_argument('--user', default="root",
-                    help='user name to use for login (default: root)')
-parser.add_argument('--password', default="grml",
-                    help='password for login (default: grml)')
-args = parser.parse_args()
-
-
-def execute(port, hostname, user, baudrate=115200, timeout=5):
-    ser = serial.Serial(port, baudrate)
-    ser.flushInput()
-    ser.flushOutput()
-    ser.write("\n")
-    ser.flush()
-
-    child = fdpexpect.fdspawn(ser.fileno())
-    child.sendline("")
-    try:
-        print("Begin of execution inside VM")
-        child.expect("%s@%s" % (user, hostname), timeout=timeout)
-        child.sendline("/usr/local/bin/goss --gossfile /root/goss.yaml " +
-                       "validate --format tap > /root/goss.tap ; " +
-                       "echo $? > /root/goss.exitcode\n")
-        # NOTE - the serial0 is hardcoded here
-        child.sendline("cat /root/goss.tap > /dev/virtio-ports/serial0\n")
-        child.sendline("grep -q '^0' /root/goss.exitcode && " +
-                       "echo clean_exit > /dev/virtio-ports/serial0\n")
-        child.sendline("grep -q '^0' /root/goss.exitcode || " +
-                       "echo failure_exit > /dev/virtio-ports/serial0\n")
-        child.sendline("poweroff\n")
-        print("End of execution inside VM")
-    except Exception as except_inst:
-        print("Execution inside VM failed: ", except_inst)
-
-
-def login(port, hostname, user, password,
-          baudrate=115200, timeout=5):
-    ser = serial.Serial(port, baudrate)
-    ser.flushInput()
-    ser.flushOutput()
-
-    child = fdpexpect.fdspawn(ser.fileno())
-    child.sendline("\n")
-
-    try:
-        child.expect("root@%s" % hostname, timeout=timeout)
-        return
-    except:
-        pass
-
-    print("Checking for login prompt...")
-    child.expect("%s login:" % hostname, timeout=timeout)
-    ser.write("%s\n" % user)
-    ser.flush()
-    time.sleep(1)
-    ser.write("%s\n" % password)
-    ser.flush()
-    time.sleep(1)
-    print("login ok...")
-
-
-if __name__ == "__main__":
-    hostname = args.hostname
-    password = args.password
-    pipefile = args.pipefile
-    port = args.port
-    user = args.user
-    vmoutput = args.vmoutput
-
-    with open(pipefile, 'r') as output_pipe:
-        success = False
-        for i in range(12):
-            try:
-                print("Logging into {0} via serial "
-                      "console [try {1}]".format(port, i))
-                login(port, hostname, user, password)
-                success = True
-                break
-            except Exception as except_inst:
-                print("Login failure (try {0}):".format(i),
-                      except_inst, file=sys.stderr)
-                time.sleep(5)
-
-        if success:
-            execute(port, hostname, user)
-            with open(vmoutput, 'w') as fp:
-                output = output_pipe.read()
-                print(output)
-                fp.write(output)