#! /bin/bash

# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
# Johannes Meixner <jsmeix@suse.de>, 2011

# Enable 'set -x' to get debug output (commands and arguments as they are executed):
#set -x

# Export all variables which are modified or created automatically to have them available
# in the backup executable, the autoinst executable, and the medium executable:
set -a

# Make sure to have a clean environment:
PATH="/sbin:/usr/sbin:/usr/bin:/bin"
LC_ALL="POSIX"
LANG="POSIX"
umask 022

# Disable bash file name globbing:
set -f

# The return value of a pipeline is the status of
# the last command to exit with a non-zero status,
# or zero if no command exited with a non-zero status:
set -o pipefail

MY_NAME=${0##*/}
MY_BLNK="$( echo "$MY_NAME" | tr '[:print:]' ' ' )"
TIMESTAMP="$( date +%Y%m%d%H%M%S )"
MY_PREFIX="$MY_NAME.$TIMESTAMP"

NUMBER_OF_COMMAND_LINE_PARAMETERS="8"
OUTPUT_LINE_WIDTH="78"

RESTORE_EXCLUDE_DEFAULT="etc/fstab etc/mtab var/adm/autoinstall"

SAVE_SYSCONFIG_FILES="clock language keyboard mouse displaymanager windowmanager"
# Re-enable bash file name globbing:
set +f
SAVE_SYSCONFIG_NETWORK_FILES="$( for F in /etc/sysconfig/network/* ; do test -f $F && basename $F ; done | tr -s '[:space:]' ' ' )"
# Re-disable bash file name globbing:
set -f
if test -z "$SAVE_SYSCONFIG_NETWORK_FILES"
then SAVE_SYSCONFIG_NETWORK_FILES="ifcfg-lo"
fi

# Function to output a synopsis:
SynopsisMessage()
{ echo ""
  echo "$MY_NAME -h"
  echo ""
  echo "$MY_NAME [ -d BASE_URI"
  echo "$MY_BLNK   -l { log-to-base-dir | LOG_DIR }"
  echo "$MY_BLNK   -b { make-rear-backup | use-existing-rear-backup"
  echo "$MY_BLNK                         | BACKUP_URI }"
  echo "$MY_BLNK   -a { clone-system | AUTOINST_FILE"
  echo "$MY_BLNK                     | use-autoinst-from-base-dir }"
  echo "$MY_BLNK   -m { autodetect-dvd | MEDIUM_URI"
  echo "$MY_BLNK                       | use-existing-medium-ISO"
  echo "$MY_BLNK                       | use-existing-ISO-files }"
  echo "$MY_BLNK   -i { install-RPMs | skip-RPM-install"
  echo "$MY_BLNK                     | no-RPM-payload }"
  echo "$MY_BLNK   -r { restore-all | restore-exclude-default"
  echo "$MY_BLNK                    | RESTORE_EXCLUDE }"
  echo "$MY_BLNK   -c { configure-all | CONFIGURE_EXCLUDE"
  echo "$MY_BLNK                      | skip-second-stage } ]"
  echo ""
}

# Function to output a help message:
HelpMessage()
{ # If the following commands do not work, the README_FILE_NAME should be empty:
  README_FILE_NAME="$( rpm -ql $( rpm -qf $( type -p $MY_NAME ) 2>/dev/null ) 2>/dev/null | grep README )"
  # Ruler for 80 character lines:
  #     12345678901234567890123456789012345678901234567890123456789012345678901234567890
  #              1         2         3         4         5         6         7         8
  echo ""
  echo "$MY_NAME creates a bootable ISO image to recover this particular system."
  echo ""
  echo "To create the bootable ISO image $MY_NAME does the following:"
  echo ""
  echo "1. Run 'rear mkbackuponly' to store a backup.tar.gz on a NFS server."
  echo ""
  echo "2. Run AutoYaST clone_system.ycp to make an autoinst.xml file."
  echo ""
  echo "3. Make a bootable system recovery ISO image which is based on"
  echo "   an install medium, for example a SUSE Linux Enterprise install DVD"
  echo "   plus autoinst.xml so that AutoYaST can recover this particular system."
  echo "   In particular a so called 'chroot script' is added to autoinst.xml"
  echo "   which is run by AutoYaST to restore the backup from the NFS server."
  echo ""
  echo "A recovery medium which is made from the ISO image would run"
  echo "AutoYaST with autoinst.xml to recreate the basic system,"
  echo "in particular the partitioning with filesystems and mount points."
  echo "Then AutoYaST runs the 'chroot script' to fill in the backup data into"
  echo "the recreated basic system when the mount points of the recreated system"
  echo "are still below '/mnt' and when the boot loader is not yet installed."
  echo "After the backup was restored, AutoYaST does a chroot into '/mnt' so that"
  echo "it is now in the recreated system and installs the boot loader."
  echo "Then the recreated system boots for its very first time and AutoYaST"
  echo "does the system configuration, in particular the network configuration."
  echo "Finally the configured system moves forward to its final runlevel"
  echo "so that all system services should then be up and running again."
  echo ""
  echo "Usage:"
  SynopsisMessage
  echo "All parameters are required (no guesswork how to recover this particular"
  echo "system)."
  echo "Either none or all parameters must be provided on the commandline."
  echo "If none is specified, the parameters are requested via a simple dialog."
  echo ""
  echo "-d specifies the destination:"
  echo "BASE_URI specifies the base directory where $MY_NAME will create"
  echo "its files except the ReaR backup which is stored according to the ReaR"
  echo "configuration and the log file location can be specified separately"
  echo "via the LOG_DIR parameter."
  echo "In particular the recovery ISO image is created in the base directory"
  echo "as $MY_NAME.TIMESTAMP.iso"
  echo "BASE_URI is either an absolute path of a local directory of the form"
  echo "'/path/to/directory' or it must have the form 'nfs://host/directory'"
  echo "so that 'mount -t nfs host:/directory' works."
  echo "In the latter case the NFS share must allow to read and write files"
  echo "(e.g. 'autoinst.xml') which means that the NFS server should export"
  echo "the NFS share with 'rw' and unless 'use-existing-ISO-files' is used,"
  echo "'chown' and 'chmod' must also work so that 'cp -a' can preserve attributes"
  echo "when copying files from the install medium which means that the NFS server"
  echo "should export it with 'no_root_squash'."
  echo "If BASE_URI is a local directory it is used as base directory."
  echo "If BASE_URI is of the form 'nfs://host/directory' the directory on that host"
  echo "is used as base directory."
  echo "If the directory which is specified via BASE_URI contains a HOSTNAME"
  echo "sub-directory (i.e. '$( hostname )' for this host)"
  echo "then $MY_NAME uses that as its base directory."
  echo "Unless 'use-existing-ISO-files' is used, $MY_NAME creates in its base"
  echo "directory a $MY_NAME.TIMESTAMP.ISOfiles sub-directory into which it"
  echo "copies the files from the install medium to make the ISO image."
  echo "No file will be removed from the ISO files directory so that it can be reused"
  echo "with 'use-existing-ISO-files' but with 'no-RPM-payload' the RPM package files"
  echo "in the ISO files directory will be made empty."
  echo "The loader/isolinux.cfg and loader/message files in the ISO files directory"
  echo "will be modified unless 'use-existing-ISO-files' is used."
  echo "In any case an AutoYaST control file will be copied into the ISO files"
  echo "directory and modified therein (in particular the 'chroot script' will"
  echo "be added)."
  echo "The base directory must have usually 10GB free space to make a DVD ISO image"
  echo "(5GB for the files from a DVD install medium plus 5GB to make the ISO image)."
  echo "With 'use-existing-ISO-files' usually 5GB for only a DVD ISO image are"
  echo "sufficient."
  echo "With a MEDIUM_URI of the form 'http://...' additional 5GB free space"
  echo "are needed to download an ISO image of a DVD install medium."
  echo ""
  echo "-l specifies the logging:"
  echo "LOG_DIR specifies an absolute path to a directory where $MY_NAME"
  echo "writes its log files."
  echo "With 'log-to-base-dir' $MY_NAME write its log files in the"
  echo "base directory."
  echo ""
  echo "-b specifies the backup:"
  echo "The backup must be a 'tar.gz' file so that 'tar -xzf backup.tar.gz' works"
  echo "to restore it."
  echo "With 'make-rear-backup' ReaR makes a new backup (may overwrite an existing"
  echo "backup) according to the ReaR configuration in /etc/rear/local.conf."
  echo "With 'use-existing-rear-backup' $MY_NAME inspects the ReaR configuration"
  echo "in /etc/rear/local.conf and tests if an existing ReaR backup is readable"
  echo "if the backup is stored at a ReaR NETFS_URL of the form 'nfs://host/path'."
  echo "BACKUP_URI is of the form 'nfs://host/path/backup.tar.gz'"
  echo "so that 'mount -t nfs host:/path' works to access the backup file."
  echo "If host is not an IP address but a hostname, DNS must work when the backup"
  echo "is restored."
  echo "Alternatively BACKUP_URI is either an absolute path of a local executable"
  echo "file of the form '/path/to/executable' or it is a relative path of an"
  echo "executable file of the form 'path/to/executable'."
  echo "If it is a relative path, it is relative to the base directory."
  echo "The executable must output on its standard output 'stdout' the actual URI of"
  echo "the backup file of the form 'nfs://host/path/backup.tar.gz' so that it works"
  echo "to extract the URI with the command: grep -o 'nfs://.*\.tar\.gz' | tail -n 1"
  echo "This way the executable can make the backup (e.g. a script which runs 'tar')"
  echo "and finally it tells $MY_NAME the URI of the backup via 'stdout'."
  echo ""
  echo "-a specifies the autoinst file:"
  echo "With 'clone-system' AutoYaST will create a control file /root/autoinst.xml"
  echo "on this system which $MY_NAME copies into its base directory"
  echo "and from there into the ISO files directory."
  echo "AUTOINST_FILE specifies a AutoYaST control file which matches to this system"
  echo "either as absolute path of a local file of the form '/path/to/file'"
  echo "or as relative path of the form 'path/to/file'."
  echo "If it is a relative path, it is relative to the base directory."
  echo "Alternatively AUTOINST_FILE is either an absolute path of a local executable"
  echo "file of the form '/path/to/executable' or it is a relative path of an"
  echo "executable file of the form 'path/to/executable'."
  echo "If it is a relative path, it is relative to the base directory."
  echo "The executable must output on its standard output 'stdout' the path of the"
  echo "actual 'autoinst.xml' file so that it works to extract the path with the"
  echo "command: grep -o '[^[:space:]]*autoinst\.xml' | tail -n 1"
  echo "If it is a relative path, it is relative to the base directory."
  echo "This way the executable can make the AutoYaST control file and finally"
  echo "it tells $MY_NAME the path to 'autoinst.xml' via 'stdout'."
  echo "With 'use-autoinst-from-base-dir' an AutoYaST control file in the base"
  echo "directory named 'autoinst.xml' or '$MY_NAME.autoinst.xml' is used."
  echo "If such a file does not exist, $MY_NAME will use the latest"
  echo "'$MY_NAME.TIMESTAMP.autoinst.xml'."
  echo "The AutoYaST control file must not yet contain the 'chroot script' because"
  echo "this will be added by $MY_NAME in any case." 
  echo ""
  echo "-m specifies the medium:"
  echo "With 'autodetect-dvd' $MY_NAME requests and tries to autodetect" 
  echo "an install medium. Autodetection depends on whether or not" 
  echo "automated media mounting magic works on this system."
  echo "MEDIUM_URI specifies the directory where the medium files are located"
  echo "which are copied into an ISO files directory to make the ISO image."
  echo "MEDIUM_URI is either an absolute path of a local directory of the"
  echo "form '/path/to/directory' or it is a relative path 'path/to/directory'"
  echo "If it is a relative path, it is relative to the base directory."
  echo "Alternatively MEDIUM_URI is of the form 'http://server/path/medium.iso'"
  echo "so that 'wget http://server/path/medium.iso' works."
  echo "In this case $MY_NAME will download an ISO image of the medium"
  echo "into the base directory as file '$MY_NAME.TIMESTAMP.MEDIUM.iso'"
  echo "and mount it with 'mount -o loop' and use the mount point"
  echo "as the directory where the medium files are located."
  echo "Alternatively MEDIUM_URI is either an absolute path to a local"
  echo "medium ISO file of the form '/path/to/medium.iso' or it is a relative path"
  echo "of the form 'path/to/medium.iso' which is relative to the base directory."
  echo "Alternatively MEDIUM_URI is either an absolute path of a local executable"
  echo "file of the form '/path/to/executable' or it is a relative path of an"
  echo "executable file of the form 'path/to/executable'."
  echo "If it is a relative path, it is relative to the base directory."
  echo "The executable must output on its standard output 'stdout' the path of the"
  echo "actual 'medium.iso' file or the actual 'medium.dir' directory so that"
  echo "it works to extract the path with the command:"
  echo "egrep -o '[^[:space:]]*medium\.iso|[^[:space:]]*medium\.dir' | tail -n 1"
  echo "If it is a relative path, it is relative to the base directory."
  echo "This way the executable can make a medium ISO file or a medium directory"
  echo "and finally it tells $MY_NAME the path via 'stdout'."
  echo "$MY_NAME will mount a medium ISO file with 'mount -o loop'"
  echo "and use the mount point as the directory where the medium files are located."
  echo "With 'use-existing-medium-ISO' $MY_NAME will look in its base directory"
  echo "for an existing medium ISO file named 'MEDIUM.iso' or"
  echo "'$MY_NAME.MEDIUM.iso' otherwise."
  echo "If such a file does not exist, $MY_NAME will use the latest file"
  echo "named '$MY_NAME.TIMESTAMP.MEDIUM.iso' as medium ISO file and"
  echo "mount it with 'mount -o loop' and use the mount point"
  echo "as the directory where the medium files are located."
  echo "With 'use-existing-ISO-files' $MY_NAME will look in its base directory"
  echo "for an existing ISO files sub-directory named 'ISOfiles' or"
  echo "'$MY_NAME.ISOfiles' otherwise."
  echo "If such a sub-directory does not exist, $MY_NAME will use the latest"
  echo "sub-directory '$MY_NAME.TIMESTAMP.ISOfiles' as ISO files directory."
  echo "Such an existing ...ISOfiles sub-directory must already contain all files"
  echo "to make the ISO image except autoinst.xml but with already appropriate"
  echo "modified loader/isolinux.cfg and loader/message files."
  echo ""
  echo "-i specifies the installation:"
  echo "With 'install-RPMs' AutoYaST installs RPMs from the recovery medium"
  echo "to recreate the system."
  echo "With 'skip-RPM-install' AutoYaST basically recreates only partitioning"
  echo "with filesystems and mount points but AutoYaST does not install RPMs."
  echo "Nevertheless the RPMs are still included in the ISO image"
  echo "(unless 'use-existing-ISO-files' is used without RPM payload in the"
  echo "ISO files directory) so that the recovery medium could still be used"
  echo "for a manual installation without AutoYaST."
  echo "A complete backup is mandatory to recreate the system when 'skip-RPM-install'"
  echo "is used."
  echo "With 'no-RPM-payload' the RPM files in the ISO files directory are made empty"
  echo "so that there is no longer RPM payload which results a small recovery medium."
  echo "In this case only 400MB free space is needed in the base directory to make"
  echo "a CD ISO image."
  echo "Without RPM payload on the recovery medium AutoYaST cannot install RPMs"
  echo "so that also with 'no-RPM-payload' AutoYaST does not install RPMs"
  echo "(same as with 'skip-RPM-install')."
  echo ""
  echo "-r specifies the backup restore:"
  echo "With 'restore-all' all files from the backup are restored using the 'tar'"
  echo "program."
  echo "With 'restore-exclude-default' files matching the 'tar' patterns"
  echo "'$RESTORE_EXCLUDE_DEFAULT'"
  echo "are by default excluded from the restore."
  echo "When AutoYaST recreates partitioning with filesystems and mount points"
  echo "a matching /etc/fstab is created anew by AutoYaST and /etc/mtab is"
  echo "maintained by the 'mount' program so that it may cause damage if those"
  echo "files would be overwritten by possibly outdated files from the backup."
  echo "Furthermore scripts and log files of the current restore which are"
  echo "in /var/adm/autoinstall/ should not be overwritten by outdated files"
  echo "from the backup."
  echo "RESTORE_EXCLUDE are 'tar' patterns separated by space which are excluded"
  echo "from the backup restore. If RESTORE_EXCLUDE contains 'restore-exclude-default'"
  echo "the above listed 'tar' patterns for 'restore-exclude-default' are also"
  echo "excluded together with the other 'tar' patterns in RESTORE_EXCLUDE."
  echo ""
  echo "-c specifies the configuration:"
  echo "With 'configure-all' AutoYaST does all configurations which are specified"
  echo "in the autoinst file."
  echo "CONFIGURE_EXCLUDE are configuration section names separated by space"
  echo "which will be removed by $MY_NAME from the autoinst file so that"
  echo "those configurations are skipped."
  echo "With 'skip-second-stage' the whole 'second stage' of the installation"
  echo "is skipped which means that no configuration at all is done by AutoYaST."
  echo "In this case all configuration files must come from the backup so that"
  echo "a complete backup is mandatory when 'skip-second-stage' is used."
  echo "'skip-second-stage' is an experimental feature which is currently"
  echo "implemented by a dirty hack to circumvent the usual AutoYaST workflow."
  echo "It may cause issues because AutoYaST is not yet prepared for the case"
  echo "when the whole 'second stage' of the installation workflow is skipped."
  echo ""
  echo "Exported variables:"
  echo ""
  echo "All variables which are modified or created are automatically exported"
  echo "to have them available in a backup executable, an autoinst executable,"
  echo "and a medium executable. In particular those variables:"
  echo "PATH = /sbin:/usr/sbin:/usr/bin:/bin"
  echo "LANG = POSIX"
  echo "LC_ALL = POSIX"
  echo "MY_NAME = $MY_NAME"
  echo "TIMESTAMP : date and time when $MY_NAME was started"
  echo "MY_PREFIX = $MY_NAME.TIMESTAMP"
  echo "BASE_URI"
  echo "BASE_DIR : the base directory"
  echo "LOG_DIR"
  echo "LOG_FILE : the primary log file"
  echo "BACKUP_URI"
  echo "AUTOINST_FILE"
  echo "MEDIUM_URI"
  echo "RPM_PAYLOAD_HANDLING : install-RPMs/skip-RPM-install/no-RPM-payload"
  echo "RESTORE_EXCLUDE_DEFAULT : what restore-exclude-default results"
  echo "RESTORE_EXCLUDE"
  echo "CONFIGURE_EXCLUDE"
  echo "BACKUP_EXECUTABLE_STDOUT : whereto stdout of a backup executable goes"
  echo "BACKUP_EXECUTABLE_STDERR : whereto stderr of a backup executable goes"
  echo "AUTOINST_EXECUTABLE_STDOUT : whereto stdout of an autoinst executable goes"
  echo "AUTOINST_EXECUTABLE_STDERR : whereto stderr of an autoinst executable goes"
  echo "MEDIUM_EXECUTABLE_STDOUT : whereto stdout of a medium executable goes"
  echo "MEDIUM_EXECUTABLE_STDERR : whereto stderr of a medium executable goes"
  echo ""
  echo "Examples:"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l /var/log -b make-rear-backup -a clone-system \\"
  echo "$MY_BLNK -m autodetect-dvd -i install-RPMs -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b use-existing-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b nfs://host/path/backup.tar.gz \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b /path/to/make_my_backup.sh \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make_my_backup.sh \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs -r restore-all \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a /root/autoinst.xml -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a autoinst.xml -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a /path/to/make_my_autoinst_xml.sh -m autodetect-dvd \\"
  echo "$MY_BLNK -i install-RPMs -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a make_my_autoinst_xml.sh -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a use-autoinst-from-base-dir -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m /media/SLES11-DVD.123 -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m SLES11-DVD.123 -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m http://server/path/medium.iso \\"
  echo "$MY_BLNK -i install-RPMs -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m /path/to/medium.iso -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m medium.iso -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m /path/to/make_my_medium_iso.sh \\"
  echo "$MY_BLNK -i install-RPMs -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m make_my_medium_iso.sh -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m /path/to/make_my_medium_dir.sh \\"
  echo "$MY_BLNK -i install-RPMs -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d nfs://host/basedir -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m make_my_medium_dir.sh -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m use-existing-medium-ISO -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m use-existing-ISO-files -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i skip-RPM-install \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i no-RPM-payload \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-exclude-default -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r 'var/log var/tmp' -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r 'var/log var/tmp restore-exclude-default' \\"
  echo "$MY_BLNK -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c configure-all"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c 'printer sound'"
  echo ""
  echo "$MY_NAME -d /var/tmp -l log-to-base-dir -b make-rear-backup \\"
  echo "$MY_BLNK -a clone-system -m autodetect-dvd -i install-RPMs \\"
  echo "$MY_BLNK -r restore-all -c skip-second-stage"
  echo ""
  echo "Exit status:"
  echo ""
  echo "0 : ISO image made"
  echo "1 : Failed because of an error"
  echo "2 : ISO image made but there have been serious warnings"
  echo ""
  echo "See also:"
  echo ""
  echo "For the full documentation for $MY_NAME see the README file"
  echo "$README_FILE_NAME"
  echo ""
}

# Directories used by this script but not necessarily by the 'chroot script':
TMP_DIR="/tmp"
LOG_DIR=$TMP_DIR
MOUNTPOINT_DIR=$TMP_DIR

# Function to create a clean file name $1 from scratch (without ugly '.XXXXXX' suffix as in 'mktemp -u'):
CleanFileName()
{ # This should be safe because it runs as root so that any existing file named $1 should be removable:
  rm -f $1
  echo $1
}

# Function to create a safe mountpoint directory with an optional extension $1:
SafeMountpoint()
{ if test -n "$1"
  then mktemp -d $MOUNTPOINT_DIR/$MY_PREFIX.$1.MOUNTPOINT.XXXXXX
  else mktemp -d $MOUNTPOINT_DIR/$MY_PREFIX.MOUNTPOINT.XXXXXX
  fi
}

# Create a temporary log file (used only for LogMessage while getting the parameters):
LOG_FILE=$( CleanFileName $LOG_DIR/$MY_PREFIX.LOG )

# Function to output $1 as stderr message:
StderrMessage()
{ echo "$MY_NAME: $1" 1>&2
}

# Get the parameters from the command line before anything is written to any (log)-file
# so that the HelpMessage can be shown without anything written to any file:
while getopts :d:l:b:a:m:i:r:c:h OPTION
do case $OPTION in
        d) BASE_URI="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        l) LOG_DIR="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        b) BACKUP_URI="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        a) AUTOINST_FILE="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        m) MEDIUM_URI="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        i) RPM_PAYLOAD_HANDLING="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        r) RESTORE_EXCLUDE="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        c) CONFIGURE_EXCLUDE="$OPTARG" ; COMMAND_LINE_OPTION_SET="yes" ;;
        h) HelpMessage ; exit 0 ;;
        :) StderrMessage "Error: Option -$OPTARG requires an argument." ; SynopsisMessage ; exit 1 ;;
        \?) SynopsisMessage ; exit 1 ;;
   esac
done

# Abort if another process with MY_NAME seems to be running at the same time.
# Using a simple 'pgrep' test for now (instead of a /var/run/MY_NAME/pid solution):
if ! test "$( pgrep "$MY_NAME" )" = "$$"
then StderrMessage "Aborting: Another $MY_NAME process is already running."
     exit 1
fi

# Make sure the effective user ID is 0 (i.e. this script must run as root):
if ! test "$( id -u )" = "0"
then StderrMessage "Error: Need 'root' privileges but the effective user ID is not '0'."
     exit 1
fi

# Function to do a sudden exit:
SuddenExit()
{ StderrMessage "Sudden exit: No cleanup done (for debugging). In particular check what might be still mounted."
  exit 1
}

# Function to output $1 as log message:
LogMessage()
{ echo "$MY_NAME $( date +%F_%T ) : $1" 1>&2
}

# Function to output $1 as normal message:
OutMessage()
{ if test -n "$1"
  then echo "$MY_NAME: $1" | fold -s -w $OUTPUT_LINE_WIDTH
  else echo ""
  fi
}

# Function to output $1 as user input request message:
InMessage()
{ if test -n "$1"
  then echo "$MY_NAME: $1" | fold -s -w $OUTPUT_LINE_WIDTH
       echo -n "$MY_BLNK  "
  else echo ""
  fi
}

# Function to check if user input is meant positive 'yes' or negative 'no':
PositiveUserInput()
{ for I in $( seq 3 )
  do read USER_INPUT
     case "$USER_INPUT" in
          [1yYzZ] | [yYzZ][eE][sS] ) return 0 ;;
          [0nN] | [nN][oO] ) return 1 ;;
          * ) InMessage "Enter one of yes/y/Y/1 or one of no/n/N/0" ;;
     esac
  done
  LogMessage "Error: Invaild user input (neither yes/y/Y/1 nor no/n/N/0)."
  SuddenExit
}

# Function to check if the file $1 is a vaild XML file:
ValidateXML()
{ if ! xmllint --noout $1
  then LogMessage "Error: $1 is not a vaild XML file ('xmllint' failed)."
       SuddenExit
  fi
}

XSLTPROC="$( type -P xsltproc )"
# If the following commands do not work, the REMOVE_TOP_LEVEL_SECTION_XSL_FILE_NAME should be empty:
REMOVE_TOP_LEVEL_SECTION_XSL_FILE_NAME="$( rpm -ql $( rpm -qf $( type -p $MY_NAME ) 2>/dev/null ) 2>/dev/null | grep remove-TOP_LEVEL_SECTION.xsl )"

# Function to remove the top level section $1 in the autoinst.xml file $2:
RemoveTopLevelSection()
{ if ! test -n "$1" -a -n "$2"
  then LogMessage "Error: RemoveTopLevelSection called with empty section '$1' or file '$2'"
       SuddenExit
  fi
  LogMessage "Removing '$1' section from $2..."
  if test -x "$XSLTPROC" -a -n "$REMOVE_TOP_LEVEL_SECTION_XSL_FILE_NAME"
  then # Use xsltproc with an xsl file:
       # If there is no closing xml element </section_name> at all
       # regardless if this element </section_name> is really the
       # closing xml element of a top level section or of another nested section
       # then there is no such top level section:
       if ! grep -q "</$1>" $2
       then LogMessage "...found no '$1' section in $2"
            # It is perfectly o.k. (in particular it is no error) when there is no such section:
            return 0
       fi
       TMP_AUTOINST=$( CleanFileName $TMP_DIR/$MY_PREFIX.TMP_AUTOINST )
       TMP_XSL=$( CleanFileName $TMP_DIR/$MY_PREFIX.TMP_XSL )
       if ! sed -e "s/TOP_LEVEL_SECTION/$1/" $REMOVE_TOP_LEVEL_SECTION_XSL_FILE_NAME >$TMP_XSL
       then LogMessage "Error: 'sed' failed to make $TMP_XSL to remove '$1' section."
            SuddenExit
       fi
       if ! $XSLTPROC -o $TMP_AUTOINST $TMP_XSL $2
       then LogMessage "Error: '$XSLTPROC' failed to remove '$1' section."
            SuddenExit
       fi
       if ! cp $TMP_AUTOINST $2
       then LogMessage "Error: 'cp $TMP_AUTOINST $2' failed after removal of '$1' section."
            SuddenExit
       fi
       ValidateXML $2
       rm -f $TMP_AUTOINST
       rm -f $TMP_XSL
       LogMessage "...removed '$1' section via 'xsltproc' from $2"
       return 0
  fi
  # Use sed as fallback:
  # Be careful what to match because there is '<firewall>no</firewall>' in the 'networking' section
  # and '<groups>video,dialout</groups>' in the 'user_defaults' section and more such stuff elsewhere.
  # The closing xml element for top level sections is </section_name>:
  NUMBER_OF_CLOSING_XML_ELEMENTS=$( grep -c "^[[:space:]]*</$1>$" $2 )
  if test "0" = "$NUMBER_OF_CLOSING_XML_ELEMENTS"
  then LogMessage "...found no '$1' section in $2"
       # It is perfectly o.k. (in particular it is no error) when there is no such section:
       return 0
  fi
  if test "$NUMBER_OF_CLOSING_XML_ELEMENTS" -ge "2"
  then SERIOUS_WARNINGS="yes"
       LogMessage "Warning: Cannot remove '$1' section because"
       LogMessage "Warning: $2"
       LogMessage "Warning: contains more than one '</$1>' entry"
       LogMessage "Warning: so that it is ambiguous."
       return 1
  fi
  # There are two kind of opening xml elements for top level sections:
  # <section_name> and <section_name config:type="list">.
  # Testing for <section_name>:
  NUMBER_OF_OPENING_XML_ELEMENTS=$( grep -c "^[[:space:]]*<$1>$" $2 )
  if test "$NUMBER_OF_OPENING_XML_ELEMENTS" -ge "2" 
  then SERIOUS_WARNINGS="yes"
       LogMessage "Warning: Cannot remove '$1' section because"
       LogMessage "Warning: $2"
       LogMessage "Warning: contains more than one '<$1>' entry"
       LogMessage "Warning: so that it is ambiguous."
       return 1
  fi
  if test "1" = "$NUMBER_OF_OPENING_XML_ELEMENTS"
  then if ! sed -i -e "/^[[:space:]]*<$1>$/,/^[[:space:]]*<\/$1>$/d" $2
       then LogMessage "Error: 'sed' failed to remove '$1' section from $2"
            SuddenExit
       fi
       ValidateXML $2
       LogMessage "...removed '$1' section via 'sed' from $2"
       return 0
  fi
  # Testing for <section_name config:type="list">:
  NUMBER_OF_OPENING_XML_ELEMENTS=$( grep -c "^[[:space:]]*<$1 config:type=\"list\">$" $2 )
  if test "$NUMBER_OF_OPENING_XML_ELEMENTS" -ge "2"       
  then SERIOUS_WARNINGS="yes"
       LogMessage "Warning: Cannot remove '$1' section because"
       LogMessage "Warning: $2"
       LogMessage "Warning: contains more than one '<$1 config:type=\"list\">' entry"
       LogMessage "Warning: so that it is ambiguous."
       return 1
  fi
  if test "1" = "$NUMBER_OF_OPENING_XML_ELEMENTS"
  then if ! sed -i -e "/^[[:space:]]*<$1 config:type=\"list\">$/,/^[[:space:]]*<\/$1>$/d" $2
       then LogMessage "Error: 'sed' failed to remove '$1' list section from $2"
            SuddenExit
       fi
       ValidateXML $2
       LogMessage "...removed '$1' list section via 'sed' from $2"
       return 0
  fi
  # Found closing </section_name> but no opening <section_name> or <section_name config:type="list"> found:
  SERIOUS_WARNINGS="yes"
  LogMessage "Warning: Cannot remove '$1' section because"
  LogMessage "Warning: $2"
  LogMessage "Warning: contains neither a <$1> entry"
  LogMessage "Warning: nor a <$1 config:type=\"list\"> entry."
  return 1
}

# Have a new file descriptor 3 which is a copy of the stdout file descriptor:
exec 3>&1
# Have a new file descriptor 4 which is a copy of the stderr file descriptor:
exec 4>&2
# Have stdout on the terminal and also in the log file:
exec 1> >( exec -a $MY_NAME:tee tee -a $LOG_FILE )
TEE_PID=$!
# Make stderr what stdout already is (i.e. terminal and also in the log file):
exec 2>&1

# Start the actual work:
LogMessage "Created files have prefix $MY_PREFIX with timestamp in 'date +%Y%m%d%H%M%S' format."

# Get the parameters:
if test -n "$COMMAND_LINE_OPTION_SET"
then # Log the parameters from the command line:
     LogMessage "The parameters from the command line are..."
     LogMessage "BASE_URI = $BASE_URI"
     LogMessage "LOG_DIR = $LOG_DIR"
     LogMessage "BACKUP_URI = $BACKUP_URI"
     LogMessage "AUTOINST_FILE = $AUTOINST_FILE"
     LogMessage "MEDIUM_URI = $MEDIUM_URI"
     LogMessage "RPM_PAYLOAD_HANDLING = $RPM_PAYLOAD_HANDLING"
     LogMessage "RESTORE_EXCLUDE = $RESTORE_EXCLUDE"
     LogMessage "CONFIGURE_EXCLUDE = $CONFIGURE_EXCLUDE"
else if test "$#" = "$NUMBER_OF_COMMAND_LINE_PARAMETERS"
     then # Get the parameters if provided as positional parameters at the command line:
          LogMessage "Getting positional parameters from the command line..."
          BASE_URI="$1"
          LogMessage "BASE_URI = $BASE_URI"
          LOG_DIR="$2"
          LogMessage "LOG_DIR = $LOG_DIR"
          BACKUP_URI="$3"
          LogMessage "BACKUP_URI = $BACKUP_URI"
          AUTOINST_FILE="$4"
          LogMessage "AUTOINST_FILE = $AUTOINST_FILE"
          MEDIUM_URI="$5"
          LogMessage "MEDIUM_URI = $MEDIUM_URI"
          RPM_PAYLOAD_HANDLING="$6"
          LogMessage "RPM_PAYLOAD_HANDLING = $RPM_PAYLOAD_HANDLING"
          RESTORE_EXCLUDE="$7"
          LogMessage "RESTORE_EXCLUDE = $RESTORE_EXCLUDE"
          CONFIGURE_EXCLUDE="$8"
          LogMessage "CONFIGURE_EXCLUDE = $CONFIGURE_EXCLUDE"
     else # Ask for the parameters:
          LogMessage "Asking for the parameters..."
          OutMessage "Regarding the base directory:"
          InMessage "Enter a directory with usually 10GB free space to make a DVD ISO image:"
          read BASE_URI
          LogMessage "The base directory is $BASE_URI"
          OutMessage "Regarding the log files:"
          InMessage "Should the log files be in the directory which is specified via $BASE_URI?"
          if PositiveUserInput
          then LogMessage "The log files will be in the directory which is specified via $BASE_URI"
               LOG_DIR="log-to-base-dir"
          else InMessage "Enter directory for the log files:"
               read LOG_DIR
               LogMessage "The log files will be in the directory $LOG_DIR"
          fi
          OutMessage "Regarding the backup:"
          InMessage "Should ReaR make a backup now (may overwrite an existing backup)?"
          if PositiveUserInput
          then LogMessage "ReaR will make a backup."
               BACKUP_URI="make-rear-backup"
          else LogMessage "ReaR will not make a backup."
               InMessage "Should an already existing ReaR backup file be used?"
               if PositiveUserInput
               then LogMessage "An existing ReaR backup file will be used."
                    BACKUP_URI="use-existing-rear-backup"
               else LogMessage "No already existing ReaR backup file will be used."
                    InMessage "Enter backup URI of the form nfs://host/path/backup.tar.gz or a path to an executable:"
                    read BACKUP_URI
                    LogMessage "The BACKUP_URI is $BACKUP_URI"
               fi
          fi
          OutMessage "Regarding AutoYaST:"
          InMessage "Should AutoYaST create a control file (needed to recreate the system)?"
          if PositiveUserInput
          then LogMessage "AutoYaST will create a control file."
               AUTOINST_FILE="clone-system"
          else LogMessage "AutoYaST will not create a control file."
               InMessage "Should 'autoinst.xml' in the directory which is specified via $BASE_URI be used?" 
               if PositiveUserInput
               then LogMessage "'autoinst.xml' from the directory which is specified via $BASE_URI will be used."
                    AUTOINST_FILE="use-autoinst-from-base-dir"
               else InMessage "Enter AutoYaST control file name (e.g. /root/autoinst.xml) or a path to an executable:"
                    read AUTOINST_FILE
                    LogMessage "The AUTOINST_FILE file is $AUTOINST_FILE"
               fi
          fi
          OutMessage "Regarding the install medium:"
          InMessage "Should an install medium requested and autodetect when needed later?"
          if PositiveUserInput
          then LogMessage "An install medium will be requested and autodetected."
               MEDIUM_URI="autodetect-dvd"
          else LogMessage "An install medium will neither be requested nor autodetected."
               InMessage "Should already existing medium files be used?"
               if PositiveUserInput
               then LogMessage "Already existing medium files will be used."
                    MEDIUM_URI="use-existing-ISO-files"
               else InMessage "Mount an install medium now and enter its mount point or enter an executable:"
                    read MEDIUM_URI
                    LogMessage "The MEDIUM_URI is $MEDIUM_URI"
               fi
          fi
          OutMessage "Regarding installing RPMs when recovering this particular system:"
          InMessage "Should AutoYaST install RPMs to recreate the basic system?"
          if PositiveUserInput
          then LogMessage "AutoYaST will install RPMs to recreate the basic system."
               RPM_PAYLOAD_HANDLING="install-RPMs"
          else LogMessage "AutoYaST will not install RPMs so that a complete backup is mandatory."
               RPM_PAYLOAD_HANDLING="skip-RPM-install"
               InMessage "Should the RPM payload be removed from the ISO image for a small recovery medium (about 400MB)?"
               if PositiveUserInput
               then LogMessage "The RPM payload will be removed from the ISO image."
                    RPM_PAYLOAD_HANDLING="no-RPM-payload"
               fi
          fi
          OutMessage "Regarding excluding files from the backup restore:"
          InMessage "Should all files from the backup be restored?"
          if PositiveUserInput
          then LogMessage "All files from the backup will be restored."
               RESTORE_EXCLUDE="restore-all"
          else InMessage "Should files matching '$RESTORE_EXCLUDE_DEFAULT' be excluded from the restore?"
               if PositiveUserInput
               then LogMessage "Files matching '$RESTORE_EXCLUDE_DEFAULT' will be excluded from the restore."
                    RESTORE_EXCLUDE="restore-exclude-default"
               else InMessage "Enter 'tar' patterns separated by space which should be excluded from the restore:"
                    read RESTORE_EXCLUDE
                    LogMessage "Files matching '$RESTORE_EXCLUDE' will be excluded from the restore."
               fi
          fi
          OutMessage "Regarding excluding configurations:"
          InMessage "Should AutoYaST do all configurations which are specified in the control file?"
          if PositiveUserInput
          then LogMessage "AutoYaST will do all configurations as specified in the control file."
               CONFIGURE_EXCLUDE="configure-all"
          else InMessage "Should all configurations (i.e. the whole 'second stage') be skipped?"
               if PositiveUserInput
               then LogMessage "The whole 'second stage' will be skipped."
                    CONFIGURE_EXCLUDE="skip-second-stage"
               else InMessage "Enter configuration section names separated by space which should be excluded:"
                    read CONFIGURE_EXCLUDE
                    LogMessage "Configuration sections '$CONFIGURE_EXCLUDE' will be excluded."
               fi
          fi

     fi
fi
if test -z "$BASE_URI" -o -z "$LOG_DIR" -o -z "$BACKUP_URI" -o -z "$AUTOINST_FILE" -o -z "$MEDIUM_URI" -o -z "$RPM_PAYLOAD_HANDLING" -o -z "$RESTORE_EXCLUDE" -o -z "$CONFIGURE_EXCLUDE"
then LogMessage "Error: At least one parameter is not set."
     # No need to keep the messages in the temporary log file:
     rm -f $LOG_FILE
     SynopsisMessage
     exit 1
fi
LogMessage "...got the parameters."

# Set the BASE_DIR:
if echo "$BASE_URI" | grep -q '^nfs://'
then # Create a temporary directory to have a mount point for the NFS share of the BASE_URI:
     BASE_MOUNTPOINT=$( SafeMountpoint "BASE" )
     # BASE_URI is of the form 'nfs://host/directory' so that 'mount -t nfs host:/directory' works:
     BASE_HOST=$( echo "$BASE_URI" | cut -s -d '/' -f3 )
     BASE_SHARE=$( echo "$BASE_URI" | cut -s -d '/' -f4- )
     # Mount the NFS share of the BASE_URI:
     LogMessage "Mounting the NFS share of $BASE_URI..."
     BASE_MOUNT_COMMAND="mount -t nfs $BASE_HOST:/$BASE_SHARE $BASE_MOUNTPOINT"
     LogMessage "$BASE_MOUNT_COMMAND"
     if ! $BASE_MOUNT_COMMAND
     then LogMessage "Error: mount failed."
          # No need to keep the messages in the temporary log file:
          rm -f $LOG_FILE
          exit 1
     fi
     LogMessage "...mounted the NFS share of $BASE_URI at $BASE_MOUNTPOINT"
     # Use a hostname sub-directory as base directory if exists:
     if test -d "$BASE_MOUNTPOINT/$( hostname )"
     then LogMessage "Using '$( hostname )' sub-directory in $BASE_URI as base directory."
          BASE_DIR="$BASE_MOUNTPOINT/$( hostname )"
     else BASE_DIR="$BASE_MOUNTPOINT"
     fi
     # Test whether or not there is read/write access at the NFS share of the BASE_URI because
     # 'mount -o rw' does not test it so that it would fail later when it is set 'ro' on the NFS server:
     INSUFFICIENT_NFS_PERMISSIONS=""
     TEST_DIR="$BASE_DIR/$MY_PREFIX.test_dir"
     TEST_FILE="$TEST_DIR/test_file"
     rm -rf $TEST_DIR
     if ! mkdir $TEST_DIR
     then LogMessage "Error: Cannot create a directory in $BASE_DIR"
          # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
          INSUFFICIENT_NFS_PERMISSIONS="yes"
     fi
     if ! echo "Write test" >$TEST_FILE
     then LogMessage "Error: Cannot write $TEST_FILE"
          # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
          INSUFFICIENT_NFS_PERMISSIONS="yes"
     fi
     if ! cat $TEST_FILE >/dev/null
     then LogMessage "Error: Cannot read $TEST_FILE"
          # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
          INSUFFICIENT_NFS_PERMISSIONS="yes"
     fi
     # When the files from the install medium are copied with 'cp -a' into the BASE_DIR
     # commands like 'chown' and 'chmod' must work to preserve file ownership and permissions:
     if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
     then if ! chown root:root $TEST_DIR
          then LogMessage "Error: Cannot change directory ownership of $TEST_DIR"
               # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
               INSUFFICIENT_NFS_PERMISSIONS="yes"
          fi
          if ! chmod a+rwx $TEST_DIR
          then LogMessage "Error: Cannot change directory permissions of $TEST_DIR"
               # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
               INSUFFICIENT_NFS_PERMISSIONS="yes"
          fi
          if ! chown root:root $TEST_FILE
          then LogMessage "Error: Cannot change file ownership of $TEST_FILE"
               # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
               INSUFFICIENT_NFS_PERMISSIONS="yes"
          fi
          if ! chmod a+rwx $TEST_FILE
          then LogMessage "Error: Cannot change file permissions of $TEST_FILE"
               # Deferred 'exit 1' until the NFS share of the BASE_URI was un-mounted:
               INSUFFICIENT_NFS_PERMISSIONS="yes"
          fi
     fi
     rm -rf $TEST_DIR
     if test -n "$INSUFFICIENT_NFS_PERMISSIONS"
     then LogMessage "Error: Insufficient permissions for the NFS share of $BASE_URI"
          LogMessage "Un-mounting the NFS share of $BASE_URI from $BASE_DIR..."
          if ! umount $BASE_DIR
          then LogMessage "Error: 'umount $BASE_DIR' failed."
               # No need to keep the messages in the temporary log file:
               rm -f $LOG_FILE
               exit 1
          fi
          LogMessage "...un-mounted the NFS share of $BASE_URI"
          if ! rmdir $BASE_DIR
          then LogMessage "Error: 'rmdir $BASE_DIR' failed."
               # No need to keep the messages in the temporary log file:
               rm -f $LOG_FILE
               exit 1
          fi
          # No need to keep the messages in the temporary log file:
          rm -f $LOG_FILE
          # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
          exit 1
    fi
else # BASE_URI is an absolute path of a local directory of the form '/path/to/directory'.
     # Use a hostname sub-directory as base directory if exists:
     if test -d "$BASE_URI/$( hostname )"
     then LogMessage "Using '$( hostname )' sub-directory in $BASE_URI as base directory."
          BASE_DIR="$BASE_URI/$( hostname )"
     else BASE_DIR="$BASE_URI"
     fi
fi
if ! test -d "$BASE_DIR"
then LogMessage "Error: '$BASE_DIR' should be used as base directory but is no directory."
     # No need to keep the messages in the temporary log file:
     rm -f $LOG_FILE
     exit 1
fi
LogMessage "The base directory is $BASE_DIR"

# Create the real log file:
if test "log-to-base-dir" = "$LOG_DIR"
then LOG_DIR="$BASE_DIR"
fi
# If the user provided LOG_DIR is TMP_DIR there is nothing to do here
# because the above temporary log file is already the real log file:
if ! test "$LOG_DIR" = "$TMP_DIR"
then REAL_LOG_FILE=$( CleanFileName $LOG_DIR/$MY_PREFIX.LOG )
     if ! cp -p $LOG_FILE $REAL_LOG_FILE
     then LogMessage "Error: 'cp -p $LOG_FILE $REAL_LOG_FILE' failed."
          # No need to keep the messages in the temporary log file:
          rm -f $LOG_FILE
          rm -f $REAL_LOG_FILE
          exit 1
     fi
     # Close stdout and stderr to finish the current MY_NAME:tee logging process:
     exec 1>&-
     exec 2>&-
     # Reopen stdout as what was saved in file descriptor 3:
     exec 1>&3
     # Reopen stderr as what was saved in file descriptor 4:
     exec 2>&4
     # Again have stdout on the terminal and also in the real log file:
     exec 1> >( exec -a $MY_NAME:tee tee -a $REAL_LOG_FILE )
     TEE_PID=$!
     # Again make stderr what stdout already is (i.e. terminal and also in the real log file):
     exec 2>&1
     # Remove the temporary log file:
     rm -f $LOG_FILE
     LOG_FILE="$REAL_LOG_FILE"
fi
# Show the log file name:
LogMessage "The primary log file is $LOG_FILE"

# Set ISO_DIR and ISO_FILE:
if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
then # Create a clean directory for all the files for the ISO image:
     ISO_DIR="$BASE_DIR/$MY_PREFIX.ISOfiles"
     if test -e "$ISO_DIR"
     then LogMessage "Error: ISO files directory $ISO_DIR already exists."
          SuddenExit
     fi
     if ! mkdir "$ISO_DIR"
     then LogMessage "Error: 'mkdir $ISO_DIR' failed."
          SuddenExit
     fi
     LogMessage "The files of the install medium will be copied to $ISO_DIR to make the ISO image."
else # Re-using existing medium files requires them to be in a sub-directory named 'ISOfiles'
     # or 'MY_NAME.ISOfiles' or 'MY_NAME.TIMESTAMP.ISOfiles' with latest TIMESTAMP:
     if test -d "$BASE_DIR/ISOfiles"
     then ISO_DIR="$BASE_DIR/ISOfiles"
     else if test -d "$BASE_DIR/$MY_NAME.ISOfiles"
          then ISO_DIR="$BASE_DIR/$MY_NAME.ISOfiles"
          else # Re-enable bash file name globbing:
               set +f
               LATEST_ISO_DIR="$( ls -1d $BASE_DIR/$MY_NAME.*.ISOfiles | sort | tail -n 1 )"
               # Re-disable bash file name globbing:
               set -f
               if test -d "$LATEST_ISO_DIR"
               then ISO_DIR="$LATEST_ISO_DIR"
               else LogMessage "Error: Found no 'ISOfiles' directory in $BASE_DIR"
                    SuddenExit
               fi
          fi
     fi
     LogMessage "Using existing files in $ISO_DIR for the ISO image."
fi
ISO_FILE="$BASE_DIR/$MY_PREFIX.iso"
LogMessage "The ISO image will be $ISO_FILE"

# Test if it seems that the RPM payload is there when 'use-existing-ISO-files' plus 'install-RPMs' is used:
if test "use-existing-ISO-files" = "$MEDIUM_URI" -a "install-RPMs" = "$RPM_PAYLOAD_HANDLING"
then ISO_DIR_NOARCH_RPMS_USED_MB="$( du -mLs $ISO_DIR/suse/noarch | grep -o '^[0-9][0-9]*' )"
    if ! test "$ISO_DIR_NOARCH_RPMS_USED_MB" -ge "10"
    then LogMessage "Error: It seems there is no RPM payload in $ISO_DIR but 'install-RPMs' was specified."
         SuddenExit
    fi
fi

# Test if there is sufficient free space at the BASE_DIR:
LogMessage "Testing if there is sufficient free disk space..."
FREE_MB="$( df -B 1M $BASE_DIR | tail -n 1 | tr -s '[:blank:]' ' ' | cut -s -d ' ' -f 4 )"
if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
then # If MEDIUM_URI is of the form 'http://...'
     # a medium ISO file is downloaded into BASE_DIR.
     if echo "$MEDIUM_URI" | grep -q '^http://'
     then # The files for the medium will be copied into a directory in BASE_DIR
          # and BASE_DIR must have free space for the ISO image:
          if ! test "no-RPM-payload" = "$RPM_PAYLOAD_HANDLING"
          then # 15G = 15000M = 5000M for the medium ISO file
               #              + 5000M for the medium files
               #              + 5000M for the recovery ISO image with RPM payload:
               if ! test "$FREE_MB" -ge "15000"
               then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but 15 GB is needed."
                    SuddenExit
               fi
          else # 10G = 5000M for the medium ISO file
               #     + 5000M for the initially copied medium files before the RPM payload will be removed and
               # after the RPM payload was removed there is 400M free space for the ISO image without RPM payload:
               if ! test "$FREE_MB" -ge "10000"
               then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but 10 GB is needed."
                    SuddenExit
               fi
          fi
          LogMessage "$FREE_MB MB in $BASE_DIR should be sufficient to download a medium ISO file and for medium files plus recovery ISO image."
     else # The files for the medium will be copied into a directory in BASE_DIR
          # and BASE_DIR must have free space for the ISO image:
          if ! test "no-RPM-payload" = "$RPM_PAYLOAD_HANDLING"
          then # 10G = 10000M = 5000M for the medium files + 5000M for the ISO image with RPM payload:
               if ! test "$FREE_MB" -ge "10000"
               then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but 10 GB is needed."
                    SuddenExit
               fi
          else # 5G = 5000M for the initially copied medium files before the RPM payload will be removed and
               # after the RPM payload was removed there is 400M free space for the ISO image without RPM payload:
               if ! test "$FREE_MB" -ge "5000"
               then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but 5 GB is needed."
                    SuddenExit
               fi
          fi
          LogMessage "$FREE_MB MB in $BASE_DIR should be sufficient for medium files and ISO image."
     fi
else # The existing medium files in ISO_DIR are used and therefore the BASE_DIR must have free space
     # only for the ISO image which needs about the same space as the disk usage of the medium files
     # if not 'no-RPM-payload' is used:
     if ! test "no-RPM-payload" = "$RPM_PAYLOAD_HANDLING"
     then ISO_DIR_USED_MB="$( du -mLs $ISO_DIR | grep -o '^[0-9][0-9]*' )"
          if ! test "$FREE_MB" -ge "$ISO_DIR_USED_MB"
          then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but $ISO_DIR_USED_MB MB is needed."
               SuddenExit
          fi
     else # 400M free space for the ISO image without RPM payload is needed
          # if the RPM payload in ISO_DIR is already removed.
          # In contrast if there is RPM payload in ISO_DIR but it will be removed in the current run
          # after the removal there will be 400M free space for the ISO image without RPM payload
          # so that FREE_MB could be zero but this special case is not specifically tested here.
          if ! test "$FREE_MB" -ge "400"
          then LogMessage "Error: $BASE_DIR has $FREE_MB MB free space but 400 MB is needed."
               SuddenExit
          fi
     fi
     LogMessage "$FREE_MB MB in $BASE_DIR should be sufficient for the ISO image."
fi
LogMessage "...tested that there is sufficient free space."

# Create a temporary directory to have a mount point for the backup:
BACKUP_MOUNTPOINT=$( SafeMountpoint "BACKUP" )
# Using '-o nolock' to keep NFS locks local is mandatory otherwise the BACKUP_MOUNT_COMMAND would fail
# when it is run by AutoYaST because at that time rpc.statd is not running which is required for remote locking:
BACKUP_MOUNT_COMMAND_OPTIONS="-o nolock"
if test "make-rear-backup" = "$BACKUP_URI" -o "use-existing-rear-backup" = "$BACKUP_URI"
then # Create temporary files for ReaR:
     REAR_DUMP_DATA=$( CleanFileName $LOG_DIR/$MY_PREFIX.REAR_DUMP_DATA )
     REAR_MKBACKUPONLY_LOG=$( CleanFileName $LOG_DIR/$MY_PREFIX.REAR_MKBACKUPONLY_LOG )
     # Test if rear is executable:
     REAR="$( type -P rear )"
     if ! test -x "$REAR"
     then LogMessage "Error: Cannot execute rear."
          SuddenExit
     fi
     # Get the ReaR configuration data:
     LogMessage "Getting the ReaR configuration data..."
     if ! $REAR dump | tr -d '[:blank:]' >$REAR_DUMP_DATA
     then LogMessage "Error: '$REAR dump' failed."
          SuddenExit
     fi
     LogMessage "The ReaR configuration data is in $REAR_DUMP_DATA"
     LogMessage "...got the ReaR configuration data."
     # Test if the ReaR configuration matches to what is supported:
     if ! grep -q '^BackupwithNETFS$' $REAR_DUMP_DATA
     then LogMessage "Error: Only ReaR backup method 'NETFS' is supported."
          SuddenExit
     fi
     if ! grep -q '^BACKUP_PROG=tar$' $REAR_DUMP_DATA
     then LogMessage "Error: Only ReaR backup program 'tar' is supported."
          SuddenExit
     fi
     if ! grep -q '^BACKUP_PROG_COMPRESS_OPTIONS=--gzip$' $REAR_DUMP_DATA
     then LogMessage "Error: Only ReaR backup compress option 'gzip' is supported."
          SuddenExit
     fi
     # Make a new ReaR backup (if not an already existing ReaR backup should be used):
     if test "make-rear-backup" = "$BACKUP_URI"
     then LogMessage "Making a new ReaR backup..."
          LogMessage "Log messages while making the ReaR backup are in $REAR_MKBACKUPONLY_LOG"
          if ! $REAR mkbackuponly 2>&1 | tee $REAR_MKBACKUPONLY_LOG
          then LogMessage "Error: '$REAR mkbackuponly' failed, see the log $REAR_MKBACKUPONLY_LOG"
               SuddenExit
          fi
          LogMessage "...made a new ReaR backup."
     else
          LogMessage "Using an already existing ReaR backup."
     fi
     # Get the ReaR URL where ReaR has stored its backup:
     # The URL defines the remote share as <proto>://<host>/<share> e.g.: nfs://host.domain/path/path/path
     # others might also work, if they can be mounted with the command: mount -t <proto> <host>:/<share>
     # Example: NETFS_URL=nfs://loki.suse.de/real-home/jsmeix/rear-backup
     REAR_NETFS_URL=$( grep '^NETFS_URL=' $REAR_DUMP_DATA | cut -d '=' -f2 )
     REAR_NETFS_PROTO=$( echo "$REAR_NETFS_URL" | cut -s -d ':' -f1 )
     REAR_NETFS_HOST=$( echo "$REAR_NETFS_URL" | cut -s -d '/' -f3 )
     REAR_NETFS_SHARE=$( echo "$REAR_NETFS_URL" | cut -s -d '/' -f4- )
     # Mount the NFS share where ReaR has stored its backup:
     LogMessage "Mounting the NFS share where ReaR has stored its backup..."
     BACKUP_MOUNT_COMMAND_WITHOUT_MOUNTPOINT="mount $BACKUP_MOUNT_COMMAND_OPTIONS -t $REAR_NETFS_PROTO $REAR_NETFS_HOST:/$REAR_NETFS_SHARE"
     BACKUP_MOUNT_COMMAND="$BACKUP_MOUNT_COMMAND_WITHOUT_MOUNTPOINT $BACKUP_MOUNTPOINT"
     LogMessage "$BACKUP_MOUNT_COMMAND"
     if ! $BACKUP_MOUNT_COMMAND
     then LogMessage "Error: mount failed."
          SuddenExit
     fi
     LogMessage "...mounted the NFS share where ReaR has stored its backup."
     # Get the ReaR backup file name items:
     # Example: NETFS_PREFIX=caps
     REAR_NETFS_PREFIX=$( grep '^NETFS_PREFIX=' $REAR_DUMP_DATA | cut -d '=' -f2 )
     # Example: BACKUP_PROG_ARCHIVE=backup
     REAR_BACKUP_PROG_ARCHIVE=$( grep '^BACKUP_PROG_ARCHIVE=' $REAR_DUMP_DATA | cut -d '=' -f2 )
     # Example: BACKUP_PROG_SUFFIX=.tar
     REAR_BACKUP_PROG_SUFFIX=$( grep '^BACKUP_PROG_SUFFIX=' $REAR_DUMP_DATA | cut -d '=' -f2 )
     # Example: BACKUP_PROG_COMPRESS_SUFFIX=.gz
     REAR_BACKUP_PROG_COMPRESS_SUFFIX=$( grep '^BACKUP_PROG_COMPRESS_SUFFIX=' $REAR_DUMP_DATA | cut -d '=' -f2 )
     # Build the backup file name:
     BACKUP_FILE_WITHOUT_MOUNTPOINT="$REAR_NETFS_PREFIX/$REAR_BACKUP_PROG_ARCHIVE$REAR_BACKUP_PROG_SUFFIX$REAR_BACKUP_PROG_COMPRESS_SUFFIX"
     BACKUP_FILE="$BACKUP_MOUNTPOINT/$BACKUP_FILE_WITHOUT_MOUNTPOINT"
else # The BACKUP_URI is neither 'make-rear-backup' nor 'use-existing-rear-backup':
     if ! echo "$BACKUP_URI" | grep -q '^nfs://'
     then # The BACKUP_URI is not 'nfs://...' so that it must be a path to an executable
          # either an absolute path of a local executable file
          # or a relative path of an executable file in the base directory:
          if ! echo "$BACKUP_URI" | grep -q '^/'
          then BACKUP_EXECUTABLE="$BASE_DIR/$BACKUP_URI"
          else BACKUP_EXECUTABLE="$BACKUP_URI"
          fi
          LogMessage "Using backup executable '$BACKUP_EXECUTABLE'"
          if ! test -e "$BACKUP_EXECUTABLE"
          then LogMessage "Error: There is no backup executable '$BACKUP_EXECUTABLE'"
               SuddenExit
          fi
          if ! test -f "$BACKUP_EXECUTABLE"
          then LogMessage "Error: The backup executable is no regular file '$BACKUP_EXECUTABLE'"
               SuddenExit
          fi
          if ! test -x "$BACKUP_EXECUTABLE"
          then LogMessage "Error: Cannot execute backup executable '$BACKUP_EXECUTABLE'"
               SuddenExit
          fi
          LogMessage "Running backup executable $BACKUP_EXECUTABLE..."
          # Have stdout and stderr of the backup executable in LOG_DIR:
          BACKUP_EXECUTABLE_STDOUT=$( CleanFileName $LOG_DIR/$MY_PREFIX.BACKUP_EXECUTABLE_STDOUT )
          LogMessage "Backup executable stdout is in '$BACKUP_EXECUTABLE_STDOUT'"
          BACKUP_EXECUTABLE_STDERR=$( CleanFileName $LOG_DIR/$MY_PREFIX.BACKUP_EXECUTABLE_STDERR )
          LogMessage "Backup executable stderr is in '$BACKUP_EXECUTABLE_STDERR'"
          # Run the backup executable:
          $BACKUP_EXECUTABLE 1>$BACKUP_EXECUTABLE_STDOUT 2>$BACKUP_EXECUTABLE_STDERR
          EXIT_CODE=$?
          if ! test "0" = "$EXIT_CODE"
          then LogMessage "Error: Backup executable failed with exit code '$EXIT_CODE'"
               SuddenExit
          fi
          LogMessage "...backup executable finished with exit code '$EXIT_CODE'"
          # Extract the backup URI of the form nfs://host/path/backup.tar.gz from stdout of the backup executable:
          BACKUP_URI="$( grep -o 'nfs://.*\.tar\.gz' $BACKUP_EXECUTABLE_STDOUT | tail -n 1 )"
          if ! test -n "$BACKUP_URI"
          then LogMessage "Error: Backup executable stdout does not contain a backup URI of the form 'nfs://...tar.gz'"
               SuddenExit
          fi
     fi
     # The BACKUP_URI is now of the form nfs://host/path/backup.tar.gz:
     LogMessage "Using backup URI '$BACKUP_URI'"
     BACKUP_URI_PROTO=$( echo "$BACKUP_URI" | cut -s -d ':' -f1 )
     if ! test "nfs" = "$BACKUP_URI_PROTO"
     then LogMessage "Error: Only a backup URI 'nfs://host/path/backup.tar.gz' is supported."
          SuddenExit
     fi
     BACKUP_URI_HOST=$( echo "$BACKUP_URI" | cut -s -d '/' -f3 )
     BACKUP_URI_SHARE_AND_FILE=$( echo "$BACKUP_URI" | cut -s -d '/' -f4- )
     BACKUP_URI_SHARE=${BACKUP_URI_SHARE_AND_FILE%/*}
     BACKUP_URI_FILE=${BACKUP_URI_SHARE_AND_FILE##*/}
     # Mount the NFS share where the backup is stored:
     LogMessage "Mounting the NFS share where the backup is stored..."
     BACKUP_MOUNT_COMMAND_WITHOUT_MOUNTPOINT="mount $BACKUP_MOUNT_COMMAND_OPTIONS -t $BACKUP_URI_PROTO $BACKUP_URI_HOST:/$BACKUP_URI_SHARE"
     BACKUP_MOUNT_COMMAND="$BACKUP_MOUNT_COMMAND_WITHOUT_MOUNTPOINT $BACKUP_MOUNTPOINT"
     LogMessage "$BACKUP_MOUNT_COMMAND"
     if ! $BACKUP_MOUNT_COMMAND
     then LogMessage "Error: mount failed."
          SuddenExit
     fi
     LogMessage "...mounted the NFS share where the backup is stored."
     # Build the backup file name:
     BACKUP_FILE_WITHOUT_MOUNTPOINT="$BACKUP_URI_FILE"
     BACKUP_FILE="$BACKUP_MOUNTPOINT/$BACKUP_FILE_WITHOUT_MOUNTPOINT"
fi
# Test if the backup file is readable:
LogMessage "Testing if the backup file is readable..."
BACKUP_FILE_NOT_READABLE=""
if ! test -e $BACKUP_FILE
then LogMessage "Error: There is no backup file $BACKUP_FILE"
     # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
     BACKUP_FILE_NOT_READABLE="yes"
else if ! test -f $BACKUP_FILE
     then LogMessage "Error: The backup is no regular file $BACKUP_FILE"
          # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
          BACKUP_FILE_NOT_READABLE="yes"
     else if ! test -r $BACKUP_FILE
          then LogMessage "Error: Cannot read backup file $BACKUP_FILE"
               # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
               BACKUP_FILE_NOT_READABLE="yes"
          else if ! file -Lz $BACKUP_FILE | grep -q 'tar archive.*compressed data'
               then LogMessage "Error: 'file -z $BACKUP_FILE' does not show 'tar archive ... compressed data'."
                    # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
                    BACKUP_FILE_NOT_READABLE="yes"
               fi
               LogMessage "...backup file $BACKUP_FILE is readable."
               LogMessage "Testing if the backup file is suspicious small..."
               BACKUP_FILE_USED_MB="$( du -mLs $BACKUP_FILE | grep -o '^[0-9][0-9]*' )"
               if ! test "$BACKUP_FILE_USED_MB" -ge "100"
               then SERIOUS_WARNINGS="yes"
                    LogMessage "Warning: Backup file $BACKUP_FILE"
                    LogMessage "Warning: has only $BACKUP_FILE_USED_MB MB which is suspicious small."
                    LogMessage "Warning: Verify that your particular backup is really correct."
               else LogMessage "...backup file $BACKUP_FILE has $BACKUP_FILE_USED_MB MB."
               fi
          fi
     fi
fi
# Un-mount the NFS share where the backup is stored:
# The actual backup file is no longer needed because
# it was tested if the backup file is accessible so that from now on
# only its reference values (NFS share plus backup file name) are needed.
LogMessage "Un-mounting the NFS share where the backup is stored..."
if ! umount $BACKUP_MOUNTPOINT
then LogMessage "Error: 'umount $BACKUP_MOUNTPOINT' failed."
     SuddenExit
fi
LogMessage "...un-mounted the NFS share where the backup is stored."
if ! rmdir $BACKUP_MOUNTPOINT
then LogMessage "Error: 'rmdir $BACKUP_MOUNTPOINT' failed."
     SuddenExit
fi
if test -n "$BACKUP_FILE_NOT_READABLE"
then # Deferred 'exit 1' until the NFS share where the backup is stored was un-mounted:
     SuddenExit
fi

# Make a new AutoYaST /root/autoinst.xml (if not an already existing AutoYaST control file should be used):
if test "clone-system" = "$AUTOINST_FILE"
then LogMessage "Making a new AutoYaST /root/autoinst.xml..."
     if ! test -f /usr/share/YaST2/clients/clone_system.ycp
     then LogMessage "Error: /usr/share/YaST2/clients/clone_system.ycp not found."
          SuddenExit
     fi
     # Save an existing AutoYaST /root/autoinst.xml file:
     if test -f /root/autoinst.xml
     then LogMessage "Saving existing AutoYaST /root/autoinst.xml file..."
          AUTOINST_SAVE_FILE="/root/$MY_PREFIX.autoinst.xml.save"
          if ! mv /root/autoinst.xml $AUTOINST_SAVE_FILE
          then LogMessage "Error: 'mv /root/autoinst.xml $AUTOINST_SAVE_FILE' failed."
               SuddenExit
          fi
          LogMessage "...saved /root/autoinst.xml file as $AUTOINST_SAVE_FILE"
     fi
     # Run the AutoYaST client clone_system:
     LogMessage "Running the AutoYaST client clone_system..."
     # Sleep one second so that the user can notice the above current LogMessage:
     sleep 1
     if ! yast2 --ncurses /usr/share/YaST2/clients/clone_system.ycp
     then LogMessage "Error: 'yast2 --ncurses /usr/share/YaST2/clients/clone_system.ycp' failed."
          SuddenExit
     fi
     LogMessage "...finished the AutoYaST client clone_system."
     LogMessage "...made a new AutoYaST /root/autoinst.xml"
     AUTOINST_FILE="$BASE_DIR/$MY_PREFIX.autoinst.xml"
     if ! cp -p /root/autoinst.xml $AUTOINST_FILE
     then LogMessage "Error: 'cp -p /root/autoinst.xml $AUTOINST_FILE' failed."
          SuddenExit
     fi
     LogMessage "Copied /root/autoinst.xml to $AUTOINST_FILE"
fi
# An already existing AutoYaST control file in the base directory should be used:
if test "use-autoinst-from-base-dir" = "$AUTOINST_FILE"
then # Using an existing AutoYaST control file requires it to be 'autoinst.xml'
     # or 'MY_NAME.autoinst.xml' or 'MY_NAME.TIMESTAMP.autoinst.xml' with latest TIMESTAMP:
     if test -r "$BASE_DIR/autoinst.xml"
     then AUTOINST_FILE="$BASE_DIR/autoinst.xml"
     else if test -r "$BASE_DIR/$MY_NAME.autoinst.xml"
          then AUTOINST_FILE="$BASE_DIR/$MY_NAME.autoinst.xml"
          else # Re-enable bash file name globbing:
               set +f
               LATEST_AUTOINST_FILE="$( ls -1d $BASE_DIR/$MY_NAME.*.autoinst.xml | sort | tail -n 1 )"
               # Re-disable bash file name globbing:
               set -f
               if test -r "$LATEST_AUTOINST_FILE"
               then AUTOINST_FILE="$LATEST_AUTOINST_FILE"
               else LogMessage "Error: Found no 'autoinst.xml' file in the base directory $BASE_DIR"
                    SuddenExit
               fi
          fi
     fi
fi
# AUTOINST_FILE specifies a path to an existing autoinst.xml file or to an executable:
if ! test "clone-system" = "$AUTOINST_FILE" -o "use-autoinst-from-base-dir" = "$AUTOINST_FILE"
then # If AUTOINST_FILE specifies a relative path, it is relative to the base directory:
     if ! echo "$AUTOINST_FILE" | grep -q '^/'
     then AUTOINST_FILE="$BASE_DIR/$AUTOINST_FILE"
     fi
     if ! test -e "$AUTOINST_FILE"
     then LogMessage "Error: There is no AUTOINST_FILE '$AUTOINST_FILE'"
          SuddenExit
     fi
     if ! test -f "$AUTOINST_FILE"
     then LogMessage "Error: The AUTOINST_FILE is no regular file '$AUTOINST_FILE'"
          SuddenExit
     fi
     if test -x "$AUTOINST_FILE"
     then # If AUTOINST_FILE specifies an executable, run it:
          AUTOINST_EXECUTABLE="$AUTOINST_FILE"
          LogMessage "Running executable AUTOINST_FILE $AUTOINST_EXECUTABLE..."
          # Have stdout and stderr of the autoinst executable in LOG_DIR:
          AUTOINST_EXECUTABLE_STDOUT=$( CleanFileName $LOG_DIR/$MY_PREFIX.AUTOINST_EXECUTABLE_STDOUT )
          LogMessage "Autoinst executable stdout is in '$AUTOINST_EXECUTABLE_STDOUT'"
          AUTOINST_EXECUTABLE_STDERR=$( CleanFileName $LOG_DIR/$MY_PREFIX.AUTOINST_EXECUTABLE_STDERR )
          LogMessage "Autoinst executable stderr is in '$AUTOINST_EXECUTABLE_STDERR'"
          # Run the autoinst executable:
          $AUTOINST_EXECUTABLE 1>$AUTOINST_EXECUTABLE_STDOUT 2>$AUTOINST_EXECUTABLE_STDERR
          EXIT_CODE=$?
          if ! test "0" = "$EXIT_CODE"
          then LogMessage "Error: Autoinst executable failed with exit code '$EXIT_CODE'"
               SuddenExit
          fi
          LogMessage "...autoinst executable finished with exit code '$EXIT_CODE'"
          # Extract the path of the actual 'autoinst.xml' file from stdout of the autoinst executable:
          AUTOINST_FILE="$( grep -o '[^[:space:]]*autoinst\.xml' $AUTOINST_EXECUTABLE_STDOUT | tail -n 1 )"
          if ! test -n "$AUTOINST_FILE"
          then LogMessage "Error: Autoinst executable stdout does not contain 'autoinst.xml' file name."
               SuddenExit
          fi
          # If AUTOINST_FILE specifies a relative path, it is relative to the base directory:
          if ! echo "$AUTOINST_FILE" | grep -q '^/'
          then AUTOINST_FILE="$BASE_DIR/$AUTOINST_FILE"
          fi
     fi
fi
LogMessage "Using AutoYaST autoinst file $AUTOINST_FILE"
# Test if AUTOINST_FILE is readable:
if ! test -e "$AUTOINST_FILE"
then LogMessage "Error: There is no autoinst file '$AUTOINST_FILE'"
     SuddenExit
fi
if ! test -f "$AUTOINST_FILE"
then LogMessage "Error: The autoinst file is no regular file '$AUTOINST_FILE'"
     SuddenExit
fi
if ! test -r $AUTOINST_FILE
then LogMessage "Error: Cannot read autoinst file $AUTOINST_FILE"
     SuddenExit
fi
# Test if AUTOINST_FILE is a vaild XML file (ValidateXML does SuddenExit if it fails):
ValidateXML $AUTOINST_FILE
# Test if AUTOINST_FILE seems to belong to this system:
AUTOINST_HOST="$( sed -n -e 's|^[[:space:]]*<hostname>\(.*\)</hostname>|\1|p' $AUTOINST_FILE | tr '[:upper:]' '[:lower:]' )"
if test -n "$AUTOINST_HOST"
then THIS_HOST="$( hostname | tr '[:upper:]' '[:lower:]' )"
     if ! test "$THIS_HOST" = "$AUTOINST_HOST"
     then # Only a note because the hostname entry in autoinst.xml is only a dummy which does not match
          # when the actual hostname is set via DHCP so that this cause would cause false alarm:
          LogMessage "Note: $AUTOINST_FILE"
          LogMessage "Note: seems to belong to host '$AUTOINST_HOST'"
          LogMessage "Note: but this host is '$THIS_HOST'."
          LogMessage "Note: A system which is recreated with this autoinst file"
          LogMessage "Note: will get its hostname set to '$AUTOINST_HOST'."
     fi
fi
# Test if AUTOINST_FILE contains suspicious partitioning data, in particular partitions which
# would be created i.e. with "<create config:type="boolean">true</create>"
# without filesystem i.e. with "<format config:type="boolean">false</format>"
# and mounted i.e. with a non-empty "<mount>...</mount>" entry
# see https://bugzilla.novell.com/show_bug.cgi?id=718118
SUSPICIOUS_MOUNTPOINTS="$( sed -n -e '/<partition>/,/<\/partition>/p' $AUTOINST_FILE | egrep '<partition>|</create>|</format>|</mount>' | tr -d '[:space:]' | sed -e 's/<partition>/\n/g' | grep 'true</create>.*false</format><mount>..*</mount>' | sed -e 's/.*<mount>\([^<]*\)<\/mount>/\1/' | tr -s '[:space:]' ' ' )"
if test -n "$SUSPICIOUS_MOUNTPOINTS"
then SERIOUS_WARNINGS="yes"
     LogMessage "Warning: $AUTOINST_FILE"
     LogMessage "Warning: contains suspicious data for one or more partitions"
     LogMessage "Warning: with those mount points: $SUSPICIOUS_MOUNTPOINTS"
     LogMessage "Warning: During system recovery those partitions"
     LogMessage "Warning: - would be created (via the '<create ...>true</create>' entry)"
     LogMessage "Warning: - without filesystem (via the '<format ...>false</format>' entry)"
     LogMessage "Warning: - and mounted (via the non-empty '<mount>...</mount>' entry)"
     LogMessage "Warning: But it would not work to mount a partition without a filesystem."
     LogMessage "Warning: A possible reason is that on the partition a filesystem is used"
     LogMessage "Warning: which is not supported by AutoYaST so that it cannot recreate"
     LogMessage "Warning: the filesystem."
     LogMessage "Warning: You may have to manually change your autoinst file"
     LogMessage "Warning: so that it works in your particular case to recreate"
     LogMessage "Warning: your particular system (see the README file)."
fi

# Get an install medium and copy all files from the install medium:
if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
then LogMessage "Getting an install medium..."
     if test "autodetect-dvd" = "$MEDIUM_URI"
     then # Autodetect the install medium:
          ASK_FOR_MOUNTPOINT=""
          ISO9660_MOUNTPOINTS=$( CleanFileName $MOUNTPOINT_DIR/$MY_PREFIX.ISO9660_MOUNTPOINTS )
          mount | grep 'type iso9660' | cut -d ' ' -f 3 >$ISO9660_MOUNTPOINTS
          OutMessage ""
          OutMessage "Insert an original SUSE Linux install medium which matches to this system"
          OutMessage "and press [enter] to autodetect its mount point (a mount point with 'type iso9660')"
          OutMessage "provided there is automated media mounting magic running on this system"
          OutMessage "or mount an install medium which matches to this system now manually"
          InMessage "and enter its mount point:"
          read MEDIUM_DIR
          if test -z "$MEDIUM_DIR"
          then LogMessage "Autodetecting install medium mount point..."
               for I in "9" "8" "7" "6" "5" "4" "3" "2" "1" "0"
               do # Sleep a bit to have time for the udev magic to actually mount it (may take up to one minute):
                  sleep 10
                  NEW_ISO9660_MOUNTPOINTS="$( mount | grep 'type iso9660' | cut -d ' ' -f 3 | diff -U 0 $ISO9660_MOUNTPOINTS - | grep '^+/' | cut -d '+' -f2 )"
                  if test -n "$NEW_ISO9660_MOUNTPOINTS"
                  then break
                  fi
                  LogMessage "...waiting for install medium to become automatically mounted ($I)..."
               done
               rm -f $ISO9660_MOUNTPOINTS
               if test -z "$NEW_ISO9660_MOUNTPOINTS"
               then LogMessage "Error: Failed to autodetect a new 'type iso9660' mount point."
                    ASK_FOR_MOUNTPOINT="yes"
               fi
               if ! test "1" = "$( echo $NEW_ISO9660_MOUNTPOINTS | wc -l )"
               then LogMessage "Error: Autodetected more than one 'type iso9660' mount point: $NEW_ISO9660_MOUNTPOINTS"
                    ASK_FOR_MOUNTPOINT="yes"
               fi
               if test "$ASK_FOR_MOUNTPOINT" = "yes"
               then OutMessage "Have an install medium which matches to this system mounted"
                    InMessage "and enter its mount point:"
                    read MEDIUM_DIR
                    if test -z "$MEDIUM_DIR"
                    then LogMessage "Error: No install medium mount point."
                         SuddenExit
                    fi
               else MEDIUM_DIR="$NEW_ISO9660_MOUNTPOINTS"
                    LogMessage "...autodetected install medium mount point."
               fi
          fi
     else # If MEDIUM_URI is of the form 'http://...'
          # a medium ISO file must be downloaded into BASE_DIR:
          if echo "$MEDIUM_URI" | grep -q '^http://'
          then # Create a separated log file for downloading the medium ISO file:
               DOWNLOAD_MEDIUM_LOG=$( CleanFileName $LOG_DIR/$MY_PREFIX.DOWNLOAD_MEDIUM_LOG )
               # Show the log file name for downloading the medium ISO file:
               LogMessage "Log messages while downloading the medium ISO file are in $DOWNLOAD_MEDIUM_LOG"
               # Create a clean file whereto the medium ISO file is downloaded:
               MEDIUM_ISO=$( CleanFileName $BASE_DIR/$MY_PREFIX.MEDIUM.iso )
               LogMessage "The medium ISO file will be downloaded to $MEDIUM_ISO"
               if ! wget -o $DOWNLOAD_MEDIUM_LOG -O $MEDIUM_ISO $MEDIUM_URI
               then LogMessage "Error: Downloading the medium ISO file failed, see $DOWNLOAD_MEDIUM_LOG"
                    SuddenExit
               fi
               # Mount the downloaded medium ISO file:
               MOUNT_MEDIUM_ISO="yes"
          else # If MEDIUM_URI is 'use-existing-medium-ISO'
               # find an existing medium ISO file and mount it:
               if test "use-existing-medium-ISO" = "$MEDIUM_URI"
               then if test -r "$BASE_DIR/MEDIUM.iso"
                    then MEDIUM_ISO="$BASE_DIR/MEDIUM.iso"
                    else if test -r "$BASE_DIR/$MY_NAME.MEDIUM.iso"
                         then MEDIUM_ISO="$BASE_DIR/$MY_NAME.MEDIUM.iso"
                         else # Re-enable bash file name globbing:
                              set +f
                              LATEST_MEDIUM_ISO="$( ls -1d $BASE_DIR/$MY_NAME.*.MEDIUM.iso | sort | tail -n 1 )"
                              # Re-disable bash file name globbing:
                              set -f
                              if test -r "$LATEST_MEDIUM_ISO"
                              then MEDIUM_ISO="$LATEST_MEDIUM_ISO"
                              else LogMessage "Error: Found no 'MEDIUM.iso' file in the base directory $BASE_DIR"
                                   SuddenExit
                              fi
                         fi
                    fi
                    LogMessage "Using existing medium ISO file $MEDIUM_ISO"
                    # Mount the existing medium ISO file:
                    MOUNT_MEDIUM_ISO="yes"
               else # MEDIUM_URI could also specify an existing medium ISO file or directory or executable
                    # via an absolute path of a local medium ISO file or directory or executable
                    # or via a relative path of a medium ISO file or directory or executable in the base directory:
                    if ! echo "$MEDIUM_URI" | grep -q '^/'
                    then MEDIUM_FILE="$BASE_DIR/$MEDIUM_URI"
                    else MEDIUM_FILE="$MEDIUM_URI"
                    fi
                    if ! test -e "$MEDIUM_FILE"
                    then LogMessage "Error: There is no medium directory or file '$MEDIUM_FILE'"
                         SuddenExit
                    fi
                    if ! test -d "$MEDIUM_FILE"
                    then # When MEDIUM_URI does not specify a directory it must specify a medium ISO file
                         # or an executable which makes the medium ISO file or the medium directory:
                         if ! test -f "$MEDIUM_FILE"
                         then LogMessage "Error: The medium file is no regular file '$MEDIUM_FILE'"
                              SuddenExit
                         fi
                         if test -x "$MEDIUM_FILE"
                         then # If MEDIUM_FILE specifies an executable, run it:
                              MEDIUM_EXECUTABLE="$MEDIUM_FILE"
                              LogMessage "Running executable medium file $MEDIUM_EXECUTABLE..."
                              # Have stdout and stderr of the medium executable in LOG_DIR:
                              MEDIUM_EXECUTABLE_STDOUT=$( CleanFileName $LOG_DIR/$MY_PREFIX.MEDIUM_EXECUTABLE_STDOUT )
                              LogMessage "Medium executable stdout is in '$MEDIUM_EXECUTABLE_STDOUT'"
                              MEDIUM_EXECUTABLE_STDERR=$( CleanFileName $LOG_DIR/$MY_PREFIX.MEDIUM_EXECUTABLE_STDERR )
                              LogMessage "Medium executable stderr is in '$MEDIUM_EXECUTABLE_STDERR'"
                              # Run the medium executable:
                              $MEDIUM_EXECUTABLE 1>$MEDIUM_EXECUTABLE_STDOUT 2>$MEDIUM_EXECUTABLE_STDERR
                              EXIT_CODE=$?
                              if ! test "0" = "$EXIT_CODE"
                              then LogMessage "Error: Medium executable failed with exit code '$EXIT_CODE'"
                                   SuddenExit
                              fi
                              LogMessage "...medium executable finished with exit code '$EXIT_CODE'"
                              # Extract the path of the actual 'medium.iso' or 'medium.dir' from stdout of the medium executable:
                              MEDIUM_FILE="$( egrep -o '[^[:space:]]*medium\.iso|[^[:space:]]*medium\.dir' $MEDIUM_EXECUTABLE_STDOUT | tail -n 1 )"
                              if ! test -n "$MEDIUM_FILE"
                              then LogMessage "Error: Medium executable stdout does not contain 'medium.iso' or 'medium.dir'."
                                   SuddenExit
                              fi
                              # If MEDIUM_FILE specifies a relative path, it is relative to the base directory:
                              if ! echo "$MEDIUM_FILE" | grep -q '^/'
                              then MEDIUM_FILE="$BASE_DIR/$MEDIUM_FILE"
                              fi
                              if ! test -e "$MEDIUM_FILE"
                              then LogMessage "Error: There is no medium directory or file '$MEDIUM_FILE'"
                                   SuddenExit
                              fi
                         fi
                    fi
                    if ! test -d "$MEDIUM_FILE"
                    then # When MEDIUM_URI does not specify a directory it must specify a medium ISO file:
                         if ! test -f "$MEDIUM_FILE"
                         then LogMessage "Error: The medium file is no regular file '$MEDIUM_FILE'"
                              SuddenExit
                         fi
                         if ! file -L "$MEDIUM_FILE" | grep -q 'ISO 9660 CD-ROM filesystem data'
                         then LogMessage "Error: A medium file was specified but 'file -L $MEDIUM_FILE' does not show 'ISO 9660 CD-ROM filesystem data'."
                              SuddenExit
                         else MEDIUM_ISO="$MEDIUM_FILE"
                              LogMessage "Using medium ISO file $MEDIUM_ISO"
                              # Mount the existing medium ISO file:
                              MOUNT_MEDIUM_ISO="yes"
                         fi
                    else # MEDIUM_URI does not specify an existing medium ISO file but a directory:
                         MEDIUM_DIR="$MEDIUM_FILE"
                    fi
               fi
          fi
     fi
     if test -n "$MOUNT_MEDIUM_ISO"
     then # Mount the medium ISO file:
          LogMessage "Mounting the medium ISO file $MEDIUM_ISO..."
          # Create a directory to have a mount point for the medium ISO file:
          MEDIUM_DIR=$( SafeMountpoint "MEDIUM" )
          MEDIUM_ISO_MOUNT_COMMAND="mount -o loop $MEDIUM_ISO $MEDIUM_DIR"
          LogMessage "$MEDIUM_ISO_MOUNT_COMMAND"
          if ! $MEDIUM_ISO_MOUNT_COMMAND
          then LogMessage "Error: mount failed."
               SuddenExit
          fi
          LogMessage "...mounted the medium ISO file at $MEDIUM_DIR"
     fi
     LogMessage "Using medium files in $MEDIUM_DIR"
     # Test if what there is in MEDIUM_DIR looks like a real install medium:
     # Re-enable bash file name globbing:
     set +f
     ISOLINUX_CFG="$( ls -1 $MEDIUM_DIR/boot/*/loader/isolinux.cfg )"
     # Re-disable bash file name globbing:
     set -f
     if test -z "$ISOLINUX_CFG"
     then LogMessage "Error: $MEDIUM_DIR/boot/*/loader/isolinux.cfg not found."
          SuddenExit
     fi
     LogMessage "...got install medium at $MEDIUM_DIR"
     # Copy all files from the install medium:
     LogMessage "Copying the files from the install medium into the ISO files directory..."
     # Create a separated log file for copying the files into the ISO files directory:
     COPY_FILES_LOG=$( CleanFileName $LOG_DIR/$MY_PREFIX.COPY_FILES_LOG )
     # Show the log file name for making the ISO image:
     LogMessage "Log messages while copying the files are in $COPY_FILES_LOG"
     # Re-enable bash file name globbing:
     set +f
     if ! cp -av $MEDIUM_DIR/* $ISO_DIR &>$COPY_FILES_LOG
     then LogMessage "Error: Copying the files from the install medium into the ISO files directory failed, see $COPY_FILES_LOG"
          SuddenExit
     fi
     # Re-disable bash file name globbing:
     set -f
     LogMessage "...copied the install medium files to $ISO_DIR"
     # If MEDIUM_URI is of the form 'http://...' or when it is 'use-existing-medium-ISO'
     # or when MEDIUM_URI specifies an existing medium ISO file
     # a medium ISO file was mounted at MEDIUM_DIR
     # which is now no longer needed so that it can be un-mounted:
     if test -n "$MOUNT_MEDIUM_ISO"
     then LogMessage "Un-mounting the medium ISO file from $MEDIUM_DIR..."
          if ! umount $MEDIUM_DIR
          then LogMessage "Error: 'umount $MEDIUM_DIR' failed."
               SuddenExit
          fi
          LogMessage "...un-mounted the medium ISO file $MEDIUM_ISO"
          if ! rmdir $MEDIUM_DIR
          then LogMessage "Error: 'rmdir $MEDIUM_DIR' failed."
               SuddenExit
          fi
     fi
fi

# Make the bootable ISO image of the recovery medium:
if test "no-RPM-payload" = "$RPM_PAYLOAD_HANDLING"
then # Empty the RPM files in the ISO_DIR/suse/<ARCH>/ directories
     # but leave the file names because they are needed during installation:
     LogMessage "Removing the RPM files payload in the ISO files directory..."
     for R in $( find $( readlink -e $ISO_DIR/suse ) -name '*.rpm' )
     do if ! cat /dev/null >$R
        then LogMessage "Error: Emptying the RPM files in the $ISO_DIR/suse/<ARCH>/ directories failed."
             SuddenExit
        fi
     done
     LogMessage "...made the RPM files in the $ISO_DIR/suse/<ARCH>/ directories empty."
fi
# Re-enable bash file name globbing:
set +f
ISOLINUX_CFG="$( ls -1 $ISO_DIR/boot/*/loader/isolinux.cfg )"
# Re-disable bash file name globbing:
set -f
if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
then # Test if the isolinux.cfg file in the ISO_DIR can be modified:
     if ! test -e "$ISOLINUX_CFG"
     then LogMessage "Error: There is no file $ISO_DIR/boot/*/loader/isolinux.cfg"
          SuddenExit
     fi
     if ! test -f "$ISOLINUX_CFG"
     then LogMessage "Error: It is no regular file $ISOLINUX_CFG"
          SuddenExit
     fi
     if ! test -w "$ISOLINUX_CFG"
     then LogMessage "Error: Cannot modify $ISOLINUX_CFG"
          SuddenExit
     fi
     # Modify the isolinux.cfg file in the ISO_DIR:
     LogMessage "Modifying $ISOLINUX_CFG..."
     if grep -q 'label[[:space:]]*autorecover' $ISOLINUX_CFG
     then LogMessage "Error: 'label autorecover' already exists in $ISOLINUX_CFG"
          SuddenExit
     fi
     if ! sed -i -e "/^# install$/i# autorecover\nlabel autorecover\n  kernel linux\n  append initrd=initrd splash=silent showopts autoyast=default netsetup=default\n" $ISOLINUX_CFG
     then LogMessage "Error: Failed to modify $ISOLINUX_CFG"
          SuddenExit
     fi
     # Replace the graphical UI with a text-only UI so that our modified isolinux message file is shown:
     if ! sed -i -e "s/^ui[[:space:]][[:space:]]*.*/display message/" $ISOLINUX_CFG
     then LogMessage "Error: Failed to modify $ISOLINUX_CFG"
          SuddenExit
     fi
     LogMessage "...modified $ISOLINUX_CFG"
else LogMessage "Using existing (unmodified) $ISOLINUX_CFG"
fi
# Get the boot architecture which is needed later in particular also for the mkisofs call:
LogMessage "Getting the boot architecture..."
BOOT_ARCH_DIR=${ISOLINUX_CFG%%/loader/isolinux.cfg}
BOOT_ARCH=${BOOT_ARCH_DIR##*/}
if test -z "$BOOT_ARCH"
then LogMessage "Error: Failed to get the boot architecture."
     SuddenExit
fi
LogMessage "...the boot architecture is $BOOT_ARCH"
ISOLINUX_MESSAGE="$( ls -1 $ISO_DIR/boot/$BOOT_ARCH/loader/message )"
if ! test "use-existing-ISO-files" = "$MEDIUM_URI"
then # Test if the isolinux message file in the ISO_DIR can be modified:
     if ! test -e "$ISOLINUX_MESSAGE"
     then LogMessage "Error: There is no file $ISO_DIR/boot/$BOOT_ARCH/loader/message"
          SuddenExit
     fi
     if ! test -f "$ISOLINUX_MESSAGE"
     then LogMessage "Error: It is no regular file $ISOLINUX_MESSAGE"
          SuddenExit
     fi
     if ! test -w "$ISOLINUX_MESSAGE"
     then LogMessage "Error: Cannot modify $ISOLINUX_MESSAGE"
          SuddenExit
     fi
     # Modify the isolinux message file in the ISO_DIR:
     LogMessage "Modifying $ISOLINUX_MESSAGE..."
     if grep -q '^[[:space:]]*autorecover' $ISOLINUX_MESSAGE
     then LogMessage "Error: Boot option 'autorecover' already exists in $ISOLINUX_MESSAGE"
          SuddenExit
     fi
     if ! sed -i -e "s/Welcome to /Recovery of /" \
                 -e "s/To start the installation enter 'linux' /To do a system recovery enter 'autorecover' /" \
                 -e "/^[[:space:]]*harddisk/a autorecover - Recovery (automated re-installation from scratch)" \
                 -e "/- Installation/d" \
                 -e "/necessary on some tricky hardware/d" \
                 -e "/Have a lot of fun/d" $ISOLINUX_MESSAGE
     then LogMessage "Error: Failed to modify $ISOLINUX_MESSAGE"
          SuddenExit
     fi
     LogMessage "...modified $ISOLINUX_MESSAGE"
else LogMessage "Using existing (unmodified) $ISOLINUX_MESSAGE"
fi
# Copy the AutoYaST autoinst.xml file:
LogMessage "Copying the AutoYaST file into the ISO files directory..."
# The target file must be 'autoinst.xml' in the root directory of the ISO image
# otherwise it would not be found by AutoYaST via the 'autoyast=default' linuxrc parameter:
ISO_AUTOINST_FILE=$ISO_DIR/autoinst.xml
if ! cp -p $AUTOINST_FILE $ISO_AUTOINST_FILE
then LogMessage "Error: 'cp -p $AUTOINST_FILE $ISO_AUTOINST_FILE' failed."
     SuddenExit
fi
LogMessage "...copied the AutoYaST file $AUTOINST_FILE to $ISO_AUTOINST_FILE"
# Modify the AutoYaST file in the ISO_DIR:
LogMessage "Modifying $ISO_AUTOINST_FILE..."
# Test if the AutoYaST file in the ISO_DIR can be modified:
if ! test -w "$ISO_AUTOINST_FILE"
then LogMessage "Error: Cannot modify $ISO_AUTOINST_FILE"
     SuddenExit
fi
# Have a backup of the original autoinst.xml file on the ISO image:
LogMessage "Saving a backup of the original $ISO_AUTOINST_FILE..."
ISO_AUTOINST_FILE_BACKUP=$ISO_AUTOINST_FILE.orig
if ! cp -p $ISO_AUTOINST_FILE $ISO_AUTOINST_FILE_BACKUP
then LogMessage "Error: 'cp -p $ISO_AUTOINST_FILE $ISO_AUTOINST_FILE_BACKUP' failed."
     SuddenExit
fi
LogMessage "...saved the original $ISO_AUTOINST_FILE as $ISO_AUTOINST_FILE_BACKUP"
# Change an infinite timeout for AutoYaST popups to 30 seconds so that
# an unattended system re-installation ignores the issues and tries to continue and
# for an attended system re-installation there is sufficient time to read the popup:
if ! sed -i -e '/<report>/,/<\/report>/s|>0</timeout>|>30</timeout>|' $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to set 30 seconds timeout for AutoYaST popups in $ISO_AUTOINST_FILE"
     SuddenExit
fi
LogMessage "Set 30 seconds timeout for AutoYaST popups in $ISO_AUTOINST_FILE"
# Do not use MOUNTPOINT_DIR but a hardcoded '/tmp/' for the mountpoint in the 'chroot script':
BACKUP_MOUNTPOINT="/tmp/recovery_backup_mountpoint"
BACKUP_MOUNT_COMMAND="$BACKUP_MOUNT_COMMAND_WITHOUT_MOUNTPOINT $BACKUP_MOUNTPOINT"
BACKUP_FILE="$BACKUP_MOUNTPOINT/$BACKUP_FILE_WITHOUT_MOUNTPOINT"
# Avoid the quoting hell by using single quotes and fixed *_PLACEHOLDER strings
# and afterwards replace the *_PLACEHOLDER strings in subsequent sed runs.
# Note the quoting of '&' in '2>\&1' so that sed results '2>&1' and not '2>CHROOT_SCRIPT_PLACEHOLDER1':
CHROOT_SCRIPT='#! /bin/bash\ncd /mnt || exit 1\nmkdir BACKUP_MOUNTPOINT_PLACEHOLDER || exit 1\nBACKUP_MOUNT_COMMAND_PLACEHOLDER || exit 1\nBACKUP_EXCLUDE_COMMAND_PLACEHOLDER || exit 1\ntar -xzvf BACKUP_FILE_PLACEHOLDER -X recovery_backup_restore_exclude 2>\&1 || exit 1\nrm recovery_backup_restore_exclude\numount BACKUP_MOUNTPOINT_PLACEHOLDER\nrmdir BACKUP_MOUNTPOINT_PLACEHOLDER'
SAVE_SYSCONFIG_FILES_SCRIPT=""
if test 'skip-second-stage' = "$CONFIGURE_EXCLUDE"
then SAVE_SYSCONFIG_FILES_SCRIPT='for F in SAVE_SYSCONFIG_FILES_PLACEHOLDER ; do cp -p etc/sysconfig/$F tmp/RecoveryImage.sysconfig.$F.backup ; done\nfor F in SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER ; do cp -p etc/sysconfig/network/$F tmp/RecoveryImage.sysconfig.network.$F.backup ; done'
fi
CHROOT_SCRIPT_XML_HEADER='<script>\n<filename>recovery_backup_restore.sh</filename>\n<chrooted config:type="boolean">false</chrooted>\n<feedback config:type="boolean">false</feedback>\n<debug config:type="boolean">true</debug>\n<interpreter>shell</interpreter>\n<source>'
SCRIPT_XML_FOOTER='</source>\n</script>'
# Carefully insert the 'chroot script' even with already existing scripts in the AutoYaST file:
if grep -q '^[[:space:]]*</chroot-scripts>' $ISO_AUTOINST_FILE
then if ! sed -i -e '/^[[:space:]]*<\/chroot-scripts>/iCHROOT_SCRIPT_XML_HEADER_PLACEHOLDER\n<![CDATA[\nCHROOT_SCRIPT_PLACEHOLDER\nSAVE_SYSCONFIG_FILES_SCRIPT_PLACEHOLDER\n]]>\nSCRIPT_XML_FOOTER_PLACEHOLDER' $ISO_AUTOINST_FILE
     then LogMessage "Error: Failed to insert 'chroot script' template into existing chroot-scripts in $ISO_AUTOINST_FILE"
          SuddenExit
     fi
else if grep -q '^[[:space:]]*</scripts>' $ISO_AUTOINST_FILE
     then if ! sed -i -e '/^[[:space:]]*<\/scripts>/i<chroot-scripts config:type="list">\nCHROOT_SCRIPT_XML_HEADER_PLACEHOLDER\n<![CDATA[\nCHROOT_SCRIPT_PLACEHOLDER\nSAVE_SYSCONFIG_FILES_SCRIPT_PLACEHOLDER\n]]>\nSCRIPT_XML_FOOTER_PLACEHOLDER\n</chroot-scripts>' $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to insert 'chroot script' template into existing scripts in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
     else if ! sed -i -e '/^[[:space:]]*<profile /a<scripts>\n<chroot-scripts config:type="list">\nCHROOT_SCRIPT_XML_HEADER_PLACEHOLDER\n<![CDATA[\nCHROOT_SCRIPT_PLACEHOLDER\nSAVE_SYSCONFIG_FILES_SCRIPT_PLACEHOLDER\n]]>\nSCRIPT_XML_FOOTER_PLACEHOLDER\n</chroot-scripts>\n</scripts>' $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to insert 'chroot script' template into $ISO_AUTOINST_FILE"
               SuddenExit
          fi
     fi
fi
# Now replace the *_PLACEHOLDER strings using '|' instead of '/' because the values of the variables contain '/'.
# Run separated 'sed' commands to be able to show a specific error message for each case and
# to be on the safe side because "echo -e '1\n4' | sed -e '/1/a3' -e '/1/a2'" does
# not result the same as "echo -e '1\n4' | sed -e '/1/a3' | sed -e '/1/a2'" while in contrast
# both "echo -e '1\n4' | sed -e '/4/i2' -e '/4/i3'" and "echo -e '1\n4' | sed -e '/4/i2' | sed -e '/4/i3'"
# result the same:
if ! sed -i -e "s|CHROOT_SCRIPT_XML_HEADER_PLACEHOLDER|$CHROOT_SCRIPT_XML_HEADER|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace CHROOT_SCRIPT_XML_HEADER_PLACEHOLDER by its value '$CHROOT_SCRIPT_XML_HEADER' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s|SCRIPT_XML_FOOTER_PLACEHOLDER|$SCRIPT_XML_FOOTER|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace SCRIPT_XML_FOOTER_PLACEHOLDER by its value '$SCRIPT_XML_FOOTER' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
# Use ':' instead of '/' or '|' because the CHROOT_SCRIPT value contains '/' and '|':
if ! sed -i -e "s:CHROOT_SCRIPT_PLACEHOLDER:$CHROOT_SCRIPT:" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace CHROOT_SCRIPT_PLACEHOLDER by its value '$CHROOT_SCRIPT' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s:SAVE_SYSCONFIG_FILES_SCRIPT_PLACEHOLDER:$SAVE_SYSCONFIG_FILES_SCRIPT:" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace SAVE_SYSCONFIG_FILES_SCRIPT_PLACEHOLDER by its value '$SAVE_SYSCONFIG_FILES_SCRIPT' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s|BACKUP_MOUNTPOINT_PLACEHOLDER|$BACKUP_MOUNTPOINT|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace BACKUP_MOUNTPOINT_PLACEHOLDER by its value '$BACKUP_MOUNTPOINT' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s|BACKUP_MOUNT_COMMAND_PLACEHOLDER|$BACKUP_MOUNT_COMMAND|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace BACKUP_MOUNT_COMMAND_PLACEHOLDER by its value '$BACKUP_MOUNT_COMMAND' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s|BACKUP_FILE_PLACEHOLDER|$BACKUP_FILE|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace BACKUP_FILE_PLACEHOLDER by its value '$BACKUP_FILE' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
# Now replace the BACKUP_EXCLUDE_COMMAND_PLACEHOLDER string as needed:
if test -z "$( echo "$RESTORE_EXCLUDE" | tr -d '[:space:]' )"
then # If RESTORE_EXCLUDE is empty, nothing should be excluded so that all should be restored:
     RESTORE_EXCLUDE="restore-all"
fi
if test "restore-all" = "$RESTORE_EXCLUDE"
then # Provide an empty exclude file, otherwise 'tar ... -X exclude_file' would fail:
     if ! sed -i -e "s|BACKUP_EXCLUDE_COMMAND_PLACEHOLDER|touch recovery_backup_restore_exclude|" $ISO_AUTOINST_FILE
     then LogMessage "Error: Failed to replace BACKUP_EXCLUDE_COMMAND_PLACEHOLDER for 'restore-all' in $ISO_AUTOINST_FILE"
          SuddenExit
     fi
else if test "restore-exclude-default" = "$RESTORE_EXCLUDE"
     then RESTORE_EXCLUDE="$RESTORE_EXCLUDE_DEFAULT"
     fi
     RESTORE_EXCLUDE_EVALUATED=$( echo "$RESTORE_EXCLUDE" | sed -e "s|restore-exclude-default|$RESTORE_EXCLUDE_DEFAULT|" | tr -s '[:space:]' '\n' | sort -u | tr -s '[:space:]' ' ' )
     # The quoting hell requires '\\\n' to get a plain '\n' in the ISO_AUTOINST_FILE:
     if ! sed -i -e "s|BACKUP_EXCLUDE_COMMAND_PLACEHOLDER|echo '$RESTORE_EXCLUDE_EVALUATED' \| tr ' ' '\\\n' >recovery_backup_restore_exclude|" $ISO_AUTOINST_FILE
     then LogMessage "Error: Failed to replace BACKUP_EXCLUDE_COMMAND_PLACEHOLDER by its value '$RESTORE_EXCLUDE_EVALUATED' in $ISO_AUTOINST_FILE"
          SuddenExit
     fi
fi
# Replace SAVE_SYSCONFIG_FILES_PLACEHOLDER and SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER:
if ! sed -i -e "s|SAVE_SYSCONFIG_FILES_PLACEHOLDER|$SAVE_SYSCONFIG_FILES|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace SAVE_SYSCONFIG_FILES_PLACEHOLDER by its value '$SAVE_SYSCONFIG_FILES' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
if ! sed -i -e "s|SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER|$SAVE_SYSCONFIG_NETWORK_FILES|" $ISO_AUTOINST_FILE
then LogMessage "Error: Failed to replace SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER by its value '$SAVE_SYSCONFIG_NETWORK_FILES' in $ISO_AUTOINST_FILE"
     SuddenExit
fi
LogMessage "Added 'chroot script' to restore the backup to $ISO_AUTOINST_FILE"
# If not 'configure-all' was specified, remove configuration sections or skip the "second stage":
if ! test 'configure-all' = "$CONFIGURE_EXCLUDE"
then if ! test 'skip-second-stage' = "$CONFIGURE_EXCLUDE"
     then # Avoid that the 'for' loop runs once when CONFIGURE_EXCLUDE is empty:
          if test -n "$CONFIGURE_EXCLUDE"
          then for C in $CONFIGURE_EXCLUDE
               do RemoveTopLevelSection "$C" $ISO_AUTOINST_FILE
               done
          fi
     else # Special addendum for /etc/init.d/boot.local 
          # to skip the "second stage" and do a plain reboot instead,
          # see https://bugzilla.novell.com/show_bug.cgi?id=729509
          # If /var/lib/YaST2/runme_at_boot exists, the system
          # is currently booting for its very first time after
          # the "first stage" during system installation has completed.
          # If /var/lib/YaST2/runme_at_boot exists, /etc/init.d/boot
          # would run /usr/lib/YaST2/startup/YaST2.Second-Stage
          # but the "second stange" should not run in this case
          # so that it can be removed via /etc/init.d/boot.local
          # which is run by /etc/init.d/boot prior to that,
          # see https://bugzilla.novell.com/show_bug.cgi?id=729509#c3
          # During "first stage" some special backups have been made
          # by RecoveryImage via the "chroot script". Restore them now
          # during the very first boot to revert changes made by (Auto)-YaST
          # during "first stage" after the "chroot script" restored the backup
          # see https://bugzilla.novell.com/show_bug.cgi?id=729509#c5
          # Finally remove the special addendum from /etc/init.d/boot.local
          # so that /var/lib/YaST2/runme_at_boot could work again as intended
          # e.g. for another system recovery without 'skip-second-stage'.
          # Note the quoting of '&' in '\&\&' so that sed results '&&'
          # and not 'CHROOTED_SCRIPT_PLACEHOLDERCHROOTED_SCRIPT_PLACEHOLDER'
          # and the quoting of '\' in 'echo " ... \\$F ... " >>/etc/...'
          # so that sed results 'echo " ... \$F ... " >>/etc/...'.
          # Because it is not possible to quote a single quote character within a quotation using single quotes
          # (i.e. it is not possible to have the single quote character apostrophe within single quotes)
          # the quotation is switched from single quotes to double quotes which contain only the apostrophe character
          # and back to single quotes without spaces in between because the shell interprets it as one long word
          # when both kinds of quotation are "glued" without spaces in between.
          # For example the command: FOO='an apostrophe '"'"' character' ; echo $FOO
          # shows this text: an apostrophe ' character
          # which is used two times to get the sed expression within single quotes: sed -i -e '...'
          CHROOTED_SCRIPT='#! /bin/bash\necho "# Begin RecoveryImage addendum (RPM package rear-SUSE):" >>/etc/init.d/boot.local\necho "echo Running RecoveryImage addendum:" >>/etc/init.d/boot.local\necho "set -x" >>/etc/init.d/boot.local\necho "if test -f /var/lib/YaST2/runme_at_boot" >>/etc/init.d/boot.local\necho "then rm /var/lib/YaST2/runme_at_boot" >>/etc/init.d/boot.local\necho "     for F in SAVE_SYSCONFIG_FILES_PLACEHOLDER ; do cp -p /tmp/RecoveryImage.sysconfig.\\$F.backup /etc/sysconfig/\\$F \&\& rm /tmp/RecoveryImage.sysconfig.\\$F.backup ; done" >>/etc/init.d/boot.local\necho "     for F in SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER ; do cp -p /tmp/RecoveryImage.sysconfig.network.\\$F.backup /etc/sysconfig/network/\\$F \&\& rm /tmp/RecoveryImage.sysconfig.network.\\$F.backup ; done" >>/etc/init.d/boot.local\necho "fi" >>/etc/init.d/boot.local\necho "sed -i -e '"'"'/^# Begin RecoveryImage addendum/,/^# End RecoveryImage addendum/d'"'"' /etc/init.d/boot.local" >>/etc/init.d/boot.local\necho "# End RecoveryImage addendum." >>/etc/init.d/boot.local'
          CHROOTED_SCRIPT_XML_HEADER='<script>\n<filename>skip_second_stage.sh</filename>\n<chrooted config:type="boolean">true</chrooted>\n<feedback config:type="boolean">false</feedback>\n<debug config:type="boolean">true</debug>\n<interpreter>shell</interpreter>\n<source>'
          # Insert the 'chrooted script' into the already existing chroot-scripts section in the AutoYaST file:
          if ! sed -i -e '/^[[:space:]]*<\/chroot-scripts>/iCHROOTED_SCRIPT_XML_HEADER_PLACEHOLDER\n<![CDATA[\nCHROOTED_SCRIPT_PLACEHOLDER\n]]>\nSCRIPT_XML_FOOTER_PLACEHOLDER' $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to insert 'chrooted script' template into existing chroot-scripts in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          if ! sed -i -e "s|CHROOTED_SCRIPT_XML_HEADER_PLACEHOLDER|$CHROOTED_SCRIPT_XML_HEADER|" $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to replace CHROOTED_SCRIPT_XML_HEADER_PLACEHOLDER by its value '$CHROOTED_SCRIPT_XML_HEADER' in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          if ! sed -i -e "s|SCRIPT_XML_FOOTER_PLACEHOLDER|$SCRIPT_XML_FOOTER|" $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to replace SCRIPT_XML_FOOTER_PLACEHOLDER by its value '$SCRIPT_XML_FOOTER' in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          if ! sed -i -e "s|CHROOTED_SCRIPT_PLACEHOLDER|$CHROOTED_SCRIPT|" $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to replace CHROOTED_SCRIPT_PLACEHOLDER by its value '$CHROOTED_SCRIPT' in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          if ! sed -i -e "s|SAVE_SYSCONFIG_FILES_PLACEHOLDER|$SAVE_SYSCONFIG_FILES|" $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to replace SAVE_SYSCONFIG_FILES_PLACEHOLDER by its value '$SAVE_SYSCONFIG_FILES' in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          if ! sed -i -e "s|SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER|$SAVE_SYSCONFIG_NETWORK_FILES|" $ISO_AUTOINST_FILE
          then LogMessage "Error: Failed to replace SAVE_SYSCONFIG_NETWORK_FILES_PLACEHOLDER by its value '$SAVE_SYSCONFIG_NETWORK_FILES' in $ISO_AUTOINST_FILE"
               SuddenExit
          fi
          LogMessage "Added 'chrooted script' to skip the 'second stage' to $ISO_AUTOINST_FILE"
     fi
fi
# If not 'install-RPMs' was specified, replace the "<software>...</software>" section
# by a dummy which effectively lets AutoYaST skip the whole RPM package installation:
if test 'skip-RPM-install' = "$RPM_PAYLOAD_HANDLING" -o 'no-RPM-payload' = "$RPM_PAYLOAD_HANDLING"
then # Remove the software section:
     if ! RemoveTopLevelSection "software" $ISO_AUTOINST_FILE
     then LogMessage "Error: Failed to remove software section to skip RPM package installation in $ISO_AUTOINST_FILE"
          SuddenExit
     fi
     # Add dummy software section:
     if ! sed -i -e '/^[[:space:]]*<profile /a<software>\n<image>\n<script_location>file:///bin/true</script_location>\n</image>\n</software>' $ISO_AUTOINST_FILE
     then LogMessage "Error: Failed to add dummy software section to skip RPM package installation in $ISO_AUTOINST_FILE"
          SuddenExit
     fi
     LogMessage "Added dummy software section to skip the RPM package installation to $ISO_AUTOINST_FILE"
fi
# Test if the modified ISO_AUTOINST_FILE is still a vaild XML file (ValidateXML does SuddenExit if it fails):
ValidateXML $ISO_AUTOINST_FILE
# Test if AUTOINST_FILE contains the mandatory sections.
# If there is no closing xml element </section_name> at all
# regardless if this element </section_name> is really the closing xml element
# of a top level section or of another nested section, then there is no such top level section:
for S in "partitioning" "software" "bootloader"
do if ! grep -q "</$S>" $ISO_AUTOINST_FILE
   then # The test for mandatory sections must be non-fatal,
        # see https://bugzilla.novell.com/show_bug.cgi?id=735652
        # and "What is smallest autoyast profile that makes sense?"
        # in http://www.suse.de/~ug/AutoYaST_FAQ.html
        SERIOUS_WARNINGS="yes"
        LogMessage "Warning: Mandatory section '$S' missing"
        LogMessage "Warning: in $ISO_AUTOINST_FILE"
   fi
done
if ! test 'skip-second-stage' = "$CONFIGURE_EXCLUDE"
then # Test if AUTOINST_FILE contains the required sections for network setup:
     for S in "host" "networking"
     do if ! grep -q "</$S>" $ISO_AUTOINST_FILE
        then SERIOUS_WARNINGS="yes"
             LogMessage "Warning: Required section '$S' for network setup missing"
             LogMessage "Warning: in $ISO_AUTOINST_FILE"
        fi
     done
     # Test if AUTOINST_FILE contains the usually required sections:
     for S in "x11"
     do if ! grep -q "</$S>" $ISO_AUTOINST_FILE
        then LogMessage "Note: Usually required section '$S'"
             LogMessage "Note: missing in $ISO_AUTOINST_FILE"
        fi
     done
     # Test if AUTOINST_FILE contains the usually needed sections:
     for S in "keyboard" "language" "runlevel" "timezone"
     do if ! grep -q "</$S>" $ISO_AUTOINST_FILE
        then LogMessage "Usually needed section '$S' missing in $ISO_AUTOINST_FILE"
        fi
     done
fi
LogMessage "...modified $ISO_AUTOINST_FILE"
# Make a bootable ISO image of all what is in the ISO_DIR:
LogMessage "Making a bootable ISO image..."
rm -f $ISO_FILE
# Just before actually making the ISO image of all what is in the ISO_DIR
# copy the current content in the primary log file LOG_FILE
# into the ISO_DIR to have the primary log file on the ISO image:
LogMessage "Copying the current content in the primary log file into the ISO files directory as $MY_PREFIX.LOG..."
LogMessage "There can be no more log message in $MY_PREFIX.LOG on the ISO image."
ISO_LOG_FILE=$ISO_DIR/$MY_PREFIX.LOG
if ! cp -p $LOG_FILE $ISO_LOG_FILE
then LogMessage "Error: 'cp -p $LOG_FILE $ISO_LOG_FILE' failed."
     SuddenExit
fi
LogMessage "...copied the current content in $LOG_FILE to $ISO_LOG_FILE"
# Remember the number of files and directories in ISO_DIR (needed for a test below):
ISO_DIR_FILES="$( find $( readlink -e $ISO_DIR ) | wc -l )"
LogMessage "Running mkisofs..."
# Create a separated log file for making the ISO image:
MKISOFS_LOG=$( CleanFileName $LOG_DIR/$MY_PREFIX.MKISOFS_LOG )
# See http://tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html
# The El Torito specification requires a "boot catalog" to be created.
# This is a 2048 byte file which is of no interest except it is required.
# The patchwork done by the author of mkisofs will cause it to automatically create the boot catalog,
# but you must specify where the boot catalog will go in the iso9660 filesystem.
BOOT_CATALOG="boot/boot.catalog"
# There is only space for 32 characters volume ID (volume name or label):
if test -n "$AUTOINST_HOST"
then VOLUME_ID="$( echo $AUTOINST_HOST System Recovery | head -c 31 )"
else VOLUME_ID="$( echo $( hostname ) System Recovery | head -c 31 )"
fi
# There is space for 128 characters to describe the preparer of the medium:
PREPARER="$( echo "$MY_PREFIX on $( hostname ) dated $( date +%F_%T ) with $RPM_PAYLOAD_HANDLING" | head -c 127 )"
# Have single quoted values for VOLUME_ID and PREPARER in MKISOFS_COMMAND to be on the safe side.
# The shell interprets it as one long word when quotations and variables are "glued" without spaces in between.
# E.g. foo="my "$HOME" directory" works as intended but foo="my" $HOME "directory" is interpreted different.
MKISOFS_COMMAND="mkisofs -V '"$VOLUME_ID"' -p '"$PREPARER"' -r -J -f -pad -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/$BOOT_ARCH/loader/isolinux.bin -c $BOOT_CATALOG -hide $BOOT_CATALOG -hide-joliet $BOOT_CATALOG -o $ISO_FILE $ISO_DIR"
LogMessage "$MKISOFS_COMMAND"
LogMessage "Log messages while running mkisofs are in $MKISOFS_LOG"
if ! eval $MKISOFS_COMMAND &>$MKISOFS_LOG
then LogMessage "Error: mkisofs failed"
     SuddenExit
fi
LogMessage "...mkisofs finished."
# Make the ISO image so that it can also boot from an USB stick,
# see http://en.opensuse.org/SDB:Live_USB_stick
# Via isohybrid the normal CD-based ISO9660 filesystem gets in its unused sector 0
# a valid-looking DOS-style partition table plus an isolinux MBR
# which loads the same isolinux boot image as the CDROM boot
# so that such an "isohybrid" image can be copied raw to an USB stick
# (e.g. via "dd if=filename.iso of=/dev/sdX")
# and a normal PC BIOS will boot the image directly:
ISOHYBRID="$( type -P isohybrid )"
if test -x "$ISOHYBRID"
then LogMessage "Making the ISO image so that it can also boot from an USB stick..."
     ISOHYBRID_COMMAND="$ISOHYBRID $ISO_FILE"
     LogMessage "$ISOHYBRID_COMMAND"
     if ! $ISOHYBRID_COMMAND
     then LogMessage "Error: isohybrid' failed."
          SuddenExit
     fi
     LogMessage "...made the ISO image so that it also boots from an USB stick."
else SERIOUS_WARNINGS="yes"
     LogMessage "Warning: Cannot make the ISO image so that it can"
     LogMessage "Warning: also boot from an USB stick because"
     LogMessage "Warning: no 'isohybrid' program was found which"
     LogMessage "Warning: should be provided by the 'syslinux' RPM."
     LogMessage "Warning: Therefore the ISO image will only boot from CD/DVD."
fi
LogMessage "...made a bootable ISO image $ISO_FILE"
# Test if the ISO image seems to be o.k.:
LogMessage "Testing if the ISO image seems to be o.k. ..."
ISO_IMAGE_BROKEN=""
if ! file $ISO_FILE | grep -q 'ISO 9660 CD-ROM filesystem data'
then LogMessage "Error: 'file $ISO_FILE' does not show 'ISO 9660 CD-ROM filesystem data'."
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: $ISO_FILE seems to be ISO 9660 CD-ROM filesystem data."
fi
if ! file $ISO_FILE | grep -q 'bootable'
then LogMessage "Error: 'file $ISO_FILE' does not show 'bootable'."
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: $ISO_FILE seems to be bootable."
fi
# Mount the ISO image:
LogMessage "Mounting the ISO image $ISO_FILE..."
# Create a temporary directory to have a mount point for the ISO image:
ISO_IMAGE_MOUNTPOINT=$( SafeMountpoint "ISO_IMAGE" )
ISO_IMAGE_MOUNT_COMMAND="mount -o loop $ISO_FILE $ISO_IMAGE_MOUNTPOINT"
LogMessage "$ISO_IMAGE_MOUNT_COMMAND"
if ! $ISO_IMAGE_MOUNT_COMMAND
then LogMessage "Error: mount failed."
     SuddenExit
fi
LogMessage "...mounted the ISO image at $ISO_IMAGE_MOUNTPOINT"
if ! test -f $ISO_IMAGE_MOUNTPOINT/boot/$BOOT_ARCH/loader/isolinux.cfg
then LogMessage "Error: $ISO_FILE does not contain /boot/$BOOT_ARCH/loader/isolinux.cfg"
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: $ISO_FILE contains /boot/$BOOT_ARCH/loader/isolinux.cfg"
fi
# ValidateXML cannot be used here because it does SuddenExit if it fails:
if ! xmllint --noout $ISO_IMAGE_MOUNTPOINT/autoinst.xml
then LogMessage "Error: 'xmllint --noout $ISO_IMAGE_MOUNTPOINT/autoinst.xml' failed."
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: $ISO_FILE contains a valid /autoinst.xml XML file."
fi
# See "RELAX NG - a schema language for XML" in the AutoYaST documentation
# e.g. at http://www.suse.de/~ug/autoyast_doc/Profile.DTD.html
AUTOYAST_SCHEMA="/usr/share/YaST2/schema/autoyast/rng/profile.rng"
if test -r $AUTOYAST_SCHEMA
then LogMessage "Running RELAX NG schema test:"
     AUTOYAST_SCHEMA_TEST_COMMAND="xmllint --noout --relaxng $AUTOYAST_SCHEMA $ISO_IMAGE_MOUNTPOINT/autoinst.xml"
     LogMessage "$AUTOYAST_SCHEMA_TEST_COMMAND"
     if ! $AUTOYAST_SCHEMA_TEST_COMMAND
     then # Only a note, see https://bugzilla.novell.com/show_bug.cgi?id=734498#c5
          LogMessage "Note: The AutoYaST control file $ISO_IMAGE_MOUNTPOINT/autoinst.xml"
          LogMessage "Note: is a valid XML file but it does not pass the RELAX NG schema test."
          LogMessage "Note: In most cases there is no serious issue so that you can ignore it."
     else LogMessage "O.k: $ISO_FILE contains /autoinst.xml which even passes the RELAX NG schema test."
     fi
fi
ISO_IMAGE_FILES="$( find $( readlink -e $ISO_IMAGE_MOUNTPOINT ) | wc -l )"
if ! test "$ISO_IMAGE_FILES" = "$ISO_DIR_FILES"
then LogMessage "Error: $ISO_FILE contains $ISO_IMAGE_FILES files but $ISO_DIR contains $ISO_DIR_FILES files."
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: $ISO_FILE ($ISO_IMAGE_FILES files) and $ISO_DIR ($ISO_DIR_FILES files) contain same number of files."
fi
# Create a separated log file for checking if all regular files on the ISO image can be read:
READ_ISO_FILES_LOG=$( CleanFileName $LOG_DIR/$MY_PREFIX.READ_ISO_FILES_LOG )
# Show the log file name for for checking if all regular files on the ISO image can be read:
LogMessage "Log messages while checking if all regular files on the ISO image can be read are in $READ_ISO_FILES_LOG"
if ! find $( readlink -e $ISO_IMAGE_MOUNTPOINT ) -type f | xargs -t -n 1 cat 1>/dev/null 2>$READ_ISO_FILES_LOG
then LogMessage "Error: Failed to read regular file(s) in $ISO_FILE, see $READ_ISO_FILES_LOG"
     ISO_IMAGE_BROKEN="yes"
else LogMessage "O.k: all regular files in $ISO_FILE can be read."
fi
# Umount the ISO image:
LogMessage "Un-mounting the ISO image from $ISO_IMAGE_MOUNTPOINT..."
if ! umount $ISO_IMAGE_MOUNTPOINT
then LogMessage "Error: 'umount $ISO_IMAGE_MOUNTPOINT' failed."
     SuddenExit
fi
LogMessage "...un-mounted the ISO image $ISO_FILE"
# Remove the mount point for the ISO image:
if ! rmdir $ISO_IMAGE_MOUNTPOINT
then LogMessage "Error: 'rmdir $ISO_IMAGE_MOUNTPOINT' failed."
     SuddenExit
fi
# The very last log message is whether or not the ISO image seems to be o.k.:
if test -n "$ISO_IMAGE_BROKEN"
then LogMessage "...the ISO image has failures. Do not use it!"
     SuddenExit
fi
LogMessage "...the ISO image seems to be o.k. but you must test if it really works for you."
if test -n "$SERIOUS_WARNINGS"
then LogMessage "Note: There have been serious warnings, see the log file $LOG_FILE"
fi
# No further log messages because when 'log-to-base-dir' the BASE_DIR may become unmounted now:
if echo "$BASE_URI" | grep -q '^nfs://'
then # BASE_URI is of the form 'nfs://host/directory':
     # Un-mount the NFS share of the BASE_DIR.
     LogMessage "Finishing with un-mounting the NFS share of $BASE_URI from $BASE_MOUNTPOINT"
     # No further log messages possible because BASE_DIR becomes unmounted now.
     # If LOG_DIR was initially specified as 'log-to-base-dir'
     # then LOG_DIR was set above to the value of BASE_DIR
     # so that this must be tested to check for 'log-to-base-dir':
     if test "$BASE_DIR" = "$LOG_DIR"
     then # Have stdout and stderr on the terminal but no longer in the log file
          # because when the log file is in the BASE_DIR it cannot be un-mounted
          # because its mount point would be in use by the MY_NAME:tee process
          # which was forked via "exec 1> >( exec -a $MY_NAME:tee tee -a $REAL_LOG_FILE )".
          # Close stdout and stderr to finish the MY_NAME:tee logging process:
          exec 1>&-
          exec 2>&-
          # Reopen stdout as what was saved in file descriptor 3:
          exec 1>&3
          # Reopen stderr as what was saved in file descriptor 4:
          exec 2>&4
          # Wait one second to be on the safe side that the MY_NAME:tee logging process has finished:
          sleep 1
          if ps $TEE_PID 1>/dev/null
          then StderrMessage "$MY_NAME:tee process with PID $TEE_PID is still running"
               StderrMessage "which writes to the log file $LOG_FILE"
               StderrMessage "on $BASE_URI so that un-mounting it may fail."
               StderrMessage "Waiting 60 seconds to give the $MY_NAME:tee"
               StderrMessage "logging process more time to finish"
               for i in $( seq 60 )
               do echo -n '.' 1>&2
                  sleep 1
               done
               echo '' 1>&2
          fi
     fi
     if ! umount $BASE_MOUNTPOINT
     then StderrMessage "Error: 'umount $BASE_MOUNTPOINT' failed."
          SuddenExit
     fi
     StderrMessage "Un-mounted the NFS share of $BASE_URI"
     if ! rmdir $BASE_MOUNTPOINT
     then StderrMessage "Error: 'rmdir $BASE_MOUNTPOINT' failed."
          SuddenExit
     fi
fi
if test -n "$SERIOUS_WARNINGS"
then StderrMessage "Note: Finished with 'exit 2' because there have been serious warnings."
     exit 2
fi
StderrMessage "Finished."
exit 0

