#!/bin/bash
# $Id$
#
# Relax-and-Recover
#
#    Relax-and-Recover is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 3 of the License, or
#    (at your option) any later version.

#    Relax-and-Recover is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.

#    You should have received a copy of the GNU General Public License
#    along with Relax-and-Recover; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# Authors:
# See https://github.com/rear/rear/graphs/contributors for full list of authors

# Usually functions belong to the library scripts (i.e. $SHARE_DIR/lib/*.sh),
# but these 2 are exceptions on the rule because the complementary global functions
# to get and apply bash flags and options commands are needed from the very beginning
# (the usual functions are sourced at "Include functions" below):
function get_bash_flags_and_options_commands () {
    # Output bash commands that set the currently set flags
    # in reverse ordering to have "set ... xtrace" (i.e. "set +/- x") first
    # so that this flag is set first via apply_bash_flags_and_options_commands
    # which results better matching logging output in debugscripts mode:
    set +o | tac | tr '\n' ';'
    # Output bash commands that set the currently set options:
    shopt -p | tr '\n' ';'
}
# This function exists only to provide a syntactically matching counterpart of get_bash_flags_and_options_commands:
function apply_bash_flags_and_options_commands () {
    # Must be called with $1 that is the output of a previous get_bash_flags_and_options_commands:
    eval "$1"
}
# At the very beginning save initial bash flags and options in a global readonly variable
# so that exactly the initial bash flags and options can be restored if needed via
#   apply_bash_flags_and_options_commands "$INITIAL_BASH_FLAGS_AND_OPTIONS_COMMANDS"
readonly INITIAL_BASH_FLAGS_AND_OPTIONS_COMMANDS="$( get_bash_flags_and_options_commands )"

# Enable as needed for development of fail-safe code:
# set -ue -o pipefail
# set -xue -o pipefail
# set -xvue -o pipefail
# Cf. the Relax-and-Recover Coding Style
# https://github.com/rear/rear/wiki/Coding-Style
# that reads (excerpt - dated 18. Nov. 2015):
# "TODO Use set -eu to die from unset variables and unhandled errors"

# Versioning
readonly PRODUCT="Relax-and-Recover"
readonly PROGRAM=${0##*/}
readonly VERSION=2.4
readonly RELEASE_DATE=Git

# Used in framework-functions.sh to calculate the time spent executing rear:
readonly STARTTIME=$SECONDS

# Provide the command line options in an array so that other scripts may read them:
readonly CMD_OPTS=( "$@" )

# Allow workflows to set the exit code to a different value (not "readonly"):
EXIT_CODE=0
# The separated EXIT_FAIL_MESSAGE variable is used to denote a failure exit.
# One cannot use EXIT_CODE for that because there are cases where a non-zero exit code
# is the intended outcome (e.g. in the 'checklayout' workflow, cf. the end of this script).
# Set EXIT_FAIL_MESSAGE to 1 to have an exit failure message by default which is needed
# to get a failure message when it exits at an arbitrary place because of 'set -e'
# cf. https://github.com/rear/rear/issues/700#issuecomment-327755633
# Before a normal exit EXIT_FAIL_MESSAGE is set to 0 (cf. the end of this script):
EXIT_FAIL_MESSAGE=1

# Find out if we're running from checkout
REAR_DIR_PREFIX=""
readonly SCRIPT_FILE="$( readlink -f $( type -p "$0" || echo "$0" ) )"
if test "$SCRIPT_FILE" != "$( readlink -f /usr/sbin/$PROGRAM )" ; then
    REAR_DIR_PREFIX=${SCRIPT_FILE%/usr/sbin/$PROGRAM}
fi
readonly REAR_DIR_PREFIX

# Program directories - they must be set here. Everything else is then dynamic.
# Not yet readonly here because they are set via the /etc/rear/rescue.conf file
# in the recovery system that is sourced by the rear command in recover mode
# and CONFIG_DIR can also be changed via '-c' command line option:
SHARE_DIR="$REAR_DIR_PREFIX/usr/share/rear"
CONFIG_DIR="$REAR_DIR_PREFIX/etc/rear"
VAR_DIR="$REAR_DIR_PREFIX/var/lib/rear"
LOG_DIR="$REAR_DIR_PREFIX/var/log/rear"

# Generic global variables that are not meant to be configured by the user
# (i.e. that do not belong into usr/share/rear/conf/default.conf),
# see https://github.com/rear/rear/issues/678
# and https://github.com/rear/rear/issues/708
# Location of the disklayout.conf file created by savelayout
# (no readonly DISKLAYOUT_FILE because it is also set in checklayout-workflow.sh and mkbackuponly-workflow.sh):
DISKLAYOUT_FILE="$VAR_DIR/layout/disklayout.conf"
# Location of the root of the filesystem tree of the target system
# in particular the root of the filesystem tree of the to-be-recovered-system in the recovery system
# i.e. the mountpoint in the recovery system where the filesystem tree of the to-be-recovered-system is mounted:
readonly TARGET_FS_ROOT="/mnt/local"

# Initialize defaults: empty value means "false"/"no":
DEBUG=""
DEBUGSCRIPTS=""
DEBUGSCRIPTS_ARGUMENT="x"
KEEP_BUILD_DIR=""
KERNEL_VERSION=""
RECOVERY_MODE=""
STEPBYSTEP=""
SIMULATE=""
VERBOSE=""
WORKFLOW=""

# Parse options
help_note_text="Use '$PROGRAM --help' or 'man $PROGRAM' for more information."
readonly OPTS="$( getopt -n $PROGRAM -o "c:C:dDhsSvVr:" -l "help,version,debugscripts:" -- "$@" )"
if test $? -ne 0 ; then
    echo "$help_note_text"
    exit 1
fi
eval set -- "$OPTS"
while true ; do
    case "$1" in
        (-h|--help)
            WORKFLOW="help"
            ;;
        (-V|--version)
            echo -e "$PRODUCT $VERSION / $RELEASE_DATE"
            exit 0
            ;;
        (-v)
            VERBOSE=1
            ;;
        (-c)
            if [[ "$2" == -* ]] ; then
                # When the item that follows '-c' starts with a '-'
                # it is considered to be the next option and not an argument for '-c':
                echo "-c requires an argument."
                echo "$help_note_text"
                exit 1
            fi
            CONFIG_DIR="$2"
            shift
            ;;
        (-C)
            if [[ "$2" == -* ]] ; then
                # When the item that follows '-C' starts with a '-'
                # it is considered to be the next option and not an argument for '-C':
                echo "-C requires an argument."
                echo "$help_note_text"
                exit 1
            fi
            CONFIG_APPEND_FILES="$2"
            shift
            ;;
        (-d)
            DEBUG=1
            VERBOSE=1
            ;;
        (-D)
            DEBUG=1
            VERBOSE=1
            DEBUGSCRIPTS=1
            ;;
        (--debugscripts)
            DEBUG=1
            VERBOSE=1
            DEBUGSCRIPTS=1
            if [[ "$2" == -* ]] ; then
                # When the item that follows '--debugscripts' starts with a '-'
                # it is considered to be the next option and not an argument for '--debugscripts':
                echo "--debugscripts requires an argument."
                echo "$help_note_text"
                exit 1
            fi
            DEBUGSCRIPTS_ARGUMENT="$2"
            shift
            ;;
        (-s)
            SIMULATE=1
            VERBOSE=1
            ;;
        (-S)
            STEPBYSTEP=1
            ;;
        (-r)
            if [[ "$2" == -* ]] ; then
                # When the item that follows '-r' starts with a '-'
                # it is considered to be the next option and not an argument for '-r':
                echo "-r requires an argument."
                echo "$help_note_text"
                exit 1
            fi
            KERNEL_VERSION="$2"
            shift
            ;;
        (--)
            shift
            break
            ;;
        (-*)
            echo "$PROGNAME: unrecognized option '$option'"
            echo "$help_note_text"
            exit 1
            ;;
        (*)
            break
            ;;
    esac
    shift
done

# Set workflow to first command line argument or to "help" as fallback:
if test -z "$WORKFLOW" ; then
    # Usually workflow is now in $1 (after the options and its arguments were shifted above)
    # but when rear is called without a workflow there exists no $1 here so that
    # an empty default value is used to avoid 'set -eu' error exit if $1 is unset:
    if test "${1:-}" ; then
        # Not "$1" to get rid of compound commands:
        WORKFLOW=$1
        shift
    else
        WORKFLOW=help
    fi
fi

# Keep the remaining command line arguments to feed to the workflow:
ARGS=( "$@" )

# The following workflows are always verbose:
case "$WORKFLOW" in
    (validate|dump|shell|recover)
        VERBOSE=1
        ;;
esac

# Set the variables v and verbose to be used in called programs
# that support the '-v' or '--verbose' options like
# "cp $v ..." or "rm $verbose ..." and so on:
v=""
verbose=""
if test "$VERBOSE" ; then
    v="-v"
    verbose="--verbose"
fi

# Mark variables that are not meant to be changed later as constants (i.e. readonly).
# Exceptions here:
# CONFIG_DIR because "rear recover" sets it in /etc/rear/rescue.conf in the recovery system
# WORKFLOW because for the udev workflow WORKFLOW is set to the actual workflow
# KERNEL_VERSION because if empty it is set when sourcing config files below
# VERBOSE because there is a special "VERBOSE=1" setting below:
readonly ARGS
readonly CONFIG_APPEND_FILES
readonly DEBUG DEBUGSCRIPTS DEBUGSCRIPTS_ARGUMENT
readonly SIMULATE STEPBYSTEP

# The udev workflow is a special case because it is only a wrapper workflow
# that calls an actual workflow that is specified as $UDEV_WORKFLOW
# (e.g. the default UDEV_WORKFLOW is "mkrescue" in default.conf)
# and then WORKFLOW is set to the actual workflow in udev-workflow.sh
# so that WORKFLOW cannot be set readonly for the udev workflow:
test "$WORKFLOW" = "udev" || readonly WORKFLOW

# Make sure we have the necessary paths (eg. in cron), /sbin will be the first path to search.
# some needed binaries are in /lib/udev or /usr/lib/udev
for path in /usr/bin /bin /usr/sbin /sbin ; do
    case ":$PATH:" in
        (*:"$path":*)
            ;;
        (*)
            test -d "$path" && PATH=$path:$PATH
            ;;
    esac
done
# No readonly PATH so that it can be later extended if needed
# (e.g. to have third-party backup/restore tools available via PATH):
PATH=$PATH:/lib/udev:/usr/lib/udev

# ReaR must run as 'root' (i.e. abort if effective user ID is not 0):
if test "$( id --user )" != "0" ; then
    echo "ERROR: $PRODUCT needs 'root' privileges (effective user ID is not 0)" >&2
    exit 1
fi

# Set some bash options:
# With nullglob set when e.g. for foo*bar no file matches are found, then foo*bar is removed
# (e.g. "ls foo*bar" becomes plain "ls" without "foo*bar: No such file or directory" error).
# The extglob shell option enables several extended pattern matching operators.
shopt -s nullglob extglob
# Save the current default bash flags and options in a global readonly variable
# so that exactly the default bash flags and options can be restored if needed via
#   apply_bash_flags_and_options_commands "$DEFAULT_BASH_FLAGS_AND_OPTIONS_COMMANDS"
readonly DEFAULT_BASH_FLAGS_AND_OPTIONS_COMMANDS="$( get_bash_flags_and_options_commands )"

# Forget all remembered full pathnames of commands:
hash -r

# Make sure that we use only English:
export LC_CTYPE=C LC_ALL=C LANG=C

# Include default config before the RUNTIME_LOGFILE value is set because
# setting the right RUNTIME_LOGFILE value requires values from default.conf
# in particular the default LOGFILE value and the values of the
# LOCKLESS_WORKFLOWS and SIMULTANEOUS_RUNNABLE_WORKFLOWS arrays:
source $SHARE_DIR/conf/default.conf

# Use RUNTIME_LOGFILE for the logfile that is actually used during runtime
# so that the user can specify a different LOGFILE in his local.conf file.
# During runtime use only the actually used RUNTIME_LOGFILE value.
# By default RUNTIME_LOGFILE is the LOGFILE from default.conf:
RUNTIME_LOGFILE="$LOGFILE"
# Set the right RUNTIME_LOGFILE value depending on whether or not
# this currently running instance can run simultaneously with another instance:
can_run_simultaneously=""
# LOCKLESS_WORKFLOWS can run simultaneously with another instance by using LOGFILE.lockless.
# FIXME: Only one lockless workflow can run otherwise the same LOGFILE.lockless
# would be used by more than one simultaneously running lockless workflows:
for lockless_workflow in "${LOCKLESS_WORKFLOWS[@]}" ; do
    if test "$WORKFLOW" = "$lockless_workflow" ; then
        RUNTIME_LOGFILE="$LOGFILE.lockless"
        can_run_simultaneously="yes"
        break
    fi
done
# SIMULTANEOUS_RUNNABLE_WORKFLOWS are allowed to run simultaneously
# but cannot use LOGFILE.lockless instead they get a LOGFILE with PID
# see https://github.com/rear/rear/issues/1102
# When a workflow is both in LOCKLESS_WORKFLOWS and in SIMULTANEOUS_RUNNABLE_WORKFLOWS
# its right LOGFILE value is the one for SIMULTANEOUS_RUNNABLE_WORKFLOWS:
for simultaneous_runnable_workflow in "${SIMULTANEOUS_RUNNABLE_WORKFLOWS[@]}" ; do
    if test "$WORKFLOW" = "$simultaneous_runnable_workflow" ; then
        # Simultaneously runnable workflows require unique logfile names
        # so that the PID is interposed in the LOGFILE value from default.conf
        # which is used as RUNTIME_LOGFILE while the workflow is running
        # and at the end it gets copied to a possibly used-defined LOGFILE.
        # The logfile_suffix also works for logfile names without '.*' suffix
        # (in this case ${LOGFILE##*.} returns the whole $LOGFILE value):
        logfile_suffix=$( test "${LOGFILE##*.}" = "$LOGFILE" && echo 'log' || echo "${LOGFILE##*.}" )
        RUNTIME_LOGFILE="${LOGFILE%.*}.$$.$logfile_suffix"
        can_run_simultaneously="yes"
        break
    fi
done
# The log file that is actually used during runtime must not be changed:
readonly RUNTIME_LOGFILE

# When this currently running instance cannot run simultaneously with another instance
# test that this currently running instance does not run simultaneously with another instance:
if ! test "$can_run_simultaneously" ; then
    # In this case pidof is needed to test what running instances there are:
    if ! type pidof 1>/dev/null ; then
        echo "ERROR: Required program 'pidof' missing, please check your PATH" >&2
        exit 1
    fi
    # For unknown reasons '-o %PPID' does not work for pidof at least in SLES11
    # so that a manual test is done to find out if another pid != $$ is running:
    for pid in $( pidof -x "$SCRIPT_FILE" ) ; do
        if test "$pid" != $$ ; then
            echo "ERROR: $PROGRAM is already running, not starting again" >&2
            exit 1
        fi
    done
fi

# Source usr/share/rear/lib/_input-output-functions.sh because therein
# the original STDIN STDOUT and STDERR file descriptors are saved as fd6 fd7 and fd8
# so that ReaR functions for actually intended user messages can use fd7 and fd8
# to show messages to the user regardless whereto STDOUT and STDERR are redirected
# and fd6 to get input from the user regardless whereto STDIN is redirected:
source $SHARE_DIR/lib/_input-output-functions.sh

# Keep old log file:
test -r "$RUNTIME_LOGFILE" && mv -f "$RUNTIME_LOGFILE" "$RUNTIME_LOGFILE".old 2>/dev/null

# Start logging:
mkdir -p $LOG_DIR || echo "ERROR: Could not create $LOG_DIR" >&2
cat /dev/null >"$RUNTIME_LOGFILE"
# Redirect both STDOUT and STDERR into the log file.
# To be more on the safe side append to the log file '>>' instead of plain writing to it '>'
# because when a program (bash in this case) is plain writing to the log file it can overwrite
# output of a possibly simultaneously running process that likes to append to the log file
# (e.g. when a background process runs that also uses the ReaR log file for logging):
exec 2>>"$RUNTIME_LOGFILE"
# Make stdout the same what stderr already is.
# This keeps strict ordering of stdout and stderr outputs
# because now both stdout and stderr use one same file descriptor.
# The redirection of stdout into the log file was postponed for ReaR v2.2
# see https://github.com/rear/rear/issues/1398#issuecomment-315318878
# for ReaR v2.3 redirection of stdout into the log file is re-enabled:
exec 1>&2

# Include functions after RUNTIME_LOGFILE is set and readonly
# so that functions can use a fixed RUNTIME_LOGFILE value:
for script in $SHARE_DIR/lib/[a-z]*.sh ; do
    source $script
done

# Show initial startup messages:
if test "$WORKFLOW" != "help" ; then
    LogPrint "$PRODUCT $VERSION / $RELEASE_DATE"
    Log "Command line options: $0 ${CMD_OPTS[@]}"
    LogPrint "Using log file: $RUNTIME_LOGFILE"
fi

# In DEBUG mode keep by default the build area but that can be overridden in user config files
# therefore no readonly KEEP_BUILD_DIR (it is also set to 1 in build/default/980_verify_rootfs.sh):
test "$DEBUG" && KEEP_BUILD_DIR=1 || true

# Check if we are in recovery mode:
test -e "/etc/rear-release" && RECOVERY_MODE="y" || true
readonly RECOVERY_MODE

test "$SIMULATE" && LogPrint "Simulation mode activated, Relax-and-Recover base directory: $SHARE_DIR" || true

if test "$DEBUGSCRIPTS_ARGUMENT" ; then
    Debug "Current set of flags is '$-'"
    Debug "The debugscripts flags are '$DEBUGSCRIPTS_ARGUMENT'"
fi

# All workflows need to read the configurations first.
# Combine configuration files:
Debug "Combining configuration files"
# Use this file to manually override the OS detection:
test -r "$CONFIG_DIR/os.conf" && Source "$CONFIG_DIR/os.conf" || true
test -r "$CONFIG_DIR/$WORKFLOW.conf" && Source "$CONFIG_DIR/$WORKFLOW.conf" || true
SetOSVendorAndVersion
# Distribution configuration files:
for config in "$ARCH" "$OS" \
        "$OS_MASTER_VENDOR" "$OS_MASTER_VENDOR_ARCH" "$OS_MASTER_VENDOR_VERSION" "$OS_MASTER_VENDOR_VERSION_ARCH" \
        "$OS_VENDOR" "$OS_VENDOR_ARCH" "$OS_VENDOR_VERSION" "$OS_VENDOR_VERSION_ARCH" ; do
    test -r "$SHARE_DIR/conf/$config.conf" && Source "$SHARE_DIR/conf/$config.conf" || true
done
# User configuration files, last thing is to overwrite variables if we are in the rescue system:
for config in site local rescue ; do
    test -r "$CONFIG_DIR/$config.conf" && Source "$CONFIG_DIR/$config.conf" || true
done
# Finally source additional configuration files if specified on the command line:
if test "$CONFIG_APPEND_FILES" ; then
    # Treat missing additional config files (almost) same as other missing config files
    # which means that missing additional config files do not let ReaR abort with an Error
    # but in contrast to other missing config files missing additional config files
    # are reported to the user via 'LogPrint' so that the user is at least informed
    # if what he requested via the '-C' command line option cannot be fulfilled.
    # An intended positive side-effect when missing additional config files are no Error
    # is that then it also works (not relly cleanly but it works) for DRLM_MANAGED=y
    # which requires that missing local config files must not let ReaR abort with an Error
    # because the needed config files get later downloaded from the DRLM server and applied
    # (cf. the drlm_import_runtime_config function in lib/drlm-functions.sh)
    # for details see https://github.com/rear/rear/issues/1229
    for config_append_file in $CONFIG_APPEND_FILES ; do
        # If what is specified on the command line starts with '/' an absolute path is meant
        # otherwise what is specified on the command line means a file in CONFIG_DIR.
        # Files in CONFIG_DIR get automatically copied into the recovery system but
        # other files are added to COPY_AS_IS to get them copied into the recovery system:
        case "$config_append_file" in
            (/*)
                config_append_file_path="$config_append_file"
                # If "-C foo" was specified on the command line but 'foo' does not exist
                # try if 'foo.conf' exists and if yes, use that:
                if test -r "$config_append_file_path" ; then
                    COPY_AS_IS=( "${COPY_AS_IS[@]}" "$config_append_file_path" )
                else if test -r "$config_append_file_path.conf" ; then
                         COPY_AS_IS=( "${COPY_AS_IS[@]}" "$config_append_file_path.conf" )
                     else
                         LogPrint "There is '-C $config_append_file' but neither '$config_append_file_path' nor '$config_append_file_path.conf' can be read."
                     fi
                fi
                ;;
            (*)
                config_append_file_path="$CONFIG_DIR/$config_append_file"
                ;;
        esac
        # If "-C foo" was specified on the command line but 'foo' does not exist
        # try if 'foo.conf' exists and if yes, use that:
        if test -r "$config_append_file_path" ; then
            LogPrint "Sourcing additional configuration file '$config_append_file_path'"
            Source "$config_append_file_path"
        else if test -r "$config_append_file_path.conf" ; then
                 LogPrint "Sourcing additional configuration file '$config_append_file_path.conf'"
                 Source "$config_append_file_path.conf"
             else
                 LogPrint "There is '-C $config_append_file' but neither '$config_append_file_path' nor '$config_append_file_path.conf' can be read."
             fi
        fi
    done
fi

# Now SHARE_DIR CONFIG_DIR VAR_DIR LOG_DIR and KERNEL_VERSION should be set to a fixed value:
readonly SHARE_DIR CONFIG_DIR VAR_DIR LOG_DIR KERNEL_VERSION

# Enable progress subsystem only in verbose mode, set some stuff that others can use:
if test "$VERBOSE" ; then
    source $SHARE_DIR/lib/progresssubsystem.nosh
fi

SourceStage "init"

# Check for requirements, do we have all required binaries?
# For details see the comments in prep/default/950_check_missing_programs.sh
# Without the empty string as initial value missing_progs ${missing_progs[*]} ${missing_progs[@]}
# would all be unbound variables that would result an error exit if 'set -eu' is used:
missing_progs=( '' )
# Check for required binaries:
for prog in "${REQUIRED_PROGS[@]}" ; do
    has_binary "$prog" || missing_progs=( "${missing_progs[@]}" "$prog" )
done
# Detect when there is any non-empty array member (the first one is always empty, see above)
# but the test should not succeed when there are only empty or blank array members:
contains_visible_char "${missing_progs[*]}" && Error "Cannot find required programs:${missing_progs[@]}"

readonly VERSION_INFO="
$PRODUCT $VERSION / $RELEASE_DATE

$PRODUCT comes with ABSOLUTELY NO WARRANTY; for details see
the GNU General Public License at: http://www.gnu.org/licenses/gpl.html

Host $( uname -n ) using Backup $BACKUP and Output $OUTPUT
Build date: $( date -R )
"

if test "$WORKFLOW" != "help" ; then
    # Create temporary work area and register removal exit task:
    BUILD_DIR="$( mktemp -d -t rear.XXXXXXXXXXXXXXX || Error "Could not create build area '$BUILD_DIR'" )"
    QuietAddExitTask cleanup_build_area_and_end_program
    Log "Using build area '$BUILD_DIR'"
    ROOTFS_DIR=$BUILD_DIR/rootfs
    TMP_DIR=$BUILD_DIR/tmp
    mkdir -p $v $ROOTFS_DIR >&2 || Error "Could not create $ROOTFS_DIR"
    mkdir -p $v $TMP_DIR >&2 || Error "Could not create $TMP_DIR"
fi

# Check for and run the requested workflow:
if has_binary WORKFLOW_$WORKFLOW ; then
    Log "Running $WORKFLOW workflow"
    # There could be no ARGS[@] which means it would be an unbound variable so that
    # an empty default is used here to avoid an error exit if 'set -eu' is used:
    WORKFLOW_$WORKFLOW "${ARGS[@]:-}"
    Log "Finished running $WORKFLOW workflow"
else
    VERBOSE=1
    LogPrint "ERROR: The specified command '$WORKFLOW' does not exist!"
    EXIT_CODE=1
fi

# Usually RUNTIME_LOGFILE=/var/log/rear/rear-$HOSTNAME.log
# The RUNTIME_LOGFILE name is set above from LOGFILE in default.conf
# but later user config files are sourced where LOGFILE can be set different
# so that the user config LOGFILE is used as final logfile name:
if test "$RUNTIME_LOGFILE" != "$LOGFILE" ; then
    test "$WORKFLOW" != "help" && LogPrint "Saving $RUNTIME_LOGFILE as $LOGFILE"
    cat "$RUNTIME_LOGFILE" > "$LOGFILE"
fi

# When this point is reached, the workflow is done without a real error because
# for real errors one of the Error functions should be called that kills rear and
# then the exit code is usually 143 = 128 + 15 (15 = SIGTERM from the USR1 trap)
# and the Error function results an "ERROR: ..." syslog message.
# Set EXIT_FAIL_MESSAGE to 0 to avoid a false exit failure message:
EXIT_FAIL_MESSAGE=0
# There should be no syslog message for the help workflow:
if test "$WORKFLOW" != "help" ; then
    if test $EXIT_CODE -eq 0 ; then
        LogToSyslog "$PROGRAM $WORKFLOW finished with zero exit code"
    else
        if test "checklayout" = "$WORKFLOW" -a $EXIT_CODE -eq 1 ; then
            # The checklayout workflow is special because it sets EXIT_CODE=1
            # when the disk layout has changed or when configuration files have changed
            # but that exit code 1 is no error but meant as a signal that things have changed
            # which require a new ISO image so that users can run "rear checklayout || rear mkrescue"
            # see https://github.com/rear/rear/issues/564
            LogToSyslog "$PROGRAM checklayout finished with exit code 1 (layout or config changed)"
        else
            LogToSyslog "$PROGRAM $WORKFLOW failed with exit code $EXIT_CODE"
        fi
    fi
fi

exit $EXIT_CODE
