Release new version 0.108
[grml-debootstrap.git] / chroot-script
index 20638a5..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
@@ -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
       ;;
@@ -269,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
 }
 # }}}
@@ -316,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 {{{
@@ -350,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"
@@ -385,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
@@ -416,6 +419,7 @@ passwords()
          a='1'
          b='2'
        else
+         # shellcheck disable=SC2086
          echo root:"$a" | chpasswd $CHPASSWD_OPTION
          unset a
          unset b
@@ -479,11 +483,16 @@ createfstab(){
 EOF
 
   if [ -n "$TARGET_UUID" ] ; then
-    local rootfs_mount_options=",errors=remount-ro"
+    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
-      f2fs)
-        # errors=remount-ro is unsupported, see https://github.com/grml/grml-debootstrap/issues/163
-        rootfs_mount_options=""
+      # errors=remount-ro is supported only by a few file systems
+      ext*|exfat|fat|jfs|nilfs2|vfat)
+        rootfs_mount_options=",errors=remount-ro"
         ;;
     esac
 
@@ -493,8 +502,8 @@ EOF
   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
@@ -525,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
@@ -575,9 +606,10 @@ initrd() {
   if [ -n "$INITRD" ] ; then
      echo "Generating initrd."
      if [ "$INITRD_GENERATOR" = 'dracut' ] ; then
-         DEBIAN_FRONTEND=$DEBIAN_FRONTEND $APTINSTALL dracut
+         # 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
@@ -596,7 +628,7 @@ 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
@@ -606,10 +638,46 @@ efi_setup() {
   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
@@ -617,7 +685,7 @@ grub_install() {
     return 0
   fi
 
-  efi_setup || return 1
+  efi_setup
 
   if [ -n "$EFI" ] ; then
     GRUB_PACKAGE=grub-efi-amd64
@@ -627,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
@@ -652,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
@@ -693,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
 }
 # }}}
 
@@ -751,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: