X-Git-Url: https://git.grml.org/?p=grml-debootstrap.git;a=blobdiff_plain;f=chroot-script;h=b0737ca77275963cb43a20d9db493619e3b7a84e;hp=766a59d8eb9aed15ecc9701b82087c130b701ca7;hb=HEAD;hpb=e426be2b57c02a85774bc72462224e4fd0260421 diff --git a/chroot-script b/chroot-script index 766a59d..c356bc8 100755 --- a/chroot-script +++ b/chroot-script @@ -2,24 +2,26 @@ # Filename: /etc/debootstrap/chroot-script # Purpose: script executed in chroot when installing Debian via grml-debootstrap # Authors: grml-team (grml.org), (c) Michael Prokop -# Bug-Reports: see http://grml.org/bugs/ +# Bug-Reports: see https://grml.org/bugs/ # License: This file is licensed under the GPL v2. ################################################################################ # 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,31 +102,27 @@ 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 - *) + 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 ;; + *) + # bullseye and newer releases use a different repository layout, see + # https://lists.debian.org/debian-devel-announce/2019/07/msg00004.html + echo "Adding security.debian.org/debian-security to sources.list." + echo "deb http://security.debian.org/debian-security ${RELEASE}-security $COMPONENTS" >> /etc/apt/sources.list + ;; esac } # }}} # 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 @@ -146,75 +144,59 @@ 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 -} -# }}} -# check available backports release version {{{ -checkbackports() { - wget -q -O/dev/null "http://backports.debian.org/debian-backports/dists/${1}-backports/Release" + 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 } # }}} # feature to provide Debian backports repos {{{ backportrepos() { - if [ -n "$BACKPORTREPOS" ] ; then - if ! checkbackports "$RELEASE" ; then - echo "Backports for ${RELEASE} are not available." >&2 - exit 1 - else - # user might have provided their own apt sources.list - if ! grep -q backports /etc/apt/sources.list.d/backports.list 2>/dev/null ; then - cat >> /etc/apt/sources.list.d/backports.list << EOF + if [ -n "$BACKPORTREPOS" ] ; then + cat >> /etc/apt/sources.list.d/backports.list << EOF # debian backports: ${RELEASE}-backports repository: -deb http://backports.debian.org/debian-backports ${RELEASE}-backports main -deb-src http://backports.debian.org/debian-backports ${RELEASE}-backports main +deb ${MIRROR} ${RELEASE}-backports main +deb-src ${MIRROR} ${RELEASE}-backports main EOF - fi - fi - fi + fi } # }}} @@ -279,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 } # }}} @@ -326,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 {{{ @@ -360,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" @@ -395,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 @@ -426,6 +419,7 @@ passwords() a='1' b='2' else + # shellcheck disable=SC2086 echo root:"$a" | chpasswd $CHPASSWD_OPTION unset a unset b @@ -465,8 +459,12 @@ default_locales() { # adjust timezone {{{ timezone() { if [ -n "$TIMEZONE" ] ; then - echo "Adjusting /etc/localtime" - ln -sf "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime + echo "Adjusting /etc/localtime" + ln -sf "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime + + echo "Setting /etc/timezone to $TIMEZONE" + printf '%s\n' "$TIMEZONE" > /etc/timezone + fi } # }}} @@ -474,15 +472,38 @@ timezone() { # helper function for fstab() {{{ createfstab(){ echo "Setting up /etc/fstab" + cat > /etc/fstab < /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 @@ -513,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 @@ -562,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 } # }}} @@ -579,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 @@ -593,7 +685,7 @@ grub_install() { return 0 fi - efi_setup || return 1 + efi_setup if [ -n "$EFI" ] ; then GRUB_PACKAGE=grub-efi-amd64 @@ -603,56 +695,62 @@ 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 GRUB="${device%%[0-9]}" echo "Installing grub on ${GRUB}:" - grub-install --no-floppy "$GRUB" + if ! grub-install --no-floppy "$GRUB" ; then + echo "Error: failed to execute 'grub-install --no-floppy $GRUB'." >&2 + exit 1 + fi + done rm -f /boot/grub/device.map else - echo "Installing grub on ${GRUB}:" - case "$RELEASE" in - lenny|squeeze|wheezy) - grub-install --no-floppy "$(readlink -f "${GRUB}")" - rm -f /boot/grub/device.map - ;; - *) - echo "(hd0) ${GRUB}" > /boot/grub/device.map - grub-install "(hd0)" - 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 + 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 fi mountpoint /boot/efi &>/dev/null && umount /boot/efi - $UPDATEGRUB + # finally install grub. Existence of update-grub is checked above. + update-grub } # }}} @@ -684,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 } @@ -708,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: