support skipping installation of grub using GRUB_INSTALL='no'
[grml-debootstrap.git] / grml-debootstrap
index 0637089..1a44c7b 100755 (executable)
@@ -40,7 +40,7 @@ fi
 
 # variables {{{
 PN="$(basename "$0")"
 
 # variables {{{
 PN="$(basename "$0")"
-if [[ -d "$(dirname "$(which "$0")")"/.git ]]; then
+if [[ -d "$(dirname "$(command -v "$0")")"/.git ]]; then
   VERSION="$(git describe | sed 's|^v||')"
 else
   VERSION="$(dpkg-query --show --showformat='${Version}' "$PN")"
   VERSION="$(git describe | sed 's|^v||')"
 else
   VERSION="$(dpkg-query --show --showformat='${Version}' "$PN")"
@@ -58,7 +58,7 @@ MNTPOINT="/mnt/debootstrap.$$"
 [ -n "$DEFAULT_LOCALES" ] || DEFAULT_LOCALES='en_US.UTF-8'
 [ -n "$DISK_IDENTIFIER" ] || DISK_IDENTIFIER='26ada0c0-1165-4098-884d-aafd2220c2c6'
 [ -n "$EXTRAPACKAGES" ] || EXTRAPACKAGES='yes'
 [ -n "$DEFAULT_LOCALES" ] || DEFAULT_LOCALES='en_US.UTF-8'
 [ -n "$DISK_IDENTIFIER" ] || DISK_IDENTIFIER='26ada0c0-1165-4098-884d-aafd2220c2c6'
 [ -n "$EXTRAPACKAGES" ] || EXTRAPACKAGES='yes'
-[ -n "$FALLBACK_MIRROR" ] || FALLBACK_MIRROR='http://httpredir.debian.org/debian'
+[ -n "$FALLBACK_MIRROR" ] || FALLBACK_MIRROR='http://deb.debian.org/debian'
 [ -n "$FIXED_DISK_IDENTIFIERS" ] || FIXED_DISK_IDENTIFIERS="no"
 [ -n "$FORCE" ] || FORCE=''
 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
 [ -n "$FIXED_DISK_IDENTIFIERS" ] || FIXED_DISK_IDENTIFIERS="no"
 [ -n "$FORCE" ] || FORCE=''
 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
@@ -80,6 +80,7 @@ MNTPOINT="/mnt/debootstrap.$$"
 [ -n "$TUNE2FS" ] || TUNE2FS='tune2fs -c0 -i0'
 [ -n "$UPGRADE_SYSTEM" ] || UPGRADE_SYSTEM='yes'
 [ -n "$VMSIZE" ] || VMSIZE="2G"
 [ -n "$TUNE2FS" ] || TUNE2FS='tune2fs -c0 -i0'
 [ -n "$UPGRADE_SYSTEM" ] || UPGRADE_SYSTEM='yes'
 [ -n "$VMSIZE" ] || VMSIZE="2G"
+[ -n "$GRUB_INSTALL" ] || GRUB_INSTALL='yes'
 
 # inside the chroot system locales might not be available, so use minimum:
 export LANG=C
 
 # inside the chroot system locales might not be available, so use minimum:
 export LANG=C
@@ -186,7 +187,7 @@ WARN='\e[33;01m'
 NORMAL='\e[0m'
 
 einfo() {
 NORMAL='\e[0m'
 
 einfo() {
-  einfon "$1\n"
+  einfon "$1\\n"
   return 0
 }
 
   return 0
 }
 
@@ -198,13 +199,13 @@ einfon() {
 }
 
 ewarn() {
 }
 
 ewarn() {
-  printf " %s*%s $*\n" "${WARN}" "${NORMAL}"
+  printf " %s*%s $*\\n" "${WARN}" "${NORMAL}"
   return 0
 }
 
 eerror() {
   [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
   return 0
 }
 
 eerror() {
   [ "${RC_ENDCOL}" != "yes" ] && [ "${LAST_E_CMD}" = "ebegin" ] && echo
-  printf " %s*%s $*\n" "${BAD}" "${NORMAL}" >&2
+  printf " %s*%s $*\\n" "${BAD}" "${NORMAL}" >&2
   LAST_E_CMD=eerror
   return 0
 }
   LAST_E_CMD=eerror
   return 0
 }
@@ -213,7 +214,7 @@ eend() {
   local retval="${1:-0}"
   shift
   if [ "$retval" -gt 0 ]; then
   local retval="${1:-0}"
   shift
   if [ "$retval" -gt 0 ]; then
-    printf " %s-> Failed (rc=%s)%s\n" "${BAD}" "${retval}" "${NORMAL}"
+    printf " %s-> Failed (rc=%s)%s\\n" "${BAD}" "${retval}" "${NORMAL}"
   fi
   return "$retval"
 }
   fi
   return "$retval"
 }
@@ -227,7 +228,7 @@ check4root(){
 check4progs(){
   local RC=''
   for arg in "$@" ; do
 check4progs(){
   local RC=''
   for arg in "$@" ; do
-    which "$arg" >/dev/null 2>&1 || RC="$arg"
+    command -v "$arg" >/dev/null 2>&1 || RC="$arg"
   done
   if [ -n "$RC" ] ; then
      echo "$RC not installed"
   done
   if [ -n "$RC" ] ; then
      echo "$RC not installed"
@@ -339,19 +340,174 @@ fi
 # }}}
 
 # cmdline handling {{{
 # }}}
 
 # cmdline handling {{{
-# source external command line parameter-processing script
-self_dir="$(dirname "$(which "$0")")"
-if [ -r "${self_dir}"/cmdlineopts.clp ] ; then
-  # shellcheck source=cmdlineopts.clp
-  . "${self_dir}"/cmdlineopts.clp
-elif [ -r /usr/share/grml-debootstrap/functions/cmdlineopts.clp ] ; then
-  # shellcheck source=cmdlineopts.clp
-  . /usr/share/grml-debootstrap/functions/cmdlineopts.clp
-else
-  eerror "Error: cmdline function file not found, exiting."
-  eend 1
-  bailout 1
+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
+
+_opt_temp=$(getopt --name grml-debootstrap -o +m:i:r:t:p:c:d:vhV --long \
+  $CMDLINE_OPTS -- "$@")
+
+if [ $? != 0 ]; then
+  eerror "Try 'grml-debootstrap --help' for more information."; eend 1; exit 1
 fi
 fi
+eval set -- "$_opt_temp"
+
+while :; do
+  case "$1" in
+
+  # == Bootstrap options
+  --mirror|-m)         # Mirror which should be used for apt-get/aptitude
+    shift; _opt_mirror="$1"
+    ;;
+  --iso|-i)            # Mountpoint where a Debian ISO is mounted to
+    shift; _opt_iso="$1"
+    ;;
+  --release|-r)        # Release of new Debian system
+    shift; _opt_release="$1"
+    ;;
+  --target|-t)         # Target partition (/dev/...) or directory
+    shift; _opt_target="$1"
+    ;;
+  --vm)                # Virtual machine image (no file)
+    _opt_vm="T"
+    ;;
+  --vmfile)            # Virtual machine file
+    _opt_vmfile="T"
+    ;;
+  --vmsize)            # size of Virtual machine file
+    shift; _opt_vmsize="$1"
+    ;;
+  --mntpoint|-p)       # Mountpoint used for mounting the target system
+    shift; _opt_mntpoint="$1"
+    ;;
+  --debopt)            # Extra parameters passed to the debootstrap command
+    shift; _opt_debopt="$1"
+    ;;
+  --filesystem)        # Filesystem that should be used
+    shift; _opt_filesystem="$1"
+    ;;
+  --interactive)       # Use interactive mode (frontend)
+    _opt_interactive=T
+    ;;
+  --nodebootstrap)     # Skip debootstrap, only do configuration to the target
+    _opt_nodebootstrap=T
+    ;;
+  --nopackages)        # Skip installation of packages defined in /etc/debootstrap/packages
+    _opt_nopackages=T
+    ;;
+  --arch)              # Target architecutre
+    shift; _opt_arch="$1"
+    ;;
+  # just for backwards compatibility
+  --insecure)
+    _opt_insecure=T
+    ;;
+  #
+
+  # == Configuration options
+  --config|-c)         # Use specified configuration file, defaults to /etc/debootstrap
+    shift; _opt_config="$1"
+    ;;
+  --confdir|-d)        # Place of config files for debootstrap, defaults to /etc/debootstrap
+    shift; _opt_confdir="$1"
+    ;;
+  --packages)          # Install packages defined in specified file
+    shift; _opt_packages="$1"
+    _opt_packages_set=T
+    ;;
+  --debconf)           # Pre-seed packages using specified file
+    shift; _opt_debconf="$1"
+    _opt_debconf_set=T
+    ;;
+  --pre-scripts)       # Execute scripts from specified directory (before chroot-scripts).
+    shift; _opt_pre_scripts="$1"
+    _opt_pre_scripts_set=T
+    ;;
+  --scripts)           # Execute scripts from specified directory [NOTE: deprecated, replaced via --post-scripts]
+    shift; _opt_scripts="$1"
+    _opt_scripts_set=T
+    ;;
+  --post-scripts)       # Execute scripts from specified directory
+    shift; _opt_post_scripts="$1"
+    _opt_post_scripts_set=T
+    ;;
+  --chroot-scripts)   # Execute chroot scripts from specified directory
+    shift; _opt_chroot_scripts="$1"
+    _opt_chroot_scripts_set=T
+    ;;
+  --keep_src_list)     # Do not overwrite user provided apt sources.list
+    _opt_keep_src_list=T
+    ;;
+  --hostname)          # Hostname of Debian system
+    shift; _opt_hostname="$1"
+    ;;
+  --password)          # Use specified password as password for user root
+    shift; _opt_password="$1"
+    ;;
+  --defaultinterfaces) # Install default /etc/network/interfaces
+    _opt_defaultinterfaces=T
+    ;;
+  --nointerfaces)      # Skip installation of /etc/network/interfaces
+    _opt_nointerfaces=T
+    ;;
+  --nokernel)          # Skip installation of default kernel images
+    _opt_nokernel=T
+    ;;
+  --nopassword)        # Skip password dialog
+    _opt_nopassword=T
+    ;;
+  --grmlrepos)         # Enable Grml repository
+    _opt_grmlrepos=T
+    ;;
+  --backportrepos)     # Enable Debian backports repository
+    _opt_backportrepos=T
+    ;;
+  --bootappend)        # Add specified appendline to kernel whilst booting
+    shift; _opt_bootappend="$1"
+    ;;
+  --grub)              # Target for grub installation. Use grub syntax for specifying
+    shift; _opt_grub="$1"
+    ;;
+  --efi)               # Target for EFI boot installation
+    shift; _opt_efi="$1"
+    ;;
+  --contrib)           # Add 'contrib' to list of components
+    _opt_contrib=T
+    ;;
+  --non-free)          # Add 'non-free' to list of components
+    _opt_non_free=T
+    ;;
+  --remove-configs)    # Drop config files from installed system
+    _opt_remove_configs=T
+    ;;
+
+  # == Other options
+  --verbose|-v)        # Increase verbosity
+    if [ "$_opt_verbose" ]; then
+      _opt_verbose=$( _opt_verbose + 1 )
+    else
+      _opt_verbose=1
+    fi
+    ;;
+  --debug)             # Execute in debug mode
+    _opt_debug=T
+    ;;
+  --help|-h)           # Print usage information and exit
+    _opt_help=T
+    ;;
+  --version|-V)        # Show version information and exit
+    _opt_version=T
+    ;;
+  --force)             # Do not prompt for user input
+    _opt_force=T
+    ;;
+  --)
+    shift; break
+    ;;
+  *)
+    eerror "Internal getopt error!"; eend 1 ; exit 1
+    ;;
+  esac
+  shift
+done
 
 # == business-logic of command line parameter-processing
 
 
 # == business-logic of command line parameter-processing
 
@@ -663,7 +819,7 @@ prompt_for_mirror()
   [ $? -eq 0 ] || bailout
 
   if [ "$CHOOSE_MIRROR" = 'net' ] ; then
   [ $? -eq 0 ] || bailout
 
   if [ "$CHOOSE_MIRROR" = 'net' ] ; then
-     [ -n "$MIRROR" ] || MIRROR='http://httpredir.debian.org/debian'
+     [ -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)"
      MIRROR="$(dialog --stdout --title "${PN}" --inputbox \
                "Please enter Debian mirror you would like to use for installing packages." \
                0 0 $MIRROR)"
@@ -773,6 +929,7 @@ Do you want to stop now?" 0 0 2>/dev/null
 }
 # }}}
 
 }
 # }}}
 
+# format efi partition {{{
 format_efi_partition() {
   if [ -z "$EFI" ] ; then
     return 0
 format_efi_partition() {
   if [ -z "$EFI" ] ; then
     return 0
@@ -798,6 +955,7 @@ format_efi_partition() {
     fi
   fi
 }
     fi
   fi
 }
+# }}}
 
 # check for EFI support or try to enable it {{{
 efi_support() {
 
 # check for EFI support or try to enable it {{{
 efi_support() {
@@ -1132,6 +1290,7 @@ mkfs() {
 }
 # }}}
 
 }
 # }}}
 
+# retrieve ID_FS_UUID {{{
 identify_target_uuid() {
   local device="$1"
 
 identify_target_uuid() {
   local device="$1"
 
@@ -1147,7 +1306,9 @@ identify_target_uuid() {
     return 1
   fi
 }
     return 1
   fi
 }
+# }}}
 
 
+# identify TARGET_UUID {{{
 mountpoint_to_blockdevice() {
   TARGET_UUID=''
 
 mountpoint_to_blockdevice() {
   TARGET_UUID=''
 
@@ -1172,6 +1333,7 @@ mountpoint_to_blockdevice() {
     fi
   done
 }
     fi
   done
 }
+# }}}
 
 # modify filesystem settings {{{
 tunefs() {
 
 # modify filesystem settings {{{
 tunefs() {
@@ -1236,7 +1398,7 @@ prepare_vm() {
     einfo "Adjusting disk signature to a fixed (non-random) value"
     MBRTMPFILE=$(mktemp)
     dd if="${TARGET}" of="${MBRTMPFILE}" bs=512 count=1
     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
+    echo -en "\\x41\\x41\\x41\\x41" | dd of="${MBRTMPFILE}" conv=notrunc seek=440 bs=1
     dd if="${MBRTMPFILE}" of="${TARGET}" conv=notrunc
     eend $?
   fi
     dd if="${MBRTMPFILE}" of="${TARGET}" conv=notrunc
     eend $?
   fi
@@ -1280,11 +1442,14 @@ prepare_vm() {
 }
 # }}}
 
 }
 # }}}
 
-# make VM image bootable and unmount it {{{
-finalize_vm() {
+# make VM image bootable {{{
+grub_install() {
   if [ -z "${VIRTUAL}" ] ; then
      return 0
   fi
   if [ -z "${VIRTUAL}" ] ; then
      return 0
   fi
+  if [ ! "$GRUB_INSTALL" = "yes" ]; then
+     return 0
+  fi
 
   if ! mount "${TARGET}" "${MNTPOINT}" ; then
     eerror "Error: Mounting ${TARGET} failed, can not continue." ; eend 1
 
   if ! mount "${TARGET}" "${MNTPOINT}" ; then
     eerror "Error: Mounting ${TARGET} failed, can not continue." ; eend 1
@@ -1298,7 +1463,7 @@ finalize_vm() {
 
 # Has chroot-script installed GRUB to MBR using grub-install (successfully), already?
 # chroot-script skips installation for unset ${GRUB}
 
 # 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 | fgrep -q GRUB; then
+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 ! chroot "${MNTPOINT}" dpkg --list grub-pc 2>/dev/null | grep -q '^ii' ; then
   einfo "Installing Grub as bootloader."
 
   if ! chroot "${MNTPOINT}" dpkg --list grub-pc 2>/dev/null | grep -q '^ii' ; then
@@ -1346,13 +1511,23 @@ fi
     ewarn "Please note that your system might NOT be able to properly boot."
   else
     einfo "Adjusting grub.cfg for successful boot sequence."
     ewarn "Please note that your system might NOT be able to properly boot."
   else
     einfo "Adjusting grub.cfg for successful boot sequence."
-    sed -i "s;root=[^ ]\+;root=UUID=$TARGET_UUID;" "${MNTPOINT}"/boot/grub/grub.cfg
+    sed -i "s;root=[^ ]\\+;root=UUID=$TARGET_UUID;" "${MNTPOINT}"/boot/grub/grub.cfg
   fi
 
   umount "${MNTPOINT}"/proc
   umount "${MNTPOINT}"/sys
   umount "${MNTPOINT}"/dev/pts
   try_umount 3 "${MNTPOINT}"/dev
   fi
 
   umount "${MNTPOINT}"/proc
   umount "${MNTPOINT}"/sys
   umount "${MNTPOINT}"/dev/pts
   try_umount 3 "${MNTPOINT}"/dev
+
+}
+# }}}
+
+# unmount VM image {{{
+umount_target() {
+  if [ -z "${VIRTUAL}" ] ; then
+     return 0
+  fi
+
   umount "${MNTPOINT}"
   kpartx -d "${ORIG_TARGET}" >/dev/null
 }
   umount "${MNTPOINT}"
   kpartx -d "${ORIG_TARGET}" >/dev/null
 }
@@ -1599,6 +1774,7 @@ execute_post_scripts() {
 }
 # }}}
 
 }
 # }}}
 
+# unmount mountpoint {{{
 try_umount() {
   local tries=$1
   local mountpoint="$2"
 try_umount() {
   local tries=$1
   local mountpoint="$2"
@@ -1618,6 +1794,7 @@ try_umount() {
   done
   return 1  # Tried enough
 }
   done
   return 1  # Tried enough
 }
+# }}}
 
 # execute chroot-script {{{
 chrootscript() {
 
 # execute chroot-script {{{
 chrootscript() {
@@ -1718,7 +1895,7 @@ remove_configs() {
 for i in format_efi_partition prepare_vm mkfs tunefs \
          mount_target mountpoint_to_blockdevice debootstrap_system \
          preparechroot execute_pre_scripts chrootscript execute_post_scripts \
 for i in format_efi_partition prepare_vm mkfs tunefs \
          mount_target mountpoint_to_blockdevice debootstrap_system \
          preparechroot execute_pre_scripts chrootscript execute_post_scripts \
-         remove_configs umount_chroot finalize_vm fscktool ; do
+         remove_configs umount_chroot grub_install umount_target fscktool ; do
     if stage "${i}" ; then
       if "$i" ; then
         stage "${i}" 'done' && rm -f "${STAGES}/${i}"
     if stage "${i}" ; then
       if "$i" ; then
         stage "${i}" 'done' && rm -f "${STAGES}/${i}"