Current File : //proc/self/root/usr/local/jetapps/usr/share/rear/lib/framework-functions.sh
# shell-script-functions.sh
#
# shell script functions for Relax-and-Recover
#
# This file is part of Relax-and-Recover, licensed under the GNU General
# Public License. Refer to the included COPYING for full text of license.
#
# convert tabs into 4 spaces with: expand --tabs=4 file >new-file

# source a file given in $1
function Source () {
    local source_file="$1"
    local source_return_code=0
    # Skip if source file name is empty:
    if test -z "$source_file" ; then
        Debug "Skipping Source() because it was called with empty source file name"
        return
    fi
    # Ensure source file is not a directory:
    test -d "$source_file" && Error "Source file '$source_file' is a directory, cannot source"
    # Skip if source file does not exist of if its content is empty:
    if ! test -s "$source_file" ; then
        Debug "Skipping Source() because source file '$source_file' not found or empty"
        return
    fi
    # Clip leading standard path to rear files (usually /usr/share/rear/):
    local relname="${source_file##$SHARE_DIR/}"
    # Simulate sourcing the scripts in $SHARE_DIR
    if test "$SIMULATE" && expr "$source_file" : "$SHARE_DIR" >/dev/null; then
        LogPrint "Source $relname"
        return
    fi
    # Step-by-step mode or breakpoint if needed
    # Usage of the external variable BREAKPOINT: sudo BREAKPOINT="*foo*" rear mkrescue
    # an empty default value is set to avoid 'set -eu' error exit if BREAKPOINT is unset:
    : ${BREAKPOINT:=}
    if [[ "$STEPBYSTEP" || ( "$BREAKPOINT" && "$relname" == "$BREAKPOINT" ) ]] ; then
        # Use the original STDIN STDOUT and STDERR when 'rear' was launched by the user
        # to get input from the user and to show output to the user (cf. _input-output-functions.sh):
        read -p "Press ENTER to include '$source_file' ... " 0<&6 1>&7 2>&8
    fi
    # The Error function is searching for 'Including .*$last_sourced_script_filename'
    # in RUNTIME_LOGFILE and/or STDOUT_STDERR_FILE so provide that info in both files:
    Log "Including $relname"
    echo "Including $relname" >>$STDOUT_STDERR_FILE
    # DEBUGSCRIPTS mode settings:
    if test "$DEBUGSCRIPTS" ; then
        Debug "Entering debugscript mode via 'set -$DEBUGSCRIPTS_ARGUMENT'."
        local saved_bash_flags_and_options_commands="$( get_bash_flags_and_options_commands )"
        set -$DEBUGSCRIPTS_ARGUMENT
    fi
    # The actual work (source the source file):
    # Do not error out here when 'source' fails (i.e. when 'source' returns a non-zero exit code)
    # because scripts usually return the exit code of their last command
    # cf. https://github.com/rear/rear/issues/1965#issuecomment-439330017
    # and in general ReaR should not error out in a (helper) function but instead
    # a function should return an error code so that its caller can decide what to do
    # cf. https://github.com/rear/rear/pull/1418#issuecomment-316004608
    source "$source_file"
    source_return_code=$?
    test "0" -eq "$source_return_code" || Debug "Source function: 'source $source_file' returns $source_return_code"
    # Ensure that after each sourced file we are back in ReaR's usual working directory
    # that is WORKING_DIR="$( pwd )" when usr/sbin/rear was launched
    # cf. https://github.com/rear/rear/issues/2461
    # Quoting "$WORKING_DIR" is needed to make it behave fail-safe if WORKING_DIR is empty
    # because cd "" succeeds without changing the current directory
    # in contrast to plain cd which changes to the home directory (usually /root)
    # cf. https://github.com/rear/rear/pull/2478#issuecomment-673500099
    cd "$WORKING_DIR" || LogPrintError "Failed to 'cd $WORKING_DIR'"
    # Undo DEBUGSCRIPTS mode settings:
    if test "$DEBUGSCRIPTS" ; then
        Debug "Leaving debugscript mode (back to previous bash flags and options settings)."
        # The only known way how to do 'set +x' after 'set -x' without 'set -x' output for the 'set +x' call
        # is a current shell environment where stderr is redirected to /dev/null before 'set +x' is run via
        #   { set +x ; } 2>/dev/null
        # here we avoid much useless 'set -x' debug output for the apply_bash_flags_and_options_commands call:
        { apply_bash_flags_and_options_commands "$saved_bash_flags_and_options_commands" ; } 2>/dev/null
    fi
    # Breakpoint if needed:
    if [[ "$BREAKPOINT" && "$relname" == "$BREAKPOINT" ]] ; then
        # Use the original STDIN STDOUT and STDERR when 'rear' was launched by the user
        # to get input from the user and to show output to the user (cf. _input-output-functions.sh):
        read -p "Press ENTER to continue ... " 0<&6 1>&7 2>&8
    fi
    # Return the return value of the actual work (source the source file):
    return $source_return_code
}

# Collect scripts given in the stage directory $1
# therein in the standard subdirectories and
# sort them by their script file name and
# Source() the scripts one by one:
function SourceStage () {
    local stage="$1"
    local start_SourceStage=$SECONDS
    Log "======================"
    Log "Running '$stage' stage"
    Log "======================"
    # In debug modes show what stage is run also on the user's terminal:
    test "$DEBUG" && Print "Running '$stage' stage ======================"
    # We always source scripts in the same subdirectory structure.
    # The ls -d {...,...,...} within the $SHARE_DIR/$stage directory expands as intended.
    # The intent is to only list those scripts below the $SHARE_DIR/$stage directory
    # that match the specified backup method and output method
    # and that match the used operating system and architecture and Linux distribution.
    # The pipe sorts the listed scripts by their 3-digit number independent of the directory of the script.
    # We want to make sure that there are no duplicates in the listed scripts
    # so that each script gets executed at most once.
    # cf. https://github.com/rear/rear/issues/3149#issuecomment-1935586311
    # First sed inserts a ! before and after the script number
    # e.g. default/123_some_script.sh becomes default/!123!_some_script.sh
    # which makes the script number field nr. 2 when dividing lines into fields by !
    # so that the subsequent sort can sort by that field.
    # Numeric sort is not needed because all script numbers have same length
    # (without numeric sort 2 and 10 get sorted as first 10 then 2).
    # The final tr removes the ! to restore the original script name.
    # This code breaks if ! or a leading 3-digit number with underscore
    # is used in a directory name of the ReaR subdirectory structure
    # but those directories below the $SHARE_DIR/$stage directory are not named by the user
    # so that it even works when a user runs a git clone in his .../ReaRtest!/ directory.
    # For example a new backup method named '123_backup' is not possible
    # but a new backup method named '123backup' (without underscore) is possible.
    local scripts=( $( cd $SHARE_DIR/$stage
                 ls -d  {default,"$ARCH","$OS","$OS_MASTER_VENDOR","$OS_MASTER_VENDOR_ARCH","$OS_MASTER_VENDOR_VERSION","$OS_VENDOR","$OS_VENDOR_ARCH","$OS_VENDOR_VERSION"}/*.sh \
              "$BACKUP"/{default,"$ARCH","$OS","$OS_MASTER_VENDOR","$OS_MASTER_VENDOR_ARCH","$OS_MASTER_VENDOR_VERSION","$OS_VENDOR","$OS_VENDOR_ARCH","$OS_VENDOR_VERSION"}/*.sh \
              "$OUTPUT"/{default,"$ARCH","$OS","$OS_MASTER_VENDOR","$OS_MASTER_VENDOR_ARCH","$OS_MASTER_VENDOR_VERSION","$OS_VENDOR","$OS_VENDOR_ARCH","$OS_VENDOR_VERSION"}/*.sh \
    "$OUTPUT"/"$BACKUP"/{default,"$ARCH","$OS","$OS_MASTER_VENDOR","$OS_MASTER_VENDOR_ARCH","$OS_MASTER_VENDOR_VERSION","$OS_VENDOR","$OS_VENDOR_ARCH","$OS_VENDOR_VERSION"}/*.sh \
                 | sed -e 's#/\([0-9][0-9][0-9]\)_#/!\1!_#g' | sort -t \! -k 2 -u | tr -d \! ) )
    # If no script is found, then the scripts array contains only one element '.'
    if test "$scripts" = '.' ; then
        Log "Finished running empty '$stage' stage"
        return 0
    fi
    # Source() the scripts one by one:
    local script=''
    for script in "${scripts[@]}" ; do
        # Tell the user about unexpected named scripts.
        # All scripts must be named with a leading three-digit number NNN_something.sh
        # otherwise the above sorting by the 3-digit number may not work as intended
        # so that scripts without leading 3-digit number are likely run in wrong order:
        grep -q '^[0-9][0-9][0-9]_' <<< $( basename $script ) || LogPrintError "Script '$script' without leading 3-digit number 'NNN_' is likely run in wrong order"
        Source $SHARE_DIR/$stage/"$script"
    done
    Log "Finished running '$stage' stage in $(( SECONDS - start_SourceStage )) seconds"
}