#!/usr/bin/env bash
# shellcheck disable=SC2004
# SC2004: $ not required in arithmentic expressions
#
#######################################################################################################################
#
# Create and restore a backup of a Raspberry running Raspbian
#
# Visit http://www.linux-tips-and-tricks.de/raspiBackup for latest code and other details
#
# Smart recycle backup strategy inspired by https://opensource.com/article/18/8/automate-backups-raspberry-pi and
# enhanced to support multiple backups in a given timeframe of days, weeks, months and years
#
# Credits to following people for their translation work
#	  FI - teemue
#	  FR - mgrafr
#
#######################################################################################################################
#
#    Copyright (c) 2013-2026 framp at linux-tips-and-tricks dot de
#
#    This program 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.
#
#    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
#######################################################################################################################

set -o pipefail

if [ -z "$BASH" ] ;then
	echo "??? ERROR: Unable to execute script. bash interpreter missing"
	echo "??? DEBUG: $(lsof -a -p $$ -d txt | tail -n 1)"
	exit 127
fi

MYSELF="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"					# use linked script name if the link is used
MYNAME=${MYSELF%.*}
VERSION="0.7.2"   								# -beta, -hotfix or -dev suffixes possible
VERSION_SCRIPT_CONFIG="0.1.10"           					# required config version for script

VERSION_VARNAME="VERSION"									# has to match above var names
VERSION_CONFIG_VARNAME="VERSION_.*CONF.*"					# used to lookup VERSION_CONFIG in config files

[ "$(kill -l | grep -c SIG)" -eq 0 ] && printf "\n\033[1;35m Don't call script with leading \"sh\"! \033[m\n\n"  >&2 && exit 255
[ -z "${BASH_VERSINFO[0]}" ] && printf "\n\033[1;35m Make sure you're using \"bash\"! \033[m\n\n" >&2 && exit 255
[ "${BASH_VERSINFO[0]}" -lt 3 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have %s \033[m\n\n" "$BASH_VERSION"  >&2 && exit 255
[ "${BASH_VERSINFO[0]}" -le 3 ] && [ "${BASH_VERSINFO[1]}" -le 1 ] && printf "\n\033[1;35m Minimum requirement is bash 3.2. You have %s \033[m\n\n" "$BASH_VERSION" >&2 && exit 255

declare -r PS4='|${LINENO}> \011${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

# add pathes if not already set (usually not set in crontab)

DEFAULT_PATHES="/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin"

if [[ -e /bin/grep ]]; then
	pathElements=("${PATH//:/ }")
	for p in $DEFAULT_PATHES; do
		if [[ ! " ${pathElements[*]} " =~ ${p} ]]; then
			[[ -z $PATH ]] && PATH=$p || PATH="$p:$PATH"
		fi
	done
	export PATH="$PATH"
fi

IS_BETA=$(( ! $(grep -iqE "alpha|beta" <<< "$VERSION"; echo $?) ))
IS_DEV=$(( ! $(grep -iq dev <<< "$VERSION"; echo $?) ))
IS_HOTFIX=$(( ! $(grep -iqE "hotfix|-m_" <<< "$VERSION"; echo $?) ))

# Expressions don't expand in single quotes, use double quotes for that.
# shellcheck disable=SC2016
GIT_DATE='$Date: 2026-05-21 10:04:55 +0200$'
GIT_DATE_ONLY=${GIT_DATE/: /}
GIT_DATE_ONLY=$(cut -f 2 -d ' ' <<< "$GIT_DATE")
GIT_TIME_ONLY=$(cut -f 3 -d ' ' <<< "$GIT_DATE" | sed 's/\$//')
# Expressions don't expand in single quotes, use double quotes for that.
# shellcheck disable=SC2016
GIT_COMMIT='$Sha1: 237070c$'
GIT_COMMIT_ONLY=$(cut -f 2 -d ' ' <<< "$GIT_COMMIT" | sed 's/\$//')

GIT_CODEVERSION="$MYSELF $VERSION, $GIT_DATE_ONLY/$GIT_TIME_ONLY - $GIT_COMMIT_ONLY"

function findUser() {

	local u

	if [[ -n "$SUDO_USER" ]]; then
		u="$SUDO_USER"
	else
		u="$USER"
	fi

	echo "$u"

}

# some general constants

readonly MYHOMEURL="https://www.linux-tips-and-tricks.de"
DATE=$(date +%Y%m%d-%H%M%S)
HOSTNAME=$(hostname)
NL=$'\n'
CURRENT_DIR=$(pwd)
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}")"; pwd | xargs readlink -f)

# Smileys used in eMail subject to notify about news/events

SMILEY_WARNING="O.o"
SMILEY_UPDATE_POSSIBLE=";-)"
SMILEY_BETA_AVAILABLE=":-D"
SMILEY_RESTORETEST_REQUIRED="8-)"
SMILEY_VERSION_DEPRECATED=":-("

# URLs and temp filenames used

# URLTARGET allows to use deployment of new code versions, example: use "beta" to test beta code as if it was published just before it's published

if [[ -n $URLTARGET ]]; then
	echo "===> URLTARGET: $URLTARGET"
	URLTARGET="/$URLTARGET"
fi

DOWNLOAD_URL="$MYHOMEURL/raspiBackup${URLTARGET}/raspiBackup.sh"
CONFIG_URL="$MYHOMEURL/raspiBackup${URLTARGET}/raspiBackup_\$lang\.conf" # used in eval for late binding of URLTAGRET
BETA_DOWNLOAD_URL="$MYHOMEURL/raspiBackup${URLTARGET}/beta/raspiBackup.sh"
BETA_CONFIG_URL="$MYHOMEURL/raspiBackup${URLTARGET}/beta/raspiBackup_\$lang\.conf" # used in eval for late binding of URLTAGRET
#INSTALLER_DOWNLOAD_URL="$MYHOMEURL/raspiBackup${URLTARGET}/raspiBackupInstallUI.sh"
#INSTALLER_BETA_DOWNLOAD_URL="$MYHOMEURL/raspiBackup${URLTARGET}/beta/raspiBackupInstallUI.sh"
PROPERTIES_DOWNLOAD_URL="$MYHOMEURL/raspiBackup${URLTARGET}/raspiBackup.properties"
VERSION_PAGE="https://github.com/framps/raspiBackup/releases"

# dd warning website
DD_WARNING_URL_DE="$MYHOMEURL/de/raspibackupcategorie/579-raspibackup-warum-sollte-man-dd-als-backupmethode-besser-nicht-benutzen/"
DD_WARNING_URL_EN="$MYHOMEURL/en/all-pages-about-raspibackup/581-raspibackup-why-shouldn-t-you-use-dd-as-backup-method/"

CALLING_USER="$(findUser)"
CALLING_HOME="$(eval echo "~${CALLING_USER}")"

PROPERTY_FILE="$MYNAME.properties"
LATEST_TEMP_PROPERTY_FILE="/tmp/$PROPERTY_FILE"
VAR_LIB_DIRECTORY="/var/lib/$MYNAME"
RESTORE_REMINDER_FILE="restore.reminder"
REPORT_COUNTER_FILE="report.counter"
VARS_FILE="/tmp/$MYNAME.vars"
TEMPORARY_MOUNTPOINT_ROOT="/tmp/${MYNAME}_mnt"

LOGFILE_EXT=".log"
LOGFILE_NAME="${MYNAME}${LOGFILE_EXT}"
LOGFILE_RESTORE_EXT=".logr"
MSGFILE_EXT=".msg"
MSGFILE_RESTORE_EXT=".msgr"
MSGFILE_NAME="${MYNAME}${MSGFILE_EXT}"
TEMP_LOG_FILE="/tmp/$LOGFILE_NAME"
TEMP_MSG_FILE="/tmp/$MSGFILE_NAME"
FINISH_LOG_FILE="/tmp/${MYNAME}.logf"
MODIFIED_SFDISK="/tmp/$$.sfdisk"

# timeouts

DOWNLOAD_TIMEOUT=30 # seconds
#DOWNLOAD_RETRIES=3

# debug option constants

LOG_NONE=0
LOG_DEBUG=1
POSSIBLE_LOG_LEVEL_NUMBERs="[$LOG_NONE$LOG_DEBUG]"

declare -A LOG_LEVELs=( [$LOG_NONE]="Off" [$LOG_DEBUG]="Debug" )
POSSIBLE_LOG_LEVELs=""
for K in "${!LOG_LEVELs[@]}"; do
	POSSIBLE_LOG_LEVELs="$POSSIBLE_LOG_LEVELs|${LOG_LEVELs[$K]}"
done
POSSIBLE_LOG_LEVELs="$(cut -c 2- <<< "$POSSIBLE_LOG_LEVELs")"

declare -A LOG_LEVEL_ARGs
for K in "${!LOG_LEVELs[@]}"; do
	k=$(tr '[:lower:]' '[:upper:]' <<< "${LOG_LEVELs[$K]}")
	LOG_LEVEL_ARGs[$k]="$K"
done

MSG_LEVEL_MINIMAL=0
MSG_LEVEL_DETAILED=1
POSSIBLE_MSG_LEVEL_NUMBERs="[$MSG_LEVEL_MINIMAL$MSG_LEVEL_DETAILED]"

declare -A MSG_LEVELs=( [$MSG_LEVEL_MINIMAL]="Minimal" [$MSG_LEVEL_DETAILED]="Detailed" )
POSSIBLE_MSG_LEVELs=""
for K in "${!MSG_LEVELs[@]}"; do
	POSSIBLE_MSG_LEVELs="$POSSIBLE_MSG_LEVELs|${MSG_LEVELs[$K]}"
done
POSSIBLE_MSG_LEVELs="$(cut -c 2- <<< "$POSSIBLE_MSG_LEVELs")"

declare -A MSG_LEVEL_ARGs
for K in "${!MSG_LEVELs[@]}"; do
	k=$(tr '[:lower:]' '[:upper:]' <<< "${MSG_LEVELs[$K]}")
	MSG_LEVEL_ARGs[$k]="$K"
done

LOG_OUTPUT_VARLOG=1
LOG_OUTPUT_BACKUPLOC=2
LOG_OUTPUT_HOME=3
POSSIBLE_LOG_OUTPUT_NUMBERs="^[$LOG_OUTPUT_BACKUPLOC|$LOG_OUTPUT_HOME|$LOG_OUTPUT_VARLOG]\$"

LOG_OUTPUT_IS_NO_USERDEFINEDFILE_REGEX="[$LOG_OUTPUT_VARLOG$LOG_OUTPUT_BACKUPLOC$LOG_OUTPUT_HOME]"
#declare -A LOG_OUTPUT_LOCs=( [$LOG_OUTPUT_VARLOG]="/var/log/raspiBackup/<hostname>.log" [$LOG_OUTPUT_BACKUPLOC]="<backupPath>" [$LOG_OUTPUT_HOME]="~/raspiBackup.log")

declare -A LOG_OUTPUTs=( [$LOG_OUTPUT_VARLOG]="Varlog" [$LOG_OUTPUT_BACKUPLOC]="Backup" [$LOG_OUTPUT_HOME]="Current")
declare -A LOG_OUTPUT_ARGs
for K in "${!LOG_OUTPUTs[@]}"; do
	k=$(tr '[:lower:]' '[:upper:]' <<< "${LOG_OUTPUTs[$K]}")
	LOG_OUTPUT_ARGs[$k]="$K"
done

POSSIBLE_LOG_OUTPUTs=""
for K in "${!LOG_OUTPUTs[@]}"; do
	POSSIBLE_LOG_OUTPUTs="$POSSIBLE_LOG_OUTPUTs|${LOG_OUTPUTs[$K]}"
done
POSSIBLE_LOG_OUTPUTs="$(cut -c 2- <<< "$POSSIBLE_LOG_OUTPUTs")"

# message option constants

LOG_TYPE_MSG=0
LOG_TYPE_DEBUG=1
declare -A LOG_TYPEs=( [$LOG_TYPE_MSG]="MSG" [$LOG_TYPE_DEBUG]="DBG")

BACKUPTYPE_DD="dd"
BACKUPTYPE_DDZ="ddz"
BACKUPTYPE_TAR="tar"
BACKUPTYPE_TGZ="tgz"
BACKUPTYPE_RSYNC="rsync"
POSSIBLE_BACKUP_TYPES_REGEX="$BACKUPTYPE_DD|$BACKUPTYPE_DDZ|$BACKUPTYPE_RSYNC|$BACKUPTYPE_TAR|$BACKUPTYPE_TGZ"
declare -A FILE_EXTENSION=( [$BACKUPTYPE_DD]=".img" [$BACKUPTYPE_DDZ]=".img.gz" [$BACKUPTYPE_RSYNC]="" [$BACKUPTYPE_TGZ]=".tgz" [$BACKUPTYPE_TAR]=".tar" )
# map dd/tar to ddz/tgz extension if -z switch is used
declare -A Z_TYPE_MAPPING=( [$BACKUPTYPE_DD]=$BACKUPTYPE_DDZ [$BACKUPTYPE_TAR]=$BACKUPTYPE_TGZ )

readarray -t SORTED < <(for a in "${!FILE_EXTENSION[@]}"; do echo "$a"; done | sort)
ALLOWED_TYPES=""
POSSIBLE_TYPES=""
POSSIBLE_TYPES_ARRAY=()
for K in "${SORTED[@]}"; do
	POSSIBLE_TYPES_ARRAY+=("$K")
	[[ -z $POSSIBLE_TYPES ]] && POSSIBLE_TYPES=$K || POSSIBLE_TYPES="$POSSIBLE_TYPES|$K"
	lastChar="${K: -1}"
	if [[ $lastChar == "z" ]]; then         # skip tgz and ddz as allowed types, now handled with -z invocation parameter, still accept old types for backward compatibility
		continue
	fi
	[[ -z $ALLOWED_TYPES ]] && ALLOWED_TYPES=$K || ALLOWED_TYPES="$ALLOWED_TYPES|$K"
done

TAR_COMPRESSION_TOOLS_SUPPORTED=(     "bzip2" "gzip" "lzip" "lzma"  "lzop" "xz"  "zstd")
TAR_COMPRESSION_EXTENSIONS_SUPPORTED=(".bz2"  ".gz"  ".lz"  ".lzma" ".lzo" ".xz" ".zst")

# grep regex used to extract partition numbers from partition oriented backups
TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP=""
for K in "${!TAR_COMPRESSION_EXTENSIONS_SUPPORTED[@]}"; do
	ext="${TAR_COMPRESSION_EXTENSIONS_SUPPORTED[$K]}"
	if [[ -z "$TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP" ]]; then
		TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP="tar${ext}"
	else
		TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP="${TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP}|tar${ext}"
	fi
done
TAR_COMPRESSION_TOOLS_SUPPORTED_LIST=""
for K in "${!TAR_COMPRESSION_TOOLS_SUPPORTED[@]}"; do
	ext="${TAR_COMPRESSION_TOOLS_SUPPORTED[$K]}"
	if [[ -z "$TAR_COMPRESSION_TOOLS_SUPPORTED_LIST" ]]; then
		TAR_COMPRESSION_TOOLS_SUPPORTED_LIST="${ext}"
	else
		TAR_COMPRESSION_TOOLS_SUPPORTED_LIST="${TAR_COMPRESSION_TOOLS_SUPPORTED_LIST},${ext}"
	fi
done

declare -A mountPoints

# variables exported to pass on to extensions

export BACKUP_TARGETDIR
export BACKUP_TARGETFILE
export MSG_FILE
export LOG_FILE

# Telegram options

TELEGRAM_NOTIFY_SUCCESS="S"
TELEGRAM_NOTIFY_FAILURE="F"
TELEGRAM_NOTIFY_MESSAGES="M"
TELEGRAM_NOTIFY_MESSAGES2="m"
TELEGRAM_POSSIBLE_NOTIFICATIONS="$TELEGRAM_NOTIFY_SUCCESS$TELEGRAM_NOTIFY_FAILURE$TELEGRAM_NOTIFY_MESSAGES$TELEGRAM_NOTIFY_MESSAGES2"
TELEGRAM_URL="https://api.telegram.org/bot"

EMOJI_OK="$(echo -ne "\xe2\x9c\x94\xef\xb8\x8f\x0a")"  # ✔️
EMOJI_WARNING="$(echo -ne "\xe2\x9a\xa0\xef\xb8\x8f\x0a")"  # ⚠️
EMOJI_FAILED="$(echo -ne "\xe2\x9d\x8c\x0a")" # ❌
EMOJI_UPDATE_POSSIBLE="$(echo -ne "\xf0\x9f\x98\x89\x0a")" # 😉
EMOJI_BETA_AVAILABLE="$(echo -ne "\xf0\x9f\x98\x83\x0a")" # 😃
EMOJI_RESTORETEST_REQUIRED="$(echo -ne "\xf0\x9f\x94\x94\x0a")" # 🔔
EMOJI_VERSION_DEPRECATED="$(echo -ne "\xf0\x9f\x92\x80\x0a")" # 💀

# convert emoji into hex
#printf "%s" "$EMOJI_WARNING"
#echo $(xxd -pu <<< "$EMOJI_WARNING")
#exit

# Pushover options

PUSHOVER_NOTIFY_SUCCESS="S"
PUSHOVER_NOTIFY_FAILURE="F"
PUSHOVER_NOTIFY_MESSAGES="M"
PUSHOVER_POSSIBLE_NOTIFICATIONS="$PUSHOVER_NOTIFY_SUCCESS$PUSHOVER_NOTIFY_FAILURE$PUSHOVER_NOTIFY_MESSAGES"
PUSHOVER_URL="https://api.pushover.net/1/messages.json"

# Slack options

SLACK_NOTIFY_SUCCESS="S"
SLACK_NOTIFY_FAILURE="F"
SLACK_NOTIFY_MESSAGES="M"
SLACK_POSSIBLE_NOTIFICATIONS="$SLACK_NOTIFY_SUCCESS$SLACK_NOTIFY_FAILURE$SLACK_NOTIFY_MESSAGES"

SLACK_EMOJI_OK=":white_check_mark:"  # ✔️
SLACK_EMOJI_WARNING=":warning:"  # ⚠️
SLACK_EMOJI_FAILED=":x:" # ❌
SLACK_EMOJI_UPDATE_POSSIBLE=":smirk:" # 😉
SLACK_EMOJI_BETA_AVAILABLE=":laughing:" # 😃
SLACK_EMOJI_RESTORETEST_REQUIRED=":bell:" # 🔔
SLACK_EMOJI_VERSION_DEPRECATED=":skull:" # 💀

# various other constants

PRE_BACKUP_EXTENSION="pre"
POST_BACKUP_EXTENSION="post"
READY_BACKUP_EXTENSION="ready"
NOTIFICATION_BACKUP_EXTENSION="notify"
EMAIL_EXTENSION="mail"
PRE_RESTORE_EXTENSION="$PRE_BACKUP_EXTENSION"
POST_RESTORE_EXTENSION="$POST_BACKUP_EXTENSION"

PRE_BACKUP_EXTENSION_CALLED=0
PRE_RESTORE_EXTENSION_CALLED=0

EMAIL_EXTENSION_PROGRAM="mailext"
EMAIL_MAILX_PROGRAM="mail"
EMAIL_SSMTP_PROGRAM="ssmtp"
EMAIL_MSMTP_PROGRAM="msmtp"
EMAIL_SENDEMAIL_PROGRAM="sendEmail"
SUPPORTED_EMAIL_PROGRAM_REGEX="^($EMAIL_MAILX_PROGRAM|$EMAIL_SSMTP_PROGRAM|$EMAIL_MSMTP_PROGRAM|$EMAIL_SENDEMAIL_PROGRAM|$EMAIL_EXTENSION_PROGRAM)$"
SUPPORTED_MAIL_PROGRAMS=$(echo $SUPPORTED_EMAIL_PROGRAM_REGEX | sed 's:^..\(.*\)..$:\1:' | sed 's/|/,/g')

EMAIL_COLORING_SUBJECT="SUBJECT"
EMAIL_COLORING_OPTION="OPTION"
SUPPORTED_EMAIL_COLORING_REGEX="^($EMAIL_COLORING_OPTION|$EMAIL_COLORING_SUBJECT)$"
SUPPORTED_EMAIL_COLORING=$(echo $SUPPORTED_EMAIL_COLORING_REGEX | sed 's:^..\(.*\)..$:\1:' | sed 's/|/,/g')

PARTITIONS_TO_BACKUP_ALL="*"
MASQUERADE_STRING="@@@@"

COLORING_CONSOLE="C"
COLORING_MAIL="M"
COLORING_VALID_OPTIONS="$COLORING_CONSOLE$COLORING_MAIL"

NEWS_AVAILABLE=0
BETA_AVAILABLE=0
LOG_INDENT=0
WARNING_MESSAGE_WRITTEN=0

PROPERTY_REGEX='.*="([^"]*)"'
NOOP_AO_ARG_REGEX="^[[:space:]]*:"

STOPPED_SERVICES=0
SHARED_BOOT_DIRECTORY=0

BOOT_TAR_EXT="tmg"
BOOT_DD_EXT="img"

CONFIG_DIR="/usr/local/etc"
ORIG_CONFIG="$CONFIG_DIR/raspiBackup.conf"
NEW_CONFIG="$CONFIG_DIR/raspiBackup.conf.new"
MERGED_CONFIG="$CONFIG_DIR/raspiBackup.conf.merged"
BACKUP_CONFIG="$CONFIG_DIR/raspiBackup.conf.bak"

PERSISTENT_JOURNAL="var/log/journal"

NEW_OPTION_TRAILER="# >>>>> NEW OPTION added in config version %s <<<<< "
DELETED_OPTION_TRAILER="# >>>>> OPTION DELETED in config version %s <<<<< "

TWO_TB=$((1024*1024*1024*1024*2))			# disks > 2TB reuquire gpt instead of mbr

SHA_PLACEHOLDER="$(base64 -d <<< "JFNoYTEkCg==")"
DATE_PLACEHOLDER="$(base64 -d <<< "JERhdGUkCg==")"

# Commands used by raspiBackup and which have to be available
# [command]=package
declare -A REQUIRED_COMMANDS=( \
		["parted"]="parted" \
		["fsck.vfat"]="dosfstools" \
		["e2label"]="e2fsprogs" \
		["dosfslabel"]="dosfstools" \
		["fdisk"]="fdisk" \
		["blkid"]="util-linux" \
		["curl"]="curl" \
		["sfdisk"]="fdisk" \
		)

declare -A REQUIRED_COMMANDS_BTRFS=( \
	["btrfs"]="btrfs-tools"
)

declare -A REQUIRED_COMMANDS_F2FS=( \
	["f2fstat"]="f2fs-tools"
)

# possible script exit codes

RC_ASSERTION=101
RC_MISC_ERROR=102
RC_CTRLC=103
#RC_EXTENSION_ERROR=104
RC_STOP_SERVICES_ERROR=105
RC_START_SERVICES_ERROR=106
RC_PARAMETER_ERROR=107
RC_MISSING_FILES=108
RC_NATIVE_BACKUP_FAILED=109
RC_LINK_FILE_FAILED=110
RC_COLLECT_PARTITIONS_FAILED=111
RC_CREATE_PARTITIONS_FAILED=112
#RC_=113
RC_DD_IMG_FAILED=114
RC_SDCARD_ERROR=115
RC_RESTORE_FAILED=116
RC_NATIVE_RESTORE_FAILED=117
RC_DEVICES_NOTFOUND=118
RC_CREATE_ERROR=119
RC_MISSING_COMMANDS=120
RC_NO_BOOT_FOUND=121
RC_BEFORE_START_SERVICES_ERROR=122
RC_BEFORE_STOP_SERVICES_ERROR=123
RC_EMAILPROG_ERROR=124
RC_MISSING_PARTITION=125
#RC_UUIDS_NOT_UNIQUE=126
#RC_INCOMPLETE_PARMS=127
#RC_CONFIGVERSION_MISMATCH=128
#RC_TELEGRAM_ERROR=129
RC_FILE_OPERATION_ERROR=130
RC_MOUNT_FAILED=131
RC_UNSUPPORTED_ENVIRONMENT=132
RC_RESTORE_EXTENSION_FAILS=133
RC_BACKUP_EXTENSION_FAILS=134
RC_DOWNLOAD_FAILED=135
RC_BACKUP_DIRNAME_ERROR=136
RC_RESTORE_IMPOSSIBLE=137
RC_INVALID_BOOTDEVICE=138
#RC_ENVIRONMENT_ERROR=139
RC_CLEANUP_ERROR=140
#RC_EXTENSION_ERROR=141
#RC_UNPROTECTED_CONFIG=142
RC_NOT_SUPPORTED=143
RC_TEMPMOVE_FAILED=144
RC_RESIZE_ERROR=145
#RC_NOT_ALL_PREVIOUS_PARTITIONS_SAVED=146
RC_UUID_UPDATE_IMPOSSIBLE=147

tty -s
# Check exit code directly with e.g. if mycmd;, not indirectly with $?
# shellcheck disable=SC2181
INTERACTIVE=$((!$?))

# defaults
MSG_LEVEL="$MSG_LEVEL_DETAILED"
LOG_LEVEL="$LOG_DEBUG"
LOG_OUTPUT="$LOG_OUTPUT_BACKUPLOC"

# borrowed from http://stackoverflow.com/questions/3685970/check-if-an-array-contains-a-value

function containsElement() { # element ${array[@]}
  local e match="$1"
  shift
  for e; do
	[[ "$e" == "$match" ]] && return 0;
  done
  return 1
}

# return index of element in array (0-n) and true, -1 and false otherwise

function getIndexInArray() { # element ${array[@]}
  logEntry "$1 $2"
  local e match="$1" i=0
  shift
  for e; do
	if [[ "$e" == "$match" ]]; then
		echo "$i"
		logExit "$i"
		return 0
	else
		(( i++ ))
	fi
  done
  echo "-1"
  logExit "-1"
  return "1"
}

#
# NLS: Either use system language if language is supported and use fallback language English otherwise
#

SUPPORTED_LANGUAGES=("EN" "DE" "FI" "FR")
FALLBACK_LANGUAGE="EN"

# use LANG variable to determine language

[[ -z "${LANG}" ]] && LANG="en_US.UTF-8"		# if no LANG set use English
LANG_EXT="${LANG,,*}"
LANG_SYSTEM="${LANG_EXT:0:2}"						# extract language id
if ! containsElement "${LANG_SYSTEM^^*}" "${SUPPORTED_LANGUAGES[@]}"; then	# if language is not supported use English
	LANG_SYSTEM=$FALLBACK_LANGUAGE
fi

#
# Messages
#
# To add a new language just execute following steps:
# 1) Add new language id LL (e.g. FI for Finnish) in variable SUPPORTED_LANGUAGES (see above)
# 2) For every MSG_ add a new message MSG_LL, e.g. MSG_FI for Finnish
# 3) For every MSG_ add a new declare -A in following line, e.g. MSG_FI for Finnish
# 4) Optionally add a help function usageLL, e.g. usageFI
# 5) Note: If a message definition or help function (MSG_LL or usageLL) is missing in a supported language the fallback language English will be selected by the code (MSG_EN or usageEN)
#

declare -A MSG_EN MSG_DE MSG_FI MSG_FR

LANGUAGE="${LANG_SYSTEM^^*}"    # that's the language until it's overwritten with an option or config entry

MSG_UNDEFINED=0
MSG_EN[$MSG_UNDEFINED]="RBK0000E: Undefined messageid"
MSG_DE[$MSG_UNDEFINED]="RBK0000E: Unbekannte Meldungsid"
MSG_FI[$MSG_UNDEFINED]="RBK0000E: Määrittämätön viestitunnus"
MSG_FR[$MSG_UNDEFINED]="RBK0000E: Id du message non défini"
MSG_ASSERTION_FAILED=1
MSG_EN[$MSG_ASSERTION_FAILED]="RBK0001E: Unexpected program error occured. (%s), Linenumber: %s, Error: %s"
MSG_DE[$MSG_ASSERTION_FAILED]="RBK0001E: Unerwarteter Programmfehler trat auf. (%s), Zeile: %s, Fehler: %s"
MSG_FI[$MSG_ASSERTION_FAILED]="RBK0001E: Tapahtui odottamaton virhe. (%s), Rivinumero: %s, Virhe: %s"
MSG_FR[$MSG_ASSERTION_FAILED]="RBK0001E: Une erreur inattendue s'est produite. (%s), à la ligne n°: %s, Erreur: %s"
MSG_RUNASROOT=2
MSG_EN[$MSG_RUNASROOT]="RBK0002E: $MYSELF has to be started as root. Try 'sudo %s%s'"
MSG_DE[$MSG_RUNASROOT]="RBK0002E: $MYSELF muss als root gestartet werden. Benutze 'sudo %s%s'"
MSG_FI[$MSG_RUNASROOT]="RBK0002E: $MYSELF tulee käynnistää root-oikeuksin. Suorita 'sudo %s%s'"
MSG_FR[$MSG_RUNASROOT]="RBK0002E: $MYSELF doit être démarré en tant que root.Essayez 'sudo %s%s'"
MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY=3
MSG_EN[$MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY]="RBK0003I: Backup size will be truncated from %s to %s"
MSG_DE[$MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY]="RBK0003I: Backupgröße wird von %s auf %s reduziert"
MSG_FI[$MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY]="RBK0003I: Varmuuskopion koko typistetään koosta %s kokoon %s"
MSG_FR[$MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY]="RBK0003I: La taille de la sauvegarde sera diminuée de %s à %s"
MSG_ADJUSTING_SECOND=4
MSG_EN[$MSG_ADJUSTING_SECOND]="RBK0004I: Adjusting second partition from %s to %s"
MSG_DE[$MSG_ADJUSTING_SECOND]="RBK0004I: Zweite Partition wird von %s auf %s angepasst"
MSG_FI[$MSG_ADJUSTING_SECOND]="RBK0004I: Säädetään toinen osio %s osioksi %s"
MSG_FR[$MSG_ADJUSTING_SECOND]="RBK0004I: Redimensionnement de la deuxième partition de %s à %s"
MSG_BACKUP_FAILED=5
MSG_EN[$MSG_BACKUP_FAILED]="RBK0005E: Backup failed. Check previous error messages for details"
MSG_DE[$MSG_BACKUP_FAILED]="RBK0005E: Backup fehlerhaft beendet. Siehe vorhergehende Fehlermeldungen"
MSG_FI[$MSG_BACKUP_FAILED]="RBK0005E: Varmuuskopiointi epäonnistui. Katso lisätiedot edellisistä virheilmoituksista"
MSG_FR[$MSG_BACKUP_FAILED]="RBK0005E: La sauvegarde a echoué. Consultez les messages d'erreur pour plus d'information"
MSG_ADJUSTING_WARNING=6
MSG_EN[$MSG_ADJUSTING_WARNING]="RBK0006W: Target %s with %s is smaller than backup source with %s. root partition will be truncated accordingly. NOTE: Restore may fail if the root partition will become too small"
MSG_DE[$MSG_ADJUSTING_WARNING]="RBK0006W: Ziel %s mit %s ist kleiner als die Backupquelle mit %s. Die root Partition wird entsprechend verkleinert. HINWEIS: Der Restore kann fehlschlagen wenn sie zu klein wird"
MSG_FI[$MSG_ADJUSTING_WARNING]="RBK0006W: Kohde %s kooltaan %s on pienempi kuin varmuuskopion lähde kooltaan %s. Juuriosio typistetään sen mukaiseksi. HUOM: Palautus saattaa epäonnistua, jos juuriosiosta tulee liian pieni"
MSG_FR[$MSG_ADJUSTING_WARNING]="RBK0006W: La cible %s avec %s est plus petite que la source avec  %s. la partition racine sera diminuée en proportion. REMARQUE : La restauration peut échouer si la partition root devient trop petite"
MSG_STARTING_SERVICES=7
MSG_EN[$MSG_STARTING_SERVICES]="RBK0007I: Starting services: '%s'"
MSG_DE[$MSG_STARTING_SERVICES]="RBK0007I: Services werden gestartet: '%s'"
MSG_FI[$MSG_STARTING_SERVICES]="RBK0007I: Käynnistetään palvelut: '%s'"
MSG_FR[$MSG_STARTING_SERVICES]="RBK0007I: Démarrage des services: '%s'"
MSG_STOPPING_SERVICES=8
MSG_EN[$MSG_STOPPING_SERVICES]="RBK0008I: Stopping services: '%s'"
MSG_DE[$MSG_STOPPING_SERVICES]="RBK0008I: Services werden gestoppt: '%s'"
MSG_FI[$MSG_STOPPING_SERVICES]="RBK0008I: Pysäytetään palvelut: '%s'"
MSG_FR[$MSG_STOPPING_SERVICES]="RBK0008I: Arrêt des services: '%s'"
MSG_STARTED=9
MSG_EN[$MSG_STARTED]="RBK0009I: %s: %s V%s - %s (%s) started at %s"
MSG_DE[$MSG_STARTED]="RBK0009I: %s: %s V%s - %s (%s) %s gestartet"
MSG_FI[$MSG_STARTED]="RBK0009I: %s: %s V%s - %s (%s) käynnistyi %s"
MSG_FR[$MSG_STARTED]="RBK0009I: %s: %s V%s - %s (%s) Début à %s"
MSG_STOPPED=10
MSG_EN[$MSG_STOPPED]="RBK0010I: %s: %s V%s - %s (%s) stopped at %s with rc %s"
MSG_DE[$MSG_STOPPED]="RBK0010I: %s: %s V%s - %s (%s) %s beendet mit Returncode %s"
MSG_FI[$MSG_STOPPED]="RBK0010I: %s: %s V%s - %s (%s) pysäytettiin %s, vastauskoodi %s"
MSG_FR[$MSG_STOPPED]="RBK0010I: %s: %s V%s - %s (%s) terminé avec le code de retour %s"
MSG_NO_BOOT_PARTITION=11
MSG_EN[$MSG_NO_BOOT_PARTITION]="RBK0011E: No boot partition ${BOOT_PARTITION_PREFIX}1 found"
MSG_DE[$MSG_NO_BOOT_PARTITION]="RBK0011E: Keine boot Partition ${BOOT_PARTITION_PREFIX}1 gefunden"
MSG_FI[$MSG_NO_BOOT_PARTITION]="RBK0011E: Käynnistysosiota ${BOOT_PARTITION_PREFIX}1 ei löytynyt"
MSG_FR[$MSG_NO_BOOT_PARTITION]="RBK0011E: Pas de partition boot ${BOOT_PARTITION_PREFIX}1 ei löytynyt"
MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP=12
MSG_EN[$MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP]="RBK0012E: DD backup not supported for partition based backup. Use normal mode instead"
MSG_DE[$MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP]="RBK0012E: DD Backup nicht unterstützt bei partitionsbasiertem Backup. Benutze den normalen Modus dafür"
MSG_FI[$MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP]="RBK0012E: DD-varmuuskopiota ei tueta osioperustaiselle varmuuskopiolle. Käytä normaalimoodia"
MSG_FR[$MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP]="RBK0012E: DD Sauvegarde non prise en charge avec le mode basée sur les partitions. Utilisez le mode normal"
MSG_MULTIPLE_PARTITIONS_FOUND=13
MSG_EN[$MSG_MULTIPLE_PARTITIONS_FOUND]="RBK0013E: More than two partitions detected which can be saved only with backuptype DD or DDZ, with option -P or with option --ignoreAdditionalPartitions"
MSG_DE[$MSG_MULTIPLE_PARTITIONS_FOUND]="RBK0013E: Es existieren mehr als zwei Partitionen, die nur mit dem Backuptype DD oder DDZ, mit der Option -P oder der Option --ignoreAdditionalPartitions gesichert werden können"
MSG_FI[$MSG_MULTIPLE_PARTITIONS_FOUND]="RBK0013E: Enemmän kuin kansi osiota löytyi, jotka voidaan tallentaa vain DD- tai DDZ-varmuuskopiona. Käytä valintaa -P tai --ignoreAdditionalPartitions"
MSG_FR[$MSG_MULTIPLE_PARTITIONS_FOUND]="RBK0013E: Il y a plus de deux partitions elles ne peuvent être sauvegardées qu'avec le type de sauvegarde DD ou DDZ, avec l'option -P ou l'option --ignoreAdditionalPartitions"
MSG_EMAIL_PROG_NOT_SUPPORTED=14
MSG_EN[$MSG_EMAIL_PROG_NOT_SUPPORTED]="RBK0014E: eMail program %s not supported. Supported are %s"
MSG_DE[$MSG_EMAIL_PROG_NOT_SUPPORTED]="RBK0014E: eMail Programm %s ist nicht unterstützt. Möglich sind %s"
MSG_FI[$MSG_EMAIL_PROG_NOT_SUPPORTED]="RBK0014E: Sähköpostisovellusta %s ei tueta. Tuettuja ovat %s"
MSG_FR[$MSG_EMAIL_PROG_NOT_SUPPORTED]="RBK0014E: Le programme de messagerie %s n'est pas pris en charge. Sont pris en charge %s"
MSG_INSTANCE_ACTIVE=15
MSG_EN[$MSG_INSTANCE_ACTIVE]="RBK0015E: There is already an instance of $MYNAME up and running"
MSG_DE[$MSG_INSTANCE_ACTIVE]="RBK0015E: Es ist schon eine Instanz von $MYNAME aktiv"
MSG_FI[$MSG_INSTANCE_ACTIVE]="RBK0015E: $MYNAME on jo tällä hetkellä käynnissä"
MSG_FR[$MSG_INSTANCE_ACTIVE]="RBK0015E: Une instance de $MYNAME est déjà active"
MSG_NO_SDCARD_FOUND=16
MSG_EN[$MSG_NO_SDCARD_FOUND]="RBK0016E: No sd card %s found"
MSG_DE[$MSG_NO_SDCARD_FOUND]="RBK0016E: Keine SD Karte %s gefunden"
MSG_FI[$MSG_NO_SDCARD_FOUND]="RBK0016E: SD-korttia %s ei löytynyt"
MSG_FR[$MSG_NO_SDCARD_FOUND]="RBK0016E: Aucune carte SD %s trouvée"
MSG_BACKUP_OK=17
MSG_EN[$MSG_BACKUP_OK]="RBK0017I: Backup finished successfully"
MSG_DE[$MSG_BACKUP_OK]="RBK0017I: Backup erfolgreich beendet"
MSG_FI[$MSG_BACKUP_OK]="RBK0017I: Varmuuskopiointi suoritettu onnistuneesti"
MSG_FR[$MSG_BACKUP_OK]="RBK0017I: Sauvegarde terminée avec succès"
#MSG_ADJUSTING_WARNING2=18
#MSG_EN[$MSG_ADJUSTING_WARNING2]="RBK0018W: Target %s with %s is larger than backup source with %s. root partition will be expanded accordingly to use the whole space"
#MSG_DE[$MSG_ADJUSTING_WARNING2]="RBK0018W: Ziel %s mit %s ist größer als die Backupquelle mit %s. Die root Partition wird entsprechend vergrößert um den ganzen Platz zu benutzen"
#MSG_FI[$MSG_ADJUSTING_WARNING2]="RBK0018W: Kohde %s kooltaan %s, on suurempi kuin varmuuskopion lähde kooltaan %s. Juuriosio laajennetaan sen mukaisesti käyttämään koko tila"
#MSG_FR[$MSG_ADJUSTING_WARNING2]="RBK0018W: La cible %s avec %s, est plus grande que la source avec %s. la partition rootfs sera étendue pour utiliser tout l'espace"
MSG_MISSING_START_STOP=19
MSG_EN[$MSG_MISSING_START_STOP]="RBK0019E: Missing option -a and -o"
MSG_DE[$MSG_MISSING_START_STOP]="RBK0019E: Option -a und -o nicht angegeben"
MSG_FI[$MSG_MISSING_START_STOP]="RBK0019E: Valinnat -a ja -o puuttuvat"
MSG_FR[$MSG_MISSING_START_STOP]="RBK0019E: Options -a et -o non spécifiées"
MSG_FILESYSTEM_INCORRECT=20
MSG_EN[$MSG_FILESYSTEM_INCORRECT]="RBK0020E: Filesystem of rsync backup directory %s does not support %s"
MSG_DE[$MSG_FILESYSTEM_INCORRECT]="RBK0020E: Dateisystem des rsync Backupverzeichnisses %s unterstützt keine %s"
MSG_FI[$MSG_FILESYSTEM_INCORRECT]="RBK0020E: Rsync-varmuuskopiohakemiston %s tiedostojärjestelmä ei tue %s"
MSG_FR[$MSG_FILESYSTEM_INCORRECT]="RBK0020E: Le système des fichiers utilisés avec rsync %s n'est pas pris en charge %s"
MSG_BACKUP_PROGRAM_ERROR=21
MSG_EN[$MSG_BACKUP_PROGRAM_ERROR]="RBK0021E: Backupprogram for type %s failed with RC %s"
MSG_DE[$MSG_BACKUP_PROGRAM_ERROR]="RBK0021E: Backupprogramm des Typs %s beendete sich mit RC %s"
MSG_FI[$MSG_BACKUP_PROGRAM_ERROR]="RBK0021E: Tyypin %s varmuuskopiointisovellus epäonnistui, RC %s"
MSG_FR[$MSG_BACKUP_PROGRAM_ERROR]="RBK0021E: Sauvegarde de type %s terminé avec un Code Retour %s"
MSG_UNKNOWN_BACKUPTYPE=22
MSG_EN[$MSG_UNKNOWN_BACKUPTYPE]="RBK0022E: Unknown backuptype %s"
MSG_DE[$MSG_UNKNOWN_BACKUPTYPE]="RBK0022E: Unbekannter Backuptyp %s"
MSG_FI[$MSG_UNKNOWN_BACKUPTYPE]="RBK0022E: Tuntematon varmuuskopiotyyppi %s"
MSG_FR[$MSG_UNKNOWN_BACKUPTYPE]="RBK0022E: Type de sauvegarde inconnu %s"
MSG_KEEPBACKUP_INVALID=23
MSG_EN[$MSG_KEEPBACKUP_INVALID]="RBK0023E: Invalid parameter %s for %s detected"
MSG_DE[$MSG_KEEPBACKUP_INVALID]="RBK0023E: Ungültiger Parameter %s für -k eingegeben"
MSG_FI[$MSG_KEEPBACKUP_INVALID]="RBK0023E: Havaittu epäkelpo parametri %s kohteelle %s"
MSG_FR[$MSG_KEEPBACKUP_INVALID]="RBK0023E: Paramètre %s non valide pour -k %s"
MSG_TOOL_ERROR=24
MSG_EN[$MSG_TOOL_ERROR]="RBK0024E: Backup tool %s received error %s. Errormessages:$NL%s"
MSG_DE[$MSG_TOOL_ERROR]="RBK0024E: Backupprogramm %s hat einen Fehler %s bekommen. Fehlermeldungen:$NL%s"
MSG_FI[$MSG_TOOL_ERROR]="RBK0024E: Varmuuskopiointityökalu %s vastaanotti virheen %s. Virheviestit:$NL%s"
MSG_FR[$MSG_TOOL_ERROR]="RBK0024E: Une erreur lors de la sauvegarde %s s'est produite %s. Message:$NL%s"
MSG_DIR_TO_BACKUP_DOESNOTEXIST=25
MSG_EN[$MSG_DIR_TO_BACKUP_DOESNOTEXIST]="RBK0025E: Backupdirectory %s does not exist"
MSG_DE[$MSG_DIR_TO_BACKUP_DOESNOTEXIST]="RBK0025E: Backupverzeichnis %s existiert nicht"
MSG_FI[$MSG_DIR_TO_BACKUP_DOESNOTEXIST]="RBK0025E: Varmuuskopiohakemistoa %s ei ole"
MSG_FR[$MSG_DIR_TO_BACKUP_DOESNOTEXIST]="RBK0025E: Le répertoire de sauvegarde %s n'existe pas"
MSG_SAVED_LOG=26
MSG_EN[$MSG_SAVED_LOG]="RBK0026I: Debug logfile saved in %s"
MSG_DE[$MSG_SAVED_LOG]="RBK0026I: Debug Logdatei wurde in %s gesichert"
MSG_FI[$MSG_SAVED_LOG]="RBK0026I: Vianmäärityksen lokitiedosto tallennettu kohteeseen %s"
MSG_FR[$MSG_SAVED_LOG]="RBK0026I: Le fichier journal de débogage a été enregistré sous %s"
MSG_NO_DEVICEMOUNTED=27
MSG_EN[$MSG_NO_DEVICEMOUNTED]="RBK0027E: No external device mounted on %s. root partition would be used for the backup"
MSG_DE[$MSG_NO_DEVICEMOUNTED]="RBK0027E: Kein externes Gerät an %s verbunden. Die root Partition würde für das Backup benutzt werden"
MSG_FI[$MSG_NO_DEVICEMOUNTED]="RBK0027E: Ulkoista laitetta ei ole otettu käyttöön kohteessa %s. Juuriosiota käytetään varmuuskopiointiin"
MSG_FR[$MSG_NO_DEVICEMOUNTED]="RBK0027E: Aucun périphérique externe monté sur %s. la partition racine sera utilisée pour la sauvegarde"
MSG_RESTORE_DIRECTORY_NO_DIRECTORY=28
MSG_EN[$MSG_RESTORE_DIRECTORY_NO_DIRECTORY]="RBK0028E: %s is no backup directory of $MYNAME"
MSG_DE[$MSG_RESTORE_DIRECTORY_NO_DIRECTORY]="RBK0028E: %s ist kein Wiederherstellungsverzeichnis von $MYNAME"
MSG_FI[$MSG_RESTORE_DIRECTORY_NO_DIRECTORY]="RBK0028E: %s ei ole kohteen $MYNAME varmuuskopiohakemisto"
MSG_FR[$MSG_RESTORE_DIRECTORY_NO_DIRECTORY]="RBK0028E: %s n'est pas un répertoire de restauration pour $MYNAME"
MSG_MPACK_NOT_INSTALLED=29
MSG_EN[$MSG_MPACK_NOT_INSTALLED]="RBK0029E: Mail program mpack not installed to send emails. No log can be attached to the eMail"
MSG_DE[$MSG_MPACK_NOT_INSTALLED]="RBK0029E: Mail Program mpack is nicht installiert. Es kann kein Log an die eMail angehängt werden"
MSG_FI[$MSG_MPACK_NOT_INSTALLED]="RBK0029E: Sähköpostisovellusta mpack ei ole asennettu sähköpostien lähetykseen. Lokitiedostoa ei voitu liittää sähköpostiin"
MSG_FR[$MSG_MPACK_NOT_INSTALLED]="RBK0029E: Le programme de messagerie mpack n'est pas installé. Aucune pièce jointe ne peut être ajoutée à l'e-mail"
MSG_IMG_DD_FAILED=30
MSG_EN[$MSG_IMG_DD_FAILED]="RBK0030E: %s file creation with dd failed with RC %s"
MSG_DE[$MSG_IMG_DD_FAILED]="RBK0030E: %s Datei Erzeugung mit dd endet fehlerhaft mit RC %s"
MSG_FI[$MSG_IMG_DD_FAILED]="RBK0030E: Tiedoston %s luonti dd:llä epäonnistui, RC %s"
MSG_FR[$MSG_IMG_DD_FAILED]="RBK0030E: La création du fichier %s avec dd s'est terminé avec un code d'erreur: %s"
MSG_CHECKING_FOR_NEW_VERSION=31
MSG_EN[$MSG_CHECKING_FOR_NEW_VERSION]="RBK0031I: Checking whether a new version of $MYSELF is available"
MSG_DE[$MSG_CHECKING_FOR_NEW_VERSION]="RBK0031I: Prüfe ob eine neue Version von $MYSELF verfügbar ist"
MSG_FI[$MSG_CHECKING_FOR_NEW_VERSION]="RBK0031I: Tarkistetaan, onko $MYSELF uusia versioita saatavilla"
MSG_FR[$MSG_CHECKING_FOR_NEW_VERSION]="RBK0031I: Vérifiez si une nouvelle version de $MYSELF est disponible"
MSG_INVALID_LOG_LEVEL=32
MSG_EN[$MSG_INVALID_LOG_LEVEL]="RBK0032E: Invalid parameter '%s' for option -l detected"
MSG_DE[$MSG_INVALID_LOG_LEVEL]="RBK0032E: Ungültiger Parameter '%s' für Option -l eingegeben"
MSG_FI[$MSG_INVALID_LOG_LEVEL]="RBK0032E: Havaittu epäkelpo parametri '%s' valinnalle -l"
MSG_FR[$MSG_INVALID_LOG_LEVEL]="RBK0032E: Paramètre non valide '%s' pour l'option -l"
MSG_CLEANING_UP=33
MSG_EN[$MSG_CLEANING_UP]="RBK0033I: Please wait until cleanup has finished"
MSG_DE[$MSG_CLEANING_UP]="RBK0033I: Bitte warten bis aufgeräumt wurde"
MSG_FI[$MSG_CLEANING_UP]="RBK0033I: Ole hyvä ja odota, kunnes puhdistus on valmistunut"
MSG_FR[$MSG_CLEANING_UP]="RBK0033I: Veuillez patienter jusqu'à la fin du nettoyage"
MSG_FILE_NOT_FOUND=34
MSG_EN[$MSG_FILE_NOT_FOUND]="RBK0034E: File %s not found"
MSG_DE[$MSG_FILE_NOT_FOUND]="RBK0034E: Datei %s nicht gefunden"
MSG_FI[$MSG_FILE_NOT_FOUND]="RBK0034E: Tiedostoa %s ei löytynyt"
MSG_FR[$MSG_FILE_NOT_FOUND]="RBK0034E: Fichier %s introuvable"
MSG_RESTORE_PROGRAM_ERROR=35
MSG_EN[$MSG_RESTORE_PROGRAM_ERROR]="RBK0035E: Backupprogram %s failed during restore with RC %s"
MSG_DE[$MSG_RESTORE_PROGRAM_ERROR]="RBK0035E: Backupprogramm %s endete beim Restore mit RC %s"
MSG_FI[$MSG_RESTORE_PROGRAM_ERROR]="RBK0035E: Varmuuskopiointisovellus %s epäonnistui palautuksen aikana, RC %s"
MSG_FR[$MSG_RESTORE_PROGRAM_ERROR]="RBK0035E: La sauvegarde %s a été interrompue avec le code erreur %s"
MSG_BACKUP_CREATING_PARTITION_INFO=36
MSG_EN[$MSG_BACKUP_CREATING_PARTITION_INFO]="RBK0036I: Saving partition layout"
MSG_DE[$MSG_BACKUP_CREATING_PARTITION_INFO]="RBK0036I: Partitionslayout wird gesichert"
MSG_FI[$MSG_BACKUP_CREATING_PARTITION_INFO]="RBK0036I: Tallennetaan osioasettelua"
MSG_FR[$MSG_BACKUP_CREATING_PARTITION_INFO]="RBK0036I: Sauvegarde de la disposition de la partition"
MSG_ANSWER_CHARS_YES=37
MSG_EN[$MSG_ANSWER_CHARS_YES]="Yy"
MSG_DE[$MSG_ANSWER_CHARS_YES]="Jj"
MSG_FI[$MSG_ANSWER_CHARS_YES]="Kk"
MSG_FR[$MSG_ANSWER_CHARS_YES]="Oo"
MSG_ARE_YOU_SURE=38
MSG_EN[$MSG_ARE_YOU_SURE]="RBK0038I: Are you sure? %s "
MSG_DE[$MSG_ARE_YOU_SURE]="RBK0038I: Bist Du sicher? %s "
MSG_FI[$MSG_ARE_YOU_SURE]="RBK0038I: Oletko varma? %s "
MSG_FR[$MSG_ARE_YOU_SURE]="RBK0038I: Etes vous sûre? %s "
MSG_MAILPROGRAM_NOT_INSTALLED=39
MSG_EN[$MSG_MAILPROGRAM_NOT_INSTALLED]="RBK0039E: Mail program %s not installed to send emails"
MSG_DE[$MSG_MAILPROGRAM_NOT_INSTALLED]="RBK0039E: Mail Program %s ist nicht installiert um eMail zu senden"
MSG_FI[$MSG_MAILPROGRAM_NOT_INSTALLED]="RBK0039E: Sähköpostisovellusta %s ei ole asennettu sähkökpostien lähettämiseen"
MSG_FR[$MSG_MAILPROGRAM_NOT_INSTALLED]="RBK0039E: Le programme de messagerie %s n'est pas installé pour envoyer des e-mails"
MSG_INCOMPATIBLE_UPDATE=40
MSG_EN[$MSG_INCOMPATIBLE_UPDATE]="RBK0040W: New version %s has some incompatibilities to previous versions. Please read %s and use option -S together with option -U to update script"
MSG_DE[$MSG_INCOMPATIBLE_UPDATE]="RBK0040W: Die neue Version %s hat inkompatible Änderungen zu vorhergehenden Versionen. Bitte %s lesen und dann die Option -S zusammen mit -U benutzen um das Script zu updaten"
MSG_FI[$MSG_INCOMPATIBLE_UPDATE]="RBK0040W: Uusi versio %s ei ole täysin yhteensopiva edellisen version kanssa. Ole hyvä ja lue %s ja käytä valintaa -S yhdessä valinnan -U kanssa päivittääksesi skriptin"
MSG_FR[$MSG_INCOMPATIBLE_UPDATE]="RBK0040W: La nouvelle version %s présente des incompatibilités avec les versions précédentes. Veuillez lire %s et utilisez les options -S et -U pour mettre à jour le script"
MSG_TITLE_OK=41
MSG_EN[$MSG_TITLE_OK]="%s: %s finished successfully"
MSG_DE[$MSG_TITLE_OK]="%s: %s erfolgreich beendet"
MSG_TITLE_ERROR=42
MSG_EN[$MSG_TITLE_ERROR]="%s: %s failed !!!"
MSG_DE[$MSG_TITLE_ERROR]="%s: %s nicht erfolgreich !!!"
MSG_REMOVING_BACKUP=43
MSG_EN[$MSG_REMOVING_BACKUP]="RBK0043I: Removing incomplete backup in %s. This may take some time. Please be patient"
MSG_DE[$MSG_REMOVING_BACKUP]="RBK0043I: Unvollständiges Backup in %s wird gelöscht. Das kann etwas dauern. Bitte Geduld"
MSG_FI[$MSG_REMOVING_BACKUP]="RBK0043I: Poistetaan keskeneräinen varmuuskopio kohteessa %s. Tämä saattaa kestää jonkin aikaa. Ole hyvä ja odota"
MSG_FR[$MSG_REMOVING_BACKUP]="RBK0043I: Suppression en cours des sauvegardes incomplètes %s. Cela peut prendre du temps, SVP soyez patient"
MSG_CREATING_BOOT_BACKUP=44
MSG_EN[$MSG_CREATING_BOOT_BACKUP]="RBK0044I: Creating backup of boot partition in %s"
MSG_DE[$MSG_CREATING_BOOT_BACKUP]="RBK0044I: Backup der Bootpartition wird in %s erstellt"
MSG_FI[$MSG_CREATING_BOOT_BACKUP]="RBK0044I: Luodaan varmuuskopiota kohteeseen %s"
MSG_FR[$MSG_CREATING_BOOT_BACKUP]="RBK0044I: La partition de boot sera sauvegardée en %s"
MSG_CREATING_PARTITION_BACKUP=45
MSG_EN[$MSG_CREATING_PARTITION_BACKUP]="RBK0045I: Creating backup of partition layout in %s"
MSG_DE[$MSG_CREATING_PARTITION_BACKUP]="RBK0044I: Backup des Partitionlayouts wird in %s erstellt"
MSG_FI[$MSG_CREATING_PARTITION_BACKUP]="RBK0045I: Luodaan varmuuskopiota osioasettelusta kohteeseen %s"
MSG_FR[$MSG_CREATING_PARTITION_BACKUP]="RBK0045I: La disposition de la partition sera sauvegardée sous %s"
MSG_CREATING_MBR_BACKUP=46
MSG_EN[$MSG_CREATING_MBR_BACKUP]="RBK0046I: Creating backup of master boot record in %s"
MSG_DE[$MSG_CREATING_MBR_BACKUP]="RBK0046I: Backup des Masterbootrecords wird in %s erstellt"
MSG_FI[$MSG_CREATING_MBR_BACKUP]="RBK0046I: Luodaan varmuuskopiota Master Boot Recordista kohteeseen %s"
MSG_FR[$MSG_CREATING_MBR_BACKUP]="RBK0046I: Le MBR, Master Boot Record, est sauvegardé sous %s"
MSG_START_SERVICES_FAILED=47
MSG_EN[$MSG_START_SERVICES_FAILED]="RBK0047W: Error occured when starting services. RC %s"
MSG_DE[$MSG_START_SERVICES_FAILED]="RBK0047W: Ein Fehler trat beim Starten von Services auf. RC %s"
MSG_FI[$MSG_START_SERVICES_FAILED]="RBK0047W: Virhe palveluita käynnistäessä. RC %s"
MSG_FR[$MSG_START_SERVICES_FAILED]="RBK0047W: Une erreur avec le code %s s'est produite lors du démarrage des services"
MSG_STOP_SERVICES_FAILED=48
MSG_EN[$MSG_STOP_SERVICES_FAILED]="RBK0048E: Error occured when stopping services. RC %s"
MSG_DE[$MSG_STOP_SERVICES_FAILED]="RBK0048E: Ein Fehler trat beim Beenden von Services auf. RC %s"
MSG_FI[$MSG_STOP_SERVICES_FAILED]="RBK0048E: Virhe palveluita pysäytettäessä. RC %s"
MSG_FR[$MSG_STOP_SERVICES_FAILED]="RBK0048E: Une erreur code %s s'est produite lors de l'arrêt des services"
#MSG_SAVED_LOG_SYSLOG=49
#MSG_EN[$MSG_SAVED_LOG_SYSLOG]="RBK0049I: Messages saved in %s"
#MSG_DE[$MSG_SAVED_LOG_SYSLOG]="RBK0049I: Meldungen wurden in %s gesichert"
#MSG_FI[$MSG_SAVED_LOG_SYSLOG]="RBK0049I: Viestit tallennettu kohteeseen %s"
#MSG_FR[$MSG_SAVED_LOG_SYSLOG]="RBK0049I: Les messages ont été enregistrés sous %s"
MSG_RESTORING_FILE=50
MSG_EN[$MSG_RESTORING_FILE]="RBK0050I: Restoring backup from %s"
MSG_DE[$MSG_RESTORING_FILE]="RBK0050I: Backup wird von %s zurückgespielt"
MSG_FI[$MSG_RESTORING_FILE]="RBK0050I: Palautetaan varmuuskopiota kohteesta %s"
MSG_FR[$MSG_RESTORING_FILE]="RBK0050I: Restauration en cours à partir de %s"
MSG_TARGET_REQUIRES_GPT=51
MSG_EN[$MSG_TARGET_REQUIRES_GPT]="RBK0051W: Target %s with %s is larger than 2TB and requires gpt instead of mbr. Otherwise only 2TB will be used"
MSG_DE[$MSG_TARGET_REQUIRES_GPT]="RBK0051W: Ziel %s mit %s ist größer als 2TB und erfordert gpt statt mbr. Ansonsten werden nur 2TB genutzt"
MSG_FI[$MSG_TARGET_REQUIRES_GPT]="RBK0051W: Kohde %s kooltaan %s, on suurempi kuin 2Tt ja vaatii mbr:n sijasta gpt:n. Muutoin vain 2Tt voidaan käyttää"
MSG_FR[$MSG_TARGET_REQUIRES_GPT]="RBK0051W: La cible %s avec %s, est supérieure à 2 To et nécessite GPT au lieu de MBR. Sinon, seuls 2 To seront utilisés"
MSG_CREATING_PARTITIONS=52
MSG_EN[$MSG_CREATING_PARTITIONS]="RBK0052W: Creating partitions on %s"
MSG_DE[$MSG_CREATING_PARTITIONS]="RBK0052W: Partitionen werden auf %s erstellt"
MSG_FI[$MSG_CREATING_PARTITIONS]="RBK0052W: Luodaan osioita kohteelle %s"
MSG_FR[$MSG_CREATING_PARTITIONS]="RBK0052W: Les partitions seront créées sur %s"
MSG_RESTORING_FIRST_PARTITION=53
MSG_EN[$MSG_RESTORING_FIRST_PARTITION]="RBK0053I: Restoring first partition (boot partition) to %s"
MSG_DE[$MSG_RESTORING_FIRST_PARTITION]="RBK0053I: Erste Partition (Bootpartition) wird auf %s zurückgespielt"
MSG_FI[$MSG_RESTORING_FIRST_PARTITION]="RBK0053I: Palautetaan ensimmäistä osoita (käynnistysosio) kohteesen %s"
MSG_FR[$MSG_RESTORING_FIRST_PARTITION]="RBK0053I: La première partition (boot) sera restaurée vers %s"
MSG_FORMATTING_SECOND_PARTITION=54
MSG_EN[$MSG_FORMATTING_SECOND_PARTITION]="RBK0054I: Formating second partition (root partition) %s"
MSG_DE[$MSG_FORMATTING_SECOND_PARTITION]="RBK0054I: Zweite Partition (Rootpartition) %s wird formatiert"
MSG_FI[$MSG_FORMATTING_SECOND_PARTITION]="RBK0054I: Alustetaan toista osiota (juuriosio) %s"
MSG_FR[$MSG_FORMATTING_SECOND_PARTITION]="RBK0054I: La deuxième partition (partition root) %s sera formatée"
MSG_RESTORING_SECOND_PARTITION=55
MSG_EN[$MSG_RESTORING_SECOND_PARTITION]="RBK0055I: Restoring second partition (root partition) to %s"
MSG_DE[$MSG_RESTORING_SECOND_PARTITION]="RBK0055I: Zweite Partition (Rootpartition) wird auf %s zurückgespielt"
MSG_FI[$MSG_RESTORING_SECOND_PARTITION]="RBK0055I: Palautetaan toista osiota (juuriosio) kohteeseen %s"
MSG_FR[$MSG_RESTORING_SECOND_PARTITION]="RBK0055I: La deuxième partition (partition root) sera restaurée sur %s"
MSG_DEPLOYMENT_PARMS_ERROR=56
MSG_EN[$MSG_DEPLOYMENT_PARMS_ERROR]="RBK0056E: Incorrect deployment parameters. Use <hostname>@<username>"
MSG_DE[$MSG_DEPLOYMENT_PARMS_ERROR]="RBK0056E: Ungültige Deploymentparameter. Erforderliches Format: <hostname>@<username>"
MSG_FI[$MSG_DEPLOYMENT_PARMS_ERROR]="RBK0056E: Virheelliset käyttöönottoparametrit. Käytä <hostname>@<username>"
MSG_FR[$MSG_DEPLOYMENT_PARMS_ERROR]="RBK0056E: Paramètres de déploiement invalides. Format requis : <hostname>@<username>"
MSG_DOWNLOADING=57
MSG_EN[$MSG_DOWNLOADING]="RBK0057I: Downloading file %s from %s"
MSG_DE[$MSG_DOWNLOADING]="RBK0057I: Datei %s wird von %s downloaded"
MSG_FI[$MSG_DOWNLOADING]="RBK0057I: Ladataan tiedosta %s kohteesta %s"
MSG_FR[$MSG_DOWNLOADING]="RBK0057I: Téléchargement du fichier %s depuis %s"
MSG_INVALID_MSG_LEVEL=58
MSG_EN[$MSG_INVALID_MSG_LEVEL]="RBK0058E: Invalid parameter '%s' for option -m detected"
MSG_DE[$MSG_INVALID_MSG_LEVEL]="RBK0058E: Ungültiger Parameter '%s' für Option -m eingegeben"
MSG_FI[$MSG_INVALID_MSG_LEVEL]="RBK0058E: Havaittu epäkelpo parametri '%s' valinnalle -m"
MSG_FR[$MSG_INVALID_MSG_LEVEL]="RBK0058E: Paramètre invalide '%s' entré pour l'option -m"
#MSG_INVALID_LOG_OUTPUT=59
#MSG_EN[$MSG_INVALID_LOG_OUTPUT]="RBK0059W: Invalid parameter '%s' for option -L detected"
#MSG_DE[$MSG_INVALID_LOG_OUTPUT]="RBK0059W: Ungültiger Parameter '%s' für Option -L eingegeben"
#MSG_FI[$MSG_INVALID_LOG_OUTPUT]="RBK0059W: Havaittu epäkelpo parametri '%s' valinnalle -L"
#MSG_FR[$MSG_INVALID_LOG_OUTPUT]="RBK0059W: Paramètre invalide '%s' entré pour l'option -L"
MSG_NO_YES=60
MSG_EN[$MSG_NO_YES]="no yes"
MSG_DE[$MSG_NO_YES]="nein ja"
MSG_FI[$MSG_NO_YES]="ei kyllä"
MSG_FR[$MSG_NO_YES]="non oui"
MSG_BOOTPATITIONFILES_NOT_FOUND=61
MSG_EN[$MSG_BOOTPATITIONFILES_NOT_FOUND]="RBK0061E: Unable to find bootpartition files %s starting with %s"
MSG_DE[$MSG_BOOTPATITIONFILES_NOT_FOUND]="RBK0061E: Keine Bootpartitionsdateien in %s gefunden die mit %s beginnen"
MSG_FI[$MSG_BOOTPATITIONFILES_NOT_FOUND]="RBK0061E: Ei voida löytää käynnsitysosion tiedostoja %s, jotka alkavat %s"
MSG_FR[$MSG_BOOTPATITIONFILES_NOT_FOUND]="RBK0061E: Fichiers de partition de boot %s , commençant par %s introuvables"
MSG_NO_RESTOREDEVICE_DEFINED=62
MSG_EN[$MSG_NO_RESTOREDEVICE_DEFINED]="RBK0062E: No restoredevice defined (Example: /dev/sda)"
MSG_DE[$MSG_NO_RESTOREDEVICE_DEFINED]="RBK0062E: Kein Zurückspielgerät ist definiert (Beispiel: /dev/sda)"
MSG_FI[$MSG_NO_RESTOREDEVICE_DEFINED]="RBK0062E: Palautuslaitetta ei ole määritetty (Esimerkki: /dev/sda)"
MSG_FR[$MSG_NO_RESTOREDEVICE_DEFINED]="RBK0062E: Aucun périphérique de lecture défini (exemple:/dev/sda)"
MSG_NO_RESTOREDEVICE_FOUND=63
MSG_EN[$MSG_NO_RESTOREDEVICE_FOUND]="RBK0063E: Restoredevice %s not found (Example: /dev/sda)"
MSG_DE[$MSG_NO_RESTOREDEVICE_FOUND]="RBK0063E: Zurückspielgerät %s existiert nicht (Beispiel: /dev/sda)"
MSG_FI[$MSG_NO_RESTOREDEVICE_FOUND]="RBK0063E: Palautuslaitetta %s ei löytynyt (Esimerkki: /dev/sda)"
MSG_FR[$MSG_NO_RESTOREDEVICE_FOUND]="RBK0063E: Périphérique de restauration %s introuvable (ex:/dev/sda)"
MSG_ROOT_PARTTITION_NOT_FOUND=64
MSG_EN[$MSG_ROOT_PARTTITION_NOT_FOUND]="RBK0064E: Partition for rootpartition %s not found (Example: /dev/sdb1)"
MSG_DE[$MSG_ROOT_PARTTITION_NOT_FOUND]="RBK0064E: Partition für die Rootpartition %s nicht gefunden (Beispiel: /dev/sda)"
MSG_FI[$MSG_ROOT_PARTTITION_NOT_FOUND]="RBK0064E: Osiota juuriosiolle %s ei löytynyt (Esimerkki: /dev/sdb1)"
MSG_FR[$MSG_ROOT_PARTTITION_NOT_FOUND]="RBK0064E: La partition Root %s est introuvable (exemple:/dev/sdb1)"
MSG_REPARTITION_WARNING=65
MSG_EN[$MSG_REPARTITION_WARNING]="RBK0065W: Device %s will be repartitioned and all data will be lost"
MSG_DE[$MSG_REPARTITION_WARNING]="RBK0065W: Gerät %s wird repartitioniert und die gesamten Daten werden gelöscht"
MSG_FI[$MSG_REPARTITION_WARNING]="RBK0065W: Laite %s osioidaan uudelleen ja kaikki tieto hävitetään"
MSG_FR[$MSG_REPARTITION_WARNING]="RBK0065W: Le périphérique %s sera repartitionné, toutes les données seront perdues"
MSG_WARN_RESTORE_DEVICE_OVERWRITTEN=66
MSG_EN[$MSG_WARN_RESTORE_DEVICE_OVERWRITTEN]="RBK0066I: Device %s will be overwritten with the saved boot and root partition"
MSG_DE[$MSG_WARN_RESTORE_DEVICE_OVERWRITTEN]="RBK0066I: Gerät %s wird überschrieben mit der gesicherten Boot- und Rootpartition"
MSG_FI[$MSG_WARN_RESTORE_DEVICE_OVERWRITTEN]="RBK0066I: Laite %s ylikirjoitetaan tallennetuilla käynnistys- ja juuriosioilla"
MSG_FR[$MSG_WARN_RESTORE_DEVICE_OVERWRITTEN]="RBK0066I: Le périphérique %s sera écrasé par la procédure de boot et la partition Root"
MSG_CURRENT_PARTITION_TABLE=67
MSG_EN[$MSG_CURRENT_PARTITION_TABLE]="RBK0067I: Current partitions on %s:"
MSG_DE[$MSG_CURRENT_PARTITION_TABLE]="RBK0067I: Momentane Partitionen auf %s:"
MSG_FI[$MSG_CURRENT_PARTITION_TABLE]="RBK0067I: Nykyiset osiot kohteella %s:"
MSG_FR[$MSG_CURRENT_PARTITION_TABLE]="RBK0067I: Partitions actuelles sur %s:"
MSG_BOOTPATITIONFILES_FOUND=68
MSG_EN[$MSG_BOOTPATITIONFILES_FOUND]="RBK0068I: Using bootpartition backup files starting with %s from directory %s"
MSG_DE[$MSG_BOOTPATITIONFILES_FOUND]="RBK0068I: Bootpartitionsdateien des Backups aus dem Verzeichnis %s die mit %s beginnen werden benutzt"
MSG_FI[$MSG_BOOTPATITIONFILES_FOUND]="RBK0068I: Käytetään käynnistysosion %s alkavia varmuuskopiointitiedostoja hakemistosta %s"
MSG_FR[$MSG_BOOTPATITIONFILES_FOUND]="RBK0068I: Les fichiers sauvegardés pour le boot commençant par %s dans le répertoire %s sont utilisés"
MSG_WARN_BOOT_PARTITION_OVERWRITTEN=69
MSG_EN[$MSG_WARN_BOOT_PARTITION_OVERWRITTEN]="RBK0069I: Bootpartition %s will be formatted and will get the restored Boot partition"
MSG_DE[$MSG_WARN_BOOT_PARTITION_OVERWRITTEN]="RBK0069I: Bootpartition %s wird formatiert und erhält die zurückgespielte Bootpartition"
MSG_FI[$MSG_WARN_BOOT_PARTITION_OVERWRITTEN]="RBK0069I: Käynnistysosio %s alustetaan ja sille palautetaan varmuuskopioitu käynnistysosio"
MSG_FR[$MSG_WARN_BOOT_PARTITION_OVERWRITTEN]="RBK0069I: La partition de boot %s sera formatée pour recevoir la partition de boot restaurée"
MSG_WARN_ROOT_PARTITION_OVERWRITTEN=70
MSG_EN[$MSG_WARN_ROOT_PARTITION_OVERWRITTEN]="RBK0070I: Rootpartition %s will be formatted and will get the restored Root partition"
MSG_DE[$MSG_WARN_ROOT_PARTITION_OVERWRITTEN]="RBK0070I: Rootpartition %s wird formatiert und erhält die zurückgespielte Rootpartition"
MSG_FI[$MSG_WARN_ROOT_PARTITION_OVERWRITTEN]="RBK0070I: Juuriosio %s alustetaan ja sille palautetaan varmuuskopioitu juuriosio"
MSG_FR[$MSG_WARN_ROOT_PARTITION_OVERWRITTEN]="RBK0070I: La partition Root %s sera formatée et restaurée avec la partition sauvegardée"
MSG_QUERY_CHARS_YES_NO=71
MSG_EN[$MSG_QUERY_CHARS_YES_NO]="y/N"
MSG_DE[$MSG_QUERY_CHARS_YES_NO]="j/N"
MSG_FI[$MSG_QUERY_CHARS_YES_NO]="k/E"
MSG_FR[$MSG_QUERY_CHARS_YES_NO]="o/N"
MSG_SCRIPT_UPDATE_OK=72
MSG_EN[$MSG_SCRIPT_UPDATE_OK]="RBK0072I: %s updated from version %s to version %s. Previous version saved as %s. Don't forget to test backup and restore with the new version now"
MSG_DE[$MSG_SCRIPT_UPDATE_OK]="RBK0072I: %s von Version %s durch die aktuelle Version %s ersetzt. Die vorherige Version wurde als %s gesichert. Nicht vergessen den Backup und Restore mit der neuen Version zu testen"
MSG_FI[$MSG_SCRIPT_UPDATE_OK]="RBK0072I: %s on päivitetty versiosta %s versioon %s. Edellinen versio on tallennettu nimellä %s. Muista testata varmuuskopiointi ja palautus uudella versiolla"
MSG_FR[$MSG_SCRIPT_UPDATE_OK]="RBK0072I: %s mis à jour de la version %s à la version %s La version précédente a été sauvée sous %s. N'oubliez pas de tester une sauvegarde suivi d'une restauration avec cette version"
MSG_SCRIPT_UPDATE_NOT_NEEDED=73
MSG_EN[$MSG_SCRIPT_UPDATE_NOT_NEEDED]="RBK0073I: %s already current with version %s"
MSG_DE[$MSG_SCRIPT_UPDATE_NOT_NEEDED]="RBK0073I: %s bereits auf der aktuellen Version %s"
MSG_FI[$MSG_SCRIPT_UPDATE_NOT_NEEDED]="RBK0073I: %s on jo ajantasalla version %s kanssa"
MSG_FR[$MSG_SCRIPT_UPDATE_NOT_NEEDED]="RBK0073I: %s est déjà à jour avec la version %s"
MSG_SCRIPT_UPDATE_FAILED=74
MSG_EN[$MSG_SCRIPT_UPDATE_FAILED]="RBK0074E: Failed to update %s"
MSG_DE[$MSG_SCRIPT_UPDATE_FAILED]="RBK0074E: %s konnte nicht ersetzt werden"
MSG_FI[$MSG_SCRIPT_UPDATE_FAILED]="RBK0074E: %s päivitys epäonnistui"
MSG_FR[$MSG_SCRIPT_UPDATE_FAILED]="RBK0074E: Échec de la mise à jour de %s"
MSG_LINK_BOOTPARTITIONFILES=75
MSG_EN[$MSG_LINK_BOOTPARTITIONFILES]="RBK0075I: Using hardlinks to reuse bootpartition backups"
MSG_DE[$MSG_LINK_BOOTPARTITIONFILES]="RBK0075I: Hardlinks werden genutzt um Bootpartitionsbackups wiederzuverwenden"
MSG_FI[$MSG_LINK_BOOTPARTITIONFILES]="RBK0075I: Käytetään hardlink-tietoja käynnistysosion varmuuskopioihin. "
MSG_FR[$MSG_LINK_BOOTPARTITIONFILES]="RBK0075I: Les liens physiques sont utilisés pour réutiliser les sauvegardes de la partition de Boot"
MSG_RESTORE_OK=76
MSG_EN[$MSG_RESTORE_OK]="RBK0076I: Restore finished successfully"
MSG_DE[$MSG_RESTORE_OK]="RBK0076I: Restore erfolgreich beendet"
MSG_FI[$MSG_RESTORE_OK]="RBK0076I: Palautus suoritettu onnistuneesti"
MSG_FR[$MSG_RESTORE_OK]="RBK0076I: Restauration terminée avec succès"
MSG_RESTORE_FAILED=77
MSG_EN[$MSG_RESTORE_FAILED]="RBK0077E: Restore failed. Check previous error messages"
MSG_DE[$MSG_RESTORE_FAILED]="RBK0077E: Restore wurde fehlerhaft beendet. Siehe vorhergehende Fehlermeldungen"
MSG_FI[$MSG_RESTORE_FAILED]="RBK0077E: Palautus epäonnistui. Katso edelliest virheilmoitukset"
MSG_FR[$MSG_RESTORE_FAILED]="RBK0077E: La restauration a échoué. Vérifier les messages d'erreur"
MSG_BACKUP_TIME=78
MSG_EN[$MSG_BACKUP_TIME]="RBK0078I: Backup time: %s:%s:%s"
MSG_DE[$MSG_BACKUP_TIME]="RBK0078I: Backupzeit: %s:%s:%s"
MSG_FI[$MSG_BACKUP_TIME]="RBK0078I: Varmuuskopiointiin kulunut aika: %s:%s:%s"
MSG_FR[$MSG_BACKUP_TIME]="RBK0078I: Temps de sauvegarde: %s:%s:%s"
MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP=79
MSG_EN[$MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP]="RBK0079E: Option -z not allowed with backuptype %s"
MSG_DE[$MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP]="RBK0079E: Option -z ist für Backuptyp %s nicht erlaubt"
MSG_FI[$MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP]="RBK0079E: Valintaa -z ei voi käyttää varmuuskopiointityyppi %s:n kanssa"
MSG_FR[$MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP]="RBK0079E: Option -z non autorisée avec ce type de sauvegarde %s"
MSG_NEW_VERSION_AVAILABLE=80
MSG_EN[$MSG_NEW_VERSION_AVAILABLE]="RBK0080I: $SMILEY_UPDATE_POSSIBLE There is a new version %s of $MYNAME available for download. You are running version %s and now can use option -U to upgrade your local version"
MSG_DE[$MSG_NEW_VERSION_AVAILABLE]="RBK0080I: $SMILEY_UPDATE_POSSIBLE Es gibt eine neue Version %s von $MYNAME zum downloaden. Die momentan benutze Version ist %s und es kann mit der Option -U die lokale Version aktualisiert werden"
MSG_FI[$MSG_NEW_VERSION_AVAILABLE]="RBK0080I: $SMILEY_UPDATE_POSSIBLE Uusi versio %s kohteesta $MYNAME on saatavilla. Käytät versiota %s ja voit käyttää valintaa -U päivittääksesi paikallisen version"
MSG_FR[$MSG_NEW_VERSION_AVAILABLE]="RBK0080I: $SMILEY_UPDATE_POSSIBLE Une nouvelle version %s de $MYNAME est disponible en téléchargement. vous exécutez la version %s et pouvez maintenant utiliser l'option -U pour la mettre à niveau"
MSG_BACKUP_TARGET=81
MSG_EN[$MSG_BACKUP_TARGET]="RBK0081I: Creating backup of type %s in %s"
MSG_DE[$MSG_BACKUP_TARGET]="RBK0081I: Backup vom Typ %s wird in %s erstellt"
MSG_FI[$MSG_BACKUP_TARGET]="RBK0081I: Luodaan %s-tyypin varmuuskopio kohteeseen %s"
MSG_FR[$MSG_BACKUP_TARGET]="RBK0081I: Création d'une sauvegarde de type %s dans %s"
MSG_EXISTING_BOOT_BACKUP=82
MSG_EN[$MSG_EXISTING_BOOT_BACKUP]="RBK0082I: Backup of boot partition alreday exists in %s"
MSG_DE[$MSG_EXISTING_BOOT_BACKUP]="RBK0082I: Backup der Bootpartition in %s existiert schon"
MSG_FI[$MSG_EXISTING_BOOT_BACKUP]="RBK0082I: Käynnistysosion varmuuskopio on jo olemassa kohteessa %s"
MSG_FR[$MSG_EXISTING_BOOT_BACKUP]="RBK0082I: La sauvegarde de la partition de Boot existe déjà dans %s"
MSG_EXISTING_PARTITION_BACKUP=83
MSG_EN[$MSG_EXISTING_PARTITION_BACKUP]="RBK0083I: Backup of partition layout already exists in %s"
MSG_DE[$MSG_EXISTING_PARTITION_BACKUP]="RBK0083I: Backup des Partitionlayouts in %s existiert schon"
MSG_FI[$MSG_EXISTING_PARTITION_BACKUP]="RBK0083I: Osioasettelun varmuuskopio on jo olemassa kohteessa %s"
MSG_FR[$MSG_EXISTING_PARTITION_BACKUP]="RBK0083I: La sauvegarde de la disposition de la partition existe déjà dans %s"
MSG_EXISTING_MBR_BACKUP=84
MSG_EN[$MSG_EXISTING_MBR_BACKUP]="RBK0084I: Backup of master boot record already exists in %s"
MSG_DE[$MSG_EXISTING_MBR_BACKUP]="RBK0084I: Backup des Masterbootrecords in %s existiert schon"
MSG_FI[$MSG_EXISTING_MBR_BACKUP]="RBK0084I: Master Boot Record-varmuuskopio on jo olemassa kohteessa %s"
MSG_FR[$MSG_EXISTING_MBR_BACKUP]="RBK0084I: La sauvegarde du MBR ,master boot record, existe déjà dans %s"
MSG_BACKUP_STARTED=85
MSG_EN[$MSG_BACKUP_STARTED]="RBK0085I: Backup of type %s started. Please be patient"
MSG_DE[$MSG_BACKUP_STARTED]="RBK0085I: Backuperstellung vom Typ %s gestartet. Bitte Geduld"
MSG_FI[$MSG_BACKUP_STARTED]="RBK0085I: %s-tyypin varmuuskopiointi on aloitettu. Ole hyvä ja odota"
MSG_FR[$MSG_BACKUP_STARTED]="RBK0085I: Démarrage de la sauvegarde de type %s SVP soyez patient"
MSG_RESTOREDEVICE_IS_PARTITION=86
MSG_EN[$MSG_RESTOREDEVICE_IS_PARTITION]="RBK0086E: Restore device has trailing partition number but cannot be a partition"
MSG_DE[$MSG_RESTOREDEVICE_IS_PARTITION]="RBK0086E: Wiederherstellungsgerät hat eine Partitionsnummer am Ende aber darf keine Partition sein"
MSG_FI[$MSG_RESTOREDEVICE_IS_PARTITION]="RBK0086E: Palautuslaitteella on osionumero, palautusta ei voida tehdä osiolle. "
MSG_FR[$MSG_RESTOREDEVICE_IS_PARTITION]="RBK0086E: Le périphérique de restauration a un numéro de partition la restauration ne peut pas être effectuée"
MSG_RESTORE_DIRECTORY_INVALID=87
MSG_EN[$MSG_RESTORE_DIRECTORY_INVALID]="RBK0087E: Restore directory %s was not created by $MYNAME"
MSG_DE[$MSG_RESTORE_DIRECTORY_INVALID]="RBK0087E: Wiederherstellungsverzeichnis %s wurde nicht von $MYNAME erstellt"
MSG_FI[$MSG_RESTORE_DIRECTORY_INVALID]="RBK0087E: $MYNAME ei luonut palautushakemistoa %s"
MSG_FR[$MSG_RESTORE_DIRECTORY_INVALID]="RBK0087E: Le répertoire de restauration %s n'a pas été créé par.$MYNAME"
MSG_RESTORE_DEVICE_NOT_ALLOWED=88
MSG_EN[$MSG_RESTORE_DEVICE_NOT_ALLOWED]="RBK0088E: -R option not supported for partitionbased backup"
MSG_DE[$MSG_RESTORE_DEVICE_NOT_ALLOWED]="RBK0088E: Option -R wird nicht beim partitionbasierten Backup unterstützt"
MSG_FI[$MSG_RESTORE_DEVICE_NOT_ALLOWED]="RBK0088E: Valintaa -R ei tueta osiopohjaisille varmuuskopioille"
MSG_FR[$MSG_RESTORE_DEVICE_NOT_ALLOWED]="RBK0088E: L'option -R n'est pas prise en charge pour une sauvegarde basée sur une partition"
MSG_UNKNOWN_OPTION=89
MSG_EN[$MSG_UNKNOWN_OPTION]="RBK0089E: Unknown option %s"
MSG_DE[$MSG_UNKNOWN_OPTION]="RBK0089E: Unbekannte Option %s"
MSG_FI[$MSG_UNKNOWN_OPTION]="RBK0089E: Tuntematon valinta %s"
MSG_FR[$MSG_UNKNOWN_OPTION]="RBK0089E: Option inconnue %s"
MSG_OPTION_REQUIRES_PARAMETER=90
MSG_EN[$MSG_OPTION_REQUIRES_PARAMETER]="RBK0090E: Option %s requires a parameter. If parameter starts with '-' start with '\-' instead"
MSG_DE[$MSG_OPTION_REQUIRES_PARAMETER]="RBK0090E: Option %s erwartet einen Parameter. Falls der Parameter mit '-' beginnt beginne stattdessen mit '\-'"
MSG_FI[$MSG_OPTION_REQUIRES_PARAMETER]="RBK0090E: Valinta %s vaatii parametrin. Jos parametri alkaa merkillä '-', korvaa se merkeillä '\-'"
MSG_FR[$MSG_OPTION_REQUIRES_PARAMETER]="RBK0090E: L'option %s requiert un paramètre. Si le paramètre commence par '-', commencez par '\-' à la place"
MSG_MENTION_HELP=91
MSG_EN[$MSG_MENTION_HELP]="RBK0091I: Invoke '%s -h' to get more detailed information of all script invocation parameters"
MSG_DE[$MSG_MENTION_HELP]="RBK0091I: '%s -h' liefert eine detailierte Beschreibung aller Scriptaufrufoptionen"
MSG_FI[$MSG_MENTION_HELP]="RBK0091I: Suorita '%s -h' saadaksesi lisätietoa skriptin parametreista"
MSG_FR[$MSG_MENTION_HELP]="RBK0091I: '%s -h' fournit une description détaillée de toutes les options du script"
MSG_PROCESSING_PARTITION=92
MSG_EN[$MSG_PROCESSING_PARTITION]="RBK0092I: Saving partition %s (%s/%s)"
MSG_DE[$MSG_PROCESSING_PARTITION]="RBK0092I: Partition %s (%s/%s) wird gesichert"
MSG_FI[$MSG_PROCESSING_PARTITION]="RBK0092I: Tallennetaan osiota %s (%s/%s)"
MSG_FR[$MSG_PROCESSING_PARTITION]="RBK0092I: Sauvegarde de la partition %s (%s/%s)"
MSG_PARTITION_NOT_FOUND=93
MSG_EN[$MSG_PARTITION_NOT_FOUND]="RBK0093E: Partition %s specified with option -T not found"
MSG_DE[$MSG_PARTITION_NOT_FOUND]="RBK0093E: Angegebene Partition %s der Option -T existiert nicht"
MSG_FI[$MSG_PARTITION_NOT_FOUND]="RBK0093E: Valinnalla -T tarkennettua osiota %s ei löytynyt"
MSG_FR[$MSG_PARTITION_NOT_FOUND]="RBK0093E: La partition %s spécifiée avec l'option -T est introuvable"
MSG_PARTITION_NUMBER_INVALID=94
MSG_EN[$MSG_PARTITION_NUMBER_INVALID]="RBK0094E: Parameter '%s' specified in option -T is not a number"
MSG_DE[$MSG_PARTITION_NUMBER_INVALID]="RBK0094E: Angegebener Parameter '%s' der Option -T ist keine Zahl"
MSG_FI[$MSG_PARTITION_NUMBER_INVALID]="RBK0094E: Valinnan -T parametri '%s' ei ole numero"
MSG_FR[$MSG_PARTITION_NUMBER_INVALID]="RBK0094E: Le paramètre '%s' spécifié pour l'option -T n'est pas un nombre"
MSG_RESTORING_PARTITIONFILE=95
MSG_EN[$MSG_RESTORING_PARTITIONFILE]="RBK0095I: Restoring partition %s"
MSG_DE[$MSG_RESTORING_PARTITIONFILE]="RBK0095I: Backup wird auf Partition %s zurückgespielt"
MSG_FI[$MSG_RESTORING_PARTITIONFILE]="RBK0095I: Palautetaan osiota %s"
MSG_FR[$MSG_RESTORING_PARTITIONFILE]="RBK0095I: Restauration de la partition %s"
MSG_LANGUAGE_NOT_SUPPORTED=96
MSG_EN[$MSG_LANGUAGE_NOT_SUPPORTED]="RBK0096I: Language %s not supported"
MSG_DE[$MSG_LANGUAGE_NOT_SUPPORTED]="RBK0096I: Die Sprache %s wird nicht unterstützt"
MSG_FI[$MSG_LANGUAGE_NOT_SUPPORTED]="RBK0096I: Kieli %s ei ole tuettu"
MSG_FR[$MSG_LANGUAGE_NOT_SUPPORTED]="RBK0096I: Langue %s non prise en charge"
#MSG_PARTITIONING_RESTORE_DEVICE=97
#MSG_EN[$MSG_PARTITIONING_RESTORE_DEVICE]="RBK0097W: Partitioning %s"
#MSG_DE[$MSG_PARTITIONING_RESTORE_DEVICE]="RBK0097W: Partitioniere %s"
#MSG_FI[$MSG_PARTITIONING_RESTORE_DEVICE]="RBK0097W: Osioidaan ja alustetaan %s"
#MSG_FR[$MSG_PARTITIONING_RESTORE_DEVICE]="RBK0097W: Partitionnement et formatage %s"
MSG_FORMATTING=98
MSG_EN[$MSG_FORMATTING]="RBK0098I: Formatting partition %s with %s"
MSG_DE[$MSG_FORMATTING]="RBK0098I: Formatiere Partition %s mit %s"
MSG_FI[$MSG_FORMATTING]="RBK0098I: Alustetaan osio %s tiedostojärjestelmälle %s"
MSG_FR[$MSG_FORMATTING]="RBK0098I: Formatage de la partition %s avec %s"
MSG_RESTORING_FILE_PARTITION_DONE=99
MSG_EN[$MSG_RESTORING_FILE_PARTITION_DONE]="RBK0099I: Restore of partition %s finished"
MSG_DE[$MSG_RESTORING_FILE_PARTITION_DONE]="RBK0099I: Zurückspielen des Backups auf Partition %s beendet"
MSG_FI[$MSG_RESTORING_FILE_PARTITION_DONE]="RBK0099I: Osio %s palautettu"
MSG_FR[$MSG_RESTORING_FILE_PARTITION_DONE]="RBK0099I: Restauration de la partition %s terminée"
#MSG_WARN_RESTORE_PARTITION_DEVICE_OVERWRITTEN=100
#MSG_EN[$MSG_WARN_RESTORE_PARTITION_DEVICE_OVERWRITTEN]="RBK0100W: Device %s will be overwritten with the backup"
#MSG_DE[$MSG_WARN_RESTORE_PARTITION_DEVICE_OVERWRITTEN]="RBK0100W: Gerät %s wird mit dem Backup beschrieben"
#MSG_FI[$MSG_WARN_RESTORE_PARTITION_DEVICE_OVERWRITTEN]="RBK0100W: Palautus ylikirjoittaa laitteen %s"
#MSG_FR[$MSG_WARN_RESTORE_PARTITION_DEVICE_OVERWRITTEN]="RBK0100W: Le périphérique %s sera écrasé par la sauvegarde"
MSG_VERSION_HISTORY_PAGE=101
MSG_EN[$MSG_VERSION_HISTORY_PAGE]="$VERSION_PAGE"
#MSG_DE[$MSG_VERSION_HISTORY_PAGE]="$MYHOMEURL/de/versionshistorie/"
#MSG_FI[$MSG_VERSION_HISTORY_PAGE]="$MYHOMEURL/en/versionhistory/" #  Defaults to en
#MSG_FR[$MSG_VERSION_HISTORY_PAGE]="$MYHOMEURL/en/versionhistory/" #  Defaults to en
MSG_UPDATING_UUID=102
MSG_EN[$MSG_UPDATING_UUID]="RBK0102I: Updating %s from %s to %s in %s"
MSG_DE[$MSG_UPDATING_UUID]="RBK0102I: %s wird von %s auf %s in %s geändert"
MSG_FI[$MSG_UPDATING_UUID]="RBK0102I: Päivitetään %s arvosta %s arvoon %s kohteessa %s"
MSG_FR[$MSG_UPDATING_UUID]="RBK0102I: mise à jour %s de %s à %s en %s"
MSG_UNABLE_TO_WRITE=103
MSG_EN[$MSG_UNABLE_TO_WRITE]="RBK0103E: Unable to create backup on %s because of missing write permission"
MSG_DE[$MSG_UNABLE_TO_WRITE]="RBK0103E: Ein Backup kann nicht auf %s erstellt werden da die Schreibberechtigung fehlt"
MSG_FI[$MSG_UNABLE_TO_WRITE]="RBK0103E: Varmuuskopion luominen kohteeseen %s ei onnistu puuttuvien kirjoitusoikeuksien vuoksi"
MSG_FR[$MSG_UNABLE_TO_WRITE]="RBK0103E: Impossible de créer une sauvegarde sur %s en raison d'un manque d'autorisation en écriture"
MSG_LABELING=104
MSG_EN[$MSG_LABELING]="RBK0104I: Labeling partition %s with label %s"
MSG_DE[$MSG_LABELING]="RBK0104I: Partition %s erhält das Label %s"
MSG_FI[$MSG_LABELING]="RBK0104I: Nimetään osio %s nimikkeellä %s"
MSG_FR[$MSG_LABELING]="RBK0104I: L'étiquette de la partition est %s"
MSG_REMOVING_BACKUP_FAILED=105
MSG_EN[$MSG_REMOVING_BACKUP_FAILED]="RBK0105E: Removing incomplete backup in %s failed with RC %s. Directory has to be cleaned up manually"
MSG_DE[$MSG_REMOVING_BACKUP_FAILED]="RBK0105E: Löschen des unvollständigen Backups in %s schlug fehl mit RC: %s. Das Verzeichnis muss manuell gelöscht werden"
MSG_FI[$MSG_REMOVING_BACKUP_FAILED]="RBK0105E: Keskeneräisen varmuuskopion poistaminen kohteesta %s epäonnistui, RC %s. Hakemisto tulee tyhjentää manuaalisesti"
MSG_FR[$MSG_REMOVING_BACKUP_FAILED]="RBK0105E: Échec de la suppression de la sauvegarde incomplète dans %s , code erreur %s. Supprimez manuellement le répertoire"
MSG_DEPLOYMENT_FAILED=106
MSG_EN[$MSG_DEPLOYMENT_FAILED]="RBK0106E: Installation of $MYNAME failed on server %s for user %s"
MSG_DE[$MSG_DEPLOYMENT_FAILED]="RBK0106E: Installation von $MYNAME auf Server %s für Benutzer %s fehlgeschlagen"
MSG_FI[$MSG_DEPLOYMENT_FAILED]="RBK0106E: $MYNAME asennus epäonnistui palvelimella %s käyttäjälle %s"
MSG_FR[$MSG_DEPLOYMENT_FAILED]="RBK0106E: L'installation de $MYNAME a échoué sur le serveur %s pour l'utilisateur %s"
MSG_EXTENSION_FAILED=107
MSG_EN[$MSG_EXTENSION_FAILED]="RBK0107W: Extension %s failed with RC %s"
MSG_DE[$MSG_EXTENSION_FAILED]="RBK0107W: Erweiterung %s fehlerhaft beendet mit RC %s"
MSG_FI[$MSG_EXTENSION_FAILED]="RBK0107W: Lisäosa %s epäonnistui, RC %s"
MSG_FR[$MSG_EXTENSION_FAILED]="RBK0107W: Échec de l'extension , code erreur %s"
MSG_SKIPPING_UNFORMATTED_PARTITION=108
MSG_EN[$MSG_SKIPPING_UNFORMATTED_PARTITION]="RBK0108W: Unformatted partition %s (%s) not saved"
MSG_DE[$MSG_SKIPPING_UNFORMATTED_PARTITION]="RBK0108W: Unformatierte Partition %s (%s) wird nicht gesichert"
MSG_FI[$MSG_SKIPPING_UNFORMATTED_PARTITION]="RBK0108W: Alustamatonta osiota %s (%s) ei tallennettu"
MSG_FR[$MSG_SKIPPING_UNFORMATTED_PARTITION]="RBK0108W: Partition non formatée %s (%s) non enregistrée"
MSG_UNSUPPORTED_FILESYSTEM_FORMAT=109
MSG_EN[$MSG_UNSUPPORTED_FILESYSTEM_FORMAT]="RBK0109E: Unsupported filesystem %s detected on partition %s"
MSG_DE[$MSG_UNSUPPORTED_FILESYSTEM_FORMAT]="RBK0109E: Nicht unterstütztes Filesystem %s auf Partition %s"
MSG_FI[$MSG_UNSUPPORTED_FILESYSTEM_FORMAT]="RBK0109E: Tiedostojärjestelmää %s joka havaittiin osiolla %s, ei tueta"
MSG_FR[$MSG_UNSUPPORTED_FILESYSTEM_FORMAT]="RBK0109E: Système de fichiers non pris en charge %s sur la partition %s"
MSG_UNABLE_TO_COLLECT_PARTITIONINFO=110
MSG_EN[$MSG_UNABLE_TO_COLLECT_PARTITIONINFO]="RBK0110E: Unable to collect partition data with %s. RC %s"
MSG_DE[$MSG_UNABLE_TO_COLLECT_PARTITIONINFO]="RBK0110E: Partitionsdaten können nicht mit %s gesammelt werden. RC %s"
MSG_FI[$MSG_UNABLE_TO_COLLECT_PARTITIONINFO]="RBK0110E: Osiotietojen kerääminen epäonnistui käyttämällä komentoa %s. RC %s"
MSG_FR[$MSG_UNABLE_TO_COLLECT_PARTITIONINFO]="RBK0110E: Impossible de collecter les données de la partition  %s. Code erreur %s"
MSG_UNABLE_TO_CREATE_PARTITIONS=111
MSG_EN[$MSG_UNABLE_TO_CREATE_PARTITIONS]="RBK0111E: Error occured when partitions were created. RC %s - %s"
MSG_DE[$MSG_UNABLE_TO_CREATE_PARTITIONS]="RBK0111E: Fehler beim Erstellen der Partitionen. RC %s - %s"
MSG_FI[$MSG_UNABLE_TO_CREATE_PARTITIONS]="RBK0111E: Virhe osioiden luomisen yhteydessä. RC %s - %s"
MSG_FR[$MSG_UNABLE_TO_CREATE_PARTITIONS]="RBK0111E: Erreur pendant la création des partitions. code erreur %s - %s"
MSG_PROCESSED_PARTITION=112
MSG_EN[$MSG_PROCESSED_PARTITION]="RBK0112I: Partition %s was saved"
MSG_DE[$MSG_PROCESSED_PARTITION]="RBK0112I: Partition %s wurde gesichert"
MSG_FI[$MSG_PROCESSED_PARTITION]="RBK0112I: Osio % tallennettiin"
MSG_FR[$MSG_PROCESSED_PARTITION]="RBK0112I: La partition %s a été enregistrée"
MSG_YES_NO_DEVICE_MISMATCH=113
MSG_EN[$MSG_YES_NO_DEVICE_MISMATCH]="RBK0113E: Restore device %s doesn't match %s"
MSG_DE[$MSG_YES_NO_DEVICE_MISMATCH]="RBK0113E: Wiederherstellungsgerät %s ähnelt nicht %s"
MSG_FI[$MSG_YES_NO_DEVICE_MISMATCH]="RBK0113E: Palautuslaite %s ja %s eivät täsmää"
MSG_FR[$MSG_YES_NO_DEVICE_MISMATCH]="RBK0113E: Le périphérique de restauration %s ne correspond pas à %s"
MSG_VISIT_VERSION_HISTORY_PAGE=114
MSG_EN[$MSG_VISIT_VERSION_HISTORY_PAGE]="RBK0114I: Visit %s to read about the changes in the new version"
MSG_DE[$MSG_VISIT_VERSION_HISTORY_PAGE]="RBK0114I: Besuche %s um die Änderungen in der neuen Version kennenzulernen"
MSG_FI[$MSG_VISIT_VERSION_HISTORY_PAGE]="RBK0114I: Käy sivulla %s lukeaksesi uuden version muutoksista"
MSG_FR[$MSG_VISIT_VERSION_HISTORY_PAGE]="RBK0114I: Visitez %s pour être informé des changements dans la nouvelle version"
MSG_DEPLOYED_HOST=115
MSG_EN[$MSG_DEPLOYED_HOST]="RBK0115I: $MYNAME $VERSION ($GIT_COMMIT_ONLY) installed on host %s for user %s"
MSG_DE[$MSG_DEPLOYED_HOST]="RBK0115I: $MYNAME $VERSION ($GIT_COMMIT_ONLY) wurde auf Server %s für Benutzer %s installiert"
MSG_FI[$MSG_DEPLOYED_HOST]="RBK0115I: $MYNAME $VERSION ($GIT_COMMIT_ONLY) asennettu isäntälaitteen %s käyttäjälle %s"
MSG_FR[$MSG_DEPLOYED_HOST]="RBK0115I: $MYNAME $VERSION ($GIT_COMMIT_ONLY) a été installé sur le serveur %s pour l'utilisateur %s"
MSG_INCLUDED_CONFIG=116
MSG_EN[$MSG_INCLUDED_CONFIG]="RBK0116I: Using config file %s"
MSG_DE[$MSG_INCLUDED_CONFIG]="RBK0116I: Konfigurationsdatei %s wird benutzt"
MSG_FI[$MSG_INCLUDED_CONFIG]="RBK0116I: Käytetään asetustiedostoa %s"
MSG_FR[$MSG_INCLUDED_CONFIG]="RBK0116I: Utilisation en cours du fichier de configuration %s"
MSG_CURRENT_SCRIPT_VERSION=117
MSG_EN[$MSG_CURRENT_SCRIPT_VERSION]="RBK0117I: Current script version: %s"
MSG_DE[$MSG_CURRENT_SCRIPT_VERSION]="RBK0117I: Aktuelle Scriptversion: %s"
MSG_FI[$MSG_CURRENT_SCRIPT_VERSION]="RBK0117I: Nykyisen skriptin vesio: %s"
MSG_FR[$MSG_CURRENT_SCRIPT_VERSION]="RBK0117I: Version actuelle du script: %s"
MSG_AVAILABLE_VERSIONS_HEADER=118
MSG_EN[$MSG_AVAILABLE_VERSIONS_HEADER]="RBK0118I: Available versions:"
MSG_DE[$MSG_AVAILABLE_VERSIONS_HEADER]="RBK0118I: Verfügbare Scriptversionen:"
MSG_FI[$MSG_AVAILABLE_VERSIONS_HEADER]="RBK0118I: Saatavilla olevat versiot:"
MSG_FR[$MSG_AVAILABLE_VERSIONS_HEADER]="RBK0118I: Versions disponibles:"
MSG_AVAILABLE_VERSIONS=119
MSG_EN[$MSG_AVAILABLE_VERSIONS]="RBK0119I: %s: %s"
MSG_DE[$MSG_AVAILABLE_VERSIONS]="RBK0119I: %s: %s"
MSG_FI[$MSG_AVAILABLE_VERSIONS]="RBK0119I: %s: %s"
MSG_FR[$MSG_AVAILABLE_VERSIONS]="RBK0119I: %s: %s"
MSG_SAVING_ACTUAL_VERSION=120
MSG_EN[$MSG_SAVING_ACTUAL_VERSION]="RBK0120I: Saving current version %s to %s"
MSG_DE[$MSG_SAVING_ACTUAL_VERSION]="RBK0120I: Aktuelle Version %s wird in %s gesichert"
MSG_FI[$MSG_SAVING_ACTUAL_VERSION]="RBK0120I: Tallennetaan nykyinen versio %s nimellä %s"
MSG_FR[$MSG_SAVING_ACTUAL_VERSION]="RBK0120I: Enregistrement de la version actuelle %s dans %s"
MSG_RESTORING_PREVIOUS_VERSION=121
MSG_EN[$MSG_RESTORING_PREVIOUS_VERSION]="RBK0121I: Restoring previous version %s to %s"
MSG_DE[$MSG_RESTORING_PREVIOUS_VERSION]="RBK0121I: Vorherige Version %s wird in %s wiederhergestellt"
MSG_FI[$MSG_RESTORING_PREVIOUS_VERSION]="RBK0121I: Palautetaan edellinen versio %s nimellä %s"
MSG_FR[$MSG_RESTORING_PREVIOUS_VERSION]="RBK0121I: Restauration de la version précédente %s vers %s"
MSG_SELECT_VERSION=122
MSG_EN[$MSG_SELECT_VERSION]="RBK0122I: Select version to restore (%s-%s)"
MSG_DE[$MSG_SELECT_VERSION]="RBK0122I: Auswahl der Version die wiederhergestellt werden soll (%s-%s)"
MSG_FI[$MSG_SELECT_VERSION]="RBK0122I: Valitse palautettava versio (%s-%s)"
MSG_FR[$MSG_SELECT_VERSION]="RBK0122I: Sélectionnez la version à restaurer (%s-%s)"
MSG_NO_PREVIOUS_VERSIONS_AVAILABLE=123
MSG_EN[$MSG_NO_PREVIOUS_VERSIONS_AVAILABLE]="RBK0123E: No version to restore available"
MSG_DE[$MSG_NO_PREVIOUS_VERSIONS_AVAILABLE]="RBK0123E: Keine Version zum Restore verfügbar"
MSG_FI[$MSG_NO_PREVIOUS_VERSIONS_AVAILABLE]="RBK0123E: Ei aiempia versioita palautettavaksi"
MSG_FR[$MSG_NO_PREVIOUS_VERSIONS_AVAILABLE]="RBK0123E: Aucune version à restaurer disponible"
MSG_FAKE_MODE_ON=124
MSG_EN[$MSG_FAKE_MODE_ON]="RBK0124W: Fake mode on"
MSG_DE[$MSG_FAKE_MODE_ON]="RBK0124W: Simulationsmodus an"
MSG_FI[$MSG_FAKE_MODE_ON]="RBK0124W: Simulaatiotila päällä"
MSG_FR[$MSG_FAKE_MODE_ON]="RBK0124W: Mode simulation activé"
MSG_UNUSED_PARAMETERS=125
MSG_EN[$MSG_UNUSED_PARAMETERS]="RBK0125W: Unused option(s) \"%s\" detected. There may be quotes missing in option arguments"
MSG_DE[$MSG_UNUSED_PARAMETERS]="RBK0125W: Unbenutzte Option(en) \" %s\" entdeckt. Es scheinen Anführungszeichen bei Optionsargumenten zu fehlen"
MSG_FI[$MSG_UNUSED_PARAMETERS]="RBK0125W: Havaittu käyttämättömiä valintoja \"%s\". Lainausmerkkejä saattaa puuttua valintojen argumenteista"
MSG_FR[$MSG_UNUSED_PARAMETERS]="RBK0125W: Option(s) non utilisable(s) \"%s\" . Les guillemets semblent manquer dans les arguments d'option."
MSG_REPLACING_FILE_BY_HARDLINK=126
MSG_EN[$MSG_REPLACING_FILE_BY_HARDLINK]="RBK0126I: Replacing %s with hardlink to %s"
MSG_DE[$MSG_REPLACING_FILE_BY_HARDLINK]="RBK0126I: Datei %s wird durch einem Hardlink auf %s ersetzt"
MSG_FI[$MSG_REPLACING_FILE_BY_HARDLINK]="RBK0126I: Korvataan %s hardlink-tiedolla kohteeseen %s"
MSG_FR[$MSG_REPLACING_FILE_BY_HARDLINK]="RBK0126I: Remplacement de %s par un lien physique vers %s"
MSG_DEPLOYING_HOST_OFFLINE=127
MSG_EN[$MSG_DEPLOYING_HOST_OFFLINE]="RBK0127E: Server %s offline"
MSG_DE[$MSG_DEPLOYING_HOST_OFFLINE]="RBK0127E: Server %s ist nicht erreichbar"
MSG_FI[$MSG_DEPLOYING_HOST_OFFLINE]="RBK0127E: Palvelin %s on offline-tilassa"
MSG_FR[$MSG_DEPLOYING_HOST_OFFLINE]="RBK0127E: Serveur %s hors ligne"
#MSG_USING_LOGFILE=128
#MSG_EN[$MSG_USING_LOGFILE]="RBK0128I: Using logfile %s"
#MSG_DE[$MSG_USING_LOGFILE]="RBK0128I: Logdatei ist %s"
#MSG_FI[$MSG_USING_LOGFILE]="RBK0128I: Käytetään lokitiedostoa %s"
#MSG_FR[$MSG_USING_LOGFILE]="RBK0128I: Le fichier journal : %s"
MSG_EMAIL_EXTENSION_NOT_FOUND=129
MSG_EN[$MSG_EMAIL_EXTENSION_NOT_FOUND]="RBK0129W: email extension %s not found"
MSG_DE[$MSG_EMAIL_EXTENSION_NOT_FOUND]="RBK0129W: Email Erweiterung %s nicht gefunden"
MSG_FI[$MSG_EMAIL_EXTENSION_NOT_FOUND]="RBK0129W: Sähköpostilisäosaa %s ei löytynyt"
MSG_FR[$MSG_EMAIL_EXTENSION_NOT_FOUND]="RBK0129W: Extension de l'e-mail %s absente"
MSG_MISSING_FILEPARAMETER=130
MSG_EN[$MSG_MISSING_FILEPARAMETER]="RBK0130E: Missing backup- or restorepath parameter"
MSG_DE[$MSG_MISSING_FILEPARAMETER]="RBK0130E: Backup- oder Restorepfadparameter fehlt"
MSG_FI[$MSG_MISSING_FILEPARAMETER]="RBK0130E: Varmuuskopiointi- tai palautushakemistoparametri puuttuu"
MSG_FR[$MSG_MISSING_FILEPARAMETER]="RBK0130E: Paramêtre manquant: chemin de sauvegarde ou de restauration"
MSG_MISSING_INSTALLED_FILE=131
MSG_EN[$MSG_MISSING_INSTALLED_FILE]="RBK0131E: Program %s not found. Use 'sudo apt-get update; sudo apt-get install %s' to install the missing program"
MSG_DE[$MSG_MISSING_INSTALLED_FILE]="RBK0131E: Programm %s nicht gefunden. Mit 'sudo apt-get update; sudo apt-get install %s' wird das fehlende Programm installiert"
MSG_FI[$MSG_MISSING_INSTALLED_FILE]="RBK0131E: Sovellusta %s ei löytynyt. Suorita 'sudo apt-get update; sudo apt-get install %s' asentaaksesi puuttuvan sovelluksen"
MSG_FR[$MSG_MISSING_INSTALLED_FILE]="RBK0131E: Programme %s introuvable. Utilisez 'sudo apt-get update ; sudo apt-get install %s' pour installer le programme manquant"
#MSG_SKIPPING_CREATING_PARTITIONS=132
#MSG_EN[$MSG_SKIPPING_CREATING_PARTITIONS]="RBK0132W: No partitions are created. Reusing existing partitions"
#MSG_DE[$MSG_SKIPPING_CREATING_PARTITIONS]="RBK0132W: Es werden keine Partitionen erstellt sondern die existierenden Partitionen benutzt"
#MSG_FI[$MSG_SKIPPING_CREATING_PARTITIONS]="RBK0132W: Osioita ei luotu. Käytetään olemassaolevia osioita"
#MSG_FR[$MSG_SKIPPING_CREATING_PARTITIONS]="RBK0132W: Aucune partition n'est créée. Réutiliser des partitions existantes"
MSG_HARDLINK_DIRECTORY_USED=133
MSG_EN[$MSG_HARDLINK_DIRECTORY_USED]="RBK0133I: Using directory %s for hardlinks"
MSG_DE[$MSG_HARDLINK_DIRECTORY_USED]="RBK0133I: Verzeichnis %s wird für Hardlinks benutzt"
MSG_FI[$MSG_HARDLINK_DIRECTORY_USED]="RBK0133I: Käytetään hakemistoa %s hardlink-tiedoille"
MSG_FR[$MSG_HARDLINK_DIRECTORY_USED]="RBK0133I: Le répertoire %s est utilisé pour les liens physiques"
MSG_UNABLE_TO_USE_HARDLINKS=134
MSG_EN[$MSG_UNABLE_TO_USE_HARDLINKS]="RBK0134E: Unable to use hardlinks on %s for bootpartition files. RC %s"
MSG_DE[$MSG_UNABLE_TO_USE_HARDLINKS]="RBK0134E: Hardlinkslinks können nicht auf %s für Bootpartitionsdateien benutzt werden. RC %s"
MSG_FI[$MSG_UNABLE_TO_USE_HARDLINKS]="RBK0134E: Hardlink-tietoja kohteessa %s ei voitu käyttäää käynnistysosion tiedostoille. RC %s"
MSG_FR[$MSG_UNABLE_TO_USE_HARDLINKS]="RBK0134E: Les liens physiques non utilisables sur %s pour les fichiers de partition de Boot. Code erreur %s"
MSG_SCRIPT_IS_DEPRECATED=135
MSG_EN[$MSG_SCRIPT_IS_DEPRECATED]="RBK0135W: ==> Current script version %s has a severe bug and should be updated immediately <==="
MSG_DE[$MSG_SCRIPT_IS_DEPRECATED]="RBK0135W: ==> Aktuelle Scriptversion %s enthält einen gravierenden Fehler und sollte sofort aktualisiert werden <==="
MSG_FI[$MSG_SCRIPT_IS_DEPRECATED]="RBK0135W: ==> Nykyisessä skriptiversiossa %s on vakava bugi ja se tulee päivittää välittömästi <==="
MSG_FR[$MSG_SCRIPT_IS_DEPRECATED]="RBK0135W: ==> La version actuelle du script %s a un bogue grave qui impose une mise à jour immédiatement <==="
MSG_MISSING_START_OR_STOP=136
MSG_EN[$MSG_MISSING_START_OR_STOP]="RBK0136E: Missing mandatory option %s"
MSG_DE[$MSG_MISSING_START_OR_STOP]="RBK0136E: Es fehlt die obligatorische Option %s"
MSG_FI[$MSG_MISSING_START_OR_STOP]="RBK0136E: Pakollinen valinta %s puuttuu"
MSG_FR[$MSG_MISSING_START_OR_STOP]="RBK0136E: Option obligatoire manquante %s"
MSG_NO_ROOTBACKUPFILE_FOUND=137
MSG_EN[$MSG_NO_ROOTBACKUPFILE_FOUND]="RBK0137E: Rootbackupfile for type %s not found"
MSG_DE[$MSG_NO_ROOTBACKUPFILE_FOUND]="RBK0137E: Rootbackupdatei für den Typ %s nicht gefunden"
MSG_FI[$MSG_NO_ROOTBACKUPFILE_FOUND]="RBK0137E: Juurivarmuuskopiota ei löytynyt tyypille %s"
MSG_FR[$MSG_NO_ROOTBACKUPFILE_FOUND]="RBK0137E: Fichier de sauvegarde Root pour le type %s introuvable"
MSG_USING_ROOTBACKUPFILE=138
MSG_EN[$MSG_USING_ROOTBACKUPFILE]="RBK0138I: Using rootbackup %s"
MSG_DE[$MSG_USING_ROOTBACKUPFILE]="RBK0138I: Rootbackup %s wird benutzt"
MSG_FI[$MSG_USING_ROOTBACKUPFILE]="RBK0138I: Käytetään käynnistysvarmuuskopiota %s"
MSG_FR[$MSG_USING_ROOTBACKUPFILE]="RBK0138I: La sauvegarde Root %s est en cours d'utilisation"
MSG_FORCING_CREATING_PARTITIONS=139
MSG_EN[$MSG_FORCING_CREATING_PARTITIONS]="RBK0139W: Partition creation ignores errors"
MSG_DE[$MSG_FORCING_CREATING_PARTITIONS]="RBK0139W: Partitionserstellung ignoriert Fehler"
MSG_FI[$MSG_FORCING_CREATING_PARTITIONS]="RBK0139W: Osion luonti ohittaa virheet"
MSG_FR[$MSG_FORCING_CREATING_PARTITIONS]="RBK0139W: Les erreurs sont ignorées lors de la création de partition"
#MSG_LABELS_NOT_SUPPORTED=140
#MSG_EN[$MSG_LABELS_NOT_SUPPORTED]="RBK0140E: LABEL definitions in /etc/fstab not supported. Use PARTUUID instead"
#MSG_DE[$MSG_LABELS_NOT_SUPPORTED]="RBK0140E: LABEL Definitionen sind in /etc/fstab nicht unterstützt. Benutze stattdessen PARTUUID"
#MSG_FI[$MSG_LABELS_NOT_SUPPORTED]="RBK0140E: LABEL määrityksiä tiedostossa /etc/fstab ei tueta. Käytä PARTUUID-määrityksiä"
#MSG_FR[$MSG_LABELS_NOT_SUPPORTED]="RBK0140E: LABEL Les définitions dans /etc/fstab ne sont pas prises en charge. Utilisez PARTUUID"
MSG_SAVING_USED_PARTITIONS_ONLY=141
MSG_EN[$MSG_SAVING_USED_PARTITIONS_ONLY]="RBK0141I: Saving space of defined partitions only"
MSG_DE[$MSG_SAVING_USED_PARTITIONS_ONLY]="RBK0141I: Nur der von den definierten Partitionen belegte Speicherplatz wird gesichert"
MSG_FI[$MSG_SAVING_USED_PARTITIONS_ONLY]="RBK0141I: Tilaa säästetään vain määritellyillä osioilla"
MSG_FR[$MSG_SAVING_USED_PARTITIONS_ONLY]="RBK0141I: Seul l'espace occupé par les partitions définies est sauvegardé"
MSG_NO_BOOTDEVICE_FOUND=142
MSG_EN[$MSG_NO_BOOTDEVICE_FOUND]="RBK0142E: Unable to detect boot device. Please report this issue on https://github.com/framps/raspiBackup/issues or https://www.linux-tips-and-tricks.de/en/rmessages"
MSG_DE[$MSG_NO_BOOTDEVICE_FOUND]="RBK0142E: Bootgerät kann nicht erkannt werden. Bitte das Problem auf https://github.com/framps/raspiBackup/issues oder auf https://www.linux-tips-and-tricks.de/de/fehlermeldungen melden"
MSG_FI[$MSG_NO_BOOTDEVICE_FOUND]="RBK0142E: Käynnistyslaitetta ei havaittu. Ole hyvä ja raportoi ongelmasta osoitteessa https://github.com/framps/raspiBackup/issues tai https://www.linux-tips-and-tricks.de/en/rmessages" #The 2nd link refers defaults to to en-vesion
MSG_FR[$MSG_NO_BOOTDEVICE_FOUND]="RBK0142E: Le périphérique de Boot n'est pas reconnu. Veuillez signaler le problème sur https://github.com/framps/raspiBackup/issues ou sur  https://www.linux-tips-and-tricks.de/en/rmessages" #Le 2eme lien renvoie vers la version anglaise
MSG_FORCE_SFDISK=143
MSG_EN[$MSG_FORCE_SFDISK]="RBK0143W: Target %s does not match with backup. Partitioning forced"
MSG_DE[$MSG_FORCE_SFDISK]="RBK0143W: Ziel %s passt nicht zu dem Backup. Partitionierung wird trotzdem vorgenommen"
MSG_FI[$MSG_FORCE_SFDISK]="RBK0143W: Kohde %s ei täsmää varmuuskopion kanssa. Pakotetaan osiointi"
MSG_FR[$MSG_FORCE_SFDISK]="RBK0143W: La cible %s ne correspond pas à la sauvegarde. Partitionnement forcé"
MSG_SKIP_SFDISK=144
MSG_EN[$MSG_SKIP_SFDISK]="RBK0144W: Target %s will not be partitioned. Using existing partitions"
MSG_DE[$MSG_SKIP_SFDISK]="RBK0144W: Ziel %s wird nicht partitioniert. Existierende Partitionen werden benutzt"
MSG_FI[$MSG_SKIP_SFDISK]="RBK0144W: Kohdetta %s ei osioida. Käytetään olemassaolevia osioita"
MSG_FR[$MSG_SKIP_SFDISK]="RBK0144W: La cible %s ne sera pas partitionné. Les partitions existantes sont utilisées"
MSG_SKIP_CREATING_PARTITIONS=145
MSG_EN[$MSG_SKIP_CREATING_PARTITIONS]="RBK0145W: Partition creation skipped. Using existing partitions"
MSG_DE[$MSG_SKIP_CREATING_PARTITIONS]="RBK0145W: Partitionen werden nicht erstellt. Existierende Partitionen werden benutzt"
MSG_FI[$MSG_SKIP_CREATING_PARTITIONS]="RBK0145W: Osion luonti ohitettu. Käytetään olemassaolevia osioita"
MSG_FR[$MSG_SKIP_CREATING_PARTITIONS]="RBK0145W: Création de partition ignorée. Les partitions existantes sont utilisées"
MSG_NO_PARTITION_TABLE_DEFINED=146
MSG_EN[$MSG_NO_PARTITION_TABLE_DEFINED]="RBK0146I: No partitiontable found on %s"
MSG_DE[$MSG_NO_PARTITION_TABLE_DEFINED]="RBK0146I: Keine Partitionstabelle auf %s gefunden"
MSG_FI[$MSG_NO_PARTITION_TABLE_DEFINED]="RBK0146I: Osiotaulukkoa ei löytynyt laitteella %s"
MSG_FR[$MSG_NO_PARTITION_TABLE_DEFINED]="RBK0146I: Aucune table de partition trouvée sur %s"
MSG_BACKUP_PARTITION_FAILED=147
MSG_EN[$MSG_BACKUP_PARTITION_FAILED]="RBK0147E: Backup of partition %s failed with RC %s"
MSG_DE[$MSG_BACKUP_PARTITION_FAILED]="RBK0147E: Sicherung der Partition %s schlug fehl mit RC %s"
MSG_FI[$MSG_BACKUP_PARTITION_FAILED]="RBK0147E: Osion %s varmuuskopiointi epäonnistui, RC %s"
MSG_FR[$MSG_BACKUP_PARTITION_FAILED]="RBK0147E: La sauvegarde de la partition %s a échoué, code erreur %s"
MSG_STACK_TRACE=148
MSG_EN[$MSG_STACK_TRACE]="RBK0148E: @@@@@@@@@@@@@@@@@@@@ Stacktrace @@@@@@@@@@@@@@@@@@@@"
MSG_DE[$MSG_STACK_TRACE]="RBK0148E: @@@@@@@@@@@@@@@@@@@@ Stacktrace @@@@@@@@@@@@@@@@@@@@"
MSG_FI[$MSG_STACK_TRACE]="RBK0148E: @@@@@@@@@@@@@@@@@@@@ Stacktrace @@@@@@@@@@@@@@@@@@@@"
MSG_FR[$MSG_STACK_TRACE]="RBK0148E: @@@@@@@@@@@@@@@@@@@@ Stacktrace @@@@@@@@@@@@@@@@@@@@"
MSG_FILE_ARG_NOT_FOUND=149
MSG_EN[$MSG_FILE_ARG_NOT_FOUND]="RBK0149E: File %s does not exist"
MSG_DE[$MSG_FILE_ARG_NOT_FOUND]="RBK0149E: Datei %s existiert nicht"
MSG_FI[$MSG_FILE_ARG_NOT_FOUND]="RBK0149E: Tiedostoa %s ei ole"
MSG_FR[$MSG_FILE_ARG_NOT_FOUND]="RBK0149E: Le fichier %s n'existe pas"
MSG_MAX_4GB_LIMIT=150
MSG_EN[$MSG_MAX_4GB_LIMIT]="RBK0150W: Maximum file size in backup directory %s is limited to 4GB"
MSG_DE[$MSG_MAX_4GB_LIMIT]="RBK0150W: Maximale Dateigröße im Backupverzeichnis %s ist auf 4GB begrenzt"
MSG_FI[$MSG_MAX_4GB_LIMIT]="RBK0150W: Suurin tiedoston koko varmuuskopion hakemistossa %s on 4Gt"
MSG_FR[$MSG_MAX_4GB_LIMIT]="RBK0150W: La taille maximale du fichier dans le répertoire de sauvegarde %s est limitée à 4 Go"
MSG_USING_BACKUPPATH=151
MSG_EN[$MSG_USING_BACKUPPATH]="RBK0151I: Using backuppath %s with partition type %s"
MSG_DE[$MSG_USING_BACKUPPATH]="RBK0151I: Backuppfad %s mit Partitionstyp %s wird benutzt"
MSG_FI[$MSG_USING_BACKUPPATH]="RBK0151I: Käytetään varmuuskopiointihakemistoa %s osiotyypin %s kanssa"
MSG_FR[$MSG_USING_BACKUPPATH]="RBK0151I: Le chemin de sauvegarde %s du type de partition %s est utilisé"
MSG_MKFS_FAILED=152
MSG_EN[$MSG_MKFS_FAILED]="RBK0152E: Unable to create filesystem: '%s' - RC: %s"
MSG_DE[$MSG_MKFS_FAILED]="RBK0152E: Dateisystem kann nicht erstellt werden: '%s' - RC: %s"
MSG_FI[$MSG_MKFS_FAILED]="RBK0152E: Ei voitu luoda tiedostojärjestelmää: '%s' - RC: %s"
MSG_FR[$MSG_MKFS_FAILED]="RBK0152E: Création du fichiers système '%s' impossible - Code erreur: %s"
MSG_LABELING_FAILED=153
MSG_EN[$MSG_LABELING_FAILED]="RBK0153E: Unable to label partition: '%s' - RC: %s"
MSG_DE[$MSG_LABELING_FAILED]="RBK0153E: Partition kann nicht mit einem Label versehen werden: '%s' - RC: %s"
MSG_FI[$MSG_LABELING_FAILED]="RBK0153E: Ei voitu nimetä osiota: '%s' - RC: %s"
MSG_FR[$MSG_LABELING_FAILED]="RBK0153E: Impossible d'étiqueter la partition : '%s' - Code erreur: %s"
MSG_RESTORE_DEVICE_MOUNTED=154
MSG_EN[$MSG_RESTORE_DEVICE_MOUNTED]="RBK0154E: Restore is not possible when a partition of device %s is mounted"
MSG_DE[$MSG_RESTORE_DEVICE_MOUNTED]="RBK0154E: Ein Restore ist nicht möglich wenn eine Partition von %s gemounted ist"
MSG_FI[$MSG_RESTORE_DEVICE_MOUNTED]="RBK0154E: Palautus ei ole mahdollista laitteen %s osion ollessa käyttöönotettuna"
MSG_FR[$MSG_RESTORE_DEVICE_MOUNTED]="RBK0154E: Restauration impossible si une partition du périphérique %s est montée"
MSG_INVALID_RESTORE_ROOT_PARTITION=155
MSG_EN[$MSG_INVALID_RESTORE_ROOT_PARTITION]="RBK0155E: Restore root partition %s is no partition"
MSG_DE[$MSG_INVALID_RESTORE_ROOT_PARTITION]="RBK0155E: Ziel Rootpartition %s ist keine Partition"
MSG_FI[$MSG_INVALID_RESTORE_ROOT_PARTITION]="RBK0155E: Palautettava juuriosio %s ei ole osio"
MSG_FR[$MSG_INVALID_RESTORE_ROOT_PARTITION]="RBK0155E: La partition Root cible %s n'est pas une partition"
MSG_SKIP_STARTING_SERVICES=156
MSG_EN[$MSG_SKIP_STARTING_SERVICES]="RBK0156W: No services to start"
MSG_DE[$MSG_SKIP_STARTING_SERVICES]="RBK0156W: Keine Systemd Services sind zu starten"
MSG_FI[$MSG_SKIP_STARTING_SERVICES]="RBK0156W: Ei käynnistettäviä palveluita"
MSG_FR[$MSG_SKIP_STARTING_SERVICES]="RBK0156W: Pas de service système à démarrer"
MSG_SKIP_STOPPING_SERVICES=157
MSG_EN[$MSG_SKIP_STOPPING_SERVICES]="RBK0157W: No services to stop"
MSG_DE[$MSG_SKIP_STOPPING_SERVICES]="RBK0157W: Keine Systemd Services sind zu stoppen"
MSG_FI[$MSG_SKIP_STOPPING_SERVICES]="RBK0157W: Ei pysäytettäviä palveluita"
MSG_FR[$MSG_SKIP_STOPPING_SERVICES]="RBK0157W: Aucun service système à arrêter"
MSG_MAIN_BACKUP_PROGRESSING=158
MSG_EN[$MSG_MAIN_BACKUP_PROGRESSING]="RBK0158I: Creating native %s backup %s"
MSG_DE[$MSG_MAIN_BACKUP_PROGRESSING]="RBK0158I: %s Backup %s wird erstellt"
MSG_FI[$MSG_MAIN_BACKUP_PROGRESSING]="RBK0158I: Luodaan natiivi %s-varmuuskopio kohteeseen %s"
MSG_FR[$MSG_MAIN_BACKUP_PROGRESSING]="RBK0158I: Création en cours de la sauvegarde %s"
MSG_BACKUPS_KEPT=159
MSG_EN[$MSG_BACKUPS_KEPT]="RBK0159I: %s backups kept for %s backup type. Please be patient"
MSG_DE[$MSG_BACKUPS_KEPT]="RBK0159I: %s Backups werden für den Backuptyp %s aufbewahrt. Bitte Geduld"
MSG_FI[$MSG_BACKUPS_KEPT]="RBK0159I: %s varmuuskopiota pidetään %s-varmuuskopiotyypille. Ole hyvä ja odota"
MSG_FR[$MSG_BACKUPS_KEPT]="RBK0159I: %s sauvegardes sont conservées pour le type de sauvegarde %s SVP patientez"
#MSG_TARGETSD_SIZE_TOO_SMALL=160
#MSG_EN[$MSG_TARGETSD_SIZE_TOO_SMALL]="RBK0160E: Target %s with %s is smaller than backup source with %s"
#MSG_DE[$MSG_TARGETSD_SIZE_TOO_SMALL]="RBK0160E: Ziel %s mit %s ist kleiner als die Backupquelle mit %s"
#MSG_FI[$MSG_TARGETSD_SIZE_TOO_SMALL]="RBK0160E: Kohde %s koollaan %s on pienempi kuin varmuuskopion lähde kooltaan %s"
#MSG_FR[$MSG_TARGETSD_SIZE_TOO_SMALL]="RBK0160E: La cible %s avec %s est plus petite que la source de sauvegarde avec %s"
#MSG_TARGETSD_SIZE_BIGGER=161
#MSG_EN[$MSG_TARGETSD_SIZE_BIGGER]="RBK0161W: Target %s with %s is larger than backup source with %s. You waste %s"
#MSG_DE[$MSG_TARGETSD_SIZE_BIGGER]="RBK0161W: Ziel %s mit %s ist größer als die Backupquelle mit %s. %s sind ungenutzt"
#MSG_FI[$MSG_TARGETSD_SIZE_BIGGER]="RBK0161W: Kohde %s koollaan %s on suurempi kuin varmuuskopion lähde kooltaan %s. %s jää hyödyntämättä"
#MSG_FR[$MSG_TARGETSD_SIZE_BIGGER]="RBK0161W: La cible %s avec %s est plus grande que la source de sauvegarde avec %s. %s sont inutilisés"
MSG_RESTORE_ABORTED=162
MSG_EN[$MSG_RESTORE_ABORTED]="RBK0162I: Restore aborted"
MSG_DE[$MSG_RESTORE_ABORTED]="RBK0162I: Restore abgebrochen"
MSG_FI[$MSG_RESTORE_ABORTED]="RBK0162I: Palautus keskeytetty"
MSG_FR[$MSG_RESTORE_ABORTED]="RBK0162I: Restauration annulée"
MSG_CTRLC_DETECTED=163
MSG_EN[$MSG_CTRLC_DETECTED]="RBK0163E: Script execution canceled with CTRL C"
MSG_DE[$MSG_CTRLC_DETECTED]="RBK0163E: Scriptausführung mit CTRL C abgebrochen"
MSG_FI[$MSG_CTRLC_DETECTED]="RBK0163E: Skriptin suoritus peruutettu CTRL C-näppäinyhdistelmällä"
MSG_FR[$MSG_CTRLC_DETECTED]="RBK0163E: Exécution du script interrompue avec CTRL C"
MSG_HARDLINK_ERROR=164
MSG_EN[$MSG_HARDLINK_ERROR]="RBK0164E: Unable to create hardlinks on %s. RC %s"
MSG_DE[$MSG_HARDLINK_ERROR]="RBK0164E: Es können keine Hardlinks auf %s erstellt werden. RC %s"
MSG_FI[$MSG_HARDLINK_ERROR]="RBK0164E: Hardlink-tietojen luonti epäonnistui %s. RC %s"
MSG_FR[$MSG_HARDLINK_ERROR]="RBK0164E: Les liens physiques ne peuvent pas être créés %s. Code erreur %s"
MSG_INTRO_BETA_MESSAGE=165
MSG_EN[$MSG_INTRO_BETA_MESSAGE]="RBK0165W: =========> NOTE  <========= \
${NL}!!! RBK0165W: This is a betaversion and should not be used in production. \
${NL}!!! RBK0165W: =========> NOTE <========="
MSG_DE[$MSG_INTRO_BETA_MESSAGE]="RBK0165W: =========> HINWEIS <========= \
${NL}!!! RBK0165W: Dieses ist eine Betaversion welche nicht in Produktion benutzt werden sollte. \
${NL}!!! RBK0165W: =========> HINWEIS <========="
MSG_FI[$MSG_INTRO_BETA_MESSAGE]="RBK0165W: =========> HUOM <========= \
${NL}!!! RBK0165W: Tämä on betaversio, jota ei tule käyttää tuotannossa. \
${NL}!!! RBK0165W: =========> HUOM <========= (FI)"
MSG_FR[$MSG_INTRO_BETA_MESSAGE]="RBK0165W: =========> REMARQUE <========= \
${NL}!!! RBK0165W: Ceci est une version bêta qui ne doit pas être utilisée en production. \
${NL}!!! RBK0165W: =========> REMARQUE <========= (FI)"
MSG_UMOUNT_ERROR=166
MSG_EN[$MSG_UMOUNT_ERROR]="RBK0166E: Umount for %s failed. RC %s. Maybe mounted somewhere else?"
MSG_DE[$MSG_UMOUNT_ERROR]="RBK0166E: Umount für %s fehlerhaft. RC %s. Vielleicht noch woanders gemounted?"
MSG_FI[$MSG_UMOUNT_ERROR]="RBK0166E: Osion %s käytöstä poisto (umount) epäonnistui. RC %s. Jokin muu käyttää sitä mahdollisesti?"
MSG_FR[$MSG_UMOUNT_ERROR]="RBK0166E: Umount incorrect pour %s Code erreur %s. Peut-elle être montée ailleurs ?"
MSG_SENDING_EMAIL=167
MSG_EN[$MSG_SENDING_EMAIL]="RBK0167I: Sending email"
MSG_DE[$MSG_SENDING_EMAIL]="RBK0167I: Eine eMail wird versendet"
MSG_FI[$MSG_SENDING_EMAIL]="RBK0167I: Lähetetään sähköposti"
MSG_FR[$MSG_SENDING_EMAIL]="RBK0167I: Envoi d'un e-mail"
MSG_BETAVERSION_AVAILABLE=168
MSG_EN[$MSG_BETAVERSION_AVAILABLE]="RBK0168I: $SMILEY_BETA_AVAILABLE $MYSELF beta version %s is available. Any help to test this beta is appreciated. Just upgrade to the new beta version with option -U. Restore to the previous version with option -V"
MSG_DE[$MSG_BETAVERSION_AVAILABLE]="RBK0168I: $SMILEY_BETA_AVAILABLE $MYSELF Beta Version %s ist verfügbar. Hilfe beim Testen dieser Beta ist sehr willkommen. Einfach auf die neue Beta Version mit der Option -U upgraden. Die vorhergehende Version kann mit der Option -V wiederhergestellt werden"
MSG_FI[$MSG_BETAVERSION_AVAILABLE]="RBK0168I: $SMILEY_BETA_AVAILABLE $MYSELF betaversio %s on saatavilla. Betatestaajien apua arvostetaan. Päivitä uuteen betaversioon valinnalla -U. Palaa edelliseen versioon valinnalla -V"
MSG_FR[$MSG_BETAVERSION_AVAILABLE]="RBK0168I: $SMILEY_BETA_AVAILABLE $MYSELF La version bêta %s est disponible. Une aide pour tester cette version bêta est la bienvenue. Passez simplement à la nouvelle version bêta avec l'option -U. La version précédente peut être restaurée avec l'option -V "
MSG_ROOT_PARTITION_NOT_FOUND=169
MSG_EN[$MSG_ROOT_PARTITION_NOT_FOUND]="RBK0169E: Target root partition %s does not exist"
MSG_DE[$MSG_ROOT_PARTITION_NOT_FOUND]="RBK0169E: Ziel Rootpartition %s existiert nicht"
MSG_FI[$MSG_ROOT_PARTITION_NOT_FOUND]="RBK0169E: Kohdejuuriosiota %s ei ole"
MSG_FR[$MSG_ROOT_PARTITION_NOT_FOUND]="RBK0169E: La partition Root cible %s n'existe pas"
MSG_MISSING_R_OPTION=170
MSG_EN[$MSG_MISSING_R_OPTION]="RBK0170E: Backup uses an external root partition. -R option missing"
MSG_DE[$MSG_MISSING_R_OPTION]="RBK0170E: Backup benutzt eine externe root Partition. Die Option -R fehlt"
MSG_FI[$MSG_MISSING_R_OPTION]="RBK0170E: Varmuuskopiointi käyttää ulkoista juurihakemistoa. Valinta -R puuttuu-"
MSG_FR[$MSG_MISSING_R_OPTION]="RBK0170E: La sauvegarde utilise une partition Root externe. L'option -R est manquante"
MSG_NOPARTITIONS_TOBACKUP_FOUND=171
MSG_EN[$MSG_NOPARTITIONS_TOBACKUP_FOUND]="RBK0171E: Unable to detect any partitions to backup"
MSG_DE[$MSG_NOPARTITIONS_TOBACKUP_FOUND]="RBK0171E: Es können keine zu sichernde Partitionen gefunden werden"
MSG_FI[$MSG_NOPARTITIONS_TOBACKUP_FOUND]="RBK0171E: Varmuuskopioitavia osioita ei havaittu"
MSG_FR[$MSG_NOPARTITIONS_TOBACKUP_FOUND]="RBK0171E: Aucune partition à sauvegarder n'a été trouvée"
MSG_UNABLE_TO_CREATE_DIRECTORY=172
MSG_EN[$MSG_UNABLE_TO_CREATE_DIRECTORY]="RBK0172E: Unable to create directory %s"
MSG_DE[$MSG_UNABLE_TO_CREATE_DIRECTORY]="RBK0172E: Verzeichnis %s kann nicht erstellt werden"
MSG_FI[$MSG_UNABLE_TO_CREATE_DIRECTORY]="RBK0172E: Hakemistoa %s ei voida luoda"
MSG_FR[$MSG_UNABLE_TO_CREATE_DIRECTORY]="RBK0172E: Impossible de créer le répertoire %s"
MSG_INTRO_HOTFIX_MESSAGE=173
MSG_EN[$MSG_INTRO_HOTFIX_MESSAGE]="RBK0173W: =========> NOTE  <========= \
${NL}!!! RBK0173W: This is a temporary hotfix and has to be upgraded to next available version as soon as one is available. \
${NL}!!! RBK0173W: =========> NOTE <========="
MSG_DE[$MSG_INTRO_HOTFIX_MESSAGE]="RBK0173W: =========> HINWEIS <========= \
${NL}!!! RBK0173W: Dieses ist ein temporärer Hotfix der auf die nächste Version upgraded werden muss sobald eine verfügbar ist. \
${NL}!!! RBK0173W: =========> HINWEIS <========="
MSG_FI[$MSG_INTRO_HOTFIX_MESSAGE]="RBK0173W: =========> HUOM  <========= \
${NL}!!! RBK0173W: Tämä on väliaikainen pikakorjaus ja tulee päivittää heti, kun uudempi versio on saatavilla. \
${NL}!!! RBK0173W: =========> HUOM <========="
MSG_FR[$MSG_INTRO_HOTFIX_MESSAGE]="RBK0173W: =========> REMARQUE  <========= \
${NL}!!! RBK0173W: Il s'agit d'un correctif temporaire qui doit être mis à niveau dans la prochaine version dès qu'elle sera disponible. \
${NL}!!! RBK0173W: =========> REMARQUE <========="
MSG_TOOL_ERROR_SKIP=174
MSG_EN[$MSG_TOOL_ERROR_SKIP]="RBK0174I: Backup tool %s error %s ignored. For errormessages see log file"
MSG_DE[$MSG_TOOL_ERROR_SKIP]="RBK0174I: Backupprogramm %s Fehler %s wurde ignoriert. Fehlermeldungen finden sich im Logfile"
MSG_FI[$MSG_TOOL_ERROR_SKIP]="RBK0174I: Varmuuskopiotyökalun %s virhe %s ohitettiin. Lue virheviestit lokitiedostosta"
MSG_FR[$MSG_TOOL_ERROR_SKIP]="RBK0174I: L'erreur %s lors de la sauvegarde a été ignorée. Les messages peuvent être consultés dans le fichier journal"
MSG_SCRIPT_UPDATE_NOT_REQUIRED=175
MSG_EN[$MSG_SCRIPT_UPDATE_NOT_REQUIRED]="RBK0175I: %s version %s is newer than version %s"
MSG_DE[$MSG_SCRIPT_UPDATE_NOT_REQUIRED]="RBK0175I: %s Version %s ist aktueller als Version %s"
MSG_FI[$MSG_SCRIPT_UPDATE_NOT_REQUIRED]="RBK0175I: %s:n versio %s on uudempi kuin versio %s"
MSG_FR[$MSG_SCRIPT_UPDATE_NOT_REQUIRED]="RBK0175I: %s version %s est plus récent que cette version %s"
MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS=176
MSG_EN[$MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS]="RBK0173E: rsync version %s doesn't support progress information"
MSG_DE[$MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS]="RBK0173E: rsync Version %s unterstüzt keine Fortschrittsanzeige"
MSG_FI[$MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS]="RBK0173E: rsyncin versio %s ei tue edistymisen seurantaa"
MSG_FR[$MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS]="RBK0173E: rsync version %s ne prend pas en charge l'affichage de la progression"
MSG_ALL_BACKUPS_KEPT=177
MSG_EN[$MSG_ALL_BACKUPS_KEPT]="RBK0177W: All backups kept for backup type %s"
MSG_DE[$MSG_ALL_BACKUPS_KEPT]="RBK0177W: Alle Backups werden für den Backuptyp %s aufbewahrt"
MSG_FI[$MSG_ALL_BACKUPS_KEPT]="RBK0177W: Kaikki varmuuskopiot pidetään varmuuskopiointityypille %s"
MSG_FR[$MSG_ALL_BACKUPS_KEPT]="RBK0177W: Toutes les sauvegardes sont conservées pour le type %s"
MSG_IMG_BOOT_BACKUP_FAILED=178
MSG_EN[$MSG_IMG_BOOT_BACKUP_FAILED]="RBK0178E: Creation of %s failed with RC %s. Usually the SD card is buggy. Option -B may help"
MSG_DE[$MSG_IMG_BOOT_BACKUP_FAILED]="RBK0178E: Erzeugung von %s Datei endet fehlerhaft mit RC %s. Normalerweise ist die SD Karte fehlerhaft. Option -B kann helfen"
MSG_FI[$MSG_IMG_BOOT_BACKUP_FAILED]="RBK0178E: %s:n luominen epäonnistui, RC %s"
MSG_FR[$MSG_IMG_BOOT_BACKUP_FAILED]="RBK0178E: La création de %s a échoué avec le code erreur %s"
MSG_IMG_BOOT_RESTORE_FAILED=179
MSG_EN[$MSG_IMG_BOOT_RESTORE_FAILED]="RBK0179E: Restore of %s file failed with RC %s"
MSG_DE[$MSG_IMG_BOOT_RESTORE_FAILED]="RBK0179E: Wiederherstellung von %s Datei endet fehlerhaft mit RC %s"
MSG_FI[$MSG_IMG_BOOT_RESTORE_FAILED]="RBK0179E: %s-tiedoston palautus epäonnistui, RC %s"
MSG_FR[$MSG_IMG_BOOT_RESTORE_FAILED]="RBK0179E: La restauration du fichier %s a échoué acec le code erreur %s"
MSG_FORMATTING_FIRST_PARTITION=180
MSG_EN[$MSG_FORMATTING_FIRST_PARTITION]="RBK0180I: Formating first partition (boot partition) %s"
MSG_DE[$MSG_FORMATTING_FIRST_PARTITION]="RBK0180I: Erste Partition (Bootpartition) %s wird formatiert"
MSG_FI[$MSG_FORMATTING_FIRST_PARTITION]="RBK0180I: Alustetaan ensimmäinen osio (käynnistysosio) %s"
MSG_FR[$MSG_FORMATTING_FIRST_PARTITION]="RBK0180I: Formatage de la première partition (partition de Boot) %s"
MSG_AFTER_STARTING_SERVICES=181
MSG_EN[$MSG_AFTER_STARTING_SERVICES]="RBK0181I: Executing commands post backup: '%s'"
MSG_DE[$MSG_AFTER_STARTING_SERVICES]="RBK0181I: Nach dem Backup ausgeführte Befehle: '%s'"
MSG_FI[$MSG_AFTER_STARTING_SERVICES]="RBK0181I: Suoritetaan varmuuskopioinnin jälkeiset komennot: '%s'"
MSG_FR[$MSG_AFTER_STARTING_SERVICES]="RBK0181I: Commandes exécutées après la sauvegarde: '%s'"
MSG_BEFORE_STOPPING_SERVICES=182
MSG_EN[$MSG_BEFORE_STOPPING_SERVICES]="RBK0182I: Executing commands pre backup: '%s'"
MSG_DE[$MSG_BEFORE_STOPPING_SERVICES]="RBK0182I: Vor dem Backup ausgeführte Befehle: '%s'"
MSG_FI[$MSG_BEFORE_STOPPING_SERVICES]="RBK0182I: Suoritetaan varmuuskopiointia edeltävät komennot: '%s'"
MSG_FR[$MSG_BEFORE_STOPPING_SERVICES]="RBK0182I: Commandes exécutées avant la sauvegarde: '%s'"
#MSG_IMG_ROOT_CHECK_FAILED=183
#MSG_EN[$MSG_IMG_ROOT_CHECK_FAILED]="RBK0183E: Rootpartition check failed with RC %s"
#MSG_DE[$MSG_IMG_ROOT_CHECK_FAILED]="RBK0183E: Rootpartitionscheck endet fehlerhaft mit RC %s"
#MSG_FI[$MSG_IMG_ROOT_CHECK_FAILED]="RBK0183E: Juuriosion tarkistus epäonnistui, RC %s"
#MSG_FR[$MSG_IMG_ROOT_CHECK_FAILED]="RBK0183E: La vérification de la partition Root a échoué ,code erreur %s"
#MSG_IMG_ROOT_CHECK_STARTED=184
#MSG_EN[$MSG_IMG_ROOT_CHECK_STARTED]="RBK0184I: Rootpartition check started"
#MSG_DE[$MSG_IMG_ROOT_CHECK_STARTED]="RBK0184I: Rootpartitionscheck gestartet"
#MSG_FI[$MSG_IMG_ROOT_CHECK_STARTED]="RBK0184I: Juuriosion tarkistus aloitettu"
#MSG_FR[$MSG_IMG_ROOT_CHECK_STARTED]="RBK0184I: Début de la vérification de la partition Root"
MSG_IMG_BOOT_CREATE_PARTITION_FAILED=185
MSG_EN[$MSG_IMG_BOOT_CREATE_PARTITION_FAILED]="RBK0185E: Bootpartition creation failed with RC %s"
MSG_DE[$MSG_IMG_BOOT_CREATE_PARTITION_FAILED]="RBK0185E: Bootpartitionserstellung endet fehlerhaft mit RC %s"
MSG_FI[$MSG_IMG_BOOT_CREATE_PARTITION_FAILED]="RBK0185E: Käynnistysosion luonti epäonnistui, RC %s"
MSG_FR[$MSG_IMG_BOOT_CREATE_PARTITION_FAILED]="RBK0185E: La création de la partition Boot a échoué , code erreur %s"
MSG_IMG_ROOT_CREATE_PARTITION_FAILED=186
MSG_EN[$MSG_IMG_ROOT_CREATE_PARTITION_FAILED]="RBK0185E: Rootpartition creation failed with RC %s"
MSG_DE[$MSG_IMG_ROOT_CREATE_PARTITION_FAILED]="RBK0185E: Rootpartitionserstellung endet fehlerhaft mit RC %s"
MSG_FI[$MSG_IMG_ROOT_CREATE_PARTITION_FAILED]="RBK0185E: Juuriosion luonti epäonnistui, RC %s"
MSG_FR[$MSG_IMG_ROOT_CREATE_PARTITION_FAILED]="RBK0185E: La création de la partition Root a échoué , code erreur %s"
MSG_DETAILED_ROOT_CHECKING=187
MSG_EN[$MSG_DETAILED_ROOT_CHECKING]="RBK0187W: Rootpartition %s will be checked for bad blocks during formatting. This will take some time. Please be patient"
MSG_DE[$MSG_DETAILED_ROOT_CHECKING]="RBK0187W: Rootpartitionsformatierung für %s prüft auf fehlerhafte Blocks. Das wird länger dauern. Bitte Geduld"
MSG_FI[$MSG_DETAILED_ROOT_CHECKING]="RBK0187W: Juuriosio %s tarkistetaan viallisten lohkojen varalta alustuksen aikana. Tämä vie jonkin aikaa. Ole hyvä ja odota"
MSG_FR[$MSG_DETAILED_ROOT_CHECKING]="RBK0187W: La partition Root %s sera vérifiée pour détecter les blocs lors du formatage. SVP  soyez patient.."
MSG_UPDATE_TO_BETA=188
MSG_EN[$MSG_UPDATE_TO_BETA]="RBK0188I: There is a Beta version of $MYSELF available. Upgrading current version %s to %s"
MSG_DE[$MSG_UPDATE_TO_BETA]="RBK0188I: Es ist eine Betaversion von $MYSELF verfügbar. Die momentane Version %s auf %s upgraden"
MSG_FI[$MSG_UPDATE_TO_BETA]="RBK0188I: $MYSELF betaversio on saatavilla. Päivitä nykyinen versio %s versioon %s"
MSG_FR[$MSG_UPDATE_TO_BETA]="RBK0188I: Une version bêta de $MYSELF est disponible. Mettez à niveau la version actuelle %s vers %s"
MSG_UPDATE_ABORTED=189
MSG_EN[$MSG_UPDATE_ABORTED]="RBK0189I: Version upgrade aborted"
MSG_DE[$MSG_UPDATE_ABORTED]="RBK0189I: Versionsupgrade abgebrochen"
MSG_FI[$MSG_UPDATE_ABORTED]="RBK0189I: Versiopäivitys keskeytetty"
MSG_FR[$MSG_UPDATE_ABORTED]="RBK0189I: Mise à niveau de version annulée"
MSG_UPDATE_TO_VERSION=190
MSG_EN[$MSG_UPDATE_TO_VERSION]="RBK0190I: Upgrading $MYSELF from version %s to %s"
MSG_DE[$MSG_UPDATE_TO_VERSION]="RBK0190I: Es wird $MYSELF von Version %s auf Version %s upgraded"
MSG_FI[$MSG_UPDATE_TO_VERSION]="RBK0190I: Päivitetään $MYSELF versiosta %s versioon %s"
MSG_FR[$MSG_UPDATE_TO_VERSION]="RBK0190I: Mise à niveau de $MYSELF de la version %s à la version %s"
MSG_ADJUSTING_DISABLED=191
MSG_EN[$MSG_ADJUSTING_DISABLED]="RBK0191E: Target %s with %s is smaller than backup source with %s. root partition resizing is disabled"
MSG_DE[$MSG_ADJUSTING_DISABLED]="RBK0191E: Ziel %s mit %s ist kleiner als die Backupquelle mit %s. Verkleinern der root Partition ist ausgeschaltet"
MSG_FI[$MSG_ADJUSTING_DISABLED]="RBK0191E: Kohde %s kooltaan %s on pienempi kuin varmuuskopion lähde kooltaan %s. Juuriosion pienentäminen on pois käytöstä"
MSG_FR[$MSG_ADJUSTING_DISABLED]="RBK0191E: La cible %s avec %s est plus petite que la source sauvegardée avec %s. La réduction de la partition Root est désactivée"
MSG_INTRO_DEV_MESSAGE=192
MSG_EN[$MSG_INTRO_DEV_MESSAGE]="RBK0192W: =========> NOTE  <========= \
${NL}!!! RBK0192W: This is a development version and should not be used in production. \
${NL}!!! RBK0192W: =========> NOTE <========="
MSG_DE[$MSG_INTRO_DEV_MESSAGE]="RBK0192W: =========> HINWEIS <========= \
${NL}!!! RBK0192W: Dieses ist eine Entwicklerversion welcher nicht in Produktion benutzt werden sollte. \
${NL}!!! RBK0192W: =========> HINWEIS <========="
MSG_FI[$MSG_INTRO_DEV_MESSAGE]="RBK0192W: =========> HUOM  <========= \
${NL}!!! RBK0192W: Tämä on kehitysversio, jota ei tule käyttää tuotannossa. \
${NL}!!! RBK0192W: =========> HUOM <========="
MSG_FR[$MSG_INTRO_DEV_MESSAGE]="RBK0192W: =========> MESSAGE  <========= \
${NL}!!! RBK0192W: Il s'agit d'une version de développement qui ne doit pas être utilisée en production. \
${NL}!!! RBK0192W: =========> MESSAGE <========="
MSG_MISSING_COMMANDS=193
MSG_EN[$MSG_MISSING_COMMANDS]="RBK0193E: Missing required commands '%s'"
MSG_DE[$MSG_MISSING_COMMANDS]="RBK0193E: Erforderliche Befehle '%s' nicht vorhanden"
MSG_FI[$MSG_MISSING_COMMANDS]="RBK0193E: Vaadittavia komentoja puuttuu '%s'"
MSG_FR[$MSG_MISSING_COMMANDS]="RBK0193E: Commandes requises '%s' absentes"
MSG_MISSING_PACKAGES=194
MSG_EN[$MSG_MISSING_PACKAGES]="RBK0194E: Missing required packages. Install them with 'sudo apt-get install %s'"
MSG_DE[$MSG_MISSING_PACKAGES]="RBK0194E: Erforderliche Pakete nicht installiert. Installiere sie mit 'sudo apt-get install %s'"
MSG_FI[$MSG_MISSING_PACKAGES]="RBK0194E: Vaadittavia paketteja puuttuu. Asenna ne suorittamalla 'sudo apt-get install %s'"
MSG_FR[$MSG_MISSING_PACKAGES]="RBK0194E: Package requis non installés. Installez-le avec 'sudo apt-get install %s'"
MSG_FORCE_UPDATE=195
MSG_EN[$MSG_FORCE_UPDATE]="RBK0195I: Update $MYSELF to version %s"
MSG_DE[$MSG_FORCE_UPDATE]="RBK0195I: $MYSELF auf %s aktualisieren"
MSG_FI[$MSG_FORCE_UPDATE]="RBK0195I: Päivitä $MYSELF versioon %s"
MSG_FR[$MSG_FORCE_UPDATE]="RBK0195I: Mettez à jour $MYSELF vers la version %s"
#MSG_NO_HARDLINKS_USED=196
#MSG_EN[$MSG_NO_HARDLINKS_USED]="RBK0196W: No hardlinks supported on %s"
#MSG_DE[$MSG_NO_HARDLINKS_USED]="RBK0196W: %s unterstützt keine Hardlinks"
#MSG_FI[$MSG_NO_HARDLINKS_USED]="RBK0196W: Hardlink-tietoja ei tueta kohteella %s"
#MSG_FR[$MSG_NO_HARDLINKS_USED]="RBK0196W: Aucun lien physique pris en charge sur %s"
MSG_EMAIL_SEND_FAILED=197
MSG_EN[$MSG_EMAIL_SEND_FAILED]="RBK0197W: eMail send command %s failed with RC %s"
MSG_DE[$MSG_EMAIL_SEND_FAILED]="RBK0197W: eMail mit %s versenden endet fehlerhaft mit RC %s"
MSG_FI[$MSG_EMAIL_SEND_FAILED]="RBK0197W: Sähköpostin lähettäminen komennolla %s epäonnistui, RC %s"
MSG_FR[$MSG_EMAIL_SEND_FAILED]="RBK0197W: L'envoi d'un e-mail avec %s a échoué ,code erreur %s"
MSG_BEFORE_START_SERVICES_FAILED=198
MSG_EN[$MSG_BEFORE_START_SERVICES_FAILED]="RBK0198E: Pre backup commands failed with %s"
MSG_DE[$MSG_BEFORE_START_SERVICES_FAILED]="RBK0198E: Fehler in vor dem Backup ausgeführten Befehlen %s"
MSG_FI[$MSG_BEFORE_START_SERVICES_FAILED]="RBK0198E: Varmuuskopiota edeltävät komennot epäonnistuivat, RC %s"
MSG_FR[$MSG_BEFORE_START_SERVICES_FAILED]="RBK0198E: Les commandes de pré-sauvegarde ont échoué ,Code erreur %s"
MSG_MISSING_RESTOREDEVICE_OPTION=199
MSG_EN[$MSG_MISSING_RESTOREDEVICE_OPTION]="RBK0199E: Option -R requires also option -d"
MSG_DE[$MSG_MISSING_RESTOREDEVICE_OPTION]="RBK0199E: Option -r benötigt auch Option -d"
MSG_FI[$MSG_MISSING_RESTOREDEVICE_OPTION]="RBK0199E: Valinta -R vaatii myös valinnan -d"
MSG_FR[$MSG_MISSING_RESTOREDEVICE_OPTION]="RBK0199E: L'option -r requiert également l'option -d"
MSG_SHARED_BOOT_DEVICE=200
MSG_EN[$MSG_SHARED_BOOT_DEVICE]="RBK0200I: /boot and / located on same partition %s"
MSG_DE[$MSG_SHARED_BOOT_DEVICE]="RBK0200I: /boot und / befinden sich auf derselben Partition %s"
MSG_FI[$MSG_SHARED_BOOT_DEVICE]="RBK0200I: /boot ja / ovat samalla osiolla %s"
MSG_FR[$MSG_SHARED_BOOT_DEVICE]="RBK0200I: /boot et / sont sur la même partition %s"
MSG_BEFORE_STOP_SERVICES_FAILED=201
MSG_EN[$MSG_BEFORE_STOP_SERVICES_FAILED]="RBK0201E: Post backup commands failed with %s"
MSG_DE[$MSG_BEFORE_STOP_SERVICES_FAILED]="RBK0201E: Fehler in nach dem Backup ausgeführten Befehlen %s"
MSG_FI[$MSG_BEFORE_STOP_SERVICES_FAILED]="RBK0201E: Varmuuskopion jälkeiset komennot epäonnistuivat, RC %s"
MSG_FR[$MSG_BEFORE_STOP_SERVICES_FAILED]="RBK0201E: Echec des commandes après la sauvegarde, code erreur %s"
MSG_RESTORETEST_REQUIRED=202
MSG_EN[$MSG_RESTORETEST_REQUIRED]="RBK0202W: $SMILEY_RESTORETEST_REQUIRED Friendly reminder: Execute now a restore test. You will be reminded %s times again"
MSG_DE[$MSG_RESTORETEST_REQUIRED]="RBK0201W: $SMILEY_RESTORETEST_REQUIRED Freundlicher Hinweis: Führe einen Restoretest durch. Du wirst noch %s mal erinnert werden"
MSG_FI[$MSG_RESTORETEST_REQUIRED]="RBK0202W: $SMILEY_RESTORETEST_REQUIRED Ystävällinen muistutus: Suorita palautustestaus nyt. Sinua muistutetaan vielä %s kertaa"
MSG_FR[$MSG_RESTORETEST_REQUIRED]="RBK0202W: $SMILEY_RESTORETEST_REQUIRED Rappel amical: effectuez un test de restauration. Vous serez à nouveau rappelé %s fois"
MSG_NO_BOOT_DEVICE_DISOVERED=203
MSG_EN[$MSG_NO_BOOT_DEVICE_DISOVERED]="RBK0203E: Unable to discover boot device. Please report this issue with a debug log created with option '-l debug'"
MSG_DE[$MSG_NO_BOOT_DEVICE_DISOVERED]="RBK0203E: Boot device kann nicht erkannt werden. Bitte das Problem mit einem Debuglog welches mit Option '-l debug' erstellt wird berichten"
MSG_FI[$MSG_NO_BOOT_DEVICE_DISOVERED]="RBK0203E: Käynnistyslaitetta ei löydetty. Ole hyvä ja raportoi ongelmasta valinnalla '-l debug' luodun vianmäärityslokin kanssa"
MSG_FR[$MSG_NO_BOOT_DEVICE_DISOVERED]="RBK0203E: Le périphérique de boot n'est pas reconnu. Veuillez signaler le problème avec un journal de débogage créé avec l'option '-l debug'"
MSG_TRUNCATING_ERROR=204
MSG_EN[$MSG_TRUNCATING_ERROR]="RBK0204E: Unable to calculate truncation backup size"
MSG_DE[$MSG_TRUNCATING_ERROR]="RBK0204E: Verkleinerte Backupgröße kann nicht berechnet werden"
MSG_FI[$MSG_TRUNCATING_ERROR]="RBK0204E: Typistetyn varmuuskopion kokoa ei voitu laskea"
MSG_FR[$MSG_TRUNCATING_ERROR]="RBK0204E: Impossible de calculer la taille réduite de la sauvegarde"
MSG_CLEANUP_BACKUP_VERSION=205
MSG_EN[$MSG_CLEANUP_BACKUP_VERSION]="RBK0205I: Deleting oldest backup in %s. This may take some time. Please be patient"
MSG_DE[$MSG_CLEANUP_BACKUP_VERSION]="RBK0205I: Ältestes Backup in %s wird gelöscht. Das kann etwas dauern. Bitte Geduld"
MSG_FI[$MSG_CLEANUP_BACKUP_VERSION]="RBK0205I: Poistetaan vanhin varmuuskopio hakemistosta %s. Tämä saattaa kestää jonkin aikaa. Ole hyvä ja odota"
MSG_FR[$MSG_CLEANUP_BACKUP_VERSION]="RBK0205I: Suppression de la sauvegarde la plus ancienne dans %s. Cela peut prendre du temps. SVP soyez patient"
MSG_CREATING_UUID=206
MSG_EN[$MSG_CREATING_UUID]="RBK0206I: Creating new %s %s on %s"
MSG_DE[$MSG_CREATING_UUID]="RBK0206I: Erzeuge neue %s %s auf %s"
MSG_FI[$MSG_CREATING_UUID]="RBK0206I: Luodaan uusi %s %s kohteelle %s"
MSG_FR[$MSG_CREATING_UUID]="RBK0206I: Création nouvelle %s %s pour %s"
MSG_MISSING_PARTITION=207
MSG_EN[$MSG_MISSING_PARTITION]="RBK0207E: Missing partitions on %s"
MSG_DE[$MSG_MISSING_PARTITION]="RBK0207E: Keine Partitionen auf %s gefunden"
MSG_FI[$MSG_MISSING_PARTITION]="RBK0207E: Osioita puuttuu laitteelta %s"
MSG_FR[$MSG_MISSING_PARTITION]="RBK0207E: Aucune partition trouvée sur %s"
MSG_NO_UUID_SYNCHRONIZED=208
MSG_EN[$MSG_NO_UUID_SYNCHRONIZED]="RBK0208E: No UUID updated in %s for %s"
MSG_DE[$MSG_NO_UUID_SYNCHRONIZED]="RBK0208E: Es konnte keine UUID in %s für %s erneuert werden"
#MSG_UUIDS_NOT_UNIQUE=209
#MSG_EN[$MSG_UUIDS_NOT_UNIQUE]="RBK0209W: UUIDs are not unique on devices and/or partitions and may cause issues. In case of error messages check them with 'sudo blkid' and make them unique"
#MSG_DE[$MSG_UUIDS_NOT_UNIQUE]="RBK0209W: UUIDs sind nicht eindeutig auf den Geräten und/oder Partitionen und kann Probleme bereiten. Falls Fehlermeldungen auftreten sollten sie mit 'sudo blkid' überprüft und dann eindeutig gemacht werden"
#MSG_FI[$MSG_UUIDS_NOT_UNIQUE]="RBK0209W: UUID:t eivot ole uniikkeja laittella ja/tai osioilla ja saattavat aiheuttaa ongelmia. Virheiden ilmaantuessa tarkista ne komennolla 'sudo blkid' ja muuta ne yksilöllisiksi"
#MSG_FR[$MSG_UUIDS_NOT_UNIQUE]="RBK0209W: Les UUID ne sont pas uniques sur les appareils et/ou les partitions et peuvent causer des problèmes. Lors de messages d'erreurs vérifiez les UUID avec 'sudo blkid' et rendez-les uniques"
MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY=210
MSG_EN[$MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY]="RBK0210W: More than two partitions detected. Only first two partitions are saved"
MSG_DE[$MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY]="RBK0210W: Es existieren mehr als zwei Partitionen. Nur die ersten beiden Partitionen werden gesichert"
MSG_FI[$MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY]="RBK0210W: Havaittu enemmän kuin kaksi osiota. Vain kaksi ensimmäistä osiota tallennetaan"
MSG_FR[$MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY]="RBK0210W: Il y a plus de deux partitions. Seules les deux premières partitions sont sauvegardées"
#MSG_EXTERNAL_PARTITION_NOT_SAVED=211
#MSG_EN[$MSG_EXTERNAL_PARTITION_NOT_SAVED]="RBK0211E: External partition %s mounted on %s will not be saved with option -P"
#MSG_DE[$MSG_EXTERNAL_PARTITION_NOT_SAVED]="RBK0211E: Externe Partition %s die an %s gemounted ist wird mit Option -P nicht gesichert"
#MSG_FI[$MSG_EXTERNAL_PARTITION_NOT_SAVED]="RBK0211E: Ulkoinsta osiota %s, joka on otettu käyttöön kohteessa %s, ei tallenneta valinnalla -P"
#MSG_FR[$MSG_EXTERNAL_PARTITION_NOT_SAVED]="RBK0211E:La partition externe %s montée sur %s n'est pas sauvegardée avec l'option -P"
MSG_BACKUP_WARNING=212
MSG_EN[$MSG_BACKUP_WARNING]="RBK0212W: Backup finished with warnings. Check previous warning messages for details"
MSG_DE[$MSG_BACKUP_WARNING]="RBK0212W: Backup endete mit Warnungen. Siehe vorhergehende Warnmeldungen"
MSG_FI[$MSG_BACKUP_WARNING]="RBK0212W: Varmuuskopiointi valmistui sisältäen varoituksia. Katso lisätiedot edellisistä varoitusviesteistä"
MSG_FR[$MSG_BACKUP_WARNING]="RBK0212W: La sauvegarde s'est terminée avec des avertissements. Consultez ces messages pour plus de détails"
MSG_MOUNT_CHECK_ERROR=213
MSG_EN[$MSG_MOUNT_CHECK_ERROR]="RBK0213E: Mount %s to %s failed. RC %s"
MSG_DE[$MSG_MOUNT_CHECK_ERROR]="RBK0213E: Mount von %s an %s ist fehlerhaft"
MSG_FI[$MSG_MOUNT_CHECK_ERROR]="RBK0213E: Kohteen %s käyttöönotto kohteeseen %s epäonnistui. RC %s"
MSG_FR[$MSG_MOUNT_CHECK_ERROR]="RBK0213E: Échec du montage de %s sur %s. Code d'erreur %s"
#MSG_MISSING_SMART_RECYCLE_PARMS=214
#MSG_EN[$MSG_MISSING_SMART_RECYCLE_PARMS]="RBK0214E: Missing smart recycle parms in %s. Have to be four:Daily Weekly Monthly Yearly"
#MSG_DE[$MSG_MISSING_SMART_RECYCLE_PARMS]="RBK0214E: Missing smart recycle parms in %s. Es müssen vier sein: Täglich Wöchentlich Monatlich Jährlich"
#MSG_FI[$MSG_MISSING_SMART_RECYCLE_PARMS]="RBK0214E: Älykkään varmuuskopion parametrejä puuttuu parametreistä %s. Niitä tulee olla neljä: Päivittäinen Viikoittainen Kuukausittainen Vuosittainen"
#MSG_FR[$MSG_MISSING_SMART_RECYCLE_PARMS]="RBK0214E: Paramètres du cycle de statégie des sauvegardes manquants en %s. Il doit y en avoir quatre : Quotidien Hebdomadaire Mensuel Annuel"
MSG_SMART_RECYCLE_PARM_INVALID=215
MSG_EN[$MSG_SMART_RECYCLE_PARM_INVALID]="RBK0215E: Invalid smart recycle parameter %s in option '%s'"
MSG_DE[$MSG_SMART_RECYCLE_PARM_INVALID]="RBK0215E: Ungültiger smart recycle Parameter %s in Option '%s'"
MSG_FI[$MSG_SMART_RECYCLE_PARM_INVALID]="RBK0215E: Virheellinen älykkään varmuuskopion parametri %s valinnassa '%s'"
MSG_FR[$MSG_SMART_RECYCLE_PARM_INVALID]="RBK0215E: Paramètre du cycle intelligent des sauvegardes %s non valide dans l'option '%s'. "
MSG_APPLYING_BACKUP_STRATEGY_ONLY=216
MSG_EN[$MSG_APPLYING_BACKUP_STRATEGY_ONLY]="RBK0216W: Applying backup strategy in %s only"
MSG_DE[$MSG_APPLYING_BACKUP_STRATEGY_ONLY]="RBK0216W: Wende nur Backupstrategie in %s an"
MSG_FI[$MSG_APPLYING_BACKUP_STRATEGY_ONLY]="RBK0216W: Sovelletaan varmuuskopiointistrategiaa vain kohteeseen %s"
MSG_FR[$MSG_APPLYING_BACKUP_STRATEGY_ONLY]="RBK0216W: Utilisez uniquement la stratégie de sauvegarde en %s"
MSG_SMART_RECYCLE_FILES=217
MSG_EN[$MSG_SMART_RECYCLE_FILES]="RBK0217I: %s backups will be smart recycled. %s backups will be kept. Please be patient"
MSG_DE[$MSG_SMART_RECYCLE_FILES]="RBK0217I: %s Backups werden smart recycled. %s Backups werden aufgehoben. Bitte Geduld"
MSG_FI[$MSG_SMART_RECYCLE_FILES]="RBK0217I: %s varmuuskopiota käsitellään älykkäästi. %s varmuuskopiota säilytetään. Ole hyvä ja odota"
MSG_FR[$MSG_SMART_RECYCLE_FILES]="RBK0217I: %s sauvegardes de %s sont intelligemment recyclées. %s sauvegardes seront annulées. SVP soyez patient"
MSG_SMART_APPLYING_BACKUP_STRATEGY=218
MSG_EN[$MSG_SMART_APPLYING_BACKUP_STRATEGY]="RBK0218I: Applying smart backup strategy. Daily:%s Weekly:%s Monthly:%s Yearly:%s"
MSG_DE[$MSG_SMART_APPLYING_BACKUP_STRATEGY]="RBK0218I: Wende smarte Backupstrategie an. Täglich:%s Wöchentlich:%s Monatlich:%s Jährlich:%s"
MSG_FI[$MSG_SMART_APPLYING_BACKUP_STRATEGY]="RBK0218I: Sovelletaan älykästä varmuuskopiointistrategiaa. Päivittäinen:%s Viikoittainen:%s Kuukausittainen:%s Vuosittainen:%s"
MSG_FR[$MSG_SMART_APPLYING_BACKUP_STRATEGY]="RBK0218I: Appliquez une stratégie de sauvegarde intelligente: Quotidiennement : %s Hebdomadaire : %s Mensuellement : %s Annuellement : %s"
MSG_SMART_RECYCLE_NO_FILES=219
MSG_EN[$MSG_SMART_RECYCLE_NO_FILES]="RBK0219I: No backups will be smart recycled"
MSG_DE[$MSG_SMART_RECYCLE_NO_FILES]="RBK0219I: Keine Backups werden smart recycled"
MSG_FI[$MSG_SMART_RECYCLE_NO_FILES]="RBK0219I: Ei älykkään varmuuskopiolla käsiteltäviä varmuuskopioita"
MSG_FR[$MSG_SMART_RECYCLE_NO_FILES]="RBK0219I: Aucune sauvegarde dans le cycle intelligent des sauvegardes"
MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED=220
MSG_EN[$MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0220W: Smart backup strategy would delete %s"
MSG_DE[$MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0220W: Smart Backup Strategie würde %s Backup löschen"
MSG_FI[$MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0220W: Älykäs varmuuskopiointistrategia poistaisi kohteen %s"
MSG_FR[$MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0220W: La stratégie de sauvegarde intelligente supprimerait %s"
MSG_SMART_RECYCLE_FILE_DELETE=221
MSG_EN[$MSG_SMART_RECYCLE_FILE_DELETE]="RBK0221I: Smart backup strategy deletes %s"
MSG_DE[$MSG_SMART_RECYCLE_FILE_DELETE]="RBK0220I: Smart Backup Strategie löscht Backup %s"
MSG_FI[$MSG_SMART_RECYCLE_FILE_DELETE]="RBK0221I: Älykäs varmuuskopiointistrategia poistaa kohteen %s"
MSG_FR[$MSG_SMART_RECYCLE_FILE_DELETE]="RBK0221I: La stratégie de sauvegarde intelligente supprime %s"
MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT=222
MSG_EN[$MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT]="RBK0222W: Smart backup strategy would keep %s"
MSG_DE[$MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT]="RBK0222W: Smart Backup Strategie würde %s Backup behalten"
MSG_FI[$MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT]="RBK0222W: Älykäs varmuuskopiointistrategia pitäisi kohteen %s"
MSG_FR[$MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT]="RBK0222W: La stratégie de sauvegarde intelligente conserverait %s"
#MSG_UMOUNT_CHECK_ERROR=223
#MSG_EN[$MSG_UMOUNT_CHECK_ERROR]="RBK0223E: Umount %s to %s failed. RC %s"
#MSG_DE[$MSG_UMOUNT_CHECK_ERROR]="RBK0223E: Umount von %s an %s ist fehlerhaft"
#MSG_FI[$MSG_UMOUNT_CHECK_ERROR]="RBK0223E: %s käytöstä poisto %s (umount) epäonnistui. RC %s. "
#MSG_FR[$MSG_UMOUNT_CHECK_ERROR]="RBK0223E: Échec du démontage de %s sur %s , Code Erreur %s"
MSG_FILE_CONTAINS_SPACES=224
MSG_EN[$MSG_FILE_CONTAINS_SPACES]="RBK0224E: Spaces are not allowed in \"%s\""
MSG_DE[$MSG_FILE_CONTAINS_SPACES]="RBK0224E: Leerzeichen sind nicht in \"%s\" erlaubt"
MSG_FI[$MSG_FILE_CONTAINS_SPACES]="RBK0224E: Välilyönnit eivät ole sallittuja nimessä \"%s\""
MSG_FR[$MSG_FILE_CONTAINS_SPACES]="RBK0224E: Les espaces ne sont pas autorisés dans \"%s\""
MSG_UNABLE_TO_CREATE_FILE=225
MSG_EN[$MSG_UNABLE_TO_CREATE_FILE]="RBK0225E: Unable to create file %s"
MSG_DE[$MSG_UNABLE_TO_CREATE_FILE]="RBK0225E: Datei %s kann nicht erstellt werden"
MSG_FI[$MSG_UNABLE_TO_CREATE_FILE]="RBK0225E: Tiedoston %s luonti epäonnistui"
MSG_FR[$MSG_UNABLE_TO_CREATE_FILE]="RBK0225E: Impossible de créer le fichier %s"
#MSG_CONFIG_VERSION_DOES_NOT_MATCH=226
#MSG_EN[$MSG_CONFIG_VERSION_DOES_NOT_MATCH]="RBK0226W: Found unexpected config version %s in %s. Expected version %s"
#MSG_DE[$MSG_CONFIG_VERSION_DOES_NOT_MATCH]="RBK0226W: Unerwartete Konfigurationsversion %s in %s gefunden. %s wird erwartet"
#MSG_FI[$MSG_CONFIG_VERSION_DOES_NOT_MATCH]="RBK0226W: Odottamaton asetustiedoston versio %s löytyi kohteessa %s. Oletettiin versiota %s"
#MSG_FR[$MSG_CONFIG_VERSION_DOES_NOT_MATCH]="RBK0226W: Version de configuration inattendue %s trouvée dans %s. Version attendue %s"
MSG_TITLE_STARTED=227
MSG_EN[$MSG_TITLE_STARTED]="%s: Backup started"
MSG_DE[$MSG_TITLE_STARTED]="%s: Backup gestarted"
MSG_FI[$MSG_TITLE_STARTED]="%s: Varmuuskopiointi aloitettu"
MSG_FR[$MSG_TITLE_STARTED]="%s: Sauvegarde démarrée"
MSG_TELEGRAM_SEND_FAILED=228
MSG_EN[$MSG_TELEGRAM_SEND_FAILED]="RBK0228W: Sent to telegram failed. curl RC: %s - HTTP CODE: %s - Error description: %s"
MSG_DE[$MSG_TELEGRAM_SEND_FAILED]="RBK0228W: Senden an Telegram fehlerhaft. curl RC: %s - HTTP CODE: %s - Fehlerbeschreibung: %s"
MSG_FI[$MSG_TELEGRAM_SEND_FAILED]="RBK0228W: Yhteys Telegramiin epäonnistui. curl RC: %s - HTTP-koodi: %s - Virheen kuvaus: %s"
MSG_FR[$MSG_TELEGRAM_SEND_FAILED]="RBK0228W: Échec de l'envoi à Telegram. erreur curl: %s - CODE HTTP : %s - Description de l'erreur : %s"
MSG_TELEGRAM_SEND_OK=229
MSG_EN[$MSG_TELEGRAM_SEND_OK]="RBK0229I: Telegram notified"
MSG_DE[$MSG_TELEGRAM_SEND_OK]="RBK0229I: Telegram benachrichtigt"
MSG_FI[$MSG_TELEGRAM_SEND_OK]="RBK0229I: Telegram-ilmoitus lähetetty"
MSG_FR[$MSG_TELEGRAM_SEND_OK]="RBK0229I: Telegram notifié"
MSG_TELEGRAM_OPTIONS_INCOMPLETE=230
MSG_EN[$MSG_TELEGRAM_OPTIONS_INCOMPLETE]="RBK0230E: Telegram options not complete"
MSG_DE[$MSG_TELEGRAM_OPTIONS_INCOMPLETE]="RBK0230E: Telegramoptionen nicht vollständig"
MSG_FI[$MSG_TELEGRAM_OPTIONS_INCOMPLETE]="RBK0230E: Telegramin asetukset ovat puutteellliset"
MSG_FR[$MSG_TELEGRAM_OPTIONS_INCOMPLETE]="RBK0230E: Options de Telegram incomplètes"
MSG_TELEGRAM_SEND_LOG_FAILED=231
MSG_EN[$MSG_TELEGRAM_SEND_LOG_FAILED]="RBK0231W: Unable to send messages to Telegram. curl RC: %s"
MSG_DE[$MSG_TELEGRAM_SEND_LOG_FAILED]="RBK0231W: Meldungen an Telegram konnten nicht gesendet werden. curl RC: %s"
MSG_FI[$MSG_TELEGRAM_SEND_LOG_FAILED]="RBK0231W: Viestien lähettäminen Telegramiin ei onnistunut. curl RC: %s"
MSG_FR[$MSG_TELEGRAM_SEND_LOG_FAILED]="RBK0231W: Impossible d'envoyer des messages à Telegram. Erreur curl: %s"
MSG_TELEGRAM_SEND_LOG_OK=232
MSG_EN[$MSG_TELEGRAM_SEND_LOG_OK]="RBK0232I: Messages sent to Telegram"
MSG_DE[$MSG_TELEGRAM_SEND_LOG_OK]="RBK0232I: Meldungen an Telegram gesendet"
MSG_FI[$MSG_TELEGRAM_SEND_LOG_OK]="RBK0232I: Viestit lähetetty Telegramiin"
MSG_FR[$MSG_TELEGRAM_SEND_LOG_OK]="RBK0232I: Messages envoyés à Telegram"
MSG_TELEGRAM_INVALID_NOTIFICATION=233
MSG_EN[$MSG_TELEGRAM_INVALID_NOTIFICATION]="RBK0233E: Invalid Telegram notification %s detected. Valid notifications are %s"
MSG_DE[$MSG_TELEGRAM_INVALID_NOTIFICATION]="RBK0233E: Ungültige Telegram Notification %s eingegeben. Mögliche Notifikationen sind %s"
MSG_FI[$MSG_TELEGRAM_INVALID_NOTIFICATION]="RBK0233E: Epäkelpo Telegram-ilmoitus %s havaittu. Kelvollisia ilmoituksia ovat %s"
MSG_FR[$MSG_TELEGRAM_INVALID_NOTIFICATION]="RBK0233E: Notification de Telegram non valide %s . Les notifications valides sont %s"
MSG_INVALID_COLORING_OPTION=234
MSG_EN[$MSG_INVALID_COLORING_OPTION]="RBK0234E: Invalid coloring option %s detected"
MSG_DE[$MSG_INVALID_COLORING_OPTION]="RBK0234E: Ungültige Färbungsoption %s entdeckt"
MSG_FI[$MSG_INVALID_COLORING_OPTION]="RBK0234E: Epäkelpo väriasetus %s havaittu"
MSG_FR[$MSG_INVALID_COLORING_OPTION]="RBK0234E: Option de coloration non valide %s détectée"
MSG_INVALID_TRUE_FALSE_OPTION=235
MSG_EN[$MSG_INVALID_TRUE_FALSE_OPTION]="RBK0235E: Invalid true/false option %s for %s detected. Should be on, off, 0 or 1"
MSG_DE[$MSG_INVALID_TRUE_FALSE_OPTION]="RBK0235E: Ungültige an/aus Option %s für %s entdeckt. Es sollte an, aus, 0 oder 1 sein"
MSG_FI[$MSG_INVALID_TRUE_FALSE_OPTION]="RBK0235E: Virheellinen päälle/pois-valinta %s havaittu kohteelle %s. Valinnan tulee olla on, off, 0 tai 1"  #on and off are OK for finnish language
MSG_FR[$MSG_INVALID_TRUE_FALSE_OPTION]="RBK0235E: Option on/off non valide %s détectée pour %s. Il doit être activé, désactivé, 0 ou 1"
#MSG_PARTITION_MODE_NO_LONGER_SUPPORTED=236
#MSG_EN[$MSG_PARTITION_MODE_NO_LONGER_SUPPORTED]="RBK0236W: Partition oriented backup will not be maintained any more and disable somewhere in the future"
#MSG_DE[$MSG_PARTITION_MODE_NO_LONGER_SUPPORTED]="RBK0236W: Partitionsorientierter Modus wird nicht mehr weiter gewartet und irgendwann in Zukunft nicht mehr verfügbar sein"
#MSG_FI[$MSG_PARTITION_MODE_NO_LONGER_SUPPORTED]="RBK0236W: Osio-orientoitua varmuuskopiota ei enää tueta ja poistetaan kokonaan käytöstä tulevaisuudessa"
#MSG_FR[$MSG_PARTITION_MODE_NO_LONGER_SUPPORTED]="RBK0236W: La sauvegarde orientée partition ne sera plus maintenue et sera désactivée quelque part dans le futur""
MSG_UPDATE_TO_LATEST_BETA=237
MSG_EN[$MSG_UPDATE_TO_LATEST_BETA]="RBK0237I: Upgrading current version %s to latest version"
MSG_DE[$MSG_UPDATE_TO_LATEST_BETA]="RBK0237I: Die momentane Version %s auf die aktuellste Version upgraden"
MSG_FI[$MSG_UPDATE_TO_LATEST_BETA]="RBK0237I: Päivitetään nykyinen versio %s viimeisimpään versioon"
MSG_FR[$MSG_UPDATE_TO_LATEST_BETA]="RBK0237I: Mise à niveau de la version actuelle %s vers la dernière version"
#MSG_JUST_TEXT=238
#MSG_EN[$MSG_JUST_TEXT]="%s"
#MSG_DE[$MSG_JUST_TEXT]="%s"
#MSG_FI[$MSG_JUST_TEXT]="%s"
#MSG_FR[$MSG_JUST_TEXT]="%s"
MSG_DOWNLOAD_FAILED=239
MSG_EN[$MSG_DOWNLOAD_FAILED]="RBK0239E: Download of %s failed. HTTP code: %s. RC: %s"
MSG_DE[$MSG_DOWNLOAD_FAILED]="RBK0239E: %s kann nicht aus dem Netz geladen werden. HTTP code: %s. RC: %s"
MSG_FI[$MSG_DOWNLOAD_FAILED]="RBK0239E: Kohteen %s lataus epäonnistui. HTTP-koodi: %s. RC: %s"
MSG_FR[$MSG_DOWNLOAD_FAILED]="RBK0239E: Le téléchargement de %s a échoué. Code HTTP : %s. RC:%s"
MSG_SAVING_CURRENT_CONFIGURATION=240
MSG_EN[$MSG_SAVING_CURRENT_CONFIGURATION]="RBK0240I: Saving current configuration %s to %s"
MSG_DE[$MSG_SAVING_CURRENT_CONFIGURATION]="RBK0240I: Aktuelle Konfiguration %s wird in %s gesichert"
MSG_FI[$MSG_SAVING_CURRENT_CONFIGURATION]="RBK0240I: Tallennetaan nykyiset asetukset %s kohteeseen %s"
MSG_FR[$MSG_SAVING_CURRENT_CONFIGURATION]="RBK0240I: Enregistrement de la configuration actuelle %s dans %s"
MSG_MERGING_VERSION=241
MSG_EN[$MSG_MERGING_VERSION]="RBK0241I: Merging current configuration %s with new configuration %s into %s"
MSG_DE[$MSG_MERGING_VERSION]="RBK0241I: Aktuelle Konfiguration %s wird mit der neuen Konfiguration %s in %s zusammengefügt"
MSG_FI[$MSG_MERGING_VERSION]="RBK0241I: Yhdistetään nykyiset asetukset %s uusiin asetuksiin %s kohteeksi %s"
MSG_FR[$MSG_MERGING_VERSION]="RBK0241I: La configuration actuelle %s sera fusionnée avec la nouvelle configuration %s dans %s"
MSG_MERGE_SUCCESSFULL=242
MSG_EN[$MSG_MERGE_SUCCESSFULL]="RBK0242I: Configuration merge finished successfully but not activated."
MSG_DE[$MSG_MERGE_SUCCESSFULL]="RBK0242I: Konfigurationszusammenfügung wurde erfolgreich beendet aber nicht aktiviert."
MSG_FI[$MSG_MERGE_SUCCESSFULL]="RBK0242I: Asetukset yhdistetty onnistuneesti, mutta niitä ei ole aktivoitu."
MSG_FR[$MSG_MERGE_SUCCESSFULL]="RBK0242I: La fusion de la configuration s'est terminée avec succès mais n'a pas été activée."
MSG_COPIED_FILE=243
MSG_EN[$MSG_COPIED_FILE]="RBK0243I: Merged configuration %s copied to %s and activated."
MSG_DE[$MSG_COPIED_FILE]="RBK0243I: Zusammengefügte Konfiguration %s nach %s kopiert und aktiviert."
MSG_FI[$MSG_COPIED_FILE]="RBK0243I: Yhdistetyt asetukset %s kopioitiin kohteeseen %s ja ne aktivoitiin."
MSG_FR[$MSG_COPIED_FILE]="RBK0243I: Configuration fusionnée %s copiée dans %s et activée."
MSG_UPDATE_CONFIG=244
MSG_EN[$MSG_UPDATE_CONFIG]="RBK0244W: Backup current configuration in %s and activate updated configuration? %s "
MSG_DE[$MSG_UPDATE_CONFIG]="RBK0244W: Soll die aktuelle Konfiguration in %s gesichert werden und die aktualisierte Konfiguration aktiviert werden? %s "
MSG_FI[$MSG_UPDATE_CONFIG]="RBK0244W: Varmuuskopioidaanko nykyiset asetukset kohteeseen %s ja aktivoidaan päivitetyt asetukset? %s "
MSG_FR[$MSG_UPDATE_CONFIG]="RBK0244W: Sauvegarder la configuration actuelle dans %s et activer la configuration mise à jour ? %s "
MSG_NO_CONFIGUPDATE_REQUIRED=245
MSG_EN[$MSG_NO_CONFIGUPDATE_REQUIRED]="RBK0245I: Local configuration version v%s does not require an update."
MSG_DE[$MSG_NO_CONFIGUPDATE_REQUIRED]="RBK0245I: Die lokale Konfigurationsversion v%s benötigt keine Aktualisierung."
MSG_FI[$MSG_NO_CONFIGUPDATE_REQUIRED]="RBK0245I: Paikallinen asetustiedoston versio v%s ei vaadi päivitystä."
MSG_FR[$MSG_NO_CONFIGUPDATE_REQUIRED]="RBK0245I: La version de configuration locale v%s ne nécessite pas de mise à jour."
#MSG_CONFIG_VERSIONS=246
#MSG_EN[$MSG_CONFIG_VERSIONS]="RBK0246I: Current configuration version: v%s. Required configuration version: v%s"
#MSG_DE[$MSG_CONFIG_VERSIONS]="RBK0246I: Lokale Konfigurationsversion: v%s. Erforderliche Konfigurationsversion: v%s"
#MSG_FI[$MSG_CONFIG_VERSIONS]="RBK0246I: Nykyisten asetusten versio: v%s. Vaaditaan versio v%s"
#MSG_FR[$MSG_CONFIG_VERSIONS]="RBK0246I: Version de configuration actuelle : v%s. Version de configuration requise : v%s"
MSG_ACTIVATE_CONFIG=247
MSG_EN[$MSG_ACTIVATE_CONFIG]="RBK0247I: Now review %s and copy the configuration file to %s to finish the configuration update"
MSG_DE[$MSG_ACTIVATE_CONFIG]="RBK0247I: Nun die zusammengefügte Konfigurationsdatei %s überprüfen und nach %s kopieren um den Konfigurationsupdate zu beenden"
MSG_FI[$MSG_ACTIVATE_CONFIG]="RBK0247I: Tarkista %s ja kopioi asetustiedosto kohteeseen %s viimeistelläksesi asetusten päivitykset"
MSG_FR[$MSG_ACTIVATE_CONFIG]="RBK0247I: Vérifiez maintenant le fichier de configuration fusionné %s et copiez-le dans %s pour terminer la mise à jour de la configuration"
MSG_ADDED_CONFIG_OPTION=248
MSG_EN[$MSG_ADDED_CONFIG_OPTION]="RBK0248I: Added option %s=%s"
MSG_DE[$MSG_ADDED_CONFIG_OPTION]="RBK0248I: Option %s=%s wurde zugefügt"
MSG_FI[$MSG_ADDED_CONFIG_OPTION]="RBK0248I: Lisättiin valinta %s=%s"
MSG_FR[$MSG_ADDED_CONFIG_OPTION]="RBK0248I: Ajout de l'option %s=%s"
MSG_DELETED_CONFIG_OPTION=249
MSG_EN[$MSG_DELETED_CONFIG_OPTION]="RBK0249I: Deleted option %s=%s"
MSG_DE[$MSG_DELETED_CONFIG_OPTION]="RBK0249I: Option %s=%s wurde gelöscht"
MSG_FI[$MSG_DELETED_CONFIG_OPTION]="RBK0249I: Poistettiin valinta %s=%s"
MSG_FR[$MSG_DELETED_CONFIG_OPTION]="RBK0249I: Option supprimée %s=%s"
MSG_CONFIG_BACKUP_FAILED=250
MSG_EN[$MSG_CONFIG_BACKUP_FAILED]="RBK0250E: Backup creation of %s failed"
MSG_DE[$MSG_CONFIG_BACKUP_FAILED]="RBK0250E: Backuperstellung von %s fehlerhaft"
MSG_FI[$MSG_CONFIG_BACKUP_FAILED]="RBK0250E: Varmuuskopion luonti kohteesta %s epäonnistui"
MSG_FR[$MSG_CONFIG_BACKUP_FAILED]="RBK0250E: La création de la sauvegarde de %s a échoué"
MSG_CHMOD_FAILED=251
MSG_EN[$MSG_CHMOD_FAILED]="RBK0251E: chmod of %s failed"
MSG_DE[$MSG_CHMOD_FAILED]="RBK0251E: chmod von %s nicht möglich"
MSG_FI[$MSG_CHMOD_FAILED]="RBK0251E: Kohteen %s chmod epäonnistui"
MSG_FR[$MSG_CHMOD_FAILED]="RBK0251E: chmod pour %s a échoué"
MSG_EMAIL_COLORING_NOT_SUPPORTED=252
MSG_EN[$MSG_EMAIL_COLORING_NOT_SUPPORTED]="RBK0252E: Invalid eMail coloring %s. Using $EMAIL_COLORING_SUBJECT. Supported are %s"
MSG_DE[$MSG_EMAIL_COLORING_NOT_SUPPORTED]="RBK0252E: Ungültige eMailKolorierung %s. Benutze $EMAIL_COLORING_SUBJECT. Unterstützt sind %s"
MSG_FI[$MSG_EMAIL_COLORING_NOT_SUPPORTED]="RBK0252E: Epäkelpo sähköpostin väritys %s. Käytetään $EMAIL_COLORING_SUBJECT. Tuettuja ovat %s"
MSG_FR[$MSG_EMAIL_COLORING_NOT_SUPPORTED]="RBK0252E: Coloration de l'e-mail %s non valide. Utiliser $EMAIL_COLORING_SUBJECT. %s qui est pris en charge"
MSG_SD_TOO_SMALL=253
MSG_EN[$MSG_SD_TOO_SMALL]="RBK0253E: Target device %s too small. Available bytes: %s. Required bytes: %s"
MSG_DE[$MSG_SD_TOO_SMALL]="RBK0253E: Zielgerät %s ist zu klein. Verfügbare Bytes: %s. Erforderliche Bytes: %s"
MSG_FI[$MSG_SD_TOO_SMALL]="RBK0253E: Kohdelaite %s on liian pieni. Käytetävissä %s tavua. Vaaditaan %s tavua"
MSG_FR[$MSG_SD_TOO_SMALL]="RBK0253E: Périphérique cible %s trop petit. Octets disponibles : %s. Octets requis : %s"
MSG_SENSITIVE_SEPARATOR=254
MSG_EN[$MSG_SENSITIVE_SEPARATOR]="+================================================================================================================================================+"
MSG_DE[$MSG_SENSITIVE_SEPARATOR]="+================================================================================================================================================+"
MSG_FI[$MSG_SENSITIVE_SEPARATOR]="+================================================================================================================================================+"
MSG_FR[$MSG_SENSITIVE_SEPARATOR]="+================================================================================================================================================+"
MSG_SENSITIVE_WARNING=255
MSG_EN[$MSG_SENSITIVE_WARNING]="| ===> A lot of sensitive information is masqueraded in this log file. Nevertheless please check the log carefully before you distribute it <=== |"
MSG_DE[$MSG_SENSITIVE_WARNING]="| ===>  Viele sensitive Informationen werden in dieser Logdatei maskiert. Vor dem Verteilen des Logs sollte es trotzdem ueberprueft werden  <=== |"
MSG_FI[$MSG_SENSITIVE_WARNING]="| ===>            Sensitiivisiä tietoja on piilotettu tästä lokitiedostosta. Tarkista lisäksi loki huolellisesti ennen sen jakoa            <=== |"
MSG_FR[$MSG_SENSITIVE_WARNING]="| ===>De nombreuses informations sensibles sont masquées dans ce fichier journal. Avant de distribuer le log, il faut quand même le vérifier<=== |"
MSG_RESTORE_WARNING=256
MSG_EN[$MSG_RESTORE_WARNING]="RBK0256W: Restore finished with warnings. Check previous warning messages for details"
MSG_DE[$MSG_RESTORE_WARNING]="RBK0256W: Restore endete mit Warnungen. Siehe vorhergehende Warnmeldungen"
MSG_FI[$MSG_RESTORE_WARNING]="RBK0256W: Palautus onnistui sisältäen vaoituksia. Katso lisätiedot edellisistä varoitusviesteistä"
MSG_FR[$MSG_RESTORE_WARNING]="RBK0256W: Restauration terminée avec des avertissements. Consultez les messages pour plus de détails"
MSG_DEPRECATED_OPTION=257
MSG_EN[$MSG_DEPRECATED_OPTION]="RBK0257W: Option %s is deprecated and will be removed in a future release"
MSG_DE[$MSG_DEPRECATED_OPTION]="RBK0257W: Option %s ist veraltet und wird in einer zukünftigen Release entfernt werden"
MSG_FI[$MSG_DEPRECATED_OPTION]="RBK0257W: Valintaa %s ei enää tueta ja se poistetaan kokonaan tulevissa julkaisuissa"
MSG_FR[$MSG_DEPRECATED_OPTION]="RBK0257W: L'option %s est obsolète et sera supprimée dans une prochaine version"
MSG_DYNAMIC_MOUNT_FAILED=258
MSG_EN[$MSG_DYNAMIC_MOUNT_FAILED]="RBK0258E: Dynamic mount of %s failed with rc %s"
MSG_DE[$MSG_DYNAMIC_MOUNT_FAILED]="RBK0258E: Dynamischer mount von %s bekommt Fehler %s"
MSG_FI[$MSG_DYNAMIC_MOUNT_FAILED]="RBK0258E: Kohteen %s dynaaminen käyttöönotto epäonnistui, RC %s"
MSG_FR[$MSG_DYNAMIC_MOUNT_FAILED]="RBK0258E: Le montage dynamique de %s a échoué avec le Code erreur %s"
MSG_DYNAMIC_MOUNT_OK=259
MSG_EN[$MSG_DYNAMIC_MOUNT_OK]="RBK0259I: Dynamic mount of %s successfull"
MSG_DE[$MSG_DYNAMIC_MOUNT_OK]="RBK0259I: Dynamischer mount von %s erfolgreich"
MSG_FI[$MSG_DYNAMIC_MOUNT_OK]="RBK0259I: Kohteen %s dynaaminen käyttöönotto onnistui"
MSG_FR[$MSG_DYNAMIC_MOUNT_OK]="RBK0259I: Montage dynamique de %s réussi"
MSG_DYNAMIC_UMOUNT_SCHEDULED=260
MSG_EN[$MSG_DYNAMIC_UMOUNT_SCHEDULED]="RBK0260I: Dynamic umount of %s will be executed"
MSG_DE[$MSG_DYNAMIC_UMOUNT_SCHEDULED]="RBK0260I: Dynamischer umount von %s wird vorgenommen"
MSG_FI[$MSG_DYNAMIC_UMOUNT_SCHEDULED]="RBK0260I: Suoritetaan kohteen %s dynaaminen käytöstäpoista"
MSG_FR[$MSG_DYNAMIC_UMOUNT_SCHEDULED]="RBK0260I: Le démontage dynamique de %s est exécuté"
#MSG_NO_SKIP_OR_FORCE_ALLOWED=261
#MSG_EN[$MSG_NO_SKIP_OR_FORCE_ALLOWED]="RBK0261E: Option -0 and -1 are not supported with option -P"
#MSG_DE[$MSG_NO_SKIP_OR_FORCE_ALLOWED]="RBK0261E: Option -0 und -1 sind nicht mit der Option -P unterstützt"
#MSG_FI[$MSG_NO_SKIP_OR_FORCE_ALLOWED]="RBK0261E: Valintaa -0 ja -1 ei tueta valinnan -P kanssa"
#MSG_FR[$MSG_NO_SKIP_OR_FORCE_ALLOWED]="RBK0261E: Les options -0 et -1 ne sont pas prises en charge avec l'option -P"
MSG_DYNAMIC_MOUNT_NOT_REQUIRED=262
MSG_EN[$MSG_DYNAMIC_MOUNT_NOT_REQUIRED]="RBK0262I: Dynamic mount of %s skipped because it's already mounted"
MSG_DE[$MSG_DYNAMIC_MOUNT_NOT_REQUIRED]="RBK0262I: Dynamischer mount von %s nicht ausgeführt da es schon gemounted ist"
MSG_FI[$MSG_DYNAMIC_MOUNT_NOT_REQUIRED]="RBK0262I: Kohteen %s dynaaminen käyttöönotto ohitettiin, koska kohde on jo käytössä"
MSG_FR[$MSG_DYNAMIC_MOUNT_NOT_REQUIRED]="RBK0262I: Le montage dynamique de %s a été ignoré car il est déjà monté"
MSG_NO_FILEATTRIBUTESUPPORT=263
MSG_EN[$MSG_NO_FILEATTRIBUTESUPPORT]="RBK0263E: Filesystem %s on %s does not support Linux fileattributes"
MSG_DE[$MSG_NO_FILEATTRIBUTESUPPORT]="RBK0263E: Dateisystem %s auf %s unterstützt keine Linux Dateiattribute"
MSG_FI[$MSG_NO_FILEATTRIBUTESUPPORT]="RBK0263E: Tiedostojärjestelmä %s kohteessa %s ei tue Linuxin tiedostoattribuutteja"
MSG_FR[$MSG_NO_FILEATTRIBUTESUPPORT]="RBK0263E: Le système de fichiers %s sur %s ne prend pas en charge les attributs de fichiers Linux"
MSG_ROOT_PARTITION_NOT_DIFFERENT=264
MSG_EN[$MSG_ROOT_PARTITION_NOT_DIFFERENT]="RBK0264E: Partition used with option -R cannot be located on same device %s used with option -d"
MSG_DE[$MSG_ROOT_PARTITION_NOT_DIFFERENT]="RBK0264E: Die mit Option -R genutzte Partition darf nicht auf demselben Gerät %s welches mit Option -d angegeben wurde liegen"
MSG_FI[$MSG_ROOT_PARTITION_NOT_DIFFERENT]="RBK0264E: Valinnalla -R määritelty osio ei voi sijaita samalla laitteella %s, joka on määritelty valinnalla -d"
MSG_FR[$MSG_ROOT_PARTITION_NOT_DIFFERENT]="RBK0264E: La partition utilisée avec l'option -R ne doit pas être sur le même périphérique %s que celui spécifié avec l'option-d"
MSG_DD_WARNING=265
MSG_EN[$MSG_DD_WARNING]="RBK0265W: It's not recommended to use the dd backup method. For details read $DD_WARNING_URL_EN"
MSG_DE[$MSG_DD_WARNING]="RBK0265W: dd als Backupmethode wird nicht empfohlen. Details dazu finden sich auf $DD_WARNING_URL_DE"
MSG_FI[$MSG_DD_WARNING]="RBK0265W: DD-varmuuskopiota ei suositella. Lue lisätietoja osoitteesta $DD_WARNING_URL_EN" #Defaults to EN link.
MSG_FR[$MSG_DD_WARNING]="RBK0265W: Il n'est pas recommandé d'utiliser la méthode de sauvegarde dd. Pour plus de détails, lisez $DD_WARNING_URL_EN" #Defaults to EN link.
MSG_NO_FILEATTRIBUTE_RIGHTS=266
MSG_EN[$MSG_NO_FILEATTRIBUTE_RIGHTS]="RBK0266E: Access rights missing to create fileattributes on %s (Filesystem: %s)"
MSG_DE[$MSG_NO_FILEATTRIBUTE_RIGHTS]="RBK0266E: Es fehlt die Berechtigung um Linux Dateiattribute auf %s zu erstellen (Dateisystem: %s)"
#shellcheck disable=SC2034
MSG_FI[$MSG_NO_FILEATTRIBUTE_RIGHTS]="RBK0266E: Käyttöoikeudet tiedostoattribuuttien luomiseen puuttuvat kohteesta %s (Tiedostojärjestelmä: %s)"
#shellcheck disable=SC2034
MSG_FR[$MSG_NO_FILEATTRIBUTE_RIGHTS]="RBK0266E: Droits d'accès manquants pour créer des attributs de fichier sur %s (système de fichiers : %s)"

#
# Non NLS messages
#

MSG_EXTENSION_CALLED=267
MSG_EN[$MSG_EXTENSION_CALLED]="RBK0267I: Extension %s called"
MSG_DE[$MSG_EXTENSION_CALLED]="RBK0267I: Erweiterung %s wird aufgerufen"
MSG_UNSUPPORTED_ENVIRONMENT=268
MSG_EN[$MSG_UNSUPPORTED_ENVIRONMENT]="RBK0268E: Only Raspberries running Raspberry PI OS are supported. Use option --unsupportedEnvironment to invoke $MYNAME WITHOUT ANY SUPPORT"
MSG_DE[$MSG_UNSUPPORTED_ENVIRONMENT]="RBK0268E: Es werden nur Raspberries mit Raspberry PI OS unterstützt. Mit der Option --unsupportedEnvironment kann man $MYNAME OHNE JEGLICHE UNTERSTÜTZUNG aufrufen"
MSG_UNSUPPORTED_ENVIRONMENT_CONFIRMED=269
MSG_EN[$MSG_UNSUPPORTED_ENVIRONMENT_CONFIRMED]="\
RBK0269W: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@${NL}\
!!! RBK0268W: @@@ Unsupported environment @@@${NL}\
!!! RBK0269W: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@${NL}"
MSG_DE[$MSG_UNSUPPORTED_ENVIRONMENT_CONFIRMED]="\
RBK0269W: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@${NL}\
!!! RBK0268W: @@@ Nicht unterstützte Umgebung @@@${NL}\
!!! RBK0269W: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@${NL}"
MSG_REBOOT_SYSTEM=270
MSG_EN[$MSG_REBOOT_SYSTEM]="RBK0270I: System will be rebooted at the end of the backup run"
MSG_DE[$MSG_REBOOT_SYSTEM]="RBK0270I: Das System wird am Ende des Backuplaufes neu gestartet"
MSG_SMART_RECYCLE_WILL_BE_APPLIED=271
MSG_EN[$MSG_SMART_RECYCLE_WILL_BE_APPLIED]="RBK0271I: Smart recycle strategy will be applied"
MSG_DE[$MSG_SMART_RECYCLE_WILL_BE_APPLIED]="RBK0271I: Wende smarte Backupstrategie an"
MSG_REBOOT_SYSTEM=272
MSG_EN[$MSG_REBOOT_SYSTEM]="RBK0272I: System will be rebooted at the end of the backup run"
MSG_DE[$MSG_REBOOT_SYSTEM]="RBK0272I: Das System wird am Ende des Backuplaufes neu gestartet"
MSG_INVALID_BACKUPNAMES_DETECTED=273
MSG_EN[$MSG_INVALID_BACKUPNAMES_DETECTED]="RBK0273E: %s invalid backup directorie(s) or files found in %s"
MSG_DE[$MSG_INVALID_BACKUPNAMES_DETECTED]="RBK0273E: %s ungültige Backupverzeichnis(se) oder Dateien in %s gefunden"
MSG_RESTORE_PARTITION_MOUNTED=274
MSG_EN[$MSG_RESTORE_PARTITION_MOUNTED]="RBK0274E: Restore device %s has mounted partitions. Note: Restore to the active system is not possible"
MSG_DE[$MSG_RESTORE_PARTITION_MOUNTED]="RBK0274E: Das Restoregerät %s hat gemountete Partitionen. Hinweis: Ein Restore auf das aktive System ist nicht möglich"
MSG_RESTORE_DEVICE_NOT_VALID=275
MSG_EN[$MSG_RESTORE_DEVICE_NOT_VALID]="RBK0275E: Restore device %s is no valid device"
MSG_DE[$MSG_RESTORE_DEVICE_NOT_VALID]="RBK0275E: Das Restoregerät %s ist kein gültiges Gerät"
MSG_INVALID_BOOT_DEVICE=276
MSG_EN[$MSG_INVALID_BOOT_DEVICE]="RBK0276E: Boot device %s is not supported"
MSG_DE[$MSG_INVALID_BOOT_DEVICE]="RBK0276E: Das Bootgerät %s ist nicht unterstützt"
#MSG_USBMOUNT_INSTALLED=277
#MSG_EN[$MSG_USBMOUNT_INSTALLED]="RBK0277E: Restore not possible when %s is active"
#MSG_DE[$MSG_USBMOUNT_INSTALLED]="RBK0277E: Restore ist nicht möglich wenn %s active ist"
MSG_BACKUP_CLEANUP_FAILED=278
MSG_EN[$MSG_BACKUP_CLEANUP_FAILED]="RBK0278E: Cleanup of backupdirectories failed. Manual deletion of the last backup directory is strongly recommended !"
MSG_DE[$MSG_BACKUP_CLEANUP_FAILED]="RBK0278E: Fehler bei den Aufräumarbeiten am Backupverzeichnis. Das letzte Backupverzeichnis sollte dringend manuell gelöscht werden !"
MSG_FINAL_COMMAND_FAILED=279
MSG_EN[$MSG_FINAL_COMMAND_FAILED]="RBK0279W: Error occured executing final command. RC %s"
MSG_DE[$MSG_FINAL_COMMAND_FAILED]="RBK0279W: Ein Fehler trat beim Ausführen der finalen Befehle auf. RC %s"
MSG_FINAL_COMMAND_EXECUTED=280
MSG_EN[$MSG_FINAL_COMMAND_EXECUTED]="RBK0280I: Executing final command: '%s'"
MSG_DE[$MSG_FINAL_COMMAND_EXECUTED]="RBK0280I: Finaler Befehl wird ausgeführt: '%s'"
MSG_UNSUPPORTED_VERSION=281
MSG_EN[$MSG_UNSUPPORTED_VERSION]="RBK0281W: Unsupported version of $MYSELF"
MSG_DE[$MSG_UNSUPPORTED_VERSION]="RBK0281W: Nicht unterstützte Version von $MYSELF"
MSG_PUSHOVER_SEND_FAILED=282
MSG_EN[$MSG_PUSHOVER_SEND_FAILED]="RBK0282W: Sent to pushover failed. curl RC: %s - HTTP CODE: %s - Error description: %s"
MSG_DE[$MSG_PUSHOVER_SEND_FAILED]="RBK0282W: Senden an Pushover fehlerhaft. curl RC: %s - HTTP CODE: %s - Fehlerbeschreibung: %s"
MSG_PUSHOVER_SEND_OK=283
MSG_EN[$MSG_PUSHOVER_SEND_OK]="RBK0283I: Pushover notified"
MSG_DE[$MSG_PUSHOVER_SEND_OK]="RBK0283I: Pushover benachrichtigt"
MSG_PUSHOVER_OPTIONS_INCOMPLETE=284
MSG_EN[$MSG_PUSHOVER_OPTIONS_INCOMPLETE]="RBK0284E: Pushover options not complete"
MSG_DE[$MSG_PUSHOVER_OPTIONS_INCOMPLETE]="RBK0284E: Pushoveroptionen nicht vollständig"
MSG_PUSHOVER_INVALID_NOTIFICATION=285
MSG_EN[$MSG_PUSHOVER_INVALID_NOTIFICATION]="RBK0285E: Invalid Pushover notification %s detected. Valid notifications are %s"
MSG_DE[$MSG_PUSHOVER_INVALID_NOTIFICATION]="RBK0285E: Ungültige Pushover Notification %s eingegeben. Mögliche Notifikationen sind %s"
MSG_SLACK_SEND_FAILED=286
MSG_EN[$MSG_SLACK_SEND_FAILED]="RBK0286W: Sent to Slack failed. curl RC: %s - HTTP CODE: %s - Error description: %s"
MSG_DE[$MSG_SLACK_SEND_FAILED]="RBK0286W: Senden an Slack fehlerhaft. curl RC: %s - HTTP CODE: %s - Fehlerbeschreibung: %s"
MSG_SLACK_SEND_OK=287
MSG_EN[$MSG_SLACK_SEND_OK]="RBK0287I: Slack notified"
MSG_DE[$MSG_SLACK_SEND_OK]="RBK0287I: Slack benachrichtigt"
#MSG_SLACK_OPTIONS_INCOMPLETE=288
#MSG_EN[$MSG_SLACK_OPTIONS_INCOMPLETE]="RBK0288E: Slack options not complete"
#MSG_DE[$MSG_SLACK_OPTIONS_INCOMPLETE]="RBK0288E: Slackoptionen nicht vollständig"
MSG_SLACK_INVALID_NOTIFICATION=289
MSG_EN[$MSG_SLACK_INVALID_NOTIFICATION]="RBK0289E: Invalid Slack notification %s detected. Valid notifications are %s"
MSG_DE[$MSG_SLACK_INVALID_NOTIFICATION]="RBK0289E: Ungültige Slack Notification %s eingegeben. Mögliche Notifikationen sind %s"
MSG_UNPROTECTED_PROPERTIESFILE=290
MSG_EN[$MSG_UNPROTECTED_PROPERTIESFILE]="RBK0290W: Configuration file %s is unprotected"
MSG_DE[$MSG_UNPROTECTED_PROPERTIESFILE]="RBK0290W: Konfigurationsdatei %s ist nicht geschützt"
MSG_IMG_BOOT_FSCHECK_FAILED=291
MSG_EN[$MSG_IMG_BOOT_FSCHECK_FAILED]="RBK0291E: Bootpartition check failed with RC %s"
MSG_DE[$MSG_IMG_BOOT_FSCHECK_FAILED]="RBK0291E: Bootpartitioncheck endet fehlerhaft mit RC %s"
MSG_IMG_BOOT_CHECK_STARTED=292
MSG_EN[$MSG_IMG_BOOT_CHECK_STARTED]="RBK0292I: Bootpartition check started"
MSG_DE[$MSG_IMG_BOOT_CHECK_STARTED]="RBK0292I: Bootpartitionscheck gestartet"
MSG_NO_PARTUUID_SYNCHRONIZED=293
MSG_EN[$MSG_NO_PARTUUID_SYNCHRONIZED]="RBK0293W: No PARTUUID updated in %s for %s. Backup may not boot correctly"
MSG_DE[$MSG_NO_PARTUUID_SYNCHRONIZED]="RBK0293W: Es konnte keine PARTUUID in %s für %s erneuert werden. Das Backup könnte nicht starten"
MSG_CURRENT_CONFIGURATION_UPDATE_REQUIRED=294
MSG_EN[$MSG_CURRENT_CONFIGURATION_UPDATE_REQUIRED]="RBK0294I: Current configuration version %s has to be be updated to %s"
MSG_DE[$MSG_CURRENT_CONFIGURATION_UPDATE_REQUIRED]="RBK0294I: Aktuelle Konfigurationsversion %s muss auf Version %s upgraded werden"
MSG_SYNC_CMDLINE_FSTAB=295
MSG_EN[$MSG_SYNC_CMDLINE_FSTAB]="RBK0295I: Synchronizing %s and %s"
MSG_DE[$MSG_SYNC_CMDLINE_FSTAB]="RBK0295I: %s und %s werden synchronisiert"
OVERLAY_FILESYSTEM_NOT_SUPPORTED=296
MSG_EN[$OVERLAY_FILESYSTEM_NOT_SUPPORTED]="RBK0296E: Overlay filesystem is not supported"
MSG_DE[$OVERLAY_FILESYSTEM_NOT_SUPPORTED]="RBK0296E: Overlayfilesystem wird nicht unterstützt"
MSG_PARTITIONS_EXTEND_DISK_SIZE=297
MSG_EN[$MSG_PARTITIONS_EXTEND_DISK_SIZE]="RBK0297E: Partitioning exceeds disk size"
MSG_DE[$MSG_PARTITIONS_EXTEND_DISK_SIZE]="RBK0297E: Partitionierung größer als Diskgröße"
#MSG_UNSUPPORTED_PARTITIONING=298
#MSG_EN[$MSG_UNSUPPORTED_PARTITIONING]="RBK0298E: Filesystem %1 on boot and/or %2 on root not supported"
#MSG_DE[$MSG_UNSUPPORTED_PARTITIONING]="RBK0298E: Filesystem %1 auf boot und/oder %2 auf root ist nicht unterstützt"
MSG_BACKUPDIR_CREATED=299
MSG_EN[$MSG_BACKUPDIR_CREATED]="RBK0299I: Backup directory %s created"
MSG_DE[$MSG_BACKUPDIR_CREATED]="RBK0299I: Backupverzeichnis %s erstellt"
MSG_ADJUSTING_LAST=300
MSG_EN[$MSG_ADJUSTING_LAST]="RBK0300I: Adjusting last partition from %s to %s"
MSG_DE[$MSG_ADJUSTING_LAST]="RBK0300I: Letzte Partition wird von %s auf %s angepasst"
MSG_TEMPMOVE_FAILED=301
MSG_EN[$MSG_TEMPMOVE_FAILED]="RBK0301E: Move of temporary backup directory failed with RC %s"
MSG_DE[$MSG_TEMPMOVE_FAILED]="RBK0301E: Move des temporären Backupverzeichnisses fehlerhaft beendet mit RC %s"
MSG_RESIZED_PARTITION_TOO_SMALL=302
MSG_EN[$MSG_RESIZED_PARTITION_TOO_SMALL]="RBK0302E: Partition %s on %s with %s is too small. Missing at least %s"
MSG_DE[$MSG_RESIZED_PARTITION_TOO_SMALL]="RBK0302E: Zu resizende Partition %s auf %s mit %s is zu klein. Es fehlen mindestens %s"
MSG_SKIP_PARTITION_RESTORE=303
MSG_EN[$MSG_SKIP_PARTITION_RESTORE]="RBK0303W: Partition %s was not restored"
MSG_DE[$MSG_SKIP_PARTITION_RESTORE]="RBK0303W: Partition %s wurde nicht zurückgespielt"
MSG_PARTITION_RESTORE_NO_BOOT_POSSIBLE=304
MSG_EN[$MSG_PARTITION_RESTORE_NO_BOOT_POSSIBLE]="RBK0304W: Not all OS partitions were restored. System may not boot"
MSG_DE[$MSG_PARTITION_RESTORE_NO_BOOT_POSSIBLE]="RBK0304W: Nicht alle OS Partitionen wurden zurückgespielt. Das System könnte nicht booten"
MSG_RESTORING_PARTITIONS=305
MSG_EN[$MSG_RESTORING_PARTITIONS]="RBK0305W: Restoring partitions %s to %s"
MSG_DE[$MSG_RESTORING_PARTITIONS]="RBK0305W: Partitionen %s werden auf %s zurüchgespielt"
#MSG_ANSWER_ALL=306
#MSG_EN[$MSG_ANSWER_ALL]="all"
#MSG_DE[$MSG_ANSWER_ALL]="Alle"
MSG_UPDATING_UUIDS=319
MSG_EN[$MSG_UPDATING_UUIDS]="RBK0319I: Generating new UUIDs"
MSG_DE[$MSG_UPDATING_UUIDS]="RBK0319I: Neue UUIDs werden generiert"
MSG_REMOVING_BACKUP_NO_FILE=320
MSG_EN[$MSG_REMOVING_BACKUP_NO_FILE]="RBK0320I: Removing incomplete backup. This may take some time. Please be patient"
MSG_DE[$MSG_REMOVING_BACKUP_NO_FILE]="RBK0320I: Unvollständiges Backup wird gelöscht. Das kann etwas dauern. Bitte Geduld"
#MSG_SAVING_LOG=321
#MSG_EN[$MSG_SAVING_LOG]="RBK0321I: Saving logfile"
#MSG_DE[$MSG_SAVING_LOG]="RBK0321I: Logdatei wird gesichert"
MSG_ADJUSTING_WARNING_P=322
MSG_EN[$MSG_ADJUSTING_WARNING_P]="RBK0322W: Target %s with %s is smaller than backup source with %s. Last partition will be truncated accordingly. NOTE: Restore may fail if the root partition will become too small"
MSG_DE[$MSG_ADJUSTING_WARNING_P]="RBK0322W: Ziel %s mit %s ist kleiner als die Backupquelle mit %s. Die letzte Partition wird entsprechend verkleinert. HINWEIS: Der Restore kann fehlschlagen wenn sie zu klein wird"
MSG_ADJUSTING_WARNING_P2=323
MSG_EN[$MSG_ADJUSTING_WARNING_P2]="RBK0323I: Target %s with %s is larger than backup source with %s. Last partition will be expanded accordingly to use the whole available space"
MSG_DE[$MSG_ADJUSTING_WARNING_P2]="RBK0323I: Ziel %s mit %s ist größer als die Backupquelle mit %s. Die letzte Partition wird entsprechend vergrößert um den ganzen verfügbaren Speicherplatz zu benutzen"
MSG_NOT_ALL_OS_PARTITIONS_SAVED=324
MSG_EN[$MSG_NOT_ALL_OS_PARTITIONS_SAVED]="RBK0324W: Not all OS partitions saved. Backup will not boot"
MSG_DE[$MSG_NOT_ALL_OS_PARTITIONS_SAVED]="RBK0324W: Es werden nicht alle OS Partition gesichert und das Backup wird nicht starten"
#MSG_WARN_RESTORE_PARTITION_DEVICE_UPDATED=325
#MSG_EN[$MSG_WARN_RESTORE_PARTITION_DEVICE_UPDATED]="RBK0325W: Device %s will be updated"
#MSG_DE[$MSG_WARN_RESTORE_PARTITION_DEVICE_UPDATED]="RBK0325W: Gerät %s wird aktualisiert"
MSG_SKIP_FORMATING=326
MSG_EN[$MSG_SKIP_FORMATING]="RBK0326W: Partitions will not be formatted"
MSG_DE[$MSG_SKIP_FORMATING]="RBK0326W: Partitionen werden nicht formatiert"
MSG_NOT_ALL_PREVIOUS_PARTITIONS_SAVED=327
MSG_EN[$MSG_NOT_ALL_PREVIOUS_PARTITIONS_SAVED]="RBK0327E: Not all partitions which were saved in the previous backup are included in option -T. Missing \"%s\""
MSG_DE[$MSG_NOT_ALL_PREVIOUS_PARTITIONS_SAVED]="RBK0327E: Nicht alle Partitionen die im vorhergehenden Backup gesichert wurden werden mit der Option -T gesichert. Es fehlen \"%s\""
MSG_NO_BOOTDEVICE_MOUNTED=328
MSG_EN[$MSG_NO_BOOTDEVICE_MOUNTED]="RBK0328E: Boot device %s not mounted"
MSG_DE[$MSG_NO_BOOTDEVICE_MOUNTED]="RBK0328E: Bootgerät %s ist nicht gemounted"
MSG_PARTITIONS_FORMATED=329
MSG_EN[$MSG_PARTITIONS_FORMATED]="RBK0329W: Partitions %1 will be formatted"
MSG_DE[$MSG_PARTITIONS_FORMATED]="RBK0329W: Partitionen %1 werden formatiert"
MSG_MISSING_PARTITIONS_NOT_SAVED=330
MSG_EN[$MSG_MISSING_PARTITIONS_NOT_SAVED]="RBK0330W: Not all partitions which were saved in the previous backup are included. Missing \"%s\""
MSG_DE[$MSG_MISSING_PARTITIONS_NOT_SAVED]="RBK0330W: Nicht alle Partitionen die im vorhergehenden Backup gesichert wurden werden gesichert. Es fehlen \"%s\""
MSG_NO_SKIP_FORMAT_POSSIBLE=331
MSG_EN[$MSG_NO_SKIP_FORMAT_POSSIBLE]="RBK0331E: Option -00 is only available for backuptype rsync"
MSG_DE[$MSG_NO_SKIP_FORMAT_POSSIBLE]="RBK0331E: Option -00 ist nur mit dem Backuptyp rsync möglich"
MSG_GENERIC_WARNING=332
MSG_EN[$MSG_GENERIC_WARNING]="RBK0332W: %s"
MSG_DE[$MSG_GENERIC_WARNING]="RBK0332W: %s"
MSG_EXISTING_BACKUP=333
MSG_EN[$MSG_EXISTING_BACKUP]="RBK0333I: Existing backup: %s"
MSG_DE[$MSG_EXISTING_BACKUP]="RBK0333I: Existierendes Backup: %s"
MSG_NORMAL_RECYCLE_FILE_WOULD_BE_DELETED=334
MSG_EN[$MSG_NORMAL_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0334W: Backup strategy would delete %s"
MSG_DE[$MSG_NORMAL_RECYCLE_FILE_WOULD_BE_DELETED]="RBK0334W: Backup Strategie würde %s Backup löschen"
MSG_BACKUP_NAMING_CHANGE=335
MSG_EN[$MSG_BACKUP_NAMING_CHANGE]="RBK0335W: With raspiBackup version %s the naming of the backup directories changed!"
MSG_DE[$MSG_BACKUP_NAMING_CHANGE]="RBK0335W: Ab raspiBackup Version %s hat sich die Bezeichnung der Backup-Verzeichnisse geändert!"
MSG_OLD_NAME_BACKUPS_FOUND=336
MSG_EN[$MSG_OLD_NAME_BACKUPS_FOUND]="RBK0336W: Old-named backups found without OS info in its directory name:"
MSG_DE[$MSG_OLD_NAME_BACKUPS_FOUND]="RBK0336W: Backups mit alter Bezeichnung ohne OS-Info im Verzeichnisnamen gefunden:"
MSG_OLD_NAME_BACKUPS_HANDLING_INFO=337
MSG_EN[$MSG_OLD_NAME_BACKUPS_HANDLING_INFO]="RBK0337W: They are not included in the backup recycle process and have to be deleted manually"
MSG_DE[$MSG_OLD_NAME_BACKUPS_HANDLING_INFO]="RBK0337W: Diese werden nicht im Backuprecycleprozess berücksichtigt und müssen manuell gelöscht werden"
MSG_OLD_NAME_BACKUPS_COUNTER_INFO=338
MSG_EN[$MSG_OLD_NAME_BACKUPS_COUNTER_INFO]="RBK0338W: Note: This message will be shown again %s times"
MSG_DE[$MSG_OLD_NAME_BACKUPS_COUNTER_INFO]="RBK0338W: Hinweis: Diese Meldung wird weitere %s Mal angezeigt werden"
MSG_OPTION_T_NOT_ALLOWED=339
MSG_EN[$MSG_OPTION_T_NOT_ALLOWED]="RBK0339E: Option -T not allowed for normal mode backup"
MSG_DE[$MSG_OPTION_T_NOT_ALLOWED]="RBK0339E: Option -T ist für einen normales Backup nicht erlaubt"
MSG_RESTORE_TIME=340
MSG_EN[$MSG_RESTORE_TIME]="RBK0340I: Restore time: %s:%s:%s"
MSG_DE[$MSG_RESTORE_TIME]="RBK0340I: Restorezeit: %s:%s:%s"
MSG_TAR_BOOT_BACKUP_NOT_POSSIBLE=341
MSG_DE[$MSG_TAR_BOOT_BACKUP_NOT_POSSIBLE]="RBK0341E: Option -B ist für einen partitionsorientierten Backup nicht erlaubt"
MSG_EN[$MSG_TAR_BOOT_BACKUP_NOT_POSSIBLE]="RBK0341E: Option -B not allowed for partition orientierted backup"
MSG_PARTITION_CHECK_EXECUTED=342
MSG_EN[$MSG_PARTITION_CHECK_EXECUTED]="RBK0342I: Executing filesystem check on %s"
MSG_DE[$MSG_PARTITION_CHECK_EXECUTED]="RBK0342I: Dateisystemcheck wird auf %s durchgeführt"
MSG_PARTITION_CHECK_FAILED=343
MSG_EN[$MSG_PARTITION_CHECK_FAILED]="RBK0343E: Filesystem check failed on %s with RC %s"
MSG_DE[$MSG_PARTITION_CHECK_FAILED]="RBK0343E: Dateisystemcheck auf %s fehlerhaft beendet mit RC %s"
MSG_NO_BOOTPARTITION_MOUNTED=344
MSG_EN[$MSG_NO_BOOTPARTITION_MOUNTED]="RBK0344E: No mounted boot partition detected"
MSG_DE[$MSG_NO_BOOTPARTITION_MOUNTED]="RBK0344E: Keine gemountete Bootpartition gefunden"
MSG_BACKUPDIR_MOVED=345
MSG_EN[$MSG_BACKUPDIR_MOVED]="RBK0345I: Temporary backup directory %s moved to %s"
MSG_DE[$MSG_BACKUPDIR_MOVED]="RBK0345I: Temporäres Backupverzeichnis %s wird in %s verschoben"
MSG_SYNCING_PARTITIONFILE=346
MSG_EN[$MSG_SYNCING_PARTITIONFILE]="RBK0346I: Syncing partition %s"
MSG_DE[$MSG_SYNCING_PARTITIONFILE]="RBK0346I: Synchronisiere Partition %s"
MSG_PARTITIONS_BACKUP_STARTED=347
MSG_EN[$MSG_PARTITIONS_BACKUP_STARTED]="RBK0347I: Partition oriented backup of type %s started for partitions %s"
MSG_DE[$MSG_PARTITIONS_BACKUP_STARTED]="RBK0347I: Partitionsorientierte Backup vom Typ %s started für die Partitionen %s"
MSG_UMOUNT_MOUNTED_PARTITIONS=348
MSG_EN[$MSG_UMOUNT_MOUNTED_PARTITIONS]="RBK0348W: Umounting all mounted partitions of %s"
MSG_DE[$MSG_UMOUNT_MOUNTED_PARTITIONS]="RBK0348W: Sollen alle gemounteten Partitionen von %s umounted werden"
MSG_UMOUNT_MOUNTED_PARTITIONS_FAILED=349
MSG_EN[$MSG_UMOUNT_MOUNTED_PARTITIONS_FAILED]="RBK0349E: Umounting mounted partitions of %s failed"
MSG_DE[$MSG_UMOUNT_MOUNTED_PARTITIONS_FAILED]="RBK0349E: Umount von gemounteten Paritionen von %s nicht möglich"
MSG_UNSUPPORTED_TAR_COMPRESS_TOOL=350
MSG_EN[$MSG_UNSUPPORTED_TAR_COMPRESS_TOOL]="RBK0350E: Unsupported tar compression tool %si. Supported tools are bzip2,gzip,lzip,lzma,lzop,xz and zstd"
MSG_DE[$MSG_UNSUPPORTED_TAR_COMPRESS_TOOL]="RBK0350E: Nicht unterstütztes tar Kompressionstool %s. Unterstützte Tools sind bzip2,gzip,lzip,lzma,lzop,xz und zstd"
MSG_TAR_COMPRESS_TOOL_USED=351
MSG_EN[$MSG_TAR_COMPRESS_TOOL_USED]="RBK0351I: Using custom tar compression tool %s"
MSG_DE[$MSG_TAR_COMPRESS_TOOL_USED]="RBK0351I: Konfigurierbares tar Kompressionstool %s wird genutzt"
MSG_TAR_COMPRESS_TOOL_NOT_FOUND=352
MSG_EN[$MSG_TAR_COMPRESS_TOOL_NOT_FOUND]="RBK0352E: Custom tar compression tool %s not installed"
MSG_DE[$MSG_TAR_COMPRESS_TOOL_NOT_FOUND]="RBK0352E: Konfigurierbares tar Kompressionstool %s nicht installiert"
MSG_OPTION_TAR_COMPRESS_TOOL_NOT_SUPPORTED=353
MSG_EN[$MSG_OPTION_TAR_COMPRESS_TOOL_NOT_SUPPORTED]="RBK0353E: Custom tar compression not possible for backuptype %s"
MSG_DE[$MSG_OPTION_TAR_COMPRESS_TOOL_NOT_SUPPORTED]="RBK0353E: Konfigurierbare tar Kompression nicht für Backuptyp %s möglich"
MSG_EXTERNAL_ROOTPARTITION_UNSUPPORTED=354
MSG_EN[$MSG_EXTERNAL_ROOTPARTITION_UNSUPPORTED]="RBK0354E: External root partition not supported with option \"-P\""
MSG_DE[$MSG_EXTERNAL_ROOTPARTITION_UNSUPPORTED]="RBK0354E: Externe Rootpartition ist mit Option -P nicht unterstützt"
MSG_OPTION_ACLS_DISABLED=355
MSG_EN[$MSG_OPTION_ACLS_DISABLED]="RBK0355I: ACLs are not copied"
MSG_DE[$MSG_OPTION_ACLS_DISABLED]="RBK0355I: ACLs werden nicht kopiert"
MSG_SYNCING_SECOND_PARTITION=356
MSG_EN[$MSG_SYNCING_SECOND_PARTITION]="RBK0356I: Synchronizing second partition (root partition) on %s"
#shellcheck disable=SC2034
MSG_DE[$MSG_SYNCING_SECOND_PARTITION]="RBK0356I: Zweite Partition (Rootpartition) auf %s wird synchronisiert"

declare -A MSG_HEADER=( ['I']="---" ['W']="!!!" ['E']="???" )

# setup trap function
# trap function then will be called with trap as argument
#
# borrowed from # from http://stackoverflow.com/a/2183063/804678

function trapWithArg() { # function trap1 trap2 ... trapn
	logEntry "$*"
	local func="$1" ; shift
	for sig ; do

# Use single quotes, otherwise this expands now rather than when signalled.
# shellcheck disable=SC2064
		trap "$func $sig" "$sig"
	done
	logExit
}

LOG_INDENT_INC=4

# Create message and substitute parameters

function getMessageText() { # messagenumber parm1 parm2 ...

	local msg p i s

	msgVar="MSG_${LANGUAGE}"

	if [[ -n ${SUPPORTED_LANGUAGES[$LANGUAGE]} ]]; then
# Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet).
#shellcheck disable=SC1087
		msgVar="$msgVar[$1]"
		msg=${!msgVar}
		if [[ -z $msg ]]; then # no translation found
			msg="${MSG_EN[$1]}" # fallback into english
		fi
	else
		msg="${MSG_EN[$1]}" # fallback into english
	fi

	if [[ -z $msg ]]; then
		msg="${MSG_EN[$MSG_UNDEFINED]} $1"
	fi

	shift

	# Change messages with old message format using %s, %s ... to new format using %1, %2 ...
	i=1
	while [[ "$msg" =~ %s ]]; do
# See if you can use ${variable//search/replace} instead
#shellcheck disable=SC2001
		msg="$(sed "s|%s|%$i|" <<<"$msg" 2>/dev/null)" # have to use explicit command name
		(( i++ ))
	done

	for ((i = 1; $i <= $#; i++)); do # substitute all message parameters
		p=${!i}
# See if you can use ${variable//search/replace} instead
#shellcheck disable=SC2001
		p="$(sed 's/\&/\\\&/g' <<< "$p")" # escape &
		(( s=$i ))
		s="%$s"
# See if you can use ${variable//search/replace} instead
#shellcheck disable=SC2001
		msg="$(sed "s|$s|$p|" <<<"$msg" 2>/dev/null)" # have to use explicit command name
	done

# See if you can use ${variable//search/replace} instead
#shellcheck disable=SC2001
	msg="$(sed "s/%[0-9]+//g" <<<"$msg" 2>/dev/null)" # delete trailing %n definitions

	local msgPref=${msg:0:3}
	if [[ $msgPref == "RBK" ]]; then # RBK0001E
		local severity=${msg:7:1}
		if [[ "$severity" =~ [EWI] ]]; then
			local msgHeader=${MSG_HEADER[$severity]}
			echo "$msgHeader $msg"
		else
			echo "$msg"
		fi
	else
		echo "$msg"
	fi

}

# --- Helper function to extract the message text in German or English and insert message parameters

function getMessage() { # messageNumber parm1 parm2

	local msg
	msg="$(getMessageText "$@")"
	echo "$msg"
}

function logItem() { # message
	logIntoOutput "$LOG_TYPE_DEBUG" "---" "" "$@"
}

function logEntry() { # message
	logIntoOutput "$LOG_TYPE_DEBUG" "-->" "" "${FUNCNAME[1]} $*"
	(( LOG_INDENT+=LOG_INDENT_INC ))
}

function logExit() { # message
	(( LOG_INDENT-=LOG_INDENT_INC ))
	logIntoOutput "$LOG_TYPE_DEBUG" "<--" "" "${FUNCNAME[1]} $*"
}

function logSystem() {
	logEntry
	logCommand "uname -a"
	[[ -f /etc/os-release ]] &&	logCommand "cat /etc/os-release"
	[[ -f /etc/debian_version ]] &&	logCommand "cat /etc/debian_version"
	[[ -f /etc/fstab ]] &&	logCommand "cat /etc/fstab"
	[[ -f /proc/cpuinfo ]] && logCommand "grep ^Model /proc/cpuinfo"
	logCommand "locale"
	logExit
}

function logCommand() { # command
	(( LOG_INDENT+=LOG_INDENT_INC ))
	local callerLineNo=${BASH_LINENO[0]}
	logIntoOutput $LOG_TYPE_DEBUG "***" "$callerLineNo" "$1"
	local r
	r="$($1 2>&1)"
	logIntoOutput $LOG_TYPE_DEBUG "   " "$callerLineNo" "$r"
	(( LOG_INDENT-=LOG_INDENT_INC ))
}

function logSystemServices() {
	logEntry
	if (( $SYSTEMSTATUS )); then
		logCommand 'service --status-all'
	fi
	logExit
}

function logIntoOutput() { # logtype prefix lineno message

	[[ "$LOG_DEBUG" != "$LOG_LEVEL" ]] && return

	local dte type prefix lineno indent line

	type="${LOG_TYPEs[$1]}"
	shift
	prefix="$1"
	shift
	lineno="$1"
	shift
	[[ -z $lineno ]] && lineno=${BASH_LINENO[1]}
	dte=$(date +%Y%m%d-%H%M%S)
	# This format string has 2 variables, but is passed 1 argument.
	#shellcheck disable=SC2183
	indent=$(printf '%*s' "$LOG_INDENT")
	local m

	while IFS= read -r line; do
		printf -v m "%s %04d: %s %s %s" "$type" "$lineno" "$indent" "$prefix" "$line"
		case $LOG_OUTPUT in
			"$LOG_OUTPUT_VARLOG" | "$LOG_OUTPUT_BACKUPLOC" | "$LOG_OUTPUT_HOME" )
				echo "$dte $m" >> "$LOG_FILE"
				;;
			*)
				echo "$dte $m" >> "$LOG_FILE"
				;;
		esac
	done <<< "$@"
}

# log everything written to stdout or stderr into log file
function logEnable() {

	LOG_FILE="$TEMP_LOG_FILE"
	MSG_FILE="$TEMP_MSG_FILE"
	rm -f "$LOG_FILE" &>/dev/null
	rm -f "$MSG_FILE" &>/dev/null

	logItem "Logfiles used: $LOG_FILE and $MSG_FILE"

	touch "$LOG_FILE"
	touch "$MSG_FILE"

	# save file descriptors, see https://unix.stackexchange.com/questions/80988/how-to-stop-redirection-in-bash
	exec 3>&1 4>&2
	# see https://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself
	exec 1> >(stdbuf -i0 -o0 -e0 tee -ia "$LOG_FILE")
	exec 2> >(stdbuf -i0 -o0 -e0 tee -ia "$LOG_FILE" >&2)

	logItem "$GIT_CODEVERSION"
	local sep=
	sep="$(getMessage $MSG_SENSITIVE_SEPARATOR)"
	local warn
	warn="$(getMessage $MSG_SENSITIVE_WARNING)"
	logItem "$sep"
	logItem "$warn"
	logItem "$sep"
}

# move temporary log file to it's destination
function logFinish() {

	logEntry

	local DEST_LOGFILE DEST_MSGFILE

	rm -f "$FINISH_LOG_FILE"

	if [[ $LOG_LEVEL != "$LOG_NONE" ]]; then
		# 1) error occured and logoutput is backup location which was deleted or fake mode
		# 2) fake
		# 3) backup location was already deleted by SR
		if [[ "$LOG_OUTPUT" =~ $LOG_OUTPUT_IS_NO_USERDEFINEDFILE_REGEX ]]; then			# no -L used
			logItem "$rc $LOG_OUTPUT $FAKE"
			if [[ (( $rc != 0 )) && (( $LOG_OUTPUT == "$LOG_OUTPUT_BACKUPLOC" )) ]] \
				|| (( $FAKE )) \
				|| [[ ! -e $BACKUPTARGET_DIR ]]; then
				LOG_OUTPUT=$LOG_OUTPUT_HOME 			# save log in home directory
				logItem "LOG_OUTPUT=$LOG_OUTPUT"
			fi
		fi

		logItem "LOG_OUTPUT: $LOG_OUTPUT"

		case $LOG_OUTPUT in
			"$LOG_OUTPUT_VARLOG" )
				LOG_BASE="/var/log/$MYNAME"
				if [[ ! -d "${LOG_BASE}" ]]; then
					if ! mkdir -p "${LOG_BASE}" &>> "$FINISH_LOG_FILE"; then
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "${LOG_BASE}"
						exitError $RC_CREATE_ERROR
					fi
				fi
				DEST_LOGFILE="$LOG_BASE/$HOSTNAME$LOGFILE_EXT"
				DEST_MSGFILE="$LOG_BASE/$HOSTNAME$MSGFILE_EXT"
				;;
			"$LOG_OUTPUT_HOME")
				DEST_LOGFILE="$CALLING_HOME/${MYNAME}$LOGFILE_EXT"
				DEST_MSGFILE="$CALLING_HOME/${MYNAME}$MSGFILE_EXT"
				;;
			"$LOG_OUTPUT_BACKUPLOC")
				DEST_LOGFILE="$BACKUPTARGET_DIR/${MYNAME}$LOGFILE_EXT"
				DEST_MSGFILE="$BACKUPTARGET_DIR/${MYNAME}$MSGFILE_EXT"
				;;
			*) # option -L <filename>
				DEST_LOGFILE="$LOG_OUTPUT$LOGFILE_EXT"
				DEST_MSGFILE="$LOG_OUTPUT$MSGFILE_EXT"
		esac

		logItem "DEST_LOGFILE: $DEST_LOGFILE"
		logItem "DEST_MSGFILE: $DEST_MSGFILE"

		if [[ "$LOG_FILE" != "$DEST_LOGFILE" ]]; then
			if [[ "$LOG_OUTPUT" == "$LOG_OUTPUT_VARLOG" ]]; then
				logItem "Appending Logfile: $LOG_FILE to $DEST_LOGFILE"
				cat "$LOG_FILE" 1>> "$DEST_LOGFILE" 2>>"$FINISH_LOG_FILE"
				rm "$LOG_FILE" &>>"$FINISH_LOG_FILE"
			else
				logItem "Moving Logfile: $LOG_FILE to $DEST_LOGFILE"
				mv "$LOG_FILE" "$DEST_LOGFILE" &>>"$FINISH_LOG_FILE"
			fi
			LOG_FILE="$DEST_LOGFILE"		# now final log location was established. log anything else in final log file
			logItem "Logfile used: $LOG_FILE"
		fi
		if [[ "$MSG_FILE" != "$DEST_MSGFILE" ]]; then
			if [[ "$LOG_OUTPUT" == "$LOG_OUTPUT_VARLOG" ]]; then
				logItem "Appending Msgfile: $MSG_FILE to $DEST_MSGFILE"
				cat "$MSG_FILE" 1>> "$DEST_MSGFILE" 2>>"$FINISH_LOG_FILE"
				rm "$MSG_FILE" &>>"$FINISH_LOG_FILE"
			else
				logItem "Moving Msgfile: $MSG_FILE to $DEST_MSGFILE"
				mv "$MSG_FILE" "$DEST_MSGFILE" &>>"$FINISH_LOG_FILE"
			fi
			MSG_FILE="$DEST_MSGFILE"		# now final msg location was established. log anything else in final log file
			logItem "Msgfile used: $MSG_FILE"
		fi

		chown "$CALLING_USER:$CALLING_USER" "$DEST_LOGFILE" &>>"$FINISH_LOG_FILE" # make sure logfile is owned by caller
		chown "$CALLING_USER:$CALLING_USER" "$DEST_MSGFILE" &>>"$FINISH_LOG_FILE" # make sure msgfile is owned by caller

		if [[ -e $FINISH_LOG_FILE ]]; then					# append optional final messages
			logCommand "cat $FINISH_LOG_FILE"
			cat "$FINISH_LOG_FILE" &>> "$DEST_LOGFILE"
			rm -f "$FINISH_LOG_FILE" &>> "$DEST_LOGFILE"
		fi

		if (( !$INCLUDE_ONLY )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SAVED_LOG "$LOG_FILE"
		fi

		if [[ $TEMP_LOG_FILE != "$DEST_LOGFILE" ]]; then		# logfile was copied somewhere, delete temp logfile
			rm -f "$TEMP_LOG_FILE" &>> "$LOG_FILE"
		fi

	fi

	logExit
}

# Borrowed from http://stackoverflow.com/questions/85880/determine-if-a-function-exists-in-bash

fn_exists() {
  [[ $(type -t "$1") == function ]]
}

# Borrowed from http://blog.yjl.im/2012/01/printing-out-call-stack-in-bash.html

function logStack () {
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_STACK_TRACE
	local i=0
	local FRAMES=${#BASH_LINENO[@]}
	# FRAMES-2 skips main, the last one in arrays
	for ((i=FRAMES-2; i>=0; i--)); do
		echo '  File' \""${BASH_SOURCE[i+1]}"\", line "${BASH_LINENO[i]}", in "${FUNCNAME[i+1]}"
		# Grab the source code of the line
		sed -n "${BASH_LINENO[i]}{s/^/    /;p}" "${BASH_SOURCE[i+1]}"
	done
}

function callExtensions() { # extensionplugpoint rc

	logEntry "$1"

	local extension rc=0

	if [[ "$1" == "$EMAIL_EXTENSION" ]]; then
		local extensionFileName="${MYNAME}_${EMAIL_EXTENSION}.sh"
		shift 1
		local args=( "$@" )

		if command -v "$extensionFileName" &>/dev/null; then
			writeToConsole $MSG_LEVEL_DETAILED $MSG_EXTENSION_CALLED "$extensionFileName"
			$extensionFileName "${args[@]}"
			rc=$?
			logItem "Extension RC: $rc"
			if (( $rc != 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_EXTENSION_FAILED "$extensionFileName" "$rc"
			fi
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_EMAIL_EXTENSION_NOT_FOUND "$extensionFileName"
		fi
	else

		local extensions="$EXTENSIONS"
		local xEnabled

		(( $RESTORE )) && extensions="$RESTORE_EXTENSIONS"

		for extension in $extensions; do

			if [[ "$1" == "$NOTIFICATION_BACKUP_EXTENSION" ]]; then
				local extensionFileName="${MYNAME}_${extension}.sh" # notification has no pre, post and ready
			else
				local extensionFileName="${MYNAME}_${extension}_$1.sh"
			fi

			if command -v "$extensionFileName" &>/dev/null; then
				logItem "Calling $extensionFileName $2"

				local extension_call=0

				writeToConsole $MSG_LEVEL_DETAILED $MSG_EXTENSION_CALLED "$extensionFileName"

				if [[ ${extension} == "$NOTIFICATION_BACKUP_EXTENSION" ]]; then
					extension_call=1
				fi

				if (( extension_call )); then
					xEnabled=0
					if [ -o xtrace ]; then	# disable xtrace
						xEnabled=1
						set +x
					fi
				fi

				executeShellCommand ". $extensionFileName $2"
				rc=$?
				if (( extension_call )); then
					if (( $xEnabled )); then	# enable xtrace again
						set -x
					fi
				fi

				logItem "Extension RC: $rc"
				if (( $rc != 0 )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_EXTENSION_FAILED "$extensionFileName" "$rc"
				fi
			else
				logItem "$extensionFileName not found - skipping"
			fi
		done
	fi

	logExit

	return $rc
}

# usage

function usage() {

	local activeLang=$FALLBACK_LANGUAGE # fallback language

	[[ -n ${SUPPORTED_LANGUAGES[$LANGUAGE]} ]] && activeLang="$LANGUAGE"

	#  Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	#shellcheck disable=SC2207
	NO_YES=( $(getMessage $MSG_NO_YES) )

	local func="usage${activeLang}"

	if ! fn_exists "$func"; then
		func="usage$FALLBACK_LANGUAGE"
	fi

	$func

}

# Write message

function writeToConsole() {  # msglevel messagenumber message
	local msg level timestamp
	(( $noNL )) && noNL="-n"

	level=$1
	shift

	msg="$(getMessageText "$@")"

	local msgNumber
	msgNumber=$(cut -f 2 -d ' ' <<< "$msg")
	local msgSev=
	msgSev=${msgNumber:7:1}

	if [[ $msgSev == "W" ]]; then
		WARNING_MESSAGE_WRITTEN=1
		NEWS_AVAILABLE=1
	fi

	if (( $level <= $MSG_LEVEL )); then

# --- RBK0105I: Deleting new backup directory /backup/obelix/obelix-rsync-backup-20180912-215541.
# ??? RBK0005E: Backup failed. Check previous error messages for details.

		if (( $TIMESTAMPS )); then
			timestamp="$(date +'%m-%d-%Y %T') "
		fi

		if (( $INTERACTIVE )); then
			local consoleMsg="$timestamp$msg"
			if [[ "$COLORING" =~ $COLORING_CONSOLE ]]; then
				consoleMsg="$(colorAnnotation $COLOR_TYPE_VT100 "$consoleMsg")"
			fi
			if [[ $msgSev == "E" ]]; then
				# Double quote to prevent globbing and word splitting.
				#shellcheck disable=SC2086
				echo $noNL -e "$consoleMsg" >&2
			else
				# Double quote to prevent globbing and word splitting.
				#shellcheck disable=SC2086
				echo $noNL -e "$consoleMsg" >&1
			fi
		fi

		if (( "$LOG_LEVEL" != "$LOG_NONE" )); then
			echo $noNL -e "$timestamp$msg" >> "$MSG_FILE"
		fi
	fi

	if (( ! $INTERACTIVE || $RESTORE )); then # don't write message twice into log for backup but once for restore
		local line
		while IFS= read -r line; do
			logIntoOutput $LOG_TYPE_MSG "$line"
		done <<< "$msg"
	fi

	unset noNL
}

function isUnsupportedVersion() {

	logEntry
	local rc=0
	[[ "$GIT_COMMIT" != "$SHA_PLACEHOLDER"  && "$GIT_DATE" != "$DATE_PLACEHOLDER" ]] && rc=1
	logExit $rc
	return $rc
}

function isSupportedEnvironment() {

	logEntry

	if (( $REGRESSION_TEST )); then
		logExit 0
		return 0
	fi

	local MODELPATH=/sys/firmware/devicetree/base/model
	local OSRELEASE=/etc/os-release
	local RPI_ISSUE=/etc/rpi-issue

	if [[ ! -e "$OSRELEASE" ]]; then
		logItem "$OSRELEASE not found"
		logExit 1
		return 1
	fi

	logItem "$(<"$OSRELEASE")"
	grep -q -E -i "^(NAME|ID)=.*ubuntu" "$OSRELEASE"
	local rc=$?

	IS_UBUNTU=$(( ! $rc ))
	logItem "IS_UBUNTU: $IS_UBUNTU"

#	Check it's Raspberry HW
	if [[ ! -e "$MODELPATH" ]]; then
		logItem "$MODELPATH not found"
		logExit 1
		return 1
	fi
	# See if you can use ${variable//search/replace} instead
	#shellcheck disable=SC2001
	logItem "Modelpath: $(sed 's/\x0/\n/g' <<< "$MODELPATH")"
	! grep -q -i "raspberry" "$MODELPATH" && return 1

#	OS was built for a Raspberry (RaspbainOS only)
	if [[ -e "$RPI_ISSUE" ]]; then
		logItem "$RPI_ISSUE: $(< $RPI_ISSUE)"
		logExit 0
		return 0
	fi
	logItem "$RPI_ISSUE not found"

	logExit $rc
	return $rc

}

# Create a backupfile FILE.bak from FILE. If this file already exists rename this file to FILE.n.bak when n is next backup number
# return filename created and error if a backup file cannot be created
function createBackupVersion() { # file

	logEntry

	local file="$1"
	local rc

	if [[ ! -f "$file" ]]; then
		logExit 1
		return 1
	fi

	if [[ -f "$file.bak" ]]; then												# .bak exists already
		local versions

		# Double quote to prevent globbing and word splitting.
		# shellcheck disable=SC2086
		versions="$(ls $file\.*\.bak -1 2>/dev/null)"

		if [[ -z $versions ]]; then												# no backup version detected
			versionNumber=1															# start with version 1
		else
			local last lastFile lastVersionNumber
			last="$(tail -n 1 <<< "$versions")" 								# extract highest version number
			lastFile="$(basename "$last")"
			lastVersionNumber="$(sed -E 's/.*([0-9]+)\.bak$/\1/' <<< $lastFile )"
			(( versionNumber = lastVersionNumber+1 ))							# use next version number
		fi

		local backupFile="$file.${versionNumber}.bak"
		logItem "Create version $backupFile"

		if ! mv "$file.bak" "$backupFile"; then
			logExit 1
			return 1
		fi
	fi

	cp -a "$file" "$file.bak"
	rc=$?

	echo "$file.bak"

	logExit "rc: $rc - $file.bak"
	return $rc	# return status of cp command
}

# Borrowed from http://unix.stackexchange.com/questions/44040/a-standard-tool-to-convert-a-byte-count-into-human-kib-mib-etc-like-du-ls1

function bytesToHuman() {
	local b d s S
	local sign=1
	b=${1:-0}; d=''; s=0; S=(Bytes {K,M,G,T,E,P,Y,Z}iB)
	if (( b < 0 )); then
		sign=-1
		(( b=-b ))
	fi
	while ((b > 1024)); do
		d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))"
		b=$((b / 1024))
		let s++
	done
	if (( sign < 0 )); then
		(( b=-b ))
	fi
	echo "$b$d ${S[$s]}"
}

function assertionFailed() { # lineno message
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_ASSERTION_FAILED "$GIT_COMMIT_ONLY" "$1" "$2"
	rc=$RC_ASSERTION
	logStack
	exit 127
}

function exitNormal() {
	saveVars
	rc=0
	exit 0
}

function saveVars() {
	if (( $UID == 0 )); then
		echo "BACKUP_TARGETDIR=\"$BACKUPTARGET_DIR\"" > "$VARS_FILE"
		echo "BACKUP_TARGETFILE=\"$BACKUPTARGET_FILE\"" >> "$VARS_FILE"
		echo "MSG_FILE=\"$MSG_FILE\"" >> "$VARS_FILE"
		echo "LOG_FILE=\"$LOG_FILE\"" >> "$VARS_FILE"
	fi
}

function exitError() { # {rc}

	logEntry "$1"
	if [[ -n "$1" ]]; then
		rc="$1"
	else
		assertionFailed $LINENO "Unkown exit error $rc"
	fi

	logExit "$rc"
	exit "$rc"
}

# ignore tool error if configured
function ignoreErrorRC() { # rc errors_to_ignore
	logEntry
	local rc="$1"
	if (( $rc != 0 )); then
		#Double quote array expansions to avoid re-splitting elements.
		#shellcheck disable=SC2068
		for i in ${@:2}; do
			if (( $i == $rc )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_TOOL_ERROR_SKIP "$BACKUPTYPE" "$rc"
				rc=0
				break
			fi
		done
	fi
	logExit "$rc"
	return "$rc"
}

function executeDD() { # cmd silent
	logEntry
	local rc cmd
	cmd="LC_ALL=C $1"
	logItem "$cmd"
	( eval "$cmd" 2>&1 1>&5 | grep -viE "records [in|out]| copied," | tee -a $MSG_FILE; exit ${PIPESTATUS[0]} ) 5>&1
	ignoreErrorRC $? "$2"
	rc=$?
	logExit "$rc"
	return "$rc"
}

# ((sh test.sh 2>&1 1>&3 | tee errors.log) 3>&1 | tee output.log) > /dev/null 2>&1

function executeRsync() { # cmd flagsToIgnore
	logEntry
	local rc cmd
	cmd="$1"
	logItem "$cmd"
	( eval "$cmd" 2>&1 1>&5 | tee -a $MSG_FILE $LOG_FILE) 5>&1
	ignoreErrorRC $? "$2"
	rc=$?
	logExit $rc
	return $rc
}

# Removing leading `/' from member names message is annoying. Use grep -v "Removing" to remove the message
# and use $PIPESTATUS and catch and return the tar RC

function executeTar() { # cmd flagsToIgnore
	logEntry
	local rc cmd
	cmd="LC_ALL=C $1"
	logItem "$cmd"
	( eval "$cmd" 2>&1 1>&5 | grep -iv " Removing" | tee -a $MSG_FILE $LOG_FILE; exit ${PIPESTATUS[0]} ) 5>&1
	ignoreErrorRC $? "$2"
	rc=$?
	logExit $rc
	return $rc
}

function executeShellCommand() { # command
	logEntry "$@"
	if (( $INTERACTIVE )); then
		eval "$1"
	else
		eval "$1 &>> $LOG_FILE"
	fi
	local rc=$?
	logExit "$rc"
	return $rc
}

# return 0 for ==, -1 for <, and 1 for >
# version format 0.1.2.3-ext, -ext will be discarded
function compareVersions() { # v1 v2

	logEntry "$1 $2"
	local v1 v2
	v1="$(sed 's/-.*$//' <<< "$1")"
	v2="$(sed 's/-.*$//' <<< "$2")"

	local v1e v2e IFS rc
	#Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
	#shellcheck disable=SC2206
	IFS="." v1e=( $v1 0 0 0 0 )
	#Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
	#shellcheck disable=SC2206
	IFS="." v2e=( $v2 0 0 0 0 )

	local rc=0
	for (( i=0; i<=3; i++ )); do
		if (( ${v1e[$i]} < ${v2e[$i]} )); then
			rc=-1
			break
		fi
		if (( ${v1e[$i]} > ${v2e[$i]} )); then
			rc=1
			break
		fi
	done
	echo $rc
	logExit $rc
	return
}

function repeat() { # char num
	local s
	s=$( yes 2>/dev/null "$1" | head -"$2" | tr -d "\n" )
	echo $s
}

# calculate time difference, return array with days, hours, minutes and seconds
function duration() { # startTime endTime
	factors=(86400 3600 60 1)
	local diff=$(( $2 - $1 ))
	local d i q
	i=0
	for f in "${factors[@]}"; do
		q=$(( diff / f ))
		diff=$(( diff - q * f ))
		d[i]=$(printf "%02d" $q)
		((i++))
	done
	echo "${d[@]}"
}

function logOptions() { # option state

	logEntry "$1"

	logItem "Options: $INVOCATIONPARMS"
	logItem "AFTER_STARTSERVICES=$AFTER_STARTSERVICES"
	logItem "APPEND_LOG=$APPEND_LOG"
	logItem "APPEND_LOG_OPTION=$APPEND_LOG_OPTION"
	logItem "BACKUPPATH=$BACKUPPATH"
	logItem "BACKUPTYPE=$BACKUPTYPE"
	logItem "BEFORE_STOPSERVICES=$BEFORE_STOPSERVICES"
	logItem "BOOT_DEVICE=$BOOT_DEVICE"
	logItem "CHECK_FOR_BAD_BLOCKS=$CHECK_FOR_BAD_BLOCKS"
	logItem "COLOR_CODES=${COLOR_CODES[*]}"
 	logItem "COLORING=$COLORING"
 	logItem "CONFIG_FILE=$CONFIG_FILE"
 	logItem "DD_BACKUP_SAVE_USED_PARTITIONS_ONLY=$DD_BACKUP_SAVE_USED_PARTITIONS_ONLY"
 	logItem "DD_BLOCKSIZE=$DD_BLOCKSIZE"
 	logItem "DD_PARMS=$DD_PARMS"
 	logItem "DD_WARNING=$DD_WARNING"
	logItem "DEPLOYMENT_HOSTS=$DEPLOYMENT_HOSTS"
	logItem "DYNAMIC_MOUNT=$DYNAMIC_MOUNT"
	logItem "EMAIL=$EMAIL"
	logItem "EMAIL_COLORING=$EMAIL_COLORING"
	logItem "EMAIL_PARMS=$EMAIL_PARMS"
	logItem "EXCLUDE_LIST=$EXCLUDE_LIST"
	logItem "EXTENSIONS=$EXTENSIONS"
	logItem "FAKE=$FAKE"
	logItem "FINAL_COMMAND=$FINAL_COMMAND"
	logItem "FORCE_EMAIL=$FORCE_EMAIL"
	logItem "HANDLE_DEPRECATED=$HANDLE_DEPRECATED"
	logItem "IGNORE_ADDITIONAL_PARTITIONS=$IGNORE_ADDITIONAL_PARTITIONS"
	logItem "IGNORE_MISSING_PARTITIONS=$IGNORE_MISSING_PARTITIONS"
	logItem "KEEPBACKUPS=$KEEPBACKUPS"
	logItem "KEEPBACKUPS_DD=$KEEPBACKUPS_DD"
	logItem "KEEPBACKUPS_DDZ=$KEEPBACKUPS_DDZ"
	logItem "KEEPBACKUPS_TAR=$KEEPBACKUPS_TAR"
	logItem "KEEPBACKUPS_TGZ=$KEEPBACKUPS_TGZ"
	logItem "KEEPBACKUPS_RSYNC=$KEEPBACKUPS_RSYNC"
	logItem "LANGUAGE=$LANGUAGE"
	logItem "LINK_BOOTPARTITIONFILES=$LINK_BOOTPARTITIONFILES"
	logItem "LOG_LEVEL=$LOG_LEVEL"
 	logItem "LOG_OUTPUT=$LOG_OUTPUT"
	logItem "MAIL_ON_ERROR_ONLY=$MAIL_ON_ERROR_ONLY"
	logItem "MAIL_PROGRAM=$EMAIL_PROGRAM"
	logItem "MSG_LEVEL=$MSG_LEVEL"
	logItem "NOTIFY_START=$NOTIFY_START"
	logItem "OLD_REMINDER_REPEAT=$OLD_REMINDER_REPEAT"
	logItem "PARTITIONBASED_BACKUP=$PARTITIONBASED_BACKUP"
	logItem "PARTITIONS_TO_BACKUP=$PARTITIONS_TO_BACKUP"
	logItem "PARTITIONS_TO_RESTORE=$PARTITIONS_TO_RESTORE"
	logItem "PUSHOVER_ADDITIONAL_OPTIONS=$PUSHOVER_ADDITIONAL_OPTIONS"
	logItem "PUSHOVER_DEVICE=$PUSHOVER_DEVICE"
	logItem "PUSHOVER_TOKEN=$PUSHOVER_TOKEN"
	logItem "PUSHOVER_USER=$PUSHOVER_USER"
	logItem "PUSHOVER_NOTIFICATIONS=$PUSHOVER_NOTIFICATIONS"
	logItem "PUSHOVER_SOUND_SUCCESS=$PUSHOVER_SOUND_SUCCESS"
	logItem "PUSHOVER_SOUND_FAILURE=$PUSHOVER_SOUND_FAILURE"
	logItem "PUSHOVER_PRIORITY_SUCCESS=$PUSHOVER_PRIORITY_SUCCESS"
	logItem "PUSHOVER_PRIORITY_FAILURE=$PUSHOVER_PRIORITY_FAILURE"
	logItem "REBOOT_SYSTEM=$REBOOT_SYSTEM"
	logItem "RESIZE_ROOTFS=$RESIZE_ROOTFS"
	logItem "RESTORE_DEVICE=$RESTORE_DEVICE"
	logItem "RESTORE_EXTENSIONS=$RESTORE_EXTENSIONS"
	logItem "RESTORE_REMINDER_INTERVAL=$RESTORE_REMINDER_INTERVAL"
	logItem "RESTORE_REMINDER_REPEAT=$RESTORE_REMINDER_REPEAT"
	logItem "ROOT_PARTITION=$ROOT_PARTITION"
	logItem "RSYNC_BACKUP_ADDITIONAL_OPTIONS=$RSYNC_BACKUP_ADDITIONAL_OPTIONS"
	logItem "RSYNC_BACKUP_OPTION_EXCLUDE_ACLS"="$RSYNC_BACKUP_OPTION_EXCLUDE_ACLS"
	logItem "RSYNC_BACKUP_OPTIONS=$RSYNC_BACKUP_OPTIONS"
	logItem "RSYNC_IGNORE_ERRORS=$RSYNC_IGNORE_ERRORS"
	logItem "SENDER_EMAIL=$SENDER_EMAIL"
 	logItem "SKIP_DEPRECATED=$SKIP_DEPRECATED"
 	logItem "SKIPLOCALCHECK=$SKIPLOCALCHECK"
	logItem "SLACK_WEBHOOK_URL=$SLACK_WEBHOOK_URL"
	logItem "SLACK_NOTIFICATIONS=$SLACK_NOTIFICATIONS"
 	logItem "SMART_RECYCLE=$SMART_RECYCLE"
 	logItem "SMART_RECYCLE_DRYRUN=$SMART_RECYCLE_DRYRUN"
 	logItem "SMART_RECYCLE_OPTIONS=$SMART_RECYCLE_OPTIONS"
	logItem "STARTSERVICES=$STARTSERVICES"
	logItem "STOPSERVICES=$STOPSERVICES"
	logItem "SYSTEMSTATUS=$SYSTEMSTATUS"
	logItem "TAR_BACKUP_ADDITIONAL_OPTIONS=$TAR_BACKUP_ADDITIONAL_OPTIONS"
	logItem "TAR_BACKUP_OPTIONS=$TAR_BACKUP_OPTIONS"
	logItem "TAR_BOOT_PARTITION_ENABLED=$TAR_BOOT_PARTITION_ENABLED"
	logItem "TAR_COMPRESSION_TOOL=$TAR_COMPRESSION_TOOL"
	logItem "TAR_COMPRESSION_TOOL_OPTIONS=$TAR_COMPRESSION_TOOL_OPTIONS"
	logItem "TAR_IGNORE_ERRORS=$TAR_IGNORE_ERRORS"
	logItem "TAR_RESTORE_ADDITIONAL_OPTIONS=$TAR_RESTORE_ADDITIONAL_OPTIONS"
	logItem "TELEGRAM_TOKEN=$TELEGRAM_TOKEN"
	logItem "TELEGRAM_CHATID=$TELEGRAM_CHATID"
	logItem "TELEGRAM_THREADID=$TELEGRAM_THREADID"
	logItem "TELEGRAM_NOTIFICATIONS=$TELEGRAM_NOTIFICATIONS"
	logItem "TIMESTAMPS=$TIMESTAMPS"
	logItem "UPDATE_UUIDS=$UPDATE_UUIDS"
	logItem "VERBOSE=$VERBOSE"
	logItem "YES_NO_RESTORE_DEVICE=$YES_NO_RESTORE_DEVICE"
	logItem "ZIP_BACKUP=$ZIP_BACKUP"

	logExit

}

function initializeDefaultConfigVariables() {

	############# Begin default config section #############

	# Part or whole of the following section can be put into
	# /usr/local/etc/raspiBackup.conf, ~/.raspiBackup.conf or $(pwd)/.raspiBackup.conf
	# and will take precedence over the following default definitions

	# path to store the backupfile
	DEFAULT_BACKUPPATH="/backup"
	# how many backups to keep of all backup types
	DEFAULT_KEEPBACKUPS=3
	# how many backups to keep of the specific backup type. If zero DEFAULT_KEEPBACKUPS is used
	DEFAULT_KEEPBACKUPS_DD=0
	DEFAULT_KEEPBACKUPS_DDZ=0
	DEFAULT_KEEPBACKUPS_TAR=0
	DEFAULT_KEEPBACKUPS_TGZ=0
	DEFAULT_KEEPBACKUPS_RSYNC=0
	# type of backup: dd, tar or rsync
	DEFAULT_BACKUPTYPE="rsync"
	# zip tar or dd backup (0 = false, 1 = true)
	DEFAULT_ZIP_BACKUP=0
	# dd backup will save space used by partitions only
	DEFAULT_DD_BACKUP_SAVE_USED_PARTITIONS_ONLY=0
	# commands to stop services before backup separated by &&
	DEFAULT_STOPSERVICES=""
	# commands to start services after backup separated by &&
	DEFAULT_STARTSERVICES=""
	# commands to execute before backup stops separated by &&
	DEFAULT_BEFORE_STOPSERVICES=""
	# commands to execute after backup start separated by &&
	DEFAULT_AFTER_STARTSERVICES=""
	# commands to execute just before terminating
	DEFAULT_FINAL_COMMAND=""
	# HTML color and VT100 color for warning and error, yellow red
	DEFAULT_COLOR_CODES=("#FF8000 33" "#FF0000 31")
	# email to send completion status
	DEFAULT_EMAIL=""
	# sender email used with ssmtp
	DEFAULT_SENDER_EMAIL=""
	# Additional parameters for email program (optional)
	DEFAULT_EMAIL_PARMS=""
	# log level  (0 = none, 1 = debug)
	DEFAULT_LOG_LEVEL=1
	# log output ( 1 = /var/log, 2 = backuppath, 3 = ./raspiBackup.log, <somefilename>)
	DEFAULT_LOG_OUTPUT=2
	# msg level (0 = minimal, 1 = detailed)
	DEFAULT_MSG_LEVEL=0
	# mailprogram
	DEFAULT_MAIL_PROGRAM="mail"
	# restore device
	DEFAULT_RESTORE_DEVICE=""
	# default append log (0 = false, 1 = true)
	DEFAULT_APPEND_LOG=0
	# option used by mail program to append log (for example -a or -A)
	DEFAULT_APPEND_LOG_OPTION="-a"
	# default verbose log (0 = false, 1 = true)
	DEFAULT_VERBOSE=0
	# skip check for remote mount of backup path (0 = false, 1 = true)
	DEFAULT_SKIPLOCALCHECK=0
	# blocksize used for dd
	DEFAULT_DD_BLOCKSIZE=1MB
	# addition parms used for dd
	DEFAULT_DD_PARMS=""
	# dd warning
	DEFAULT_DD_WARNING=0
	# exclude list
	DEFAULT_EXCLUDE_LIST=""
	# backup extensions to call
	DEFAULT_EXTENSIONS=""
	# restore extensions to call
	DEFAULT_RESTORE_EXTENSIONS=""
	# partition based backup  (0 = false, 1 = true)
	DEFAULT_PARTITIONBASED_BACKUP=0
	# backup and restore first two partitions only
	DEFAULT_PARTITIONS_TO_BACKUP="1 2"
	DEFAULT_PARTITIONS_TO_RESTORE="1 2"
	# language (DE or EN)
	DEFAULT_LANGUAGE=""
	# hosts which will get the updated backup script with parm -y - non pwd access with keys has to be enabled
	# Example: "root@raspberrypi root@fhem root@openhab root@magicmirror"
	DEFAULT_DEPLOYMENT_HOSTS=""
	# Use with care !
	DEFAULT_YES_NO_RESTORE_DEVICE="loop"
	# Use hardlinks for partitionbootfiles
	DEFAULT_LINK_BOOTPARTITIONFILES=0
	# save boot partition with tar
	DEFAULT_TAR_BOOT_PARTITION_ENABLED=0
	# Compression tool to use for tar. Supported: bzip2 gzip lzip lzma lzop xz zstd
	DEFAULT_TAR_COMPRESSION_TOOL=""
	# Options to be passed to compression tool
	DEFAULT_TAR_COMPRESSION_TOOL_OPTIONS=""
	# reboot system at end of backup
	DEFAULT_REBOOT_SYSTEM=0
	# Change these options only if you know what you are doing !!!
	DEFAULT_RSYNC_BACKUP_OPTIONS="-aHAx --delete --force --sparse" 						# -a <=> -rlptgoD, H = preserve hardlinks, x = one filesystem, A = preserver ACLs
	DEFAULT_RSYNC_BACKUP_ADDITIONAL_OPTIONS=""
	DEFAULT_RSYNC_BACKUP_OPTION_EXCLUDE_ACLS=0
	DEFAULT_RSYNC_IGNORE_ERRORS="" 														# See https://bugzilla.samba.org/show_bug.cgi?id=3653
	DEFAULT_TAR_BACKUP_OPTIONS="-cpi --one-file-system"
	DEFAULT_TAR_BACKUP_ADDITIONAL_OPTIONS=""
	DEFAULT_TAR_RESTORE_ADDITIONAL_OPTIONS=""
	DEFAULT_TAR_IGNORE_ERRORS=""
	# Send email only in case of errors. Use with care !
	DEFAULT_MAIL_ON_ERROR_ONLY=0
	# Smart recycle
	DEFAULT_SMART_RECYCLE=0
	# Smart recycle dryrun
	DEFAULT_SMART_RECYCLE_DRYRUN=1
	# Smart recycle parameters (daily, weekly, monthly and yearly)
	DEFAULT_SMART_RECYCLE_OPTIONS="7 4 12 1"
	# Check for back blocks when formating restore device (Will take a long time)
	DEFAULT_CHECK_FOR_BAD_BLOCKS=0
	# Resize root filesystem during restore
	DEFAULT_RESIZE_ROOTFS=1
	# add timestamps in front of messages
	DEFAULT_TIMESTAMPS=0
	# add system status in debug log (Attention: may expose sensible information)
	DEFAULT_SYSTEMSTATUS=0
	# reminder to test restore (unit: months)
	DEFAULT_RESTORE_REMINDER_INTERVAL=6
	# Number of times restore reminder bothers you
	DEFAULT_RESTORE_REMINDER_REPEAT=3
	# update device UUIDs
	DEFAULT_UPDATE_UUIDS=1
	# send stats
	DEFAULT_SEND_STATS=1
	# ignore partitions > 2 in normal mode
	DEFAULT_IGNORE_ADDITIONAL_PARTITIONS=0
	# Allow to save not all previously saved partitions
	DEFAULT_IGNORE_MISSING_PARTITIONS=0
	# notify in email and telegram when backup starts
	DEFAULT_NOTIFY_START=0
	# Telegram token
	DEFAULT_TELEGRAM_TOKEN=""
	# Telegram target chatid
	DEFAULT_TELEGRAM_CHATID=""
	# Telegram thread ID for the target chat (optional)
	DEFAULT_TELEGRAM_THREADID=""
	# Telegram notifications to send. S(uccess), F(ailure), M(messages as file), m(essages as text)
	DEFAULT_TELEGRAM_NOTIFICATIONS="F"
	# Pushover additional options
	# Note: All additional API keys have to be prefixed with --form-string. Example: "--form-string ttl=3600 --form-string priority=0"
	DEFAULT_PUSHOVER_ADDITIONAL_OPTIONS=""
	# Pushover device
	DEFAULT_PUSHOVER_DEVICE=""
	# Pushover token
	DEFAULT_PUSHOVER_TOKEN=""
	# Pushover user
	DEFAULT_PUSHOVER_USER=""
	# Pushover notifications to send. S(uccess), F(ailure), M(essages)
	DEFAULT_PUSHOVER_NOTIFICATIONS="F"
	# Pushover sound for success
	DEFAULT_PUSHOVER_SOUND_SUCCESS=""
	# Pushover sound for failure
	DEFAULT_PUSHOVER_SOUND_FAILURE=""
	# Pushover priorities
	DEFAULT_PUSHOVER_PRIORITY_SUCCESS="0"
	DEFAULT_PUSHOVER_PRIORITY_FAILURE="1"
	# Slack
	DEFAULT_SLACK_WEBHOOK_URL=""
	DEFAULT_SLACK_NOTIFICATIONS=""
	# Colorize console output (C) and/or email (E)
	DEFAULT_COLORING="CM"
	# mail coloring scheme (SUBJECT or OPTION)
	DEFAULT_EMAIL_COLORING="$EMAIL_COLORING_SUBJECT"
	# Name of backup partition to dynamically mount (e.g. /dev/sda1 or /backup)
	DEFAULT_DYNAMIC_MOUNT=""
	# Define bootdevice (e.g. /dev/mmcblk0, /dev/nvme0n1 or /dev/sda) and turn off boot device autodiscovery
	DEFAULT_BOOT_DEVICE=""
	# How often inform about possible old-named backups
	DEFAULT_OLD_REMINDER_REPEAT="5"
	# Sent notifications and eMails also when script is invoked in the foreground on the console
	DEFAULT_FORCE_EMAIL=1
	############# End default config section #############
}

function copyDefaultConfigVariables() {

	APPEND_LOG="$DEFAULT_APPEND_LOG"
	APPEND_LOG_OPTION="$DEFAULT_APPEND_LOG_OPTION"
	BACKUPPATH="$DEFAULT_BACKUPPATH"
	BACKUPTYPE="$DEFAULT_BACKUPTYPE"
	BOOT_DEVICE="$DEFAULT_BOOT_DEVICE"
	AFTER_STARTSERVICES="$DEFAULT_AFTER_STARTSERVICES"
	BEFORE_STOPSERVICES="$DEFAULT_BEFORE_STOPSERVICES"
	CHECK_FOR_BAD_BLOCKS="$DEFAULT_CHECK_FOR_BAD_BLOCKS"
	COLOR_CODES=("${DEFAULT_COLOR_CODES[0]}" "${DEFAULT_COLOR_CODES[1]}")
	COLORING="$DEFAULT_COLORING"
	DD_BACKUP_SAVE_USED_PARTITIONS_ONLY="$DEFAULT_DD_BACKUP_SAVE_USED_PARTITIONS_ONLY"
	DD_BLOCKSIZE="$DEFAULT_DD_BLOCKSIZE"
	DD_PARMS="$DEFAULT_DD_PARMS"
	DD_WARNING="$DEFAULT_DD_WARNING"
	DEPLOYMENT_HOSTS="$DEFAULT_DEPLOYMENT_HOSTS"
	EMAIL="$DEFAULT_EMAIL"
	EMAIL_COLORING="$DEFAULT_EMAIL_COLORING"
	EMAIL_PARMS="$DEFAULT_EMAIL_PARMS"
	EMAIL_PROGRAM="$DEFAULT_MAIL_PROGRAM"
	EXCLUDE_LIST="$DEFAULT_EXCLUDE_LIST"
	EXTENSIONS="$DEFAULT_EXTENSIONS"
	FINAL_COMMAND="$DEFAULT_FINAL_COMMAND"
	FORCE_EMAIL="$DEFAULT_FORCE_EMAIL"
	IGNORE_ADDITIONAL_PARTITIONS="$DEFAULT_IGNORE_ADDITIONAL_PARTITIONS"
	IGNORE_MISSING_PARTITIONS="$DEFAULT_IGNORE_MISSING_PARTITIONS"
	KEEPBACKUPS="$DEFAULT_KEEPBACKUPS"
	KEEPBACKUPS_DD="$DEFAULT_KEEPBACKUPS_DD"
	KEEPBACKUPS_DDZ="$DEFAULT_KEEPBACKUPS_DDZ"
	KEEPBACKUPS_TAR="$DEFAULT_KEEPBACKUPS_TAR"
	KEEPBACKUPS_TGZ="$DEFAULT_KEEPBACKUPS_TGZ"
	KEEPBACKUPS_RSYNC="$DEFAULT_KEEPBACKUPS_RSYNC"
	LINK_BOOTPARTITIONFILES="$DEFAULT_LINK_BOOTPARTITIONFILES"
	LOG_LEVEL="$DEFAULT_LOG_LEVEL"
	LOG_OUTPUT="$DEFAULT_LOG_OUTPUT"
	MAIL_ON_ERROR_ONLY="$DEFAULT_MAIL_ON_ERROR_ONLY"
	MSG_LEVEL="$DEFAULT_MSG_LEVEL"
	NOTIFY_START="$DEFAULT_NOTIFY_START"
	OLD_REMINDER_REPEAT="$DEFAULT_OLD_REMINDER_REPEAT"
	PARTITIONBASED_BACKUP="$DEFAULT_PARTITIONBASED_BACKUP"
	PARTITIONS_TO_BACKUP="$DEFAULT_PARTITIONS_TO_BACKUP"
	PARTITIONS_TO_RESTORE="$DEFAULT_PARTITIONS_TO_RESTORE"
	PUSHOVER_ADDITIONAL_OPTIONS="$DEFAULT_PUSHOVER_ADDITIONAL_OPTIONS"
	PUSHOVER_DEVICE="$DEFAULT_PUSHOVER_DEVICE"
	PUSHOVER_TOKEN="$DEFAULT_PUSHOVER_TOKEN"
	PUSHOVER_USER="$DEFAULT_PUSHOVER_USER"
	PUSHOVER_NOTIFICATIONS="$DEFAULT_PUSHOVER_NOTIFICATIONS"
	PUSHOVER_SOUND_SUCCESS="$DEFAULT_PUSHOVER_SOUND_SUCCESS"
	PUSHOVER_SOUND_FAILURE="$DEFAULT_PUSHOVER_SOUND_FAILURE"
	PUSHOVER_PRIORITY_SUCCESS="$DEFAULT_PUSHOVER_PRIORITY_SUCCESS"
	PUSHOVER_PRIORITY_FAILURE="$DEFAULT_PUSHOVER_PRIORITY_FAILURE"
	REBOOT_SYSTEM="$DEFAULT_REBOOT_SYSTEM"
	RESIZE_ROOTFS="$DEFAULT_RESIZE_ROOTFS"
	RESTORE_DEVICE="$DEFAULT_RESTORE_DEVICE"
	RESTORE_EXTENSIONS="$DEFAULT_RESTORE_EXTENSIONS"
	RESTORE_REMINDER_INTERVAL="$DEFAULT_RESTORE_REMINDER_INTERVAL"
	RESTORE_REMINDER_REPEAT="$DEFAULT_RESTORE_REMINDER_REPEAT"
	RSYNC_BACKUP_ADDITIONAL_OPTIONS="$DEFAULT_RSYNC_BACKUP_ADDITIONAL_OPTIONS"
	RSYNC_BACKUP_OPTION_EXCLUDE_ACLS="$DEFAULT_RSYNC_BACKUP_OPTION_EXCLUDE_ACLS"
	RSYNC_IGNORE_ERRORS="$DEFAULT_RSYNC_IGNORE_ERRORS"
	RSYNC_BACKUP_OPTIONS="$DEFAULT_RSYNC_BACKUP_OPTIONS"
	SENDER_EMAIL="$DEFAULT_SENDER_EMAIL"
	SKIPLOCALCHECK="$DEFAULT_SKIPLOCALCHECK"
	SLACK_WEBHOOK_URL="$DEFAULT_SLACK_WEBHOOK_URL"
	SLACK_NOTIFICATIONS="$DEFAULT_SLACK_NOTIFICATIONS"
	SMART_RECYCLE="$DEFAULT_SMART_RECYCLE"
	SMART_RECYCLE_DRYRUN="$DEFAULT_SMART_RECYCLE_DRYRUN"
	SMART_RECYCLE_OPTIONS="$DEFAULT_SMART_RECYCLE_OPTIONS"
	STARTSERVICES="$DEFAULT_STARTSERVICES"
	SEND_STATS="$DEFAULT_SEND_STATS"
	STOPSERVICES="$DEFAULT_STOPSERVICES"
	SYSTEMSTATUS="$DEFAULT_SYSTEMSTATUS"
	TAR_BACKUP_ADDITIONAL_OPTIONS="$DEFAULT_TAR_BACKUP_ADDITIONAL_OPTIONS"
	TAR_BACKUP_OPTIONS="$DEFAULT_TAR_BACKUP_OPTIONS"
	TAR_BOOT_PARTITION_ENABLED="$DEFAULT_TAR_BOOT_PARTITION_ENABLED"
	TAR_COMPRESSION_TOOL="$DEFAULT_TAR_COMPRESSION_TOOL"
	TAR_COMPRESSION_TOOL_OPTIONS="$DEFAULT_TAR_COMPRESSION_TOOL_OPTIONS"
	TAR_RESTORE_ADDITIONAL_OPTIONS="$DEFAULT_TAR_RESTORE_ADDITIONAL_OPTIONS"
	TAR_IGNORE_ERRORS="$DEFAULT_TAR_IGNORE_ERRORS"
	TELEGRAM_CHATID="$DEFAULT_TELEGRAM_CHATID"
	TELEGRAM_THREADID="$DEFAULT_TELEGRAM_THREADID"
	TELEGRAM_NOTIFICATIONS="$DEFAULT_TELEGRAM_NOTIFICATIONS"
	TELEGRAM_TOKEN="$DEFAULT_TELEGRAM_TOKEN"
	TIMESTAMPS="$DEFAULT_TIMESTAMPS"
	UPDATE_UUIDS="$DEFAULT_UPDATE_UUIDS"
	VERBOSE="$DEFAULT_VERBOSE"
	YES_NO_RESTORE_DEVICE="$DEFAULT_YES_NO_RESTORE_DEVICE"
	ZIP_BACKUP="$DEFAULT_ZIP_BACKUP"
	DYNAMIC_MOUNT="$DEFAULT_DYNAMIC_MOUNT"

	checkImportantParameters

}

function isSpecialBlockDevice() { # either device (mmcblk, sd) or device name (/dev/mmcblk, /dev/sd )

	logEntry "$1"

	local rc

	[[ $1 =~ mmcblk|loop|nvme ]]
	rc=$?

	logExit "$rc"

	return $rc
}

function createPartitionName() { # either device (mmcblk0, sda) or device name (/dev/mmcblk0, /dev/sda ) and partition number (may be empty)

	logEntry "$1 $2"

	local result="$1"

	if isSpecialBlockDevice "$1"; then
		result="${result}p"
	fi

	if [[ -n "$2" ]]; then
		result="${result}$2"
	fi

	logExit "$result"

	echo "$result"

}

# Input:
# 	mmcblk0
# 	sda
#       nvme0n1
# Output:
# 	mmcblk0p
# 	sda
#       nvme0n1p

function getPartitionPrefix() { # device

	logEntry "$1"
	local pref="$1"

	if isSpecialBlockDevice "$1"; then
		pref="${1}p"
	fi

	logExit "$pref"
	echo "$pref"

}

# Input:
# 	/dev/mmcblk0p1
#	/dev/sda2
#       /dev/nvme0n1p1
# Output:
# 	1
#	2

function getPartitionNumber() { # deviceName

	logEntry "$1"
	local id
	if [[ $1 =~ ^/dev/(mmcblk|loop)[0-9]+p([0-9]+) || $1 =~ ^/dev/((s|v)d[a-z])([0-9]+) || $1 =~ ^/dev/(nvme)[0-9]+n[0-9]+p([0-9]+) ]]; then
		id=${BASH_REMATCH[2]}
	else
		assertionFailed $LINENO "Unable to retrieve partition number from deviceName $1"
	fi
	echo "$id"
	logExit "$id"

}

function hasSpaces() { # file- or directory name
	[[ $1 = *" "* ]]
	return
}

# borrowed from https://gist.github.com/cdown/1163649#file-gistfile1-sh
function urlencode() {

    local old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    local i
    for (( i = 0; i < length; i++ )); do
        local c="${1:$i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf '%s' "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=$old_lc_collate
}

# borrowed from https://gist.github.com/cdown/1163649#file-gistfile1-sh
function urldecode() {

    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}

function dynamic_mount() { # mountpoint

	logEntry "$1"

	local rc=0
	if ! isMounted $1; then
		mount "$1" &>> $LOG_FILE
		rc=$?
		if (( $rc != 0 )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_DYNAMIC_MOUNT_FAILED "$1" "$rc"
			exitError "$RC_MOUNT_FAILED"
		else
			DYNAMIC_MOUNT_EXECUTED=1
			writeToConsole $MSG_LEVEL_DETAILED $MSG_DYNAMIC_MOUNT_OK "$1"
		fi
	else
		writeToConsole $MSG_LEVEL_DETAILED $MSG_DYNAMIC_MOUNT_NOT_REQUIRED "$1"
	fi

	logCommand "mount"

	logExit

}

function isUpdatePossible() {

	logEntry

	local versions version_rc latestVersion newVersion oldVersion

	# Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	#shellcheck disable=SC2207
	versions=( $(isNewVersionAvailable) )
	version_rc=$?
	if [[ $version_rc == 0 ]]; then
		NEWS_AVAILABLE=1
		UPDATE_POSSIBLE=1
		latestVersion="${versions[0]}"
		newVersion="${versions[1]}"
		oldVersion="${versions[2]}"

		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NEW_VERSION_AVAILABLE "$newVersion" "$oldVersion"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_VISIT_VERSION_HISTORY_PAGE "$(getMessage $MSG_VERSION_HISTORY_PAGE)"
	fi

	logExit

}

function downloadPropertiesFile() { # FORCE

	logEntry "$1"

	NEW_PROPERTIES_FILE=0

	if shouldRenewDownloadPropertiesFile "$1"  && (( ! $REGRESSION_TEST && ! $IS_DEV )); then # don't execute any update checks

		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CHECKING_FOR_NEW_VERSION

		if (( $SEND_STATS )); then
			local mode="N"; (( $PARTITIONBASED_BACKUP )) && mode="P"
			local type=$BACKUPTYPE
			local keep=$KEEPBACKUPS
			local func="B"; (( $RESTORE )) && func="R"
			local srOptions
			srOptions="$(urlencode "$SMART_RECYCLE_OPTIONS")"
			local srs=""; [[ -n $SMART_RECYCLE_DRYRUN ]] && (( ! $SMART_RECYCLE_DRYRUN )) && srs="$srOptions"
			local os="rsp"; (( $IS_UBUNTU )) && os="ubu"
			local downloadURL="${PROPERTIES_DOWNLOAD_URL}?version=$VERSION&type=$type&mode=$mode&keep=$keep&func=$func&srs=$srs&os=$os"
		else
			local downloadURL="$PROPERTIES_DOWNLOAD_URL"
		fi

		local dlHttpCode dlRC
		dlHttpCode=$(downloadFile "$downloadURL" "$LATEST_TEMP_PROPERTY_FILE")
		dlRC=$?
		if (( $dlRC != 0 )); then
			if [[ $1 == "FORCE" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_DOWNLOAD_FAILED "$(sed "s/\?.*$//" <<< "$downloadURL")" "$dlHttpCode" $dlRC
				exitError $RC_DOWNLOAD_FAILED
			else
				: # silently ignore download error or property file
			fi
		else
			NEW_PROPERTIES_FILE=1
			parsePropertiesFile "$LATEST_TEMP_PROPERTY_FILE"
		fi
	fi

	logExit "$NEW_PROPERTIES_FILE"
	return
}

#VERSION="0.6.3.1"
#INCOMPATIBLE=""
#DEPRECATED=""
#BETA="0.6.3.2"

function parsePropertiesFile() { # propertyFileName

	logEntry

	local properties

	properties="$(grep "^VERSION=" "$1" 2>/dev/null)"
	[[ $properties =~ $PROPERTY_REGEX ]] && VERSION_PROPERTY=${BASH_REMATCH[1]}

	properties="$(grep "^INCOMPATIBLE=" "$1" 2>/dev/null)"
	[[ $properties =~ $PROPERTY_REGEX ]] && INCOMPATIBLE_PROPERTY=${BASH_REMATCH[1]}

	properties="$(grep "^DEPRECATED=" "$1" 2>/dev/null)"
	[[ $properties =~ $PROPERTY_REGEX ]] && DEPRECATED_PROPERTY=${BASH_REMATCH[1]}

	properties="$(grep "^BETA=" "$1" 2>/dev/null)"
	[[ $properties =~ $PROPERTY_REGEX ]] && BETA_PROPERTY=${BASH_REMATCH[1]}

	logItem "Properties: v: $VERSION_PROPERTY i: $INCOMPATIBLE_PROPERTY d: $DEPRECATED_PROPERTY b: $BETA_PROPERTY"

	logExit

}

function isVersionDeprecated() { # versionNumber

	logEntry

	local rc=1	# no/failure

	local deprecatedVersions=( "$DEPRECATED_PROPERTY" )
	if containsElement "$1" "${deprecatedVersions[@]}"; then
		rc=0
		logItem "Version $1 is deprecated"
	fi

	local skip=( "$SKIP_DEPRECATED" )
	if containsElement "$1" "${skip[@]}"; then
		rc=1
		logItem "Version $1 is deprecated but message is disabled"
	fi

	logExit "$rc"
	return $rc
}

function shouldRenewDownloadPropertiesFile() { # FORCE

	logEntry

	local rc currentTime lastCheckTime

	if [[ -e $LATEST_TEMP_PROPERTY_FILE ]]; then
		lastCheckTime=$(stat -c %y $LATEST_TEMP_PROPERTY_FILE | cut -d ' ' -f 1 | sed 's/-//g')
	else
		lastCheckTime="00000000"
	fi

	currentTime=$(date +%Y%m%d)

	logItem "$currentTime : $lastCheckTime"

	if [[ $currentTime == "$lastCheckTime" && "$1" != "FORCE" ]]; then
		logItem "Skip download"
		rc=1		#  download already done today
	else
		rc=0
	fi

	logExit "$rc"
	return $rc
}

function verifyIsOnOff() { # arg

	local v=${!1}
	local uc="${v^^}"

	case "$uc" in
		ON|TRUE|AN|1) : echo "1"
			return
			;;
		OFF|FALSE|AUS|0) : echo "0"
			return
			;;
	esac

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_TRUE_FALSE_OPTION "$v" "$1"
	exitError $RC_PARAMETER_ERROR
}

function downloadFile() { # url, targetFileName

		local url

		url="$(sed -E 's/\?.*$//' <<< $1)"

		logEntry "URL: $url, file: $2"

		local httpCode rc f

		local url="$1"
		local file="$2"
		f=$(mktemp)
		local httpCode rc
		# This {/} is literal. Check if ; is missing or quote the expression.
		#shellcheck disable=SC1083
		httpCode=$(curl -sSL -o "$f" -m $DOWNLOAD_TIMEOUT -w %{http_code} -L "$url" 2>>"$LOG_FILE")
		rc=$?
		logItem "httpCode: $httpCode RC: $rc"

		# Some nasty code required because download plugin doesn't return 404 if file not found but a HTML doc

		if (( $rc == 0 )); then
			if [[ ! -f "$f" ]]; then
					httpCode="404"
					rc=101
			elif [[ ${httpCode:0:1} == "2" ]]; then
				if head -n 1 "$f" | grep -q "^<!DOCTYPE html>"; then
					httpCode="404"
					rc=101
				fi
			else
				rc=101
			fi
		fi

		if (( $rc != 0 )); then
			[[ -f $f ]] && rm $f &>>$LOG_FILE
			echo "$httpCode"
			logExit "$rc $httpCode"
			return $rc
		fi

		[[ -f $f ]] && mv $f $file &>>$LOG_FILE
		echo "200"
		logExit 0
		return 0
}

function askYesNo() { # message message_parms

	local yes_no yes

	yes_no=$(getMessage $MSG_QUERY_CHARS_YES_NO)
	local addtlMsg=0

	if (( $# > 1 )); then
		local m="$1"
		shift
		addtlMsg=1
		# Variable was used as an array but is now assigned a string.
		#shellcheck disable=SC2178,SC2124
		local args="$@"
	fi

	local answer

	if (( $addtlMsg )); then
		noNL=1
		#Expanding an array without an index only gives the element in the index 0.
		#shellcheck disable=SC2128
		writeToConsole $MSG_LEVEL_MINIMAL "$m" "$args" "$yes_no"
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_ARE_YOU_SURE "$yes_no"
	fi

	if (( $NO_YES_QUESTION )); then
		answer=$(getMessage $MSG_ANSWER_CHARS_YES)
	else
		read answer
	fi

	answer=${answer:0:1}	# first char only
	answer=${answer:-"n"}	# set default no

	yes=$(getMessage $MSG_ANSWER_CHARS_YES)
	if [[ ! $yes =~ $answer ]]; then
		return 1
	else
		return 0
	fi
}

function isNewVersionAvailable() {

	logEntry

	local newVersion="0.0"
	local latestVersion="0.0"

	local rc=99			# update not possible

	local version="$VERSION"
	local suffix=""
	if [[ "$VERSION" =~ ^([^-]*)(-(.*))?$ ]]; then
		version=${BASH_REMATCH[1]}
		suffix=${BASH_REMATCH[3]}
	fi

	logItem "Versionsplit: $version - $suffix"

	if (( $NEW_PROPERTIES_FILE )); then
		local newVersion=$VERSION_PROPERTY
		latestVersion=$(echo -e "$newVersion\n$version" | sort -V | tail -1)
		logItem "new: $newVersion runtime: $version latest: $latestVersion"

		if (( $(compareVersions $version $newVersion) < 0 )); then # $version < $newVersion
			rc=0	# new version available
		elif (( $(compareVersions $version $newVersion) > 0 )); then  # $version > $newVersion
			rc=2	# current version is a newer version
		else	    # versions are identical
			if [[ -z $suffix ]]; then
				rc=1	# no suffix, current version is latest version
			else
				if (( $IS_BETA || $IS_DEV )); then
					rc=0	# current is beta or development version, replace with final version
				elif (( $IS_HOTFIX )); then
					rc=2	# current version is hotfix, keep it until new version is available
				else
					rc=1	# current version is latest version
				fi
			fi
		fi
	fi

	result="$latestVersion $newVersion $VERSION"
	echo "$result"

	logItem "Returning: $result"

	logExit "$rc"

	return $rc

}

function stopServices() {

	logEntry

	if [[ -n "$STOPSERVICES" ]]; then
		if [[ "$STOPSERVICES" =~ $NOOP_AO_ARG_REGEX ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_STOPPING_SERVICES
		else
			writeToConsole $MSG_LEVEL_DETAILED $MSG_STOPPING_SERVICES "$STOPSERVICES"
			logItem "$STOPSERVICES"
			STOPPED_SERVICES=1
			executeShellCommand "$STOPSERVICES"
			local rc=$?
			if [[ $rc != 0 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_STOP_SERVICES_FAILED "$rc"
				exitError $RC_STOP_SERVICES_ERROR
			fi
		fi
	fi
	logSystemServices
	logExit
}

function executeBeforeStopServices() {
	logEntry
	if [[ -n "$BEFORE_STOPSERVICES" ]]; then
		writeToConsole $MSG_LEVEL_DETAILED $MSG_BEFORE_STOPPING_SERVICES "$BEFORE_STOPSERVICES"
		logItem "$BEFORE_STOPSERVICES"
		executeShellCommand "$BEFORE_STOPSERVICES"
		local rc=$?
		if [[ $rc != 0 ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_BEFORE_STOP_SERVICES_FAILED "$rc"
			exitError $RC_BEFORE_STOP_SERVICES_ERROR
		fi
	fi
	logExit
}

function finalCommand() {

	logEntry

	if [[ -n "$FINAL_COMMAND" ]]; then
		writeToConsole $MSG_LEVEL_DETAILED $MSG_FINAL_COMMAND_EXECUTED "$FINAL_COMMAND"
		logItem "$FINAL_COMMAND"
		executeShellCommand "$FINAL_COMMAND"
		local rc=$?
		if [[ $rc != 0 ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FINAL_COMMAND_FAILED "$rc"
		fi
	fi

	logExit
}

function startServices() {

	logEntry

	logSystemServices

	if (( $STOPPED_SERVICES )); then
		if [[ -n "$STARTSERVICES" ]]; then
			if (( ! $RESTORE && $REBOOT_SYSTEM && ! $FAKE )); then
				:	# just ignore STARTSERVICES
			elif [[ "$STARTSERVICES" =~ $NOOP_AO_ARG_REGEX ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_STARTING_SERVICES
			else
				writeToConsole $MSG_LEVEL_DETAILED $MSG_STARTING_SERVICES "$STARTSERVICES"
				logItem "$STARTSERVICES"
				executeShellCommand "$STARTSERVICES"
				local rc=$?
				if [[ $rc != 0 ]]; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_START_SERVICES_FAILED "$rc"
					if [[ "$1" != "noexit" ]]; then
						exitError $RC_START_SERVICES_ERROR
					fi
				fi
				STOPPED_SERVICES=0
			fi
		fi
	fi

	logExit
}

function executeAfterStartServices() {
	logEntry
	if [[ -n "$AFTER_STARTSERVICES" ]]; then
		writeToConsole $MSG_LEVEL_DETAILED $MSG_AFTER_STARTING_SERVICES "$AFTER_STARTSERVICES"
		logItem "$AFTER_STARTSERVICES"
		executeShellCommand "$AFTER_STARTSERVICES"
		local rc=$?
		if [[ $rc != 0 ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_BEFORE_START_SERVICES_FAILED "$rc"
			if [[ "$1" != "noexit" ]]; then
				exitError $RC_BEFORE_START_SERVICES_ERROR
			fi
		fi
	fi
	logExit
}

function extractVersionFromFile() { # fileName type (VERSION|VERSION_CONFIG)
	logEntry "$@"
	local v
	v="$(grep -E "^$2=" "$1" | cut -f 2 -d = | sed  -e 's/[[:space:]]*#.*$//g' -e 's/\"//g')"
	echo "$v"
	logExit "$v"
}

# update script with latest version

function updateScript() {

	logEntry

	local rc versions latestVersion newVersion oldVersion newName betaVersion properties
	local updateNow=0

	if (( $NEW_PROPERTIES_FILE )) ; then

		# Prefer mapfile or read -a to split command output (or quote to avoid splitting).
		#shellcheck disable=SC2207
		versions=( $(isNewVersionAvailable) )
		rc=$?										# need rc so no map usage possible

		latestVersion=${versions[0]}
		newVersion=${versions[1]}
		oldVersion=${versions[2]}

		logItem "$rc - $latestVersion - $newVersion - $oldVersion"

		if (( ! $FORCE_UPDATE )) ; then
			local incompatibleVersions=( "$INCOMPATIBLE_PROPERTY" )
			if containsElement "$newVersion" "${incompatibleVersions[@]}"; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_INCOMPATIBLE_UPDATE "$newVersion" "$(getMessage $MSG_VERSION_HISTORY_PAGE)"
				exitNormal
			fi
		fi

		betaVersion=$(isBetaAvailable)

		if [[ -n $betaVersion ]]; then
			if (( ! $FORCE_UPDATE )) && [[ "${betaVersion}-beta" > $oldVersion ]]; then 			# beta version available
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UPDATE_TO_BETA "$oldVersion" "${betaVersion}-beta"
				if askYesNo; then
					DOWNLOAD_URL="$BETA_DOWNLOAD_URL"
					newVersion="${betaVersion}-beta"
					updateNow=1
				fi
			elif (( $FORCE_UPDATE )) && [[ "${betaVersion}-beta" == "$oldVersion" ]]; then		# refresh current beta with latest version
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UPDATE_TO_LATEST_BETA "${betaVersion}-beta"
				if askYesNo; then
					DOWNLOAD_URL="$BETA_DOWNLOAD_URL"
					newVersion="${betaVersion}-beta"
					updateNow=1
				fi
			fi
		fi

		if [[ $rc == 0 ]] && (( ! $updateNow )); then							# new version available
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UPDATE_TO_VERSION "$oldVersion" "$newVersion"
			if ! askYesNo; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UPDATE_ABORTED
				exitNormal
			fi
			updateNow=1
		elif [[ $rc == 1 || $rc == 2 ]] && (( ! $IS_BETA )) && (( ! $updateNow && $FORCE_UPDATE )); then		# no beta version, same or upper version (maybe development version) but force update
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FORCE_UPDATE "$newVersion"
			if askYesNo; then
				updateNow=1
			fi
		fi

		if (( $updateNow )); then
			local tmpFile="/tmp/${MYSELF}~"
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_DOWNLOADING "$MYSELF" "$MYHOMEURL"

			local dlHttpCode dlRC
			dlHttpCode="$(downloadFile "$DOWNLOAD_URL" "${tmpFile}")"
			dlRC=$?
			if (( $dlRC != 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_DOWNLOAD_FAILED "$DOWNLOAD_URL" "$dlHttpCode" $dlRC
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_UPDATE_FAILED "$MYSELF"
				exitError $RC_DOWNLOAD_FAILED
			fi
			newName="$SCRIPT_DIR/$MYNAME.$oldVersion.sh"
			mv $SCRIPT_DIR/$MYSELF $newName
			mv $tmpFile $SCRIPT_DIR/$MYSELF
			chown --reference=$newName $SCRIPT_DIR/$MYSELF
			chmod --reference=$newName $SCRIPT_DIR/$MYSELF
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_UPDATE_OK "$SCRIPT_DIR/$MYSELF" "$oldVersion" "$newVersion" "$newName"
			# refresh version information from updated script
			properties="$(grep "^VERSION=" "$SCRIPT_DIR/$MYSELF" 2>/dev/null)"
			[[ $properties =~ $PROPERTY_REGEX ]] && VERSION=${BASH_REMATCH[1]}
			logItem "Updating VERSION from updated script to $VERSION"
			properties="$(grep "^VERSION_SCRIPT_CONFIG=" "$SCRIPT_DIR/$MYSELF" 2>/dev/null)"
			[[ $properties =~ $PROPERTY_REGEX ]] && VERSION_SCRIPT_CONFIG=${BASH_REMATCH[1]}
			logItem "Updating VERSION_SCRIPT_CONFIG from updated script to $VERSION_SCRIPT_CONFIG"
		else
			rm $MYSELF~ &>/dev/null
			if [[ $rc == 1 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_UPDATE_NOT_NEEDED "$SCRIPT_DIR/$MYSELF" "$newVersion"
			elif [[ $rc == 2 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_UPDATE_NOT_REQUIRED "$SCRIPT_DIR/$MYSELF" "$oldVersion" "$newVersion"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_UPDATE_FAILED "$MYSELF"
			fi
		fi
	fi

	logExit $updateNow

	return $updateNow

}

function hasDefaultACLs() { # directory
	local rc=2	# getfacl not found
	logEntry "$1"
	if hash "getfacl" 2>/dev/null; then
		getfacl -p $1 | grep -q -E "^default" &>>$LOG_FILE
		rc=$?
	else
		logItem "getfacl not found"
	fi
	logExit "$rc"
	return $rc
}

# 0 = yes, no otherwise

function supportsFileAttributes() {	# directory

	logEntry "$1"

	local attrs owner group r x
	local attrsT ownerT groupT
	local result=1	# no

	local MAXRETRY=3						# retries
	local retryCount=$(( MAXRETRY + 1 ))

	touch /tmp/$MYNAME.fileattributes &>>$LOG_FILE
	chown 65534:65534 /tmp/$MYNAME.fileattributes &>>$LOG_FILE
	chmod 057 /tmp/$MYNAME.fileattributes &>>$LOG_FILE

	# ls -la output
	# ----r-xrwx 1 nobody nogroup 0 Oct 30 19:06 /tmp/supportsFileattributes.fileattributes

	read -r attrs x owner group r <<< "$(ls -la "/tmp/$MYNAME.fileattributes")"
	logItem "$attrs # $owner # $group"

	while (( retryCount-- > 0 && result == 1 )); do
		# following command will return an error and message
		# cp: failed to preserve ownership for '/mnt/supportsFileattributes.fileattributes': Operation not permitted
		cp -a "/tmp/$MYNAME.fileattributes" "/$1" &>>"$LOG_FILE"
		local rc=$?
		if (( $rc )); then
			logItem "cp failed with rc $rc - retryCount"
		else
			# SC2034: x appears unused. Verify it or export it.
			# shellcheck disable=SC2034
			read -r attrsT x ownerT groupT r <<< "$(ls -la "/$1/$MYNAME.fileattributes")"

			logItem "Remote: $attrsT # $ownerT # $groupT"
			attrsT="$(sed 's/+$//' <<< $attrsT)" # delete + sign present if there are any extended attributes

			# check fileattributes and ownerships are identical
			if [[ "$attrs" == "$attrsT" && "$owner" == "$ownerT" && "$group" == "$groupT" ]]; then
				result=0
				break
			fi
		fi
		sleep 3s
	done

	rm /tmp/$MYNAME.fileattributes &>>$LOG_FILE
	rm /$1/$MYNAME.fileattributes &>>$LOG_FILE

	logExit $result

	return $result
}

function disableACLsIfRequested() {
	if (( $RSYNC_BACKUP_OPTION_EXCLUDE_ACLS )); then
		RSYNC_BACKUP_OPTIONS="$(sed 's/A//' <<< "$RSYNC_BACKUP_OPTIONS")"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_OPTION_ACLS_DISABLED
	fi
}

# 0 = yes, no otherwise

function supportsHardlinks() {	# directory

	logEntry "$1"

	local links
	local result=1 # no

	touch /$1/$MYNAME.hlinkfile &>>$LOG_FILE

	local MAXRETRY=3						# retries
	local retryCount=$(( MAXRETRY + 1 ))

	while (( retryCount-- > 0 && result == 1 )); do
		cp -l /$1/$MYNAME.hlinkfile /$1/$MYNAME.hlinklink &>>$LOG_FILE
		links=$(ls -la /$1/$MYNAME.hlinkfile | cut -f 2 -d ' ')
		logItem "Links: $links"
		if (( $links == 2 )); then
			result=0
			break
		fi
	done

	rm -f /$1/$MYNAME.hlinkfile &>/dev/null
	rm -f /$1/$MYNAME.hlinklink &>/dev/null

	logExit "$result"

	return $result
}

# 0 = yes, no otherwise

function supportsSymlinks() {	# directory

	logEntry "$1"

	local result=1	# no
	touch /$1/$MYNAME.slinkfile &>>$LOG_FILE
	ln -s /$1/$MYNAME.slinkfile /$1/$MYNAME.slinklink &>>$LOG_FILE
	[[ -L /$1/$MYNAME.slinklink ]] && result=0
	rm -f /$1/$MYNAME.slinkfile &>/dev/null
	rm -f /$1/$MYNAME.slinklink &>/dev/null

	logExit "$result"

	return $result
}

function isMounted() { # dir
	local rc
	logEntry "$1"
	if [[ -n "$1" ]]; then
		#logCommand "cat /proc/mounts"
		grep -qs "$1" /proc/mounts
		rc=$?
	else
		rc=1
	fi
	logExit "$rc"
	return $rc
}

function getFsType() { # file or path

	logEntry "$1"

	local mp
	mp="$(findMountPath "$1")"
	logItem "Mountpoint: $mp"

	local df
	df="$(LC_ALL=C df --output=fstype,target | grep -E " ${mp}$" | cut -f 1 -d " ")"
	logItem "df -T: $df"
	echo $df

	logExit "$df"

}

# sfdisk sanity check to make sure last partition does not extend device size

#						label: dos
#						label-id: 0x3c3f4bdb
#						device: /dev/mmcblk0
#						unit: sectors
#						sector-size: 512
#
#						/dev/mmcblk0p1 : start=        8192, size=      524288, type=c
#						/dev/mmcblk0p2 : start=      532480, size=    15196160, type=83

function checkSfdiskOK() { # device, e.g. /dev/mmcblk0
	logEntry "$1"

	local rc
	local deviceSize
	deviceSize=$(blockdev --getsz $1)

	logCommand "sfdisk -d $1"

	logItem "DeviceSize: $deviceSize"

	# Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	#shellcheck disable=SC2207
	local sourceValues=( $(awk '/[0-9]+ :/ { v=$4 $6; gsub(","," ",v); printf "%s",v }' <<< "$(sfdisk -d $1)") )

	local s=${#sourceValues[@]}
	logItem "Size: $s"

	if (( $s < 4 )); then
		assertionFailed $LINENO "Expected at least 2 partitions on $1"
	fi

	local sm1=$((s-1))
	local sm2=$((s-2))

	logItem "${sourceValues[$sm2]} - ${sourceValues[$sm1]}"

	local usedSize=$(( ${sourceValues[$sm2]} + ${sourceValues[$sm1]} ))
	logItem "usedSize: $usedSize"

	local freeSize=$(( $deviceSize - $usedSize ))
	logItem "freeSize: $freeSize"

	rc=$(( ( $deviceSize / 512 ) > $usedSize ))

	logExit $rc
	return $rc
}

# check if directory is located on a mounted device

function isPathMounted() {

	logEntry "$1"

	local path
	local rc=1
	path=$1

	# backup path has to be mount point of the file system (second field fs_file in /etc/fstab) and NOT fs_spec otherwise test algorithm will create endless loop
	if [[ "${1:0:1}" == "/" ]]; then
		while [[ "$path" != "" ]]; do
			logItem "Path: $path"
			if mountpoint -q "$path"; then
				rc=0
				break
			fi
			path=${path%/*}
		done
	fi
	logExit "$rc"

	return $rc
}

# find path of mount of file or directory

function findMountPath() {

	logEntry "$1"

	local path
	path="$1"

	# path has to be mount point of the file system (second field fs_file in /etc/fstab) and NOT fs_spec otherwise test algorithm will create endless loop
	if [[ "${1:0:1}" == "/" ]]; then
		while [[ "$path" != "" ]]; do
			logItem "Path: $path"
			if mountpoint -q "$path"; then
				break
			fi
			path=${path%/*}
		done
	fi
	echo "$path"
	logExit "$path"

	return
}

function readConfigParameters() {

	logEntry

	local attrs

	ETC_CONFIG_FILE="/usr/local/etc/${MYNAME}.conf"
	HOME_CONFIG_FILE="$CALLING_HOME/.${MYNAME}.conf"
	CURRENTDIR_CONFIG_FILE="$CURRENT_DIR/.${MYNAME}.conf"

	local file
	local files=( "$ETC_CONFIG_FILE" "$HOME_CONFIG_FILE" "$CURRENTDIR_CONFIG_FILE" )

	local warnedFiles=""

	for file in "${files[@]}"; do
		if [[ -e $file ]]; then
			attrs="$(stat -c %a $file)"
			if (( ( 0$attrs & 077 ) != 0 )); then
				if ! grep -q $file <<< "$warnedFiles"; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNPROTECTED_PROPERTIESFILE $file
					warnedFiles="$warnedFiles $file"
				fi
			fi
		fi
	done

	# Override default parms with parms in global config file

	ETC_CONFIG_FILE_INCLUDED=0
	if [ -f "$ETC_CONFIG_FILE" ]; then
		set -e
		# Can't follow non-constant source. Use a directive to specify location
		#shellcheck disable=SC1090
		. "$ETC_CONFIG_FILE"
		set +e
		ETC_CONFIG_FILE_INCLUDED=1
		ETC_CONFIG_FILE_VERSION="$(extractVersionFromFile "$ETC_CONFIG_FILE" "$VERSION_CONFIG_VARNAME" )"
		logItem "Read config ${ETC_CONFIG_FILE} : ${ETC_CONFIG_FILE_VERSION}$NL$(egrep -v '^\s*$|^#' $ETC_CONFIG_FILE)"
	fi

	# Override default parms with parms in user config file

	HOME_CONFIG_FILE_INCLUDED=0
	if [ -f "$HOME_CONFIG_FILE" ]; then
		set -e
		# Can't follow non-constant source. Use a directive to specify location
		#shellcheck disable=SC1090
		. "$HOME_CONFIG_FILE"
		set +e
		HOME_CONFIG_FILE_INCLUDED=1
		HOME_CONFIG_FILE_VERSION="$(extractVersionFromFile "$HOME_CONFIG_FILE" "$VERSION_CONFIG_VARNAME" )"
		logItem "Read config ${HOME_CONFIG_FILE} : ${HOME_CONFIG_FILE_VERSION}$NL$(egrep -v '^\s*$|^#' $HOME_CONFIG_FILE)"

	fi

	# Override default parms with parms in current directory config file

	CURRENTDIR_CONFIG_FILE_INCLUDED=0
	if [[ "$HOME_CONFIG_FILE" != "$CURRENTDIR_CONFIG_FILE" ]]; then
		if [ -f "$CURRENTDIR_CONFIG_FILE" ]; then
			set -e
			# Can't follow non-constant source. Use a directive to specify location
			#shellcheck disable=SC1090
			. "$CURRENTDIR_CONFIG_FILE"
			set +e
			CURRENTDIR_CONFIG_FILE_INCLUDED=1
			CURRENTDIR_CONFIG_FILE_VERSION="$(extractVersionFromFile "$CURRENTDIR_CONFIG_FILE" "$VERSION_CONFIG_VARNAME" )"
			logItem "Read config ${CURRENTDIR_CONFIG_FILE} : ${HOME_CONFIG_FILE_VERSION}$NL$(egrep -v '^\s*$|^#' $CURRENTDIR_CONFIG_FILE)"
		fi
	fi

	logExit
}

function getOSRelease() {

	local os_release_file
	local os_release

	for os_release_file in /etc/os-release /usr/lib/os-release /dev/null ; do
		[[ -e "$os_release_file" ]] && break
	done

	# the prefix "osr_" prevents a lonely "local" with its output below when grep is unsuccessful
	unset osr_ID osr_VERSION_ID              # unset possible values used from global scope then

	#Quote this to prevent word splitting.
	#var is referenced but not assigned.
	#shellcheck disable=SC2154,SC2046
	local osr_$(grep -E "^ID="         "$os_release_file")
	#Quote this to prevent word splitting.
	#var is referenced but not assigned.
	#shellcheck disable=SC2154,SC2046
	local osr_$(grep -E "^VERSION_ID=" "$os_release_file")

	#var is referenced but not assigned.
	#shellcheck disable=SC2154
	os_release="${osr_ID}${osr_VERSION_ID}"  # e.g. debian12 or even debian"12"
	os_release="${os_release//\"/}"          # remove any double quotes
	echo "${os_release:-unknownOS}"          # handle empty result
}

function setupEnvironment() {

	logEntry

	if (( ! $RESTORE )); then
		if (( $ZIP_BACKUP )); then
			TAR_COMPRESSION_TOOL=""			# zip has higher prio than tarcompressiontool
			if [[ $BACKUPTYPE == "$BACKUPTYPE_DD" || $BACKUPTYPE == "$BACKUPTYPE_TAR" ]]; then
				BACKUPTYPE=${Z_TYPE_MAPPING[${BACKUPTYPE}]}	# tar-> tgz and dd -> ddz
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNKNOWN_BACKUPTYPE_FOR_ZIP $BACKUPTYPE
				exitError $RC_PARAMETER_ERROR
			fi
		fi

		if [[ -n "$DYNAMIC_MOUNT" ]]; then
			dynamic_mount "$DYNAMIC_MOUNT"
		fi

		BACKUPFILES_PARTITION_DATE="$HOSTNAME-backup"

		# For including the OS release into the name of the backup directory
		os_release=$(getOSRelease)
		# Note: Sanitize the os_release to be usable as (part of) directory name.
		# But don't allow or use "-" or "_" as replacement character!
		# Both characters are already used as dividers/markers later on!
		# The "~" seems to be okay. Even safer would be "", a.k.a. nothing.
		HOSTNAME_OSR="${HOSTNAME}@${os_release//[ \/\\\:\.\-_]/\~}"

		if [[ -z "$BACKUP_DIRECTORY_NAME" ]]; then
			BACKUPFILE="${HOSTNAME_OSR}-${BACKUPTYPE}-backup-$DATE"
		else
			BACKUPFILE="${HOSTNAME_OSR}-${BACKUPTYPE}-backup-${DATE}_${BACKUP_DIRECTORY_NAME}"
		fi

		BACKUPTARGET_ROOT="$BACKUPPATH/$HOSTNAME"
		BACKUPTARGET_FINAL_DIR="$BACKUPTARGET_ROOT/$BACKUPFILE"				# final directory for backup if backup was successful
		BACKUP_TEMP_ROOT_DIR="$BACKUPTARGET_ROOT/tmp"						# temporary backup root directory
		BACKUPTARGET_TEMP_DIR="$BACKUP_TEMP_ROOT_DIR/$BACKUPFILE"			# temporary backup directory for current backup
		BACKUPTARGET_DIR="$BACKUPTARGET_TEMP_DIR"							# use temporary backup directory, will be renamend to BACKUPTARGET_FINAL_DIR if backup succeeded

		local targetExtension="${FILE_EXTENSION[$BACKUPTYPE]}"

		if [[ -n $TAR_COMPRESSION_TOOL ]] || (( $ZIP_BACKUP )); then
			TAR_COMPRESSION_EXTENSION="${FILE_EXTENSION[$BACKUPTYPE]}"			# assume for now -z option is used
			if [[ -n $TAR_COMPRESSION_TOOL ]]; then
				local i
				i=$(getIndexInArray "$TAR_COMPRESSION_TOOL" "${TAR_COMPRESSION_TOOLS_SUPPORTED[@]}")
				if (( ! $? )); then
					TAR_COMPRESSION_EXTENSION=".tar${TAR_COMPRESSION_EXTENSIONS_SUPPORTED[$i]}"
				else
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_TAR_COMPRESS_TOOL "$TAR_COMPRESSION_TOOL"
					exitError $RC_PARAMETER_ERROR
				fi
			fi

			logItem "Use tar extension $TAR_COMPRESSION_EXTENSION"
			targetExtension="$TAR_COMPRESSION_EXTENSION"
		fi

		BACKUPTARGET_FILE="$BACKUPTARGET_DIR/$BACKUPFILE${targetExtension}"
		BACKUPTARGET_FINAL_FILE="$BACKUPTARGET_FINAL_DIR/$BACKUPFILE${targetExtension}"

		logItem "BACKUPTARGET_FILE=$BACKUPTARGET_FILE"
		logItem "BACKUPTARGET_FINAL_FILE=$BACKUPTARGET_FINAL_FILE"

		if [[ ! -d "${BACKUPTARGET_DIR}" ]]; then
			if (( $FAKE || ( $SMART_RECYCLE && $SMART_RECYCLE_DRYRUN ) )); then
				: # don't create backupdirectory
			else
				if ! mkdir -p "${BACKUPTARGET_DIR}" &>>"$LOG_FILE"; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "${BACKUPTARGET_DIR}"
					exitError $RC_CREATE_ERROR
				fi
			fi
		fi

		BACKUPPATH="$(sed -E 's@/+$@@g' <<< "$BACKUPPATH")"

		if [[ ! -d "$BACKUPPATH" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_ARG_NOT_FOUND "$BACKUPPATH"
			exitError $RC_MISSING_FILES
		fi

		if ! touch "$BACKUPPATH/$MYNAME.tmp" &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_WRITE "$BACKUPPATH"
			exitError $RC_MISC_ERROR
		else
			rm -f "$BACKUPPATH/$MYNAME.tmp" &>/dev/null
		fi

		if (( $FAKE )) && [[ "$LOG_OUTPUT" =~ $LOG_OUTPUT_IS_NO_USERDEFINEDFILE_REGEX ]]; then
			LOG_OUTPUT=$LOG_OUTPUT_HOME
			logItem "LOG_OUTPUT=$LOG_OUTPUT"
		fi
	fi

	logItem "BACKUPTARGET_DIR: $BACKUPTARGET_DIR"
	logItem "BACKUPTARGET_FINAL_DIR: $BACKUPTARGET_FINAL_DIR"
	logItem "BACKUPTARGET_FILE: $BACKUPTARGET_FILE"
	logItem "BACKUPTARGET_FINAL_FILE: $BACKUPTARGET_FINAL_FILE"

	logExit

}

# deploy script on my local PIs

function deployMyself() {

	logEntry

	for hostLogon in $DEPLOYMENT_HOSTS; do

		host=$(cut -d '@' -f 2 <<< $hostLogon)
		user=$(cut -d '@' -f 1 <<< $hostLogon)

		if [[ -z "$host" || -z "$user" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_DEPLOYMENT_PARMS_ERROR
			exitError $RC_PARAMETER_ERROR
		fi

		if ping -c 1 $host &>/dev/null; then
			if [[ $user == "root" ]]; then
				scp -p $MYSELF $hostLogon:/usr/local/bin > /dev/null
			else
				scp -p $MYSELF $hostLogon:/home/$user > /dev/null
			fi
			if [[ $? == 0 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_DEPLOYED_HOST "$host" "$user"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_DEPLOYMENT_FAILED "$host" "$user"
			fi
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_DEPLOYING_HOST_OFFLINE "$host"
		fi
	done

		logExit

}

# calculate last used sector

function calcSumSizeFromSFDISK() { # sfdisk file name

	logEntry "$1"

	local file="$1"

# /dev/mmcblk0p1 : start=     8192, size=    83968, Id= c
# or
# /dev/sdb1 : start=          63, size=  1953520002, type=83
# or
# /dev/nvme0n1p1 : start=        8192, size=     1048576, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=A1D7A9AA-D2CD-4A61-A709-096793B25EEC, name="bootfs"

	local partitionregex="/dev/.*([0-9]+) [^=]+=[^0-9]*([0-9]+)[^=]+=[^0-9]*([0-9]+)[^=]+=[^0-9a-zA-Z\\-]*([0-9a-zA-Z\\-]+)"
	local sectorSize=512 # default

	[[ -v RESIZE_FSDISK ]] && logCommand "cat $file"

	local sectorSize=512 # default

	if grep -q "^sector-size:" $file; then
		sectorSize=$(cut -f 2 -d ' ' <<< "$sectorSize")
		if [[ -z $sectorSize ]]; then
			assertionFailed $LINENO "Unable to retrieve sectorsize"
		fi
	fi

	local line
	local lineNo=0
	local sumSize=0

	while IFS="" read line; do

		(( lineNo++ ))

		if [[ -z $line || $line =~ ^[^#]*# ]]; then
			continue
		fi

		if [[ $line =~ $partitionregex ]]; then
			local p=${BASH_REMATCH[1]}
			local start=${BASH_REMATCH[2]}
			local size=${BASH_REMATCH[3]}
			local id=${BASH_REMATCH[4]}
			local end
			(( end = start + size ))

			logItem "Processing $p - Start: $start - Size: $((size*512)) - End: $end - id: $id"

      if [[ "$id" != "83" && "$id" != "5" && "$id" != "c" && \
            "$id" != "0FC63DAF-8483-4772-8E79-3D69D8477DE4" && \
            "$id" != "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7" ]]; then
				continue
			fi

			(( sumSize = (start + size) * sectorSize ))

			[[ -v RESIZE_FSDISK ]] && logItem "$p: Start: $start - Size: $((size*512)) : $(bytesToHuman $((size*512))) - SumSize: $sumSize : $(bytesToHuman $sumSize)"

		fi
	done < $file

	if (( sumSize == 0 )) || { [[ "$id" != "83" ]] && [[ "$id" != "0FC63DAF-8483-4772-8E79-3D69D8477DE4" ]]; }; then
		assertionFailed $LINENO "No matching last partition found"
	fi

	echo "$sumSize"

	logExit "$sumSize - $(bytesToHuman $sumSize)"
}


# Return oldParttiionSize and newPartitionsize of modified last partition together with partition number
# if last partition is too small to shrink the newPartitionSize == -1

function createResizedSFDisk() { # sfdisk_source_filename targetDeviceSize sfdisk_target_filename -> oldPartitionSize newPartitionSize

	logEntry "$@"

	local sourceFile="$1"
	local targetDeviceSize="$2"
	local targetFile="$3"

	local oldPartitionSize newPartitionSize

	local partitionregex="/dev/.*([0-9]+) [^=]+=[^0-9]*([0-9]+)[^=]+=[^0-9]*([0-9]+)[^=]+=[^0-9a-zA-Z\\-]*([0-9a-zA-Z\\-]+)"

	local sectorSize=512
	if grep -q "^sector-size:" $sourceFile; then
		sectorSize=$(cut -f 2 -d ' ' <<< "$sectorSize")
		if [[ -z $sectorSize ]]; then
			assertionFailed $LINENO "Unable to retrieve sector size"
		fi
	fi

	logCommand "cat $sourceFile"

	local sourceDeviceSize
	sourceDeviceSize=$(calcSumSizeFromSFDISK "$sourceFile")

	cp "$sourceFile" "$targetFile"

	local line newSize diffSize

	logItem "sourceDeviceSize: $sourceDeviceSize ($(bytesToHuman $(($sourceDeviceSize)))) targetDeviceSize: $targetDeviceSize ($(bytesToHuman $(($targetDeviceSize))))"

	while IFS="" read line; do

		(( lineNo++ ))

		if [[ -z $line || $line =~ ^[^#]*# ]]; then
			continue
		fi

		if [[ $line =~ $partitionregex ]]; then
			local p=${BASH_REMATCH[1]}
			local start=${BASH_REMATCH[2]}
			local size=${BASH_REMATCH[3]}
			local id=${BASH_REMATCH[4]}
			local end
			(( end = start + size ))

			logItem "Processing $p - Start: $start - Size: $((size*512)) - End: $end - id: $id"

			if [[ "$id" == "5" ]]; then
				logItem "Extended partition detected"
				local p5=$p
				local size5=$size
				continue
			fi

			if [[ "$id" != "83" ]] && [[ "$id" != "0FC63DAF-8483-4772-8E79-3D69D8477DE4" ]]; then
				continue
			fi

			logItem "--- Processing partition $p ---"

			(( oldPartitionSize = size * sectorSize ))

			logItem "OldPartitionSize: $oldPartitionSize ($(bytesToHuman $oldPartitionSize)))"

			if (( sourceDeviceSize > targetDeviceSize )); then
				[[ -v RESIZE_FSDISK ]] && logItem "newSize = ( $size - ( $sourceDeviceSize - $targetDeviceSize ) / $sectorSize )"
				(( newSize = ( size - ( sourceDeviceSize - targetDeviceSize ) / sectorSize ) ))
			elif (( sourceDeviceSize < targetDeviceSize )); then
				[[ -v RESIZE_FSDISK ]] && logItem "newSize = ( $size + ( $targetDeviceSize - $sourceDeviceSize ) / $sectorSize )"
				(( newSize = ( size + ( targetDeviceSize - sourceDeviceSize ) / sectorSize ) ))
			else
				[[ -v RESIZE_FSDISK ]] && logItem "newSize = $size"
				(( newSize = size ))
			fi

			(( diffSize = newSize - size ))

			logItem "NewSize: $newSize ($(bytesToHuman $((newSize*512)))) DiffSize: $diffSize ($(bytesToHuman $((diffSize*512))))"

			if (( newSize > 0 )); then
				[[ -v RESIZE_FSDISK ]] && logItem "(( newPartitionSize = ( $newSize * $sectorSize )))"
				(( newPartitionSize = ( newSize * sectorSize )))
			else
				[[ -v RESIZE_FSDISK ]] && logItem "((newPartitionSize =($newSize-1) * $sectorSize ))"		# too small, adjust for 512 division truncation gap
				(( newPartitionSize = (newSize-1) * sectorSize ))		# too small, adjust for 512 division truncation gap
			fi

			logItem "NewPartitionSize: $newPartitionSize ($(bytesToHuman $newPartitionSize)))"

			logItem "$p - Start: $start - Size: $((size*512)) - id: $id"
			logItem "- newSize: $newSize ($(bytesToHuman $(($newSize*512)))) oldPartitionSize: $(bytesToHuman $oldPartitionSize) newPartitionSize ($(bytesToHuman $newPartitionSize))"
		fi

	done < $sourceFile

	if [[ -z $newSize ]]; then
		assertionFailed $LINENO "No last Linux partition found which can be resized"
	fi

	if (( newPartitionSize <= 0 )); then			# last partition too small to shrink, return missing size
		logItem "Partition too small: Missing $(bytesToHuman $newPartitionSize)"
	fi

	local sfDiskFileUpdated
	if (( newSize > 0 )); then
		logItem "Update partition sectorsize to $newSize"
		sed -E -i "s/($p :.+size=[ ]*)([0-9]+)/\1${newSize}/" $targetFile
		if (( $? )); then
			assertionFailed $LINENO "SFDISK sed unsuccessfull"
		fi
		if [[ -n $p5 ]]; then
			local newP5Size
			[[ -v RESIZE_FSDISK ]] && logItem "(( newP5Size = $size5 + $diffSize ))"
			(( newP5Size = size5 + diffSize ))
			logItem "Update extended partition sectorsize to $newP5Size"
			sed -E -i "s/(p$p5 :.+size=[ ]*)([0-9]+)/\1${newP5Size}/" $targetFile
		fi
		sfDiskFileUpdated=true
	fi

	# Remove the "last-lba" header, it may or may not match the real target GPT partition, depending on its size, and is optional anyway
	if sed -E -i '/^last-lba:/d' "$targetFile"; then
      if ! grep -q '^last-lba:' "$targetFile"; then
          sfDiskFileUpdated=true
      fi
  fi

  if $sfDiskFileUpdated; then
		logItem "Updated sfdisk file"
		logCommand "cat $targetFile"
	fi

	logItem "Old: $oldPartitionSize ($(bytesToHuman $oldPartitionSize)) - New: $newPartitionSize $(bytesToHuman $newPartitionSize))"

	local ret="$oldPartitionSize $newPartitionSize $p"

	echo "$ret"

	logExit "$ret"

}

# colorAnnotation

# html vt100
COLOR_WARNING=0
COLOR_ERROR=1
COLOR_TYPE_HTML=0
COLOR_TYPE_VT100=1

COLOR_ON=("<span style=\"color:\%s\">" "\e[1;%sm")
COLOR_OFF=("</span><br/>" "\e[0m")

function colorOn() { # colortype color
	local on="${COLOR_ON[$1]}"
	local color="${COLOR_CODES[$2]}"
	#  Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
	#shellcheck disable=SC2206
	color=( $color )
	printf -v r "$on" "${color[$1]}"
	echo -e -n "$r"
}

function colorOff() { # colortype color
	local off="${COLOR_OFF[$1]}"
	echo -e -n "$off"
}

# add color annotations for console and/or email

function colorAnnotation() { # colortype text

	# logEntry "$1"

	colorType="$1"
	shift
	local line
	while IFS= read -r line; do
	  if [[ "$line" =~ RBK....W ]]; then
			colorOn $colorType $COLOR_WARNING
			echo -n "$line"
			colorOff $colorType
			echo
		elif [[ "$line" =~ RBK....E ]]; then
			colorOn $colorType $COLOR_ERROR
			echo -n "$line"
			colorOff $colorType
			echo
		else
			if [[ $colorType == "$COLOR_TYPE_HTML" ]]; then
				echo "$line<br/>"
			else
				echo "$line"
			fi
		fi
	done <<< "$@"

	#logExit
}

function sendTelegramDocument() { # filename

		logEntry "$1"

		local rsp curlRC error_code error_description

		local curl_params=(
			"-F" "chat_id=$TELEGRAM_CHATID"
			"-F" "document=@$MSG_FILE"
		)

		if [[ -n "$TELEGRAM_THREADID" ]]; then
			curl_params+=("-F" "message_thread_id=$TELEGRAM_THREADID")
		fi

		# Build log message
		local log_cmd="curl -s -X GET '$TELEGRAM_URL$TELEGRAM_TOKEN/sendDocument' ${curl_params[*]}"
		logItem "Telegram curl call: $log_cmd"

		# Execute the curl command
		rsp="$(curl -s -X GET "$TELEGRAM_URL$TELEGRAM_TOKEN/sendDocument" "${curl_params[@]}")"
		curlRC=$?

		if (( $curlRC )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_LOG_FAILED $curlRC "N/A" "N/A"
		else
			logItem "Telegram response:${NL}${rsp}"
			ok=$(jq .ok <<< "$rsp")
			if [[ $ok == "true" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_LOG_OK
			else
				error_code="$(jq .error_code  <<< "$rsp")"
				error_description="$(jq .description <<< "$rsp")"
				logItem "Error sending msg: $rsp"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_FAILED "$curlRC" "$error_code" "$error_description"
			fi
		fi

		logExit
}

# Send message, exit

function sendTelegramMessage() { # message html(yes/no)

		logEntry "$1"

		local rsp error_code error_description

		local curl_params=(
			"--data-urlencode" "chat_id=$TELEGRAM_CHATID"
			"--data-urlencode" "text=$1"
		)

		if [[ -n "$TELEGRAM_THREADID" ]]; then
			curl_params+=("--data-urlencode" "message_thread_id=$TELEGRAM_THREADID")
		fi

		if [[ -n $2 ]]; then
			curl_params+=("--data" "parse_mode=html")
		fi

		# Build log message
		local log_cmd="curl -s -X POST '$TELEGRAM_URL$TELEGRAM_TOKEN/sendMessage' ${curl_params[*]}"
		logItem "Telegram curl call: $log_cmd"

		# Execute the curl command
		rsp="$(curl -s -X POST "$TELEGRAM_URL$TELEGRAM_TOKEN/sendMessage" "${curl_params[@]}")"
		local curlRC=$?

		if (( $curlRC )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_FAILED "$curlRC" "N/A" "N/A"
		else
			#logItem "Telegram response:${NL}${rsp}"
			local ok
			ok=$(jq .ok <<< "$rsp")
			if [[ $ok == "true" ]]; then
				logItem "Message sent"
				if [[ -n $2 ]]; then	# write message only for html, not for messages
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_OK
				fi
			else
				error_code="$(jq .error_code  <<< "$rsp")"
				error_description="$(jq .description <<< "$rsp")"
				logItem "Error sending msg: $rsp"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_SEND_FAILED "$curlRC" "$error_code" "$error_description"
			fi
		fi

		logExit
}

function sendTelegramm() { # subject

	logEntry "$1"

	if [[ -n "$TELEGRAM_TOKEN" ]] ; then
		if ! which jq &>/dev/null; then # suppress error message when jq is not installed
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "jq" "jq"
		else
			local smiley
			if (( $WARNING_MESSAGE_WRITTEN )); then
				smiley="$EMOJI_WARNING ${smiley}"
			fi
			if (( $UPDATE_POSSIBLE )); then
				smiley="$EMOJI_UPDATE_POSSIBLE ${smiley}"
			fi
			if (( $BETA_AVAILABLE )); then
				smiley="$EMOJI_BETA_AVAILABLE ${smiley}"
			fi
			if (( $RESTORETEST_REQUIRED )); then
				smiley="$EMOJI_RESTORETEST_REQUIRED ${smiley}"
			fi
			if (( $VERSION_DEPRECATED )); then
				smiley="$EMOJI_VERSION_DEPRECATED ${smiley}"
			fi

			sendTelegramMessage "${smiley}$1" 1 # html
		fi
	fi

	logExit

}

# M -> add messages inline, m -> attach messages in a file
function sendTelegrammLogMessages() {

	logEntry

	if [[ -n "$TELEGRAM_TOKEN" ]] ; then
		if ! which jq &>/dev/null; then # suppress error message when jq is not installed
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "jq" "jq"
		else
			if [[ "$TELEGRAM_NOTIFICATIONS" =~ $TELEGRAM_NOTIFY_MESSAGES ]]; then
				sendTelegramDocument "$MSG_FILE"
			elif [[ "$TELEGRAM_NOTIFICATIONS" =~ $TELEGRAM_NOTIFY_MESSAGES2 ]]; then
				sendTelegramMessage "$(<$MSG_FILE)" # no html
			fi
		fi
	fi

	logExit

}

function sendPushover() { # subject sucess/failure

	logEntry "$1"

	if [[ -n "$PUSHOVER_TOKEN" ]] ; then
		if ! which jq &>/dev/null; then # suppress error message when jq is not installed
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "jq" "jq"
		else
			sendPushoverMessage "$1" "$2"
		fi
	fi

	logExit

}

# Send message, exit

function sendPushoverMessage() { # message 0/1->success/failure sound

		logEntry "$1"

		local sound prio o msg msgEnd cmd httpCode curlRC ok

		if [[ -n $2 && "$2" == "1" ]]; then
			sound="$PUSHOVER_SOUND_FAILURE"
			prio="$PUSHOVER_PRIORITY_FAILURE"
		else
			sound="$PUSHOVER_SOUND_SUCCESS"
			prio="$PUSHOVER_PRIORITY_SUCCESS"
		fi

		o=$(mktemp)

		msg="$(grep -o "RBK0009.\+" $MSG_FILE)" # assume NOTIFY_START is set
		msgEnd="$(grep -o "RBK0010.\+" $MSG_FILE)" # no, script finished

		[[ -n "$msgEnd" ]] && msg="$msgEnd"

		if [[ "$PUSHOVER_NOTIFICATIONS" =~ $PUSHOVER_NOTIFY_MESSAGES ]]; then
			msg="$(tail -c 1024 $MSG_FILE)"
		fi

		# The = here is literal. To assign by index, use ( [index]=value ) with no spaces. To keep as literal, quote it.
		#shellcheck disable=SC2191
		cmd=(--form-string message="$1")

		cmd+=(--form-string "token=$PUSHOVER_TOKEN" \
              --form-string "user=$PUSHOVER_USER"\
              --form-string "priority=$prio"\
              --form-string "html=1"\
              --form-string "message=$msg"\
              --form-string "title=$1"\
              --form-string "sound=$sound")

		[[ -n $PUSHOVER_DEVICE ]] && cmd+=(--form-string "device=$PUSHOVER_DEVICE" )
		#shellcheck disable=SC2206
		# Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
		[[ -n $PUSHOVER_ADDITIONAL_OPTIONS ]] && cmd+=( $PUSHOVER_ADDITIONAL_OPTIONS )

		logItem "Pushover curl call: ${cmd[*]}"
		# This {/} is literal. Check if ; is missing or quote the expression.
		#shellcheck disable=SC1083
		httpCode="$(curl -s -w %{http_code} -o $o "${cmd[@]}" "$PUSHOVER_URL")"
		curlRC=$?
		logItem "Pushover response:${NL}$(<$o)"

		if (( $curlRC )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_PUSHOVER_SEND_FAILED "$curlRC" "$httpCode" "$rsp"
		else
			ok=$(jq .status "$o")
			if [[ $ok == "1" ]]; then
				logItem "Message sent"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PUSHOVER_SEND_OK
			else
				error_description="$(jq .errors "$o" | tr -d '\n[]')"
				logItem "Error sending msg: $rsp"
				logItem "ErrorDescription: $error_description"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PUSHOVER_SEND_FAILED "$curlRC" "$httpCode" "$error_description"
			fi
		fi

		[[ -n $o ]] && rm $o

		logExit
}

function sendSlack() { # subject sucess/failure

	logEntry "$1"

	if [[ -n "$SLACK_WEBHOOK_URL" ]] ; then
		local smiley
		if (( $WARNING_MESSAGE_WRITTEN )); then
			smiley="$SLACK_EMOJI_WARNING ${smiley}"
		fi
		if (( $UPDATE_POSSIBLE )); then
			smiley="$SLACK_EMOJI_UPDATE_POSSIBLE ${smiley}"
		fi
		if (( $BETA_AVAILABLE )); then
			smiley="$SLACK_EMOJI_BETA_AVAILABLE ${smiley}"
		fi
		if (( $RESTORETEST_REQUIRED )); then
			smiley="$SLACK_EMOJI_RESTORETEST_REQUIRED ${smiley}"
		fi
		if (( $VERSION_DEPRECATED )); then
			smiley="$SLACK_EMOJI_VERSION_DEPRECATED ${smiley}"
		fi

		sendSlackMessage "${smiley}$1" "$2"
	fi

	logExit

}

# Send message, exit

function sendSlackMessage() { # message 0/1->success/failure

		logEntry "$1"

		local msg_json statusMsg error_description msg msgEnd curlRC httpCode

		local o
		o=$(mktemp)

		if [[ -n $2 && "$2" == "1" ]]; then
			statusMsg="${SLACK_EMOJI_FAILED}$1"
		else
			statusMsg="${SLACK_EMOJI_OK}$1"
		fi

		msg="$(grep -o "RBK0009.\+" $MSG_FILE)" # assume NOTIFY_START is set
		msgEnd="$(grep -o "RBK0010.\+" $MSG_FILE)" # no, script finished

		[[ -n "$msgEnd" ]] && msg="$msgEnd"

		if [[ "$SLACK_NOTIFICATIONS" =~ $SLACK_NOTIFY_MESSAGES ]]; then
			msg="$(tail -n 32 $MSG_FILE)"
		fi

		read -r -d '' msg_json <<EOF
{
	"blocks": [
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "*$statusMsg*\n$msg"
			}
		}
	]
}
EOF

		local cmd=(-X POST)
		cmd+=(-H 'Content-type: application/json')
		cmd+=(--data "$msg_json")

		logItem "Slack curl call: ${cmd[*]}"

		# This {/} is literal. Check if ; is missing or quote the expression.
		#shellcheck disable=SC1083
		httpCode="$(curl -s -w %{http_code} -o $o "${cmd[@]}" "$SLACK_WEBHOOK_URL")"
		curlRC=$?

		logItem "Slack response:${NL}$(<$o)"

		if (( $curlRC )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SLACK_SEND_FAILED "$curlRC" "$httpCode" "$rsp"
		else
			if [[ "ok" == $(<$o) ]]; then
				logItem "Message sent"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SLACK_SEND_OK
			else
				logItem "Error sending msg: $rsp"
				error_description="$(<$o)"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SLACK_SEND_FAILED "$curlRC" "$httpCode" "$error_description"
			fi
		fi

		[[ -n $o ]] && rm $o

		logExit
}

function sendEMail() { # content subject

	logEntry

	if [[ -n "$EMAIL" && rc != "$RC_CTRLC" ]]; then
		local attach content subject

		local attach=""
		local subject="$2"
		local coloringOption=""
		local contentType=""

		local smiley=""
		if (( $NEWS_AVAILABLE )); then
			if (( $WARNING_MESSAGE_WRITTEN )); then
				smiley="$SMILEY_WARNING ${smiley}"
			fi
			if (( $UPDATE_POSSIBLE )); then
				smiley="$SMILEY_UPDATE_POSSIBLE ${smiley}"
			fi
			if (( $BETA_AVAILABLE )); then
				smiley="$SMILEY_BETA_AVAILABLE ${smiley}"
			fi
			if (( $RESTORETEST_REQUIRED )); then
				smiley="$SMILEY_RESTORETEST_REQUIRED ${smiley}"
			fi
			if (( $VERSION_DEPRECATED )); then
				smiley="$SMILEY_VERSION_DEPRECATED ${smiley}"
			fi
		fi

		subject="$smiley$subject"

		if [[ "$COLORING" =~ $COLORING_MAIL ]]; then
			if [[ ! $EMAIL_COLORING =~ $SUPPORTED_EMAIL_COLORING_REGEX ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_EMAIL_COLORING_NOT_SUPPORTED "$EMAIL_COLORING" "$SUPPORTED_EMAIL_COLORING"
				EMAIL_COLORING="$EMAIL_COLORING_SUBJECT"
			else
				if [[ "$EMAIL_COLORING" == "$EMAIL_COLORING_SUBJECT" ]]; then
					contentType="${NL}MIME-Version: 1.0${NL}Content-Type: text/html; charset=utf-8"
				elif [[ "$EMAIL_COLORING" == "$EMAIL_COLORING_OPTION" ]]; then
					coloringOption=("-a" "Content-Type: text/html;")
				else
					assertionFailed $LINENO "Unexpected email coloring $EMAIL_COLORING"
				fi
				logItem "Coloring option: $COLORING${NL}eMailColoring: $EMAIL_COLORING${NL}subject: $subject${NL}coloring: ${coloringOption[*]}"
			fi
		fi

		if (( ! $MAIL_ON_ERROR_ONLY || ( $MAIL_ON_ERROR_ONLY && ( rc != 0 || ( $NEWS_AVAILABLE ) ) ) )); then

			writeToConsole $MSG_LEVEL_DETAILED $MSG_SENDING_EMAIL

			if (( $APPEND_LOG )); then
				attach="$DEFAULT_APPEND_LOG_OPTION $LOG_FILE"
				logItem "Appendlog $attach"
			fi

			IFS=" "
			content="$NL$(<"$MSG_FILE")$NL$1$NL"
			unset IFS

			if [[ "$COLORING" =~ $COLORING_MAIL ]]; then
				content="$(colorAnnotation $COLOR_TYPE_HTML "$content")"
			fi

			subject="$subject$contentType"

			logItem "eMail: $EMAIL"
			logItem "eMail Program: $EMAIL_PROGRAM"
			logItem "Subject: ${subject[0]}"
			logItem "ColoringOption: ${coloringOption[*]}"
			logItem "ContentType: $contentType"
			logItem "Parms: $EMAIL_PARMS"

			local rc
			case $EMAIL_PROGRAM in
				"$EMAIL_MAILX_PROGRAM")
					logItem "$EMAIL_PROGRAM" "${coloringOption[@]}" $EMAIL_PARMS -s "\"$subject\"" $attach $EMAIL <<< "\"$content\""
					"$EMAIL_PROGRAM" "${coloringOption[@]}" $EMAIL_PARMS -s "$subject" $attach "$EMAIL" <<< "$content"
					rc=$?
					logItem "$EMAIL_PROGRAM: RC: $rc"
					;;
				"$EMAIL_SENDEMAIL_PROGRAM")
					logItem "echo $content | $EMAIL_PROGRAM $EMAIL_PARMS -u $subject $attach -t $EMAIL"
					echo "$content" | "$EMAIL_PROGRAM" $EMAIL_PARMS -u "$subject" $attach -t "$EMAIL"
					rc=$?
					logItem "$EMAIL_PROGRAM: RC: $rc"
					;;
				"$EMAIL_SSMTP_PROGRAM"|"$EMAIL_MSMTP_PROGRAM")
					local msmtp_default=""
					if [[ $EMAIL_PROGRAM == "$EMAIL_MSMTP_PROGRAM" ]]; then
						msmtp_default="-a default"
					fi
					if (( $APPEND_LOG )); then
						logItem "Sending email with mpack"
						echo "$content" > /tmp/$$
						mpack -s "$subject" -d /tmp/$$ "$LOG_FILE" "$EMAIL"
						rm /tmp/$$ &>/dev/null
					else
						local sender=${SENDER_EMAIL:-root@$(hostname -f)}
						logItem "Sendig email with s/msmtp"
						logItem "echo -e To: $EMAIL${NL}From: $sender${NL}Subject: $subject${NL}${NL}$content | $EMAIL_PROGRAM $msmtp_default $EMAIL"
						echo -e "To: $EMAIL${NL}From: $sender${NL}Subject: $subject${NL}${NL}$content" | "$EMAIL_PROGRAM" $msmtp_default "$EMAIL"
						rc=$?
						logItem "$EMAIL_PROGRAM: RC: $rc"
					fi
					;;
				"$EMAIL_EXTENSION_PROGRAM")
					local append=""
					(( $APPEND_LOG )) && append="$LOG_FILE"
					args=( "$EMAIL" "$subject" "$content" "$EMAIL_PARMS" "$append" )
					callExtensions $EMAIL_EXTENSION "${args[@]}"
					rc=$?
					;;
				*) assertionFailed $LINENO  "Unsupported email programm $EMAIL_PROGRAM detected"
					;;
			esac
		fi
		if (( $rc )) ; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_EMAIL_SEND_FAILED $EMAIL_PROGRAM $rc
		fi

	fi
	logExit

}

function cleanupBackupDirectory() {

	logEntry

	logItem "Checking $BACKUP_TEMP_ROOT_DIR for clean up"

	if [[ -d "$BACKUP_TEMP_ROOT_DIR" ]]; then
		if [[ -n $(ls "$BACKUP_TEMP_ROOT_DIR") ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_REMOVING_BACKUP_NO_FILE "$BACKUP_TEMP_ROOT_DIR"
			rm -rfd $BACKUP_TEMP_ROOT_DIR &>> "$LOG_FILE"# delete temp backupdir with all incomplete contents
			local rmrc=$?
			if (( $rmrc != 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_REMOVING_BACKUP_FAILED "$BACKUP_TEMP_ROOT_DIR" "$rmrc"
			fi
		else
			logItem "Removing $BACKUP_TEMP_ROOT_DIR"
			rmdir "$BACKUP_TEMP_ROOT_DIR"
		fi
		logItem "Deleting $BACKUP_TEMP_ROOT_DIR"
		rmdir "$BACKUP_TEMP_ROOT_DIR" &>>$LOG_FILE
	fi

	logExit
}

# return text masqueraded
#
# Algorithm:
#
# if string lenght < 8 return @@@@(<string length>)
# if string lenght < 16 return first char followed by @*<string length-2> followed by last char
# otherwise return first char followed by @@@@ followed by last char and (<string length>)

function masquerade() { # text

	[[ -z "$1" ]] && return 1

	local t="$1"
	local l="${#t}"
	local lm="\($l\)"
	local m

	if (( $l < 8 )); then
		echo "$MASQUERADE_STRING$l"
		return 0
	fi

	local s=${t:0:1}
	local e=${t: -1}

	if (( $l < 16 )); then
		m="$(yes 2>/dev/null ${MASQUERADE_STRING:0:1} | head -n $(($l-2)) | tr -d "\n" )"
		echo "$s$m$e"
	else
		echo "$s$MASQUERADE_STRING$e$lm"
	fi
	return 0
}

# Escape slashes for masquerading with sed which will fail if slashes are included in the string

function escapeSlashes() { # string

        local i r="" p
        local s="$1"

        for (( i=0; i<${#s}; i++ )); do
			p="${s:$i:1}"
			if [[ "$p" == "/" ]]; then
					r+='\/'
			else
					r+="$p"
			fi
        done

        echo "$r"
}

function masqueradeSensitiveInfoInLog() {

	local xEnabled=0 e
	if [ -o xtrace ]; then	# disable xtrace
		xEnabled=1
        set +x
	fi

	# no logging any more

	local m

	# receiver email

	if [[ -n "$EMAIL" ]]; then
		logItem "Masquerading eMail"
		m="$(masquerade "$EMAIL")"
		e="$(escapeSlashes "$EMAIL")"
		sed -i -E "s/$e/${m}/g" $LOG_FILE
	fi

	# sender email

	if [[ -n "$SENDER_EMAIL" ]]; then
		logItem "Masquerading sender eMail"
		m="$(masquerade "$SENDER_EMAIL")"
		e="$(escapeSlashes "$SENDER_EMAIL")"
		sed -i -E "s/$e/${m}/g" $LOG_FILE
	fi

	# email parms usually also contain eMails and passwords

	if [[ -n "$EMAIL_PARMS" ]]; then
		logItem "Masquerading eMail parameters"
		m="$(masquerade "$EMAIL_PARMS")"
		e="$(escapeSlashes "$EMAIL_PARMS")"
		sed -i -E "s/$e/${m}/" "$LOG_FILE" # may contain passwords
	fi

	# some mount options

	logItem "Masquerading some mount options"
	sed -i -E "s/username=[^,]+\,/username=${MASQUERADE_STRING},/" $LOG_FILE # used in cifs mount options
	sed -i -E "s/password=[^,]+\,/password=${MASQUERADE_STRING},/" $LOG_FILE
	sed -i -E "s/domain=[^,]+\,/domain=${MASQUERADE_STRING},/" $LOG_FILE

	# slack

	if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
		logItem "Masquerading slack webhook"
		m="$(masquerade $SLACK_WEBHOOK_URL)"
		e="$(escapeSlashes "$SLACK_WEBHOOK_URL")"
		sed -i -E "s/${e}/${m}/g" $LOG_FILE
	fi

	# telegram token, chatid and threadid

	if [[ -n "$TELEGRAM_TOKEN" ]]; then
		logItem "Masquerading telegram token"
		m="$(masquerade $TELEGRAM_TOKEN)"
		e="$(escapeSlashes "$TELEGRAM_TOKEN")"
		sed -i -E "s/${e}/${m}/g" $LOG_FILE
	fi

	if [[ -n "$TELEGRAM_CHATID" ]]; then
		logItem "Masquerading telegram chatid"
		m="$(masquerade $TELEGRAM_CHATID)"
		e="$(escapeSlashes "$TELEGRAM_CHATID")"
		sed -i -E "s/${e}/${m}/g" $LOG_FILE
	fi

	if [[ -n "$TELEGRAM_THREADID" ]]; then
		logItem "Masquerading telegram threadid"
		m="$(masquerade $TELEGRAM_THREADID)"
		e="$(escapeSlashes "$TELEGRAM_THREADID")"
		sed -i -E "s/${e}/${m}/g" $LOG_FILE
	fi

	# pushover token and user

	if	[[ -n "$PUSHOVER_USER" ]]; then
		logItem "Masquerading pushover user"
		m="$(masquerade $PUSHOVER_USER)"
		e="$(escapeSlashes "$PUSHOVER_USER")"
		sed -i -E "s/${e}/${m}/g" $LOG_FILE
	fi

	if [[ -n "$PUSHOVER_TOKEN" ]]; then
		logItem "Masquerading pushover token"
		m="$(masquerade $PUSHOVER_TOKEN)"
		e="$(escapeSlashes "$PUSHOVER_TOKEN")"
		sed -i -E "s/${PUSHOVER_TOKEN}/${m}/g" $LOG_FILE
	fi

	# In home directories usually first names are used

	logItem "Masquerading home directory name"
	sed -i -E -e 's|/home/[^/]+/([^/]+)|/home/@USER@/\1|g' -e 's|/home/[^/]+|/home/@USER@|g' $LOG_FILE

	# hostname may expose domain names

	logItem "Masquerading hostname"
	e="$(escapeSlashes "$HOSTNAME")"
	sed -i -E "s/$e/@HOSTNAME@/g" $LOG_FILE

	# any non local IPs used somewhere (mounts et al)

	logItem "Masquerading sensitive non local IPs"
	masqueradeNonlocalIPs $LOG_FILE

	# now delete console color annotation ESC sequences

	sed -i 's/\x1b\[1;33m//g' $LOG_FILE
	sed -i 's/\x1b\[1;31m//g' $LOG_FILE
	sed -i 's/\x1b\[0m//g' $LOG_FILE

	if (( $xEnabled )); then	# enable xtrace again
        	set -x
	fi

}

# Following regex was optimized by __blackjack__ (https://forum-raspberrypi.de/user/50585-blackjack) from a ChatGPT generated regex ;-)

function masqueradeNonlocalIPs() {

	LC_ALL=C perl -i -pe 's{
(\b
(?!                                 # exclude following local ips
	(10\.\d{1,3} 					# 10er net
	|172\.(1[6-9]|2[0-9]|3[01])		# 172er net
	|192\.168)						# 192er net
	|169\.254						# link local net
	|0\.\d{1,3}						# skip any net with leading 0 to ignore raspiBackup release info
	(\.\d{1,3}){2})					# followed by two trailing nibbles
									# now catch external ips
\d{1,3}\.\d{1,3}					# accept 2 leading nibbles
((\.\d{1,3}){2})					# followed by 2 trailing nibbles
\b)
		}
{"%%%.%%%$5"}gex' $1
}

function callNotificationExtension() { # rc
		logEntry "$1"

		local xEnabled=0
		if [ -o xtrace ]; then	# disable xtrace
			xEnabled=1
			set +x
		fi
		callExtensions $NOTIFICATION_BACKUP_EXTENSION $1
		local rc=$?
		logItem "NotificationExtension rc: $rc"
		if (( $xEnabled )); then	# enable xtrace again
			set -x
		fi

		logExit $rc
		return $rc
}

function cleanupStartup() { # trap

	logEntry

	rc=${rc:-42}	# some failure during startup of script (RT error, option validation, ...)

	if [[ $1 == "SIGINT" ]]; then
		# ignore CTRL-C now
		trap '' SIGINT SIGTERM SIGHUP
		rc=$RC_CTRLC
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CTRLC_DETECTED
	fi

	cleanupTempFiles

	logFinish

	if (( $LOG_LEVEL == $LOG_DEBUG )); then
		masqueradeSensitiveInfoInLog # and now masquerade sensitive details in log file
	fi

	logExit

	if [[ -n "$DYNAMIC_MOUNT" ]] && (( $DYNAMIC_MOUNT_EXECUTED )); then
		writeToConsole $MSG_LEVEL_DETAILED $MSG_DYNAMIC_UMOUNT_SCHEDULED "$DYNAMIC_MOUNT"
		umount -l $DYNAMIC_MOUNT &>>$LOG_FILE
	fi

	exit $rc
}

function lockMe() {
	logEntry
	exlock_now
	logExit
}

function unLockMe() {
	logEntry
	unlock
	logExit
}

function cleanup() { # trap

	logEntry

	rc=${rc:-42}	# some failure during startup of script (RT error, option validation, ...)

	if [[ $1 == "SIGINT" ]]; then
		# ignore CTRL-C now
		trap '' SIGINT SIGTERM EXIT
		rc=$RC_CTRLC
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CTRLC_DETECTED
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_CLEANING_UP

	logSystemServices

	CLEANUP_RC=$rc

	if (( $RESTORE )); then
		cleanupRestore $1
	else

		if (( $PRE_BACKUP_EXTENSION_CALLED )); then
			callExtensions $POST_BACKUP_EXTENSION $rc
		fi

		startServices "noexit"
		executeAfterStartServices "noexit"

		if [[ $rc -eq 0 ]]; then # don't apply BS if SR dryrun a second time, BS was done already previously
			logItem "BACKUPTARGET_DIR: $BACKUPTARGET_DIR"
			if [[ -d "${BACKUPTARGET_DIR}" ]]; then   # does not exists if raspiBackup7412Test runs
				local rc
				mv "${BACKUPTARGET_DIR}" "${BACKUPTARGET_FINAL_DIR}"
				rc=$?
				if (( $rc )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_TEMPMOVE_FAILED $rc
					CLEANUP_RC=$RC_TEMPMOVE_FAILED
				else
					if [[ $MSG_LEVEL == "$MSG_LEVEL_MINIMAL" ]]; then
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUPDIR_CREATED "$BACKUPTARGET_FINAL_DIR"
					else
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUPDIR_MOVED "$BACKUPTARGET_DIR" "$BACKUPTARGET_FINAL_DIR"
					fi
					BACKUPTARGET_FILE="$BACKUPTARGET_FINAL_FILE"
				fi
			else
				logItem "??? BACKUPTARGET_DIR: $BACKUPTARGET_DIR not found"
			fi

			if (( ! $CLEANUP_RC && ! $IS_SNAPSHOT )); then # smartrecycle only if mv succeeded and no snapshot was created
				BACKUPTARGET_DIR="$BACKUPTARGET_FINAL_DIR"
				if (( \
					( $SMART_RECYCLE && ! $SMART_RECYCLE_DRYRUN ) \
					|| ! $SMART_RECYCLE \
					)); then
						applyBackupStrategy
				fi
			fi

			reportOldBackups
		fi
	fi

	cleanupBackup
	cleanupTempFiles

	finalCommand "$CLEANUP_RC"

	logItem "Terminate now with rc $CLEANUP_RC"

	if (( $rc != 0 )); then
		if (( ! $MAIL_ON_ERROR_ONLY )); then
			if (( $WARNING_MESSAGE_WRITTEN )); then
				if (( $RESTORE )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_WARNING
				else
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_WARNING
				fi
			fi
		fi

		task="Backup"
		if (( $rc != $RC_CTRLC )); then
			if (( $RESTORE )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_FAILED
				task="Restore"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_FAILED
			fi

			writeToConsole $MSG_LEVEL_MINIMAL $MSG_STOPPED "$HOSTNAME" "$MYSELF" "$VERSION" "$GIT_DATE_ONLY" "$GIT_COMMIT_ONLY" "$(date)" "$rc"
			logger -t $MYNAME "Stopped $VERSION ($GIT_COMMIT_ONLY). rc $rc"

			logger "INTERACTIVE: $INTERACTIVE"

			if (( ! $INTERACTIVE || $FAKE || $FORCE_EMAIL )); then
				if (( $rc != $RC_EMAILPROG_ERROR )); then
					msgTitle=$(getMessage $MSG_TITLE_ERROR $HOSTNAME $task)
					sendEMail "$msg" "$msgTitle"
				fi
				if [[ -n "$TELEGRAM_TOKEN" ]]; then
					msg=$(getMessage $MSG_TITLE_ERROR $HOSTNAME $task)
					if [[ "$TELEGRAM_NOTIFICATIONS" =~ $TELEGRAM_NOTIFY_FAILURE ]]; then
						sendTelegramm "${EMOJI_FAILED} <b><u> $msg </u></b>"		# add warning icon to message
						sendTelegrammLogMessages
					fi
				fi
				if [[ -n "$PUSHOVER_TOKEN" ]]; then
					msg=$(getMessage $MSG_TITLE_ERROR $HOSTNAME $task)
					if [[ "$PUSHOVER_NOTIFICATIONS" =~ $PUSHOVER_NOTIFY_FAILURE_NOTIFY_FAILURE ]]; then
						sendPushover "${EMOJI_FAILED} $msg" 1		# add warning icon to message
					fi
				fi
				if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
					msg=$(getMessage $MSG_TITLE_ERROR $HOSTNAME $task)
					if [[ "$SLACK_NOTIFICATIONS" =~ $SLACK_NOTIFY_FAILURE_NOTIFY_FAILURE ]]; then
						sendSlack "$msg" 1		# add warning icon to message
					fi
				fi
			fi 
		fi

	else 	# success

		local task="Backup"
		if (( $RESTORE )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_OK
			task="Restore"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_OK
		fi

		writeToConsole $MSG_LEVEL_MINIMAL $MSG_STOPPED "$HOSTNAME" "$MYSELF" "$VERSION" "$GIT_DATE_ONLY" "$GIT_COMMIT_ONLY" "$(date)" "$rc"
		logger -t $MYNAME "Stopped $VERSION ($GIT_COMMIT_ONLY). rc $rc"

		logger "INTERACTIVE: $INTERACTIVE"

		if (( ! $INTERACTIVE || $FAKE | $FORCE_EMAIL )); then
			if [[ -n "$TELEGRAM_TOKEN"  ]]; then
				msg=$(getMessage $MSG_TITLE_OK $HOSTNAME $task)
				if [[ "$TELEGRAM_NOTIFICATIONS" =~ $TELEGRAM_NOTIFY_SUCCESS ]]; then
					sendTelegramm "${EMOJI_OK} $msg"
					sendTelegrammLogMessages
				fi
			fi
			if [[ -n "$PUSHOVER_TOKEN"  ]]; then
				msg=$(getMessage $MSG_TITLE_OK $HOSTNAME $task)
				if [[ "$PUSHOVER_NOTIFICATIONS" =~ $PUSHOVER_NOTIFY_SUCCESS ]]; then
					sendPushover "${EMOJI_OK} $msg" 0
				fi
			fi
			if [[ -n "$SLACK_WEBHOOK_URL"  ]]; then
				msg=$(getMessage $MSG_TITLE_OK $HOSTNAME $task)
				if [[ "$SLACK_NOTIFICATIONS" =~ $SLACK_NOTIFY_SUCCESS ]]; then
					sendSlack "${EMOJI_OK} $msg" 0
				fi
			fi

			msg=$(getMessage $MSG_TITLE_OK $HOSTNAME $task)
			sendEMail "" "$msg"
		fi
	fi

	if (( $LOG_LEVEL == $LOG_DEBUG )); then
		masqueradeSensitiveInfoInLog # and now masquerade sensitive details in log file
	fi

	logFinish

	saveVars

	callNotificationExtension $rc

	logExit

	unLockMe

	if [[ -n "$DYNAMIC_MOUNT" ]] && (( $DYNAMIC_MOUNT_EXECUTED )); then
		writeToConsole $MSG_LEVEL_DETAILED $MSG_DYNAMIC_UMOUNT_SCHEDULED "$DYNAMIC_MOUNT"
		umount -l $DYNAMIC_MOUNT &>>$LOG_FILE
	fi

	if (( ! $RESTORE && $REBOOT_SYSTEM )); then
		shutdown -r +3						# wait some time to allow eMail to be sent
	fi

	exit $rc
}

function cleanupRestore() { # trap

	logEntry

	local error=0

	logItem "Got trap $1"
	logItem "rc: $rc"

	rm $MODIFIED_SFDISK &>/dev/null

	if (( $PRE_RESTORE_EXTENSION_CALLED )); then
		callExtensions $POST_RESTORE_EXTENSION $rc
	fi

	if [[ -n "$MNT_POINT" ]]; then
		umountPartition "$MNT_POINT"

		logItem "Deleting dir $MNT_POINT"
		rmdir "$MNT_POINT" &>>"$LOG_FILE"
	fi

	if [[ -d $TEMPORARY_MOUNTPOINT_ROOT ]]; then
		logItem "Deleting dir $TEMPORARY_MOUNTPOINT_ROOT"
		rmdir "$TEMPORARY_MOUNTPOINT_ROOT" &>>"$LOG_FILE"
	fi

	if (( ! $PARTITIONBASED_BACKUP )); then
		umountPartition "$BOOT_PARTITION"
		umountPartition "$ROOT_PARTITION"
	fi

	cleanupTempFiles

	logExit "$rc"

}

function revertScriptVersion() {

	logEntry

	local currentVersion version sortedVersions existingVersionFiles

	#shellcheck disable=SC2207
	# (warning): Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	local existingVersionFiles=( $(ls $SCRIPT_DIR/$MYNAME.*sh) )

	if [[ ! -e "$SCRIPT_DIR/$MYSELF" ]]; then
		assertionFailed $LINENO "$SCRIPT_DIR/$MYSELF not found"
	fi

	currentVersion="$(extractVersionFromFile "$SCRIPT_DIR/$MYSELF" "$VERSION_VARNAME")"
	if [[ -z "$currentVersion" ]]; then
		assertionFailed $LINENO "Current version not found"
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_SCRIPT_VERSION "$currentVersion"

	declare -A versionsOfFiles

	local version
	for versionFile in "${existingVersionFiles[@]}"; do
		version="$(extractVersionFromFile "$versionFile" "$VERSION_VARNAME" )"
		if [[ -n "$version" ]]; then
			if [[ $version != "$currentVersion" ]]; then
				versionsOfFiles+=([$version]=$versionFile)
			fi
		fi
	done

	for version in "${!versionsOfFiles[@]}"; do
		logItem "$version: ${versionsOfFiles[$version]}"
	done

	#shellcheck disable=SC2207
	# (warning): Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	local sortedVersions=( $(echo -e "${!versionsOfFiles[@]}" | sed -e 's/ /\n/g' | sort) )

	local min=0
	local max=$(( ${#sortedVersions[@]} - 1))

	if [[ $max == -1 ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_PREVIOUS_VERSIONS_AVAILABLE
		return
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_AVAILABLE_VERSIONS_HEADER
	for version in "${!sortedVersions[@]}"; do
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_AVAILABLE_VERSIONS "$version" "${sortedVersions[$version]}"
	done

	local selection
	local valid=0
	while (( ! $valid )); do
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SELECT_VERSION "$min" "$max"
		read selection
		if (( "$selection" < $min || "$selection" > $max )); then
			continue
		fi

		version=${sortedVersions[$selection]}
		valid=1
	done

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_SAVING_ACTUAL_VERSION "$currentVersion" "$MYNAME.$currentVersion.sh"
	logItem "mv $SCRIPT_DIR/$MYNAME.sh $SCRIPT_DIR/$MYNAME.$currentVersion.sh"
	mv "$SCRIPT_DIR/$MYNAME.sh" "$SCRIPT_DIR/$MYNAME.$currentVersion.sh"

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_PREVIOUS_VERSION "$version" "$MYNAME.sh"
	logItem "cp -a ${versionsOfFiles[$version]} $SCRIPT_DIR/$MYNAME.sh"
	cp -a "${versionsOfFiles[$version]}" "$SCRIPT_DIR/$MYNAME.sh"

	logExit

}

function isBetaAvailable() {

	logEntry

	local betaVersion=""

	if (( $NEW_PROPERTIES_FILE )); then
		betaVersion=${BETA_PROPERTY//\"/}
	fi

	echo $betaVersion

	logExit "$betaVersion"

}

function cleanupBackup() {

	logEntry

	if (( $PARTITIONBASED_BACKUP )); then
		umountPartitions "$TEMPORARY_MOUNTPOINT_ROOT"
	fi

	cleanupBackupDirectory
	cleanupTempFiles

	logExit

}

function cleanupTempFiles() {

	logEntry

	if [[ -f $MYSELF~ ]]; then
		logItem "Removing new version $MYSELF~"
		rm -f $MYSELF~ &>/dev/null
	fi

	if [[ -d "$TEMPORARY_MOUNTPOINT_ROOT" ]]; then
		logItem "Removing $TEMPORARY_MOUNTPOINT_ROOT"
		rmdir -p "$TEMPORARY_MOUNTPOINT_ROOT" &>/dev/null
	fi

	logExit

}

function checkImportantParameters() {

	local ll lla pll org

	org="$LOG_LEVEL"
	ll="${LOG_LEVEL^^}"
	pll="^${POSSIBLE_LOG_LEVELs^^}\$"
	if [[ "$ll" =~ $pll ]]; then
		lla="$(tr '[:lower:]' '[:upper:]'<<< ${LOG_LEVEL_ARGs[$ll]+abc})"
		if [[ "$lla" == "ABC" ]]; then
			LOG_LEVEL=${LOG_LEVEL_ARGs[$ll]}
		else
			LOG_LEVEL=$LOG_DEBUG
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_LOG_LEVEL "$org"
			exitError $RC_PARAMETER_ERROR
		fi
	fi
	if [[ ! "$LOG_LEVEL" =~ $POSSIBLE_LOG_LEVEL_NUMBERs ]]; then
		LOG_LEVEL=$LOG_DEBUG
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_LOG_LEVEL "$org"
		exitError $RC_PARAMETER_ERROR
	fi

	local ml mla mll

	org="$MSG_LEVEL"
	ml="${MSG_LEVEL^^}"
	mll="^${POSSIBLE_MSG_LEVELs^^}\$"
	if [[ "$ml" =~ $mll ]]; then
		mla="$(tr '[:lower:]' '[:upper:]'<<< ${MSG_LEVEL_ARGs[$ml]+abc})"
		if [[ "$mla" == "ABC" ]]; then
			MSG_LEVEL=${MSG_LEVEL_ARGs[$ml]}
		else
			MSG_LEVEL=$MSG_LEVEL_DETAILED
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_MSG_LEVEL "$org"
			exitError $RC_PARAMETER_ERROR
		fi
	fi
	if [[ ! "$MSG_LEVEL" =~ $POSSIBLE_MSG_LEVEL_NUMBERs ]]; then
		MSG_LEVEL=$MSG_LEVEL_DETAILED
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_MSG_LEVEL "$org"
		exitError $RC_PARAMETER_ERROR
	fi

	local lo loa plo

	lo="${LOG_OUTPUT^^}"
	plo="^${POSSIBLE_LOG_OUTPUTs^^}\$"
	if [[ "$lo" =~ $plo ]]; then
		loa="$(tr '[:lower:]' '[:upper:]'<<< ${LOG_OUTPUT_ARGs[$lo]+abc})"
		if [[ "$loa" == "ABC" ]]; then
			LOG_OUTPUT=${LOG_OUTPUT_ARGs[$lo]}
			logItem "LOG_OUTPUT=$LOG_OUTPUT"
		fi
	fi

	if [[ ! "$LOG_OUTPUT" =~ $POSSIBLE_LOG_OUTPUT_NUMBERs ]]; then
		if [[ ${LOG_OUTPUT:0:1} != "/" ]]; then
			LOG_OUTPUT="$CURRENT_DIR/$LOG_OUTPUT"
			logItem "LOG_OUTPUT=$LOG_OUTPUT"
		fi

		if ! touch "$LOG_OUTPUT" &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_FILE "$LOG_OUTPUT"
			LOG_OUTPUT=$LOG_OUTPUT_HOME
			logItem "LOG_OUTPUT=$LOG_OUTPUT"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if ! containsElement "${LANGUAGE}" "${SUPPORTED_LANGUAGES[@]}"; then
		local l=$LANGUAGE
		LANGUAGE=$FALLBACK_LANGUAGE
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_LANGUAGE_NOT_SUPPORTED "$l"
	fi

}

function createLinks() { # backuptargetroot extension newfile

	logEntry "$1 $2 $3"

	local file rc possibleLinkTargetDirectory possibleLinkTarget

	possibleLinkTargetDirectory=$(ls -d $1/${HOSTNAME_OSR}-$BACKUPTYPE-backup-* 2>/dev/null | tail -2 | head -1)

	if [[ -z "$possibleLinkTargetDirectory" || "$possibleLinkTargetDirectory" == "$BACKUPTARGET_DIR" ]]; then
		logItem "No possible link target directory found"
		return
	fi

	logItem "PossibleLinkTargetDirectory: $possibleLinkTargetDirectory"
	possibleLinkTarget=$(find "$possibleLinkTargetDirectory" -maxdepth 1 -name "$HOSTNAME-backup.$2")
	logItem "Possible link target: $possibleLinkTarget"

	if [[ -z $possibleLinkTarget ]]; then
		logItem "No possible link target found"
		return
	fi

	if cmp -s $3 $possibleLinkTarget; then
		rm $3 &>/dev/null
		writeToConsole $MSG_LEVEL_DETAILED $MSG_REPLACING_FILE_BY_HARDLINK "$3" "$possibleLinkTarget"
		cp -l "$possibleLinkTarget" "$3" &>/dev/null
		rc=$?
		if [[ $rc != 0 ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_HARDLINK_ERROR "$1" "$rc"
			exitError $RC_LINK_FILE_FAILED
		fi
		local links
		links="$(stat -c %h -- "$3")"
		if (( links < 2 )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_HARDLINK_ERROR "$1" "$rc"
			exitError $RC_LINK_FILE_FAILED
		fi
	fi

	logExit
}

function bootPartitionBackup() {

		logEntry

		local p rc cmd

		logItem "Starting boot partition backup..."

		if (( ! $FAKE && ! $EXCLUDE_DD && ! $SHARED_BOOT_DIRECTORY )); then
			local ext=$BOOT_DD_EXT
			(( $TAR_BOOT_PARTITION_ENABLED )) && ext=$BOOT_TAR_EXT
			if  [[ ! -e "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_CREATING_BOOT_BACKUP "$BACKUPTARGET_FINAL_DIR/$BACKUPFILES_PARTITION_DATE.$ext"
				if (( $TAR_BOOT_PARTITION_ENABLED )); then
					local bootMountpoint
					[[ -d /boot/firmware ]] && bootMountpoint="/boot/firmware" || bootMountpoint="/boot"
					cmd="cd $bootMountpoint; tar $TAR_BACKUP_OPTIONS -f \"$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext\" ."
					executeTar "$cmd"
				else
					cmd="dd if=/dev/${BOOT_PARTITION_PREFIX}1 of=\"$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext\" bs=$DD_BLOCKSIZE"
					executeDD "$cmd"
				fi
				rc=$?
				if [ $rc != 0 ]; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_BOOT_BACKUP_FAILED "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext" "$rc"
					exitError $RC_DD_IMG_FAILED
				fi

				if (( ! $TAR_BOOT_PARTITION_ENABLED )); then
					local loopDev
					loopDev="$(losetup -f)"
					logItem "Loop device: $loopDev"
					losetup -P $loopDev $BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext &>>$LOG_FILE
					rc=$?
					logItem "losetup rc: $rc"
					if (( $rc != 0 )); then
						losetup -d $loopDev &>>$LOG_FILE
						logItem "Mount of boot partition backup file failed with rc $rc" # silently ignore losetup error
					else
						writeToConsole $MSG_LEVEL_DETAILED $MSG_IMG_BOOT_CHECK_STARTED
						fsck -fp $loopDev &>>$LOG_FILE
						rc=$?
						logItem "fsck rc: $rc"
						losetup -d $loopDev &>>$LOG_FILE
						if (( $rc > 1 )); then
							writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_BOOT_FSCHECK_FAILED "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext" "$rc"
							exitError $RC_DD_IMG_FAILED
						fi
					fi
				fi

				if (( $LINK_BOOTPARTITIONFILES )); then
					createLinks "$BACKUPTARGET_ROOT" $ext "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext"
				fi

			else
				logItem "Found existing backup of boot partition $BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext ..."
				writeToConsole $MSG_LEVEL_DETAILED $MSG_EXISTING_BOOT_BACKUP "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.$ext"
			fi

			if  [[ ! -e "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_PARTITION_BACKUP "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk"
				local stripMultiple
				if (( $IGNORE_ADDITIONAL_PARTITIONS )); then
					logItem "Stripping partitions > 2"
					stripMultiple='| grep -v -E "[3-9] :"'
				fi
				eval "sfdisk -d $BOOT_DEVICENAME $stripMultiple" > "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk" 2>>$LOG_FILE
				local rc=$?
				if [ $rc != 0 ]; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_COLLECT_PARTITIONINFO "sfdisk" "$rc"
					exitError $RC_COLLECT_PARTITIONS_FAILED
				fi
				logCommand "cat $BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk"

				if (( $LINK_BOOTPARTITIONFILES )); then
					createLinks "$BACKUPTARGET_ROOT" "sfdisk" "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk"
				fi
			else
				logItem "Found existing backup of partition layout $BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk ..."
				writeToConsole $MSG_LEVEL_DETAILED $MSG_EXISTING_PARTITION_BACKUP "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk"
			fi

			if  [[ ! -e "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_MBR_BACKUP "$BACKUPTARGET_FINAL_DIR/$BACKUPFILES_PARTITION_DATE.mbr"
				cmd="dd if=$BOOT_DEVICENAME of=\"$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr\" bs=512 count=1"
				executeDD "$cmd"
				local rc=$?
				if [ $rc != 0 ]; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_DD_FAILED ".mbr" "$rc"
					exitError $RC_COLLECT_PARTITIONS_FAILED
				fi

				if (( $LINK_BOOTPARTITIONFILES )); then
					createLinks "$BACKUPTARGET_ROOT" "mbr" "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr"
				fi

			else
				logItem "Found existing backup of master boot record $BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr ..."
				writeToConsole $MSG_LEVEL_DETAILED $MSG_EXISTING_MBR_BACKUP "$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr"
			fi
		fi

		logItem "Finished boot partition backup..."

		logExit

}
function partitionLayoutBackup() {

		logEntry

		local p rc

		writeToConsole $MSG_LEVEL_DETAILED $MSG_BACKUP_CREATING_PARTITION_INFO

		SF_FILE="$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.sfdisk"
		MBR_FILE="$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.mbr"
		BLKID_FILE="$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.blkid"
		PARTED_FILE="$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.parted"
		FDISK_FILE="$BACKUPTARGET_DIR/$BACKUPFILES_PARTITION_DATE.fdisk"

		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_PARTITION_BACKUP "$SF_FILE"
		sfdisk -d $BOOT_DEVICENAME > "$SF_FILE" 2>>$LOG_FILE
		local rc=$?
		if [ $rc != 0 ]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_COLLECT_PARTITIONINFO "sfdisk" "$rc"
			exitError $RC_COLLECT_PARTITIONS_FAILED
		fi
		logItem "sfdisk"
		logItem "$(<"$SF_FILE")"

		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_PARTITION_BACKUP "$BLKID_FILE"
		logItem "Saving blkid"
		blkid > "$BLKID_FILE"
		local rc=$?
		if [ $rc != 0 ]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_COLLECT_PARTITIONINFO "blkid" "$rc"
			exitError $RC_COLLECT_PARTITIONS_FAILED
		fi
		logItem "blkid"
		logItem "$(<"$BLKID_FILE")"

		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_PARTITION_BACKUP "$PARTED_FILE"
		logItem "Saving parted"
		parted -m $BOOT_DEVICENAME print > "$PARTED_FILE"
		local rc=$?
		if [ $rc != 0 ]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_COLLECT_PARTITIONINFO "parted" "$rc"
			exitError $RC_COLLECT_PARTITIONS_FAILED
		fi
		logItem "parted"
		logItem "$(<"$PARTED_FILE")"

		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_PARTITION_BACKUP "$FDISK_FILE"
		logItem "Saving fdisk"
		fdisk -l $BOOT_DEVICENAME > "$FDISK_FILE"
		local rc=$?
		if [ $rc != 0 ] ; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_COLLECT_PARTITIONINFO "fdisk" "$rc"
			exitError $RC_COLLECT_PARTITIONS_FAILED
		fi
		logItem "fdisk"
		logItem "$(<"$FDISK_FILE")"

		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_MBR_BACKUP "$MBR_FILE"
		cmd="dd if=$BOOT_DEVICENAME of=$MBR_FILE bs=512 count=1"
		executeDD "$cmd"
		rc=$?
		if [ $rc != 0 ]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_DD_FAILED ".mbr" "$rc"
			exitError $RC_COLLECT_PARTITIONS_FAILED
		fi

		logExit

}

function backupDD() {

	logEntry

	local cmd verbose partition

	(( $VERBOSE )) && verbose="-v" || verbose=""

	local progressFlag=""
	(( $PROGRESS && $INTERACTIVE )) && progressFlag="status=progress"

	if (( $PARTITIONBASED_BACKUP )); then

		partition="${BOOT_DEVICENAME}p$1"
		partitionName="${BOOT_PARTITION_PREFIX}$1"

		if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
			cmd="dd if=$partition bs=$DD_BLOCKSIZE $progressFlag $DD_PARMS | gzip ${verbose} > \"${BACKUPTARGET_DIR}/$partitionName${FILE_EXTENSION[$BACKUPTYPE]}\""
		else
			cmd="dd if=$partition bs=$DD_BLOCKSIZE $progressFlag $DD_PARMS of=\"${BACKUPTARGET_DIR}/$partitionName${FILE_EXTENSION[$BACKUPTYPE]}\""
		fi

	else

		if (( ! $DD_BACKUP_SAVE_USED_PARTITIONS_ONLY )); then
			if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
				cmd="dd if=$BOOT_DEVICENAME bs=$DD_BLOCKSIZE $progressFlag $DD_PARMS | gzip ${verbose} > \"$BACKUPTARGET_FILE\""
			else
				cmd="dd if=$BOOT_DEVICENAME bs=$DD_BLOCKSIZE $progressFlag $DD_PARMS of=\"$BACKUPTARGET_FILE\""
			fi
		else
			local lastByte spaceUsedHuman sdcardSize sdcardSizeHuman count blocksize
			logCommand "fdisk -l $BOOT_DEVICENAME"
			lastByte=$(lastUsedPartitionByte $BOOT_DEVICENAME)
			if (( lastByte == 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_TRUNCATING_ERROR "$sdcardSizeHuman" "$spaceUsedHuman"
				exitError $RC_MISC_ERROR
			fi
			spaceUsedHuman=$(bytesToHuman $lastByte)
			sdcardSize=$(blockdev --getsize64 $BOOT_DEVICENAME)
			sdcardSizeHuman=$(bytesToHuman $sdcardSize)
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_TRUNCATING_TO_USED_PARTITIONS_ONLY "$sdcardSizeHuman" "$spaceUsedHuman"

			(( blocksize=1024*1024 ))		# 1MB hard coded
			(( count = lastByte / blocksize ))
			logItem "Count: $count"
			if (( count * blocksize < lastByte )); then
				(( count++ ))
				logItem "Updated count: $count"
			fi

			if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
				if (( $PROGRESS && $INTERACTIVE )); then
					cmd="dd if=$BOOT_DEVICENAME bs=$blocksize count=$count | pv -fs $(fdisk -l "$BOOT_DEVICENAME" | grep "Disk.*$BOOT_DEVICENAME" | cut -d ' ' -f 5) | gzip ${verbose} > \"$BACKUPTARGET_FILE\""
				else
					cmd="dd if=$BOOT_DEVICENAME bs=$blocksize count=$count | gzip ${verbose} > \"$BACKUPTARGET_FILE\""
				fi
			else
				if (( $PROGRESS && $INTERACTIVE )); then
					cmd="dd if=$BOOT_DEVICENAME bs=$blocksize count=$count | pv -fs $(fdisk -l "$BOOT_DEVICENAME" | grep "Disk.*$BOOT_DEVICENAME" | cut -d ' ' -f 5) | dd of=\"$BACKUPTARGET_FILE\""
				else
					cmd="dd if=$BOOT_DEVICENAME bs=$blocksize count=$count of=\"$BACKUPTARGET_FILE\""
				fi
			fi

		fi
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_STARTED "$BACKUPTYPE"

	if (( ! $EXCLUDE_DD )); then
		if (( ! $FAKE)); then
			executeDD "$cmd"
			rc=$?
		else
			rc=0
		fi
	fi

	logExit  "$rc"

	return $rc
}

function backupTar() {

	local verbose="" zip="" cmd partition source target devroot sourceDir journalExclude="" extension

	logEntry

	(( $VERBOSE )) && verbose="-v"
	if [[ -n "$TAR_COMPRESSION_TOOL" ]]; then
			zip="-I\"${TAR_COMPRESSION_TOOL} $TAR_COMPRESSION_TOOL_OPTIONS\""
			extension="$TAR_COMPRESSION_EXTENSION"
	else
		extension="${FILE_EXTENSION[$BACKUPTYPE]}"
		[[ "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]] && zip="-z"
	fi

	if (( $PARTITIONBASED_BACKUP )); then
		partition="${BOOT_PARTITION_PREFIX}$1"
		source="."
		devroot="."
		sourceDir="$TEMPORARY_MOUNTPOINT_ROOT/$partition"
		target="${BACKUPTARGET_DIR}/${partition}${extension}"

	else
		bootPartitionBackup
		source="/"
		devroot=""
		target="\"$BACKUPTARGET_FILE\""
	fi

	if [[ -e /$PERSISTENT_JOURNAL ]]; then
		logItem "Excluding /$PERSISTENT_JOURNAL"
		journalExclude="--exclude=$devroot/${PERSISTENT_JOURNAL}"
	fi

	writeToConsole $MSG_LEVEL_DETAILED $MSG_MAIN_BACKUP_PROGRESSING $BACKUPTYPE "${target//\\/}"

	local log_file="${LOG_FILE/\//}" # remove leading /
	local msg_file="${MSG_FILE/\//}" # remove leading /

	cmd="tar \
		$TAR_BACKUP_OPTIONS \
		$TAR_BACKUP_ADDITIONAL_OPTIONS \
		${zip} \
		${verbose} \
		-f $target \
		--warning=no-xdev \
		--numeric-owner \
		--exclude=\"$BACKUPPATH_PARAMETER/*\" \
		--exclude=\"$devroot/$log_file\" \
		--exclude=\"$devroot/$msg_file\" \
		--exclude='.gvfs' \
		--exclude=$devroot/proc/* \
		--exclude=$devroot/lost+found/* \
		--exclude=$devroot/sys/* \
		--exclude=$devroot/dev/* \
		--exclude=$devroot/tmp/* \
		--exclude=$devroot/var/swap \
		--exclude=$devroot/swapfile \
		--exclude=$devroot/run/* \
		--exclude=$devroot/media/* \
		$journalExclude \
		$EXCLUDE_LIST \
		$source"

	if (( $PARTITIONBASED_BACKUP )); then
		if ! pushd $sourceDir &>>"$LOG_FILE"; then
				assertionFailed $LINENO "push to $sourceDir failed"
		fi
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_STARTED "$BACKUPTYPE"

	if [[ -n $TAR_COMPRESSION_TOOL ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_TAR_COMPRESS_TOOL_USED "$TAR_COMPRESSION_TOOL"
	fi

	if (( ! $FAKE )); then
		executeTar "${cmd}" "$TAR_IGNORE_ERRORS"
		rc=$?
	fi

	if (( $PARTITIONBASED_BACKUP )); then
		if ! popd &>>"$LOG_FILE"; then
			assertionFailed $LINENO "pop failed"
		fi
	fi

	logExit  "$rc"

	return $rc
}


function waitForPartitionDefsChanged {
	logEntry
	sync
	sleep 3
	logItem "--- partprobe ---"
	partprobe -s &>>$LOG_FILE
	sleep 3
	logItem "--- udevadm ---"
	udevadm settle &>>$LOG_FILE
	logExit
}

function updateUUIDs() {
	logEntry
	if (( $UPDATE_UUIDS )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UPDATING_UUIDS
		logItem "Old blkid"
		logCommand "blkid"
		updatePartUUID
		updateUUID
		logItem "blkid after UUID update${NL}$(blkid)"
	fi
	logExit
}

function updatePartUUID() {
	logEntry
	local newUUID
	if (( $UPDATE_UUIDS )); then
		newUUID=$(od -A n -t x -N 4 /dev/urandom | tr -d " ")
		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_UUID "PARTUUID" "$newUUID" "$RESTORE_DEVICE"
		echo -ne "x\ni\n0x$newUUID\nr\nw\nq\n" | fdisk "$RESTORE_DEVICE" &>> "$LOG_FILE"
		waitForPartitionDefsChanged
	fi
	logExit
}

function updateUUID() {
	logEntry
	if (( $UPDATE_UUIDS )); then
		logItem "BOOT_PARTITION: $BOOT_PARTITION - ROOT_PARTITION: $ROOT_PARTITION"
		local newUUID
		if (( ! $SHARED_BOOT_DIRECTORY )); then
			newUUID="$(od -A n -t x -N 4 /dev/urandom | tr -d " " | sed -r 's/(.{4})/\1-/')"
			newUUID="${newUUID^^*}"
			writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_UUID "UUID" "$newUUID" "$BOOT_PARTITION"
			printf "\x${newUUID:7:2}\x${newUUID:5:2}\x${newUUID:2:2}\x${newUUID:0:2}" \
				| dd bs=1 seek=67 count=4 conv=notrunc of=$BOOT_PARTITION &>>"$LOG_FILE" # 39 for fat16, 67 for fat32
			waitForPartitionDefsChanged
		fi
		newUUID="$(</proc/sys/kernel/random/uuid)"
		writeToConsole $MSG_LEVEL_DETAILED $MSG_CREATING_UUID "UUID" "$newUUID" "$ROOT_PARTITION"
		e2fsck -y -f $ROOT_PARTITION &>> "$LOG_FILE"
		tune2fs -U "$newUUID" $ROOT_PARTITION &>>"$LOG_FILE"
		waitForPartitionDefsChanged
	fi
	logExit
}

function collectPartitionsInBackup() { # lastBackupDir

	logEntry "$1"

	local result

	# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
	#shellcheck disable=SC2010
	result=$(ls -l "$1" | grep "^d" | grep -Eo "[0-9]+$")

	echo "$result"
	logExit "$result"
}

function checkIfAllPreviousPartitionsAreIncludedInBackup() { # lastBackupDir

	logEntry "$1"

	local rc partitionsInBackup partitionsToBackup

	#  Prefer mapfile or read -a to split command output (or quote to avoid splitting).
	#shellcheck disable=SC2207
	partitionsInBackup=( $(collectAvailableBackupPartitions "$1") )

	# Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
	#shellcheck disable=SC2206
	partitionsToBackup=( ${PARTITIONS_TO_BACKUP[@]} )

	local missingPartition=()

	for (( i=0; i<${#partitionsInBackup[@]}; i++ )); do
		if ! containsElement "${partitionsInBackup[i]}" "${partitionsToBackup[@]}"; then
			logItem "Missing ${partitionsInBackup[i]}"
			missingPartition+=( "${partitionsInBackup[i]}" )
		fi
	done

	echo "${missingPartition[@]}"

	(( ${#missingPartition[@]} == 0 ))
	rc=$?

	logExit "$rc - ${missingPartition[*]}"
	return $rc
}

function backupRsync() { # partition number (for partition based backup)

	local verbose partition target source cmd cmdParms excludeMeta journalExclude

	logEntry

	(( $PROGRESS )) && VERBOSE=0

	verbose="--info=NAME0"
	(( $VERBOSE )) && verbose="-v"

	if [[ -e "/$PERSISTENT_JOURNAL" ]]; then
		logItem "Excluding /$PERSISTENT_JOURNAL"
		journalExclude="--exclude=/${PERSISTENT_JOURNAL}"
	fi

	logCommand "ls $BACKUPTARGET_ROOT"

	if (( $PARTITIONBASED_BACKUP )); then
		partition="${BOOT_PARTITION_PREFIX}$1"
		target="${BACKUPTARGET_DIR}/$partition"
		source="$TEMPORARY_MOUNTPOINT_ROOT/$partition/"
	else
		target="\"${BACKUPTARGET_DIR}\""
		source="/"
		bootPartitionBackup
		excludeMeta="--exclude=/$BACKUPFILES_PARTITION_DATE.img --exclude=/$BACKUPFILES_PARTITION_DATE.tmg --exclude=/$BACKUPFILES_PARTITION_DATE.sfdisk --exclude=/$BACKUPFILES_PARTITION_DATE.blkid --exclude=/$BACKUPFILES_PARTITION_DATE.fdisk --exclude=/$BACKUPFILES_PARTITION_DATE.parted --exclude=/$BACKUPFILES_PARTITION_DATE.mbr --exclude=/$MYNAME.log --exclude=/$MYNAME.msg"
	fi

	lastBackupDir=$(find "$BACKUPTARGET_ROOT" -maxdepth 1 -type d -name "${HOSTNAME_OSR}-$BACKUPTYPE-*" ! -name $BACKUPFILE 2>>/dev/null | sort | tail -n 1)

	logItem "lastBackupDir: $lastBackupDir"

	if [[ -n "$lastBackupDir" ]]; then
		if [[ -d "$lastBackupDir/$partition" ]]; then
			lastBackupDir="$lastBackupDir/${partition}"
		else
			lastBackupDir=""
		fi
	fi

	local LINK_DEST=""
	if [[ -n "$lastBackupDir" ]]; then
		LINK_DEST="--link-dest=\"$lastBackupDir\""
		logItem "LinkDest: $LINK_DEST"
		writeToConsole $MSG_LEVEL_DETAILED $MSG_HARDLINK_DIRECTORY_USED "$lastBackupDir"
	fi

	writeToConsole $MSG_LEVEL_DETAILED $MSG_MAIN_BACKUP_PROGRESSING $BACKUPTYPE "${target//\\/}"

	local log_file="${LOG_FILE/\//}" # remove leading /
	local msg_file="${MSG_FILE/\//}" # remove leading /

	cmdParms="--exclude=\"$BACKUPPATH_PARAMETER/*\" \
--exclude=\"$log_file\" \
--exclude=\"$msg_file\" \
--exclude='.gvfs' \
--exclude=/proc/* \
--exclude=/lost+found/* \
--exclude=/sys/* \
--exclude=/dev/* \
--exclude=/var/swap \
--exclude=/swapfile \
--exclude=/tmp/* \
--exclude=/run/* \
--exclude=/media/* \
$journalExclude \
$excludeMeta \
$EXCLUDE_LIST \
$LINK_DEST \
--numeric-ids \
$RSYNC_BACKUP_OPTIONS \
$RSYNC_BACKUP_ADDITIONAL_OPTIONS \
$verbose \
$source \
$target \
"

	if (( $PROGRESS && $INTERACTIVE )); then
		cmd="rsync --info=progress2 $cmdParms"
	else
		cmd="rsync $cmdParms"
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_STARTED "$BACKUPTYPE"

	if (( ! $FAKE )); then
		executeRsync "$cmd" "$RSYNC_IGNORE_ERRORS"
		rc=$?
	fi

	logExit  "$rc"

}

function areDevicesUnique() {

	logEntry

	local -A UUID
	local -A PARTUUID
	local line
	local unique=0

	local uuid uuidsub partuuid

	logCommand "blkid -o udev"

	while read line; do

		if grep -q ID_FS_UUID= <<< "$line"; then
			uuid="$(cut -f2 -d= <<< "$line")"
		fi
		if grep -q ID_FS_UUID_SUB= <<< "$line"; then
			uuidsub="$(cut -f2 -d= <<< "$line")"
			uuid="${uuid}_${uuidsub}"
		fi
		if grep -q ID_FS_PARTUUID= <<< "$line"; then
			partuuid="$(cut -f2 -d= <<< "$line")"
			if [[ ${PARTUUID[$partuuid]}+abc != "+abc" ]]; then
				logItem "PARTUUID $partuuid is not unique"
				unique=1
			else
				PARTUUID[$partuuid]=1
			fi
		fi

		if [[ -z "$line" ]]; then								# groups are separated by empty lines thus one group parsed now
			if [[ -n $uuid ]]; then
				if [[ ${UUID[$uuid]}+abc != "+abc" ]]; then
					logItem "UUID $uuid is not unique"
					unique=1
				else
					UUID[$uuid]=1
				fi
			fi
			uuid=""
			uuidsub=""
		fi

	done < <(blkid -o udev)

	if [[ -n $uuid && ${UUID[$uuid]}+abc != "+abc" ]]; then # check last group in output with no trailing empty line
		logItem "UUID $uuid is not unique"
		unique=1
	fi

	logExit $unique
	return $unique

}

function logSystemDiskState() {
	logEntry
	logCommand "blkid"
	logCommand "fdisk -l"
	logCommand "mount"
	logCommand "df -h -l"
	logExit
}

function partitionRestoredeviceIfRequested() {

	logEntry

	if (( $SKIP_SFDISK )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_CREATING_PARTITIONS

		if ! askYesNo; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
			exitError $RC_RESTORE_FAILED
		fi

		if (( $NO_YES_QUESTION )); then
			echo "Y"
		fi

		if (( $SKIP_FORMAT )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_FORMATING

			if ! askYesNo; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
				exitError $RC_RESTORE_FAILED
			fi

			if (( $NO_YES_QUESTION )); then
				echo "Y"
			fi
		else

			if [[ "${PARTITIONS_TO_RESTORE}" == "$PARTITIONS_TO_BACKUP_ALL" ]]; then
				# Prefer mapfile or read -a to split command output (or quote to avoid splitting).
				#shellcheck disable=SC2207
				local partitions=( $(collectPartitionsInBackup $RESTOREFILE) )
				local partitionsString="${partitions[*]}"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITIONS_FORMATED "\"$partitionsString\""
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITIONS_FORMATED "\"$PARTITIONS_TO_RESTORE\""
			fi

			if ! askYesNo; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
				exitError $RC_RESTORE_FAILED
			fi

			if (( $NO_YES_QUESTION )); then
				echo "Y"
			fi
		fi

	elif [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then

		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CREATING_PARTITIONS $RESTORE_DEVICE

		if ! askYesNo; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
			exitError $RC_RESTORE_FAILED
		fi

		if (( $NO_YES_QUESTION )); then
			echo "Y"
		fi

		if (( $FORCE_SFDISK )); then
			local tmpSF

			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FORCING_CREATING_PARTITIONS
			sfdisk --wipe always -f "$RESTORE_DEVICE" < "$SF_FILE" &>>"$LOG_FILE"
			rc=$?
			if (( $rc )); then
				if (( $rc == 1 )); then
					tmpSF="$(basename $SF_FILE)"
					cp "$SF_FILE" "/tmp/$tmpSF"
					sed -i 's/sector-size/d' "/tmp/$tmpSF"
					sfdisk --wipe always -f "$RESTORE_DEVICE" < "/tmp/$tmpSF" &>>"$LOG_FILE"
					rc=$?
					rm "/tmp/$tmpSF"
				fi
			fi
			if (( $rc )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_PARTITIONS $rc "sfdisk error"
				exitError $RC_CREATE_PARTITIONS_FAILED
			fi

			waitForPartitionDefsChanged

		else

			if (( ! $ROOT_PARTITION_DEFINED )) && (( $RESIZE_ROOTFS )); then

				local sourceSDSize targetSDSize
				sourceSDSize=$(calcSumSizeFromSFDISK "$SF_FILE")

				local partitionLabel totalSize
				partitionLabel=$(awk -F': ' '/^label:/ {print $2}' "$SF_FILE")
				totalSize=$(blockdev --getsize64 "$RESTORE_DEVICE")

				if [[ "$partitionLabel" == "gpt" ]]; then
					# Subtract 33 sectors for GPT metadata at the end of the disk as these are unusable (for example, see https://wiki.archlinux.org/title/GPT_fdisk)
					local sectorSize
					sectorSize=$(awk -F': ' '/^sector-size:/ {print $2}' "$SF_FILE")
					sectorSize=${sectorSize:-512}  # fallback if missing
					targetSDSize=$((totalSize - (33 * sectorSize)))
				else
					targetSDSize=$totalSize
				fi

				logItem "sourceSDSize: $sourceSDSize - targetSDSize: $targetSDSize"

				if (( sourceSDSize != targetSDSize )); then

					if (( sourceSDSize > targetSDSize )); then
						if (( $RESIZE_ROOTFS )); then
							writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADJUSTING_WARNING_P "$RESTORE_DEVICE" "$(bytesToHuman "$targetSDSize")" "$(bytesToHuman "$sourceSDSize")"
						else
							writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADJUSTING_DISABLED "$RESTORE_DEVICE" "$(bytesToHuman "$targetSDSize")" "$(bytesToHuman "$sourceSDSize")"
							exitError $RC_PARAMETER_ERROR
						fi
					else
						if (( $RESIZE_ROOTFS )); then
							if (( $targetSDSize >= $TWO_TB )); then		# target should have gpt in order to use space > 2TB during expansion
								writeToConsole $MSG_LEVEL_MINIMAL $MSG_TARGET_REQUIRES_GPT "$RESTORE_DEVICE" "$(bytesToHuman "$targetSDSize")"
							fi
							writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADJUSTING_WARNING_P2 "$RESTORE_DEVICE" "$(bytesToHuman "$targetSDSize")" "$(bytesToHuman "$sourceSDSize")"
						fi
					fi

#						label: dos
#						label-id: 0x3c3f4bdb
#						device: /dev/mmcblk0
#						unit: sectors
#						sector-size: 512
#
#						/dev/mmcblk0p1 : start=        8192, size=      524288, type=c
#						/dev/mmcblk0p2 : start=      532480, size=    15196160, type=83

					local sourceValues
					mapfile -d " " -t sourceValues < <( awk '/[0-9] :/ { v=$4 $6; gsub(","," ",v); printf "%s",v }' "$SF_FILE" )

					if (( ${#sourceValues[@]} < 4 )); then
						logCommand "cat $SF_FILE"
						assertionFailed $LINENO "Expected at least 2 partitions in $SF_FILE"
					fi

					if (( ! PARTITIONBASED_BACKUP && ( ${sourceValues[2]} == 0 || ${sourceValues[3]} == 0 ) )); then
							writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_R_OPTION
							exitError $RC_MISC_ERROR
					fi

					local partitionSizes
					mapfile -d " " -t partitionSizes < <( createResizedSFDisk "$SF_FILE" "$targetSDSize" "$MODIFIED_SFDISK" )

					local oldPartitionSourceSize=${partitionSizes[0]}
					local newPartitionTargetSize=${partitionSizes[1]}
					local resizedPartitionNumber=${partitionSizes[2]}

					if (( newPartitionTargetSize <= 0 )); then
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESIZED_PARTITION_TOO_SMALL "$resizedPartitionNumber" "$RESTORE_DEVICE" "$(bytesToHuman $oldPartitionSourceSize)" "$(bytesToHuman -${newPartitionTargetSize})"
						exitError "$RC_RESIZE_ERROR"
					fi

					if (( ${#sourceValues[@]} == 4 )); then
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADJUSTING_SECOND "$(bytesToHuman $oldPartitionSourceSize)" "$(bytesToHuman $newPartitionTargetSize)"
					else
						writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADJUSTING_LAST "$(bytesToHuman $oldPartitionSourceSize)" "$(bytesToHuman $newPartitionTargetSize)"
					fi
				else
					cp "$SF_FILE" "$MODIFIED_SFDISK" # no repartitioning required
				fi
			else
				cp "$SF_FILE" "$MODIFIED_SFDISK" # just use unmodified sfdisk when option -R is used for a hybrid system
			fi

			sfdisk --wipe always -f "$RESTORE_DEVICE" < "$MODIFIED_SFDISK" &>>"$LOG_FILE"
			rc=$?
			if (( $rc )); then
				logItem "sfdisk first attempt fails with rc $rc"
				if (( $rc == 1 )); then								# sector-size is new in bullseye and breaks restore with older OS
					sed -i '/sector-size/d' "$MODIFIED_SFDISK"		# remove sector-size
					logCommand "cat $MODIFIED_SFDISK"
					sfdisk --wipe always -f "$RESTORE_DEVICE" < "$MODIFIED_SFDISK" &>>"$LOG_FILE"
					rc=$?
				fi
			fi
			rm $MODIFIED_SFDISK &>/dev/null

			if (( $rc )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_PARTITIONS $rc "sfdisk error"
				exitError "$RC_CREATE_PARTITIONS_FAILED"
			fi

			waitForPartitionDefsChanged

		fi

		logItem "Targetpartitionlayout$NL$(fdisk -l "$RESTORE_DEVICE")"
	fi

	logExit
}

# return all partitionnumbers available in backup

function collectAvailableBackupPartitions() { # lastBackupDir

	logEntry "$1"

	local lastBackupDir="$1"

	local directories partitionNo availablePartitions=""

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_TAR" || "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]]; then
		# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
		#shellcheck disable=SC2010
		directories="$(ls -l ${lastBackupDir} | grep -E "\.($BACKUPTYPE_TAR|$BACKUPTYPE_TGZ)" | sed -E 's/\..+//' )"  # delete trailing .tar or .tgz)
	elif [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" ]]; then
		# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
		#shellcheck disable=SC2010
		directories="$(ls -l ${lastBackupDir} | grep '^d')"
	else
		assertionFailed $LINENO "Unsupported partitions backup type"
	fi

	logItem "Directories: $directories"

	directories="$(grep -Po "(((s|v)d[a-z]|(mmcblk|loop)[0-9]p)|nvme[0-9]n[0-9]p)[0-9]+$" <<< $directories )" # extract valid backup partitions

	partitionNo="$(grep -Eo "[0-9]+$" <<< $directories )"

	availablePartitions=$(tr '\n' ' ' <<< "$partitionNo")	# substitute nl from ls with space
	availablePartitions="${availablePartitions::-1}" # delete last space

	logItem "Found available partitions: $availablePartitions in $lastBackupDir"

	echo "${availablePartitions}"

	logExit "-${availablePartitions}-"
}

function restoreNormalBackupType() {

	logEntry

	rc=0
	local verbose zip

	(( $VERBOSE )) && verbose="-v" || verbose=""

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_FILE "$RESTOREFILE"
	logCommand "ls -la $RESTOREFILE"

	START_TIME=$(date +%s)

	rc=$RC_NATIVE_RESTORE_FAILED

	logSystemDiskState

	callExtensions "$PRE_RESTORE_EXTENSION" "0"
	rc=$?
	PRE_RESTORE_EXTENSION_CALLED=1
	if (( $rc )); then
		exitError "$RC_RESTORE_EXTENSION_FAILS"
	fi

	case $BACKUPTYPE in

		"$BACKUPTYPE_DD"|"$BACKUPTYPE_DDZ")

			local progressFlag=""
			(( $PROGRESS && $INTERACTIVE )) && progressFlag="status=progress"

			if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" ]]; then
				cmd="dd if=\"$ROOT_RESTOREFILE\" $progressFlag of=$RESTORE_DEVICE bs=$DD_BLOCKSIZE $DD_PARMS"
			else
				cmd="gunzip -c \"$ROOT_RESTOREFILE\" | dd of=$RESTORE_DEVICE $progressFlag bs=$DD_BLOCKSIZE $DD_PARMS"
			fi

			executeDD "$cmd"
			rc=$?
			;;

		*)	MNT_POINT="$TEMPORARY_MOUNTPOINT_ROOT"

			umountPartition "$MNT_POINT"

			logItem "Creating mountpoint $MNT_POINT"

			if ! mkdir -p "$MNT_POINT" &>>"$LOG_FILE"; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "${MNT_POINT}"
					exitError $RC_CREATE_ERROR
			fi

			partitionRestoredeviceIfRequested

			if [[ -e $TAR_FILE ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_FORMATTING_FIRST_PARTITION "$BOOT_PARTITION"
				mkfs.vfat $BOOT_PARTITION &>>$LOG_FILE
				rc=$?
				if [ $rc != 0 ]; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_BOOT_CREATE_PARTITION_FAILED "$rc"
					exitError $RC_NATIVE_RESTORE_FAILED
				fi
			fi

			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_FIRST_PARTITION "$BOOT_PARTITION"

			local ext=$BOOT_DD_EXT
			if [[ -e "$DD_FILE" ]]; then
				logItem "Restoring boot partition from $DD_FILE"
				local progressFlag=""
				(( $PROGRESS && $INTERACTIVE )) && progressFlag="status=progress"
				local cmd="dd if=$DD_FILE $progressFlag of=$BOOT_PARTITION bs=$DD_BLOCKSIZE"
				executeDD "$cmd"
				rc=$?
			else
				ext=$BOOT_TAR_EXT
				logItem "Restoring boot partition from $TAR_FILE to $BOOT_PARTITION"
				mountAndCheck $BOOT_PARTITION "$MNT_POINT"
				if ! pushd "$MNT_POINT" &>>"$LOG_FILE"; then
					assertionFailed $LINENO "push to $MNT_POINT failed"
				fi
				if (( $PROGRESS && $INTERACTIVE )); then
					local cmd="pv -f $TAR_FILE | tar -xf -"
				else
					local cmd="tar -xf  \"$TAR_FILE\""
				fi
				executeTar "$cmd"
				rc=$?
				popd &>>"$LOG_FILE"
			fi

			if (( $rc != 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_BOOT_RESTORE_FAILED ".$ext" "$rc"
				exitError $RC_NATIVE_RESTORE_FAILED
			fi

			executeFilesystemCheck "$BOOT_PARTITION"

			if (( ! SKIP_FORMAT )) || [[ "$BACKUPTYPE" != "$BACKUPTYPE_RSYNC" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_FORMATTING_SECOND_PARTITION "$ROOT_PARTITION"
				local check=""
				(( $REGRESSION_TEST )) && check="-F "
				if (( $CHECK_FOR_BAD_BLOCKS )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_DETAILED_ROOT_CHECKING "$ROOT_PARTITION"
					check="-c"
					mkfs.ext4 $check "$ROOT_PARTITION"
				else
					mkfs.ext4 $check "$ROOT_PARTITION" &>>"$LOG_FILE"
				fi
				rc=$?
				if (( $rc != 0 )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_IMG_ROOT_CREATE_PARTITION_FAILED "$rc"
					exitError $RC_NATIVE_RESTORE_FAILED
				fi

				waitForPartitionDefsChanged
				
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_SECOND_PARTITION "$ROOT_PARTITION"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SYNCING_SECOND_PARTITION "$ROOT_PARTITION"
			fi
			
			mountAndCheck $ROOT_PARTITION "$MNT_POINT"

			case $BACKUPTYPE in

				"$BACKUPTYPE_TAR"|"$BACKUPTYPE_TGZ")
					local archiveFlags="--same-owner --same-permissions --numeric-owner ${TAR_RESTORE_ADDITIONAL_OPTIONS}"

					if ! pushd "$MNT_POINT" &>>"$LOG_FILE"; then
						assertionFailed $LINENO "push to $MNT_POINT failed"
					fi
					[[ "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]] && zip="-z" || zip=""
					if (( $PROGRESS && $INTERACTIVE )); then
						local cmd="pv -f $ROOT_RESTOREFILE | tar ${archiveFlags} -x ${verbose} ${zip} -f -"
					else
						local cmd="tar ${archiveFlags} -x ${verbose} ${zip} -f \"$ROOT_RESTOREFILE\""
					fi
					executeTar "$cmd"
					rc=$?
					popd &>>"$LOG_FILE"
					;;

				"$BACKUPTYPE_RSYNC")
					local excludePattern="--exclude=/$HOSTNAME-backup.*"
					logItem "Excluding excludePattern"
					local progressFlag=""
					(( $PROGRESS && $INTERACTIVE )) && progressFlag="--info=progress2"
					local cmd="rsync $progressFlag --numeric-ids ${RSYNC_BACKUP_OPTIONS} ${verbose} ${RSYNC_BACKUP_ADDITIONAL_OPTIONS} $excludePattern \"$ROOT_RESTOREFILE/\" $MNT_POINT"
					executeRsync "$cmd"
					rc=$?
					;;

				*) assertionFailed $LINENO "Invalid backuptype $BACKUPTYPE"
					;;
			esac

			if [[ $rc != 0 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_PROGRAM_ERROR $BACKUPTYPE $rc
				exitError $RC_NATIVE_RESTORE_FAILED
			fi

			umountPartition $ROOT_PARTITION

			executeFilesystemCheck "$ROOT_PARTITION"

			updateUUIDs

			mountAndCheck "$ROOT_PARTITION" "$MNT_POINT"

			# date -u +"%Y-%m-%d %T" > "$MNT_POINT/etc/fake-hwclock.data"
			# make sure raspiBackup is not started during initial boot of restored image
			date -d "$(date) 5min" +"%Y-%m-%d %T" > "$MNT_POINT/etc/fake-hwclock.data"
			logItem "Updated hw clock to $(<$MNT_POINT/etc/fake-hwclock.data)"

			#logItem "Force fsck on reboot"
			#touch $MNT_POINT/forcefsck

			logCommand "parted -s $RESTORE_DEVICE print"

			if isSpecialBlockDevice "$RESTORE_DEVICE"; then
				ROOT_DEVICE=$(sed -E 's/p[0-9]+$//' <<< "$ROOT_PARTITION")
			else
				ROOT_DEVICE=$(sed -E 's/[0-9]+$//' <<< "$ROOT_PARTITION")
			fi

			if [[ "$ROOT_DEVICE" != "$RESTORE_DEVICE" ]]; then
				logCommand "parted -s $ROOT_DEVICE print"
			fi

	esac

	END_TIME="$(date +%s)"

	logItem "Syncing filesystems"
	sync

	umountPartition "$MNT_POINT"

	logSystemDiskState

	logExit "$rc"

}

function applyBackupStrategy() {

	logEntry "$BACKUP_TARGETDIR"

	if (( $SMART_RECYCLE )); then

		local dir_to_delete dir_to_keep

		logItem "SR Parms: ${SMART_RECYCLE_PARMS[*]}"
		SR_DAILY="${SMART_RECYCLE_PARMS[0]}"
		SR_WEEKLY="${SMART_RECYCLE_PARMS[1]}"
		SR_MONTHLY="${SMART_RECYCLE_PARMS[2]}"
		SR_YEARLY="${SMART_RECYCLE_PARMS[3]}"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_APPLYING_BACKUP_STRATEGY $SR_DAILY $SR_WEEKLY $SR_MONTHLY $SR_YEARLY

		logCommand "ls -d $BACKUPPATH/*"

		local keptBackups numKeptBackups
		keptBackups="$(SR_listUniqueBackups $BACKUPTARGET_ROOT)"
		numKeptBackups="$(countLines "$keptBackups")"
		logItem "Keptbackups $numKeptBackups: $keptBackups"

		local tobeDeletedBackups
		tobeDeletedBackups="$(SR_listBackupsToDelete "$BACKUPTARGET_ROOT")"
		local numTobeDeletedBackups
		numTobeDeletedBackups="$(countLines "$tobeDeletedBackups")"
		logItem "TobeDeletedBackups $numTobeDeletedBackups: $tobeDeletedBackups"

		if [[ -n "$tobeDeletedBackups" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_FILES "$numTobeDeletedBackups" "$numKeptBackups"
			echo "$tobeDeletedBackups" | while read -r dir_to_delete; do
				logItem "Recycling $BACKUPTARGET_ROOT/${dir_to_delete}"
				if (( ! $SMART_RECYCLE_DRYRUN && ( ! $FAKE || $REGRESSION_TEST ) )); then
					writeToConsole $MSG_LEVEL_DETAILED $MSG_SMART_RECYCLE_FILE_DELETE "$BACKUPTARGET_ROOT/${dir_to_delete}"
					[[ -n "$dir_to_delete" ]] && rm -rf "$BACKUPTARGET_ROOT/${dir_to_delete:?}" # guard against whole backup dir deletion
				else
					[[ -n "$dir_to_delete" ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_FILE_WOULD_BE_DELETED "$BACKUPTARGET_ROOT/${dir_to_delete}"
				fi
			done
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_NO_FILES
		fi

		if (( $SMART_RECYCLE_DRYRUN || $FAKE )); then
			echo "$keptBackups" | while read dir_to_keep; do
				[[ -n $dir_to_keep ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_FILE_WOULD_BE_KEPT "$BACKUPTARGET_ROOT/${dir_to_keep}"
			done
		fi

	else

		local bt="${BACKUPTYPE^^}"
		local v="KEEPBACKUPS_${bt}"
		local keepOverwrite="${!v}"
		local dir_to_delete
		local dir_to_check
		local tobeDeletedBackups
		local tobeCheckedBackups
		local keepBackups=$KEEPBACKUPS
		(( $keepOverwrite != 0 )) && keepBackups=$keepOverwrite

		if (( $keepBackups != -1 )); then
			logItem "Deleting oldest directory in $BACKUPPATH"
			logCommand "ls -d $BACKUPPATH/*"

			writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUPS_KEPT "$keepBackups" "$BACKUPTYPE"

			if (( $FAKE )); then
				fakeKeepBackups=$(( keepBackups - 1 ))   # because in FAKE mode no real current backup has been created
				writeToConsole $MSG_LEVEL_DETAILED $MSG_CLEANUP_BACKUP_VERSION "$BACKUPPATH"
				if ! pushd "$BACKUPPATH" &>>"$LOG_FILE"; then
					assertionFailed $LINENO "push to $BACKUPPATH failed"
				fi
				# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
				#shellcheck disable=SC2010
				tobeCheckedBackups=$(ls -d ${HOSTNAME_OSR}-${BACKUPTYPE}-backup-* 2>>"$LOG_FILE" | grep -vE "_")
				echo "$tobeCheckedBackups" | while read dir_to_check; do
					[[ -n $dir_to_check ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_EXISTING_BACKUP  $BACKUPTARGET_ROOT/${dir_to_check}
				done
				# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
				#shellcheck disable=SC2010
				tobeDeletedBackups=$(ls -d ${HOSTNAME_OSR}-${BACKUPTYPE}-backup-* 2>>"$LOG_FILE" | grep -vE "_" | head -n -$fakeKeepBackups 2>>"$LOG_FILE")
				echo "$tobeDeletedBackups" | while read dir_to_delete; do
					[[ -n $dir_to_delete ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_NORMAL_RECYCLE_FILE_WOULD_BE_DELETED "$BACKUPTARGET_ROOT/${dir_to_delete}"
				done
				if ! popd &>>"$LOG_FILE"; then
					assertionFailed $LINENO "pop failed"
				fi
		       else
				writeToConsole $MSG_LEVEL_DETAILED $MSG_CLEANUP_BACKUP_VERSION "$BACKUPPATH"
				if ! pushd "$BACKUPPATH" &>>"$LOG_FILE"; then
					assertionFailed $LINENO "push to $BACKUPPATH failed"
				fi
				# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
				#shellcheck disable=SC2010
				ls -d ${HOSTNAME_OSR}-${BACKUPTYPE}-backup-* 2>>"$LOG_FILE" | grep -vE "_" | head -n -$keepBackups | xargs -I {} rm -rf "{}" &>>"$LOG_FILE";
				if ! popd &>>"$LOG_FILE"; then
					assertionFailed $LINENO "pop failed"
				fi

				local rmRC=$?
				if (( $rmRC != 0 )); then
					logItem "rmRC: $rmRC"
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_CLEANUP_FAILED
					exitError $RC_CLEANUP_ERROR
				fi

				local regex="\-([0-9]{8}\-[0-9]{6})\.(img|mbr|sfdisk|log)$"
				local regexDD="\-dd\-backup\-([0-9]{8}\-[0-9]{6})\.img$"

				if ! pushd "$BACKUPPATH" 1>/dev/null; then
					assertionFailed $LINENO "push to $BACKUPPATH failed"
				fi

				for imgFile in *.img *.mbr *.sfdisk *.log *.msg; do

					[[ ! -e $imgFile ]] && continue

					if [[ $imgFile =~ $regexDD ]]; then
						logItem "Skipping DD file $imgFile"
						continue
					fi

					if [[ ! $imgFile =~ $regex ]]; then
						logItem "Skipping $imgFile"
						continue
					else
						logItem "Processing $imgFile"
					fi

					local date=${BASH_REMATCH[1]}
					logItem "Extracted date: $date"

					if [[ -z "$date" ]]; then
						assert $LINENO "Unable to extract date from backup files"
					fi
					local file
					# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
					#shellcheck disable=SC2010
					file=$(ls -d *-*-backup-$date* 2>/dev/null| grep -Ev "\.(log|msg|img|mbr|sfdisk)$");

					if [[ -n "$file" ]];  then
						logItem "Found backup for $imgFile"
					else
						logItem "Found NO backup for $imgFile - removing"
						rm -f "$imgFile" &>>"$LOG_FILE"
					fi
				done
				popd > /dev/null

				logItem "post - ls$NL$(ls -d $BACKUPPATH/* 2>/dev/null)"
			fi
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_ALL_BACKUPS_KEPT "$BACKUPTYPE"
		fi
	fi
	logExit
}

function reportOldBackups() {

	logEntry

	local dir_to_list

	if ! pushd "$BACKUPPATH" &>>"$LOG_FILE"; then
		assertionFailed $LINENO "push to $BACKUPPATH failed"
	fi

	if ls -d ${HOSTNAME}-${BACKUPTYPE}-backup-* &>/dev/null; then

		# Double quote to prevent globbing and word splitting.
		# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
		#shellcheck disable=SC2010,SC2086
		tobeListedOldBackups=$(ls -d ${HOSTNAME}-${BACKUPTYPE}-backup-* 2>>"$LOG_FILE")

		if [[ -n $tobeListedOldBackups ]]; then

			local report_counter_file="$VAR_LIB_DIRECTORY/$REPORT_COUNTER_FILE"

			# create directory to save counter
			if [[ ! -d "$VAR_LIB_DIRECTORY" ]]; then
				if ! mkdir -p "$VAR_LIB_DIRECTORY" &>>"$LOG_FILE"; then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "${VAR_LIB_DIRECTORY}"
					exitError $RC_CREATE_ERROR
				fi
			fi

			# initialize counter
			if [[ ! -e "$report_counter_file" ]]; then
				echo "$OLD_REMINDER_REPEAT" > "$report_counter_file"
			fi

			# retrieve counter
			local rf
			rf=$(<$report_counter_file)
			if [[ -z "${rf}" ]]; then				# counter file exists but is empty
				echo "$OLD_REMINDER_REPEAT" > "$report_counter_file"
				return
			fi
			rf=$(<$report_counter_file)

			# only print report if counter says so
			if (( $rf > 0 )); then

				# update counter, but only if not in FAKE mode
				local rfn=$(( ${rf} - 1 ))
				if (( ! $FAKE )); then
					echo "${rfn}" > "$report_counter_file"
				fi

				writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_NAMING_CHANGE "0.7"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_FOUND
				echo "$tobeListedOldBackups" | while read -r dir_to_list; do
					[[ -n $dir_to_list ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "  - $BACKUPTARGET_ROOT/${dir_to_list}"
				done
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_HANDLING_INFO
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_COUNTER_INFO "${rfn}"

				writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

				# only print report if counter says so
				if (( $rf > 0 )); then

					# update counter, but only if not in FAKE mode
					local rfn=$(( ${rf} - 1 ))
					if (( ! $FAKE )); then
						echo "${rfn}" > "$report_counter_file"
					fi

					writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_NAMING_CHANGE "0.7"
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_FOUND
					echo "$tobeListedOldBackups" | while read -r dir_to_list; do
						[[ -n $dir_to_list ]] && writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "  - $BACKUPTARGET_ROOT/${dir_to_list}"
					done
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_HANDLING_INFO
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_OLD_NAME_BACKUPS_COUNTER_INFO "${rfn}"

					writeToConsole $MSG_LEVEL_MINIMAL $MSG_GENERIC_WARNING "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

				fi
			fi
		fi
	else
		logItem "No old backups found"
	fi

	if ! popd &>>"$LOG_FILE"; then
		assertionFailed $LINENO "pop failed"
	fi

	logExit
}

function backup() {

	logEntry

	logSystemDiskState

	executeBeforeStopServices
	stopServices
	callExtensions $PRE_BACKUP_EXTENSION "0"
	rc=$?
	PRE_BACKUP_EXTENSION_CALLED=1
	if (( $rc )); then
		exitError "$RC_BACKUP_EXTENSION_FAILS"
	fi

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" || (( $PARTITIONBASED_BACKUP )) ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_TARGET "$BACKUPTYPE" "$BACKUPTARGET_FINAL_DIR"
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_TARGET "$BACKUPTYPE" "$BACKUPTARGET_FILE"
	fi

	logItem "Storing backup in backuppath $BACKUPPATH"

	if [[ -f $BOOT_DEVICENAME ]]; then
		logCommand "fdisk -l $BOOT_DEVICENAME"
	fi

	logItem "Starting $BACKUPTYPE backup..."

	rc=0

	callExtensions "$READY_BACKUP_EXTENSION" "$rc"

	START_TIME=$(date +%s)

	if (( ! $FAKE )); then
		if (( ! $PARTITIONBASED_BACKUP )); then

			case "$BACKUPTYPE" in

				"$BACKUPTYPE_DD"|"$BACKUPTYPE_DDZ") backupDD
					;;

				"$BACKUPTYPE_TAR"|"$BACKUPTYPE_TGZ") backupTar
					;;

				"$BACKUPTYPE_RSYNC") backupRsync
					;;

				*) assertionFailed $LINENO "Invalid backuptype $BACKUPTYPE"
					;;
			esac

			if [[ $rc != 0 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_PROGRAM_ERROR $BACKUPTYPE "$rc"
				exitError $RC_NATIVE_BACKUP_FAILED
			fi
		else
			backupPartitions
		fi
	fi
	END_TIME=$(date +%s)

	mapfile -d " " -t BACKUP_TIME < <( duration "$START_TIME" "$END_TIME" )

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_TIME "${BACKUP_TIME[1]}" "${BACKUP_TIME[2]}" "${BACKUP_TIME[3]}"

	logItem "Syncing"
	sync
	logItem "Finished $BACKUPTYPE backup"

	logItem "Backup created with return code: $rc"

	logItem "Current directory: $(pwd)"
	if [[ -z $BACKUPPATH || "$BACKUPPATH" == *"*"* ]]; then
		assertionFailed $LINENO "Unexpected backup path $BACKUPPATH"
	fi

	logSystemDiskState

	logExit

}

function mountPartitions() { # sourcePath

	local partition partitionName
	logEntry "${PARTITIONS_TO_BACKUP[@]}"

	if (( ! $FAKE )); then
		logItem "BEFORE: mount $(mount)"
		# Double quote array expansions to avoid re-splitting elements.
		#shellcheck disable=SC2068
		for partition in ${PARTITIONS_TO_BACKUP[@]}; do
			partitionName="$BOOT_PARTITION_PREFIX$partition"
			logItem "mkdir $1/$partitionName"
			if ! mkdir -p "$1/$partitionName" &>>"$LOG_FILE"; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "$1/$partitionName"
				exitError $RC_CREATE_ERROR
			fi
			logItem "mount /dev/$partitionName to $1/$partitionName"
			mountAndCheck "/dev/$partitionName" "$1/$partitionName"
		done
		logItem "AFTER: mount $(mount)"
	fi
	logExit
}

function umountPartitions() { # sourcePath

	local partitionName partition
	logEntry
	if (( ! $FAKE )); then
		logItem "BEFORE: mount $(mount)"
		for partition in "${PARTITIONS_TO_BACKUP[@]}"; do
			partitionName="$BOOT_PARTITION_PREFIX$partition"
			umountPartition "$1/$partitionName"
			if [[ -d "$1/$partitionName" ]]; then
				logItem "rmdir $1/$partitionName"
				rmdir "$1/$partitionName" &>>"$LOG_FILE"
			fi
		done
		logItem "AFTER: mount $(mount)"
	fi
	logExit
}

function umountPartition() { # partition

	logEntry "$1"

	local retry=3 rc

	if isMounted "$1"; then
		umount "$1" &>>"$LOG_FILE"
		rc=$?
		if (( $rc )); then
			if (( --retry > 0 )); then
				logItem "RC $rc - Retrying umount $retry"
				sleep 3
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UMOUNT_ERROR "$1" "$rc"
				exitError "$RC_MISC_ERROR"
			fi
		fi
	fi

	logExit
}

function array2String() {
    local IFS="$1"
    shift
    echo "$*"
}

function backupPartitions() {

	logEntry

	local partition

	logItem "PARTITIONS_TO_BACKUP: $(echo "${PARTITIONS_TO_BACKUP[@]}")"

	local parts
	parts="$(array2String " " "${PARTITIONS_TO_BACKUP[@]}")"
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITIONS_BACKUP_STARTED "$BACKUPTYPE" "$parts"

	if ! containsElement "1" "${PARTITIONS_TO_BACKUP[@]}" || ! containsElement "2" "${PARTITIONS_TO_BACKUP[@]}"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NOT_ALL_OS_PARTITIONS_SAVED
	fi

	if (( ! $FAKE )); then
		partitionLayoutBackup
	fi

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" || "$BACKUPTYPE" == "$BACKUPTYPE_TAR" || "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]]; then
		mountPartitions "$TEMPORARY_MOUNTPOINT_ROOT"
	fi

	for partition in "${PARTITIONS_TO_BACKUP[@]}"; do

		logItem "Processing partition $partition"

		local fileSystem
		fileSystem="$(getBackupPartitionFilesystem "$partition")"

		if [[ -z $fileSystem ]]; then
			local unusedSize
			unusedSize="$(extractDataFromBackupPartedFile "${BOOT_PARTITION_PREFIX}$partition" "4")"
			unusedSize="$(bytesToHuman "$unusedSize")"
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIPPING_UNFORMATTED_PARTITION "${BOOT_PARTITION_PREFIX}$partition" "$unusedSize"
		else
			local pref
			pref="$(getPartitionPrefix $BOOT_DEVICENAME)"

			local fileSystemSize
			fileSystemSize="$(getBackupPartitionFilesystemSize "${pref}$partition")"
			local fileSystemUsed
			fileSystemUsed="$(getBackupPartitionFilesystemUsed "${pref}$partition")"

			logItem "fileSystem: $fileSystem - fileSystemSize: $fileSystemSize - fileSystemUsed: $fileSystemUsed"

			local fileSystemSize
			fileSystemSize="$(bytesToHuman $fileSystemSize)"
			local fileSystemUsed
			fileSystemUsed="$(bytesToHuman $fileSystemUsed)"

			writeToConsole $MSG_LEVEL_MINIMAL $MSG_PROCESSING_PARTITION "${BOOT_PARTITION_PREFIX}$partition" "$fileSystemUsed" "$fileSystemSize"

			case "$BACKUPTYPE" in

				"$BACKUPTYPE_DD"|"$BACKUPTYPE_DDZ") backupDD "$partition"
					;;

				"$BACKUPTYPE_TAR"|"$BACKUPTYPE_TGZ") backupTar "$partition"
					;;

				"$BACKUPTYPE_RSYNC") backupRsync "$partition"
					;;

				*) assertionFailed $LINENO "Invalid backuptype $BACKUPTYPE"
					;;
			esac

			if (( $rc != 0 )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_PARTITION_FAILED "${BOOT_PARTITION_PREFIX}$partition" $rc
				exitError "$RC_NATIVE_RESTORE_FAILED"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PROCESSED_PARTITION "${BOOT_PARTITION_PREFIX}$partition"
			fi
		fi

	done

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" || "$BACKUPTYPE" == "$BACKUPTYPE_TAR" || "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]]; then
		umountPartitions "$TEMPORARY_MOUNTPOINT_ROOT"
	fi

	logExit "$rc"

}

function doit() {

	logEntry

	local msg
	logItem "Startingdirectory: $(pwd)"
	logCommand "fdisk -l | grep -v "^$""
	logCommand "mount"

	if isUnsupportedVersion; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_VERSION
	fi

	if (( $RESTORE )); then
		doitRestore
	else
		if (( $FAKE )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FAKE_MODE_ON
		fi
		doitBackup
	fi

	logItem "Enddirectory: $(pwd)"

	logExit

}

# blkid
# /dev/mmcblk0p2: UUID="ea98d3bf-9345-4bd7-b365-5cc7c543079f" TYPE="ext4" PARTUUID="d888a167-02"

# Args: /dev/mmcblk0p2, /PARTUUID=xxxxx, LABEL=xxxxx or UUID=xxxxxx
# Result: $1, /dev/sda1, /dev/mmcblk0p1, /dev/sdb1 or "" if not found in blkid

function getPartitionName() { # /etc/fstab first col

	logEntry "$1"

	local prfx
	prfx="$(cut -f 1 -d '=' <<< $1)"
	local id
	id="$(cut -f 2 -d '=' <<< $1)"

	local b
	b="$(blkid)"

	local match
	match="$(grep "$prfx=\"$id\"" <<< "$b")"
	local result="$1"

	if [[ -n "$match" ]]; then
		result="$(cut -f 1 -d ":" <<< $match)"
	fi

	echo "$result"

	logExit "$result"

}

function collectPartitions() {

	logEntry

# raspbian:
# /dev/mmcblk0p1 : start=     8192, size=   114688, Id= c
# /dev/mmcblk0p2 : start=   122880, size=  1069056, Id=83

# ubuntu:
#/dev/mmcblk0p1 : start=        2048, size=      131072, type=c, bootable
#/dev/mmcblk0p2 : start=      133120, size=    20971520, type=83
#/dev/mmcblk0p3 : start=    21104640, size=    10485760, type=83
#/dev/mmcblk0p4 : start=    31590400, size=    29161472, type=83

	local regexPartitionLine="(${BOOT_DEVICENAME}[a-z0-9]+).*start[^0-9]+([0-9]+).*size[^0-9]+([0-9]+).*(Id|type)=[ ]?([^,]+)"

# /dev/mmvblk0p1 on /media/Log1 type ext2 (rw,nosuid,nodev,uhelper=udisks)
	local regexMountLine="(${BOOT_DEVICENAME}[a-z0-9]+).*on ([^ ]+)"

	logItem "PARTITIONS_TO_BACKUP - 1: $(echo "${PARTITIONS_TO_BACKUP[@]}")"

	local backupAllPartitions
	if [[ "$PARTITIONS_TO_BACKUP" == "$PARTITIONS_TO_BACKUP_ALL" ]]; then
		backupAllPartitions=1
		PARTITIONS_TO_BACKUP=()
	else
		# Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
		#shellcheck disable=SC2206
		PARTITIONS_TO_BACKUP=( ${PARTITIONS_TO_BACKUP[@]} )
		backupAllPartitions=0
	fi

	logItem "backupAllPartitions: $backupAllPartitions"

	local mountLine partition size type
	local line
	while read -r line; do
		if [[ "$line" =~ $regexPartitionLine ]]; then
			partition=${BASH_REMATCH[1]}
			size=${BASH_REMATCH[3]}
			type=${BASH_REMATCH[5]}
			logItem "partition: $partition - size: $size - type: $type"
			if [[ "$type" != "5" && "$type" != "85" && "$size" -gt 0 ]]; then # skip empty and extended partitions
				logItem "mount: $(mount)"
				logItem "Partition: $partition"
				mountLine=$(mount | grep "$partition" )
				if ! (( $? )); then
					logItem "mountline: $mountLine"
					logItem "regexMountLIne: $regexMountLine"
					if [[ "$mountLine" =~ $regexMountLine ]]; then
						local mountPoint=${BASH_REMATCH[2]}
						logItem "partition $partition mounted on $mountPoint"
						mountPoints[$partition]="$mountPoint"
					else
						assertionFailed $LINENO "Unable to find mountpoint for $partition"
					fi
				else
					if [[ "$partition" == "$ROOT_PARTITION" ]]; then
						mountPoints[$partition]="/"
						logItem "partition $partition mounted on /"
					else
						logItem "partition $partition not mounted"
						mountPoints[$partition]=""
					fi
				fi

				if (( $backupAllPartitions )); then
					id=$(getPartitionNumber "$partition")
					logItem "Adding partition $id to list of partitions to backup"
					PARTITIONS_TO_BACKUP["$id"]="$id"
				fi
			fi
		fi

	done < <(sfdisk -d "$BOOT_DEVICENAME" 2>>"$LOG_FILE")

	logItem "PARTITIONS_TO_BACKUP - 2: $(echo "${PARTITIONS_TO_BACKUP[@]}")"
	logItem "mountPoints: $(echo "${mountPoints[@]}")"

	if (( ${#PARTITIONS_TO_BACKUP[@]} == 0 )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NOPARTITIONS_TOBACKUP_FOUND
		exitError $RC_MISC_ERROR
	fi

	logExit

}

function checksForPartitionBasedBackup() {

	local partition

	logEntry

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" || "$BACKUPTYPE" == "$BACKUPTYPE_TAR" || "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]]; then
		local lastBackupDir
		lastBackupDir=$(find "$BACKUPTARGET_ROOT" -maxdepth 1 -type d -name "${HOSTNAME}@*-$BACKUPTYPE-*" ! -name "$BACKUPFILE" 2>>/dev/null | sort | tail -n 1)

		logItem "lastBackupDir: $lastBackupDir"
		if [[ -n "$lastBackupDir" ]]; then
			local missing
			missing="$(checkIfAllPreviousPartitionsAreIncludedInBackup "$lastBackupDir")"
			local rc=$?
			logItem "Missing: $missing"
			if (( $rc )); then
				if (( $IGNORE_MISSING_PARTITIONS )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_PARTITIONS_NOT_SAVED  "$missing"
				else
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_NOT_ALL_PREVIOUS_PARTITIONS_SAVED  "$missing"
					exitError $MSG_NOT_ALL_PREVIOUS_PARTITIONS_SAVED
				fi
			fi
		fi
	fi

	logItem "PARTITIONS_TO_BACKUP: ${PARTITIONS_TO_BACKUP[*]}"

	SUPPORTED_PARTITIONBACKUP_PARTITIONTYPE_REGEX='^(ext[234]|fat(16|32)|btrfs|f2fs|.*swap.*)$'

	local error=0
	for partition in "${PARTITIONS_TO_BACKUP[@]}"; do
		local fileSystem
		fileSystem=$(getPartitionBootFilesystem "$partition")
		if [[ -n $fileSystem && ! $fileSystem =~ $SUPPORTED_PARTITIONBACKUP_PARTITIONTYPE_REGEX ]]; then
			error=1
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_FILESYSTEM_FORMAT "$fileSystem" "${BOOT_PARTITION_PREFIX}$partition"
		fi
	done

	if (( error )) ; then
		exitError $RC_PARAMETER_ERROR
	fi

	error=0

	logItem "mountPoints: ${mountPoints[*]}"
	logItem "mountPoints - keys: ${!mountPoints[*]}"
	# Double quote array expansions to avoid re-splitting elements.
	#shellcheck disable=SC2068
	for partition in ${PARTITIONS_TO_BACKUP[@]}; do
		logItem "Checking partition $partition"
		if ! [[ $partition =~ ^[0-9]+ ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITION_NUMBER_INVALID "$partition"
			error=1
		else
			local key="/dev/${BOOT_PARTITION_PREFIX}${partition}"
			logItem "Checking partition $partition against $key: ${mountPoints[$key]+isset}"
			if [[ ! ${mountPoints[$key]+isset} ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITION_NOT_FOUND "$partition"
				error=1
			fi
		fi
	done

	if hasExternalRootpartition; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_EXTERNAL_ROOTPARTITION_UNSUPPORTED "$r"
		exitError $RC_PARAMETER_ERROR
	fi

	logExit

}

function hasExternalRootpartition() {

	local b r
	b="$(grep -E "^[^#]+\s/boot(/firmware)?\s.*" /etc/fstab | cut -f 1 -d ' ')"
	r="$(grep -E "^[^#]+\s/\s.*" /etc/fstab | cut -f 1 -d ' ')"

	[[ "$r" = "$b"  ]]
}

function commonChecks() {

	logEntry

	if hasSpaces "$CUSTOM_CONFIG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_CONTAINS_SPACES "$CUSTOM_CONFIG_FILE"
		exitError $RC_MISC_ERROR
	fi

	if [[ -n "$EMAIL" ]]; then
		if [[ ! $EMAIL_PROGRAM =~ $SUPPORTED_EMAIL_PROGRAM_REGEX ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_EMAIL_PROG_NOT_SUPPORTED "$EMAIL_PROGRAM" "$SUPPORTED_MAIL_PROGRAMS"
			exitError $RC_EMAILPROG_ERROR
		fi
		if [[ ! $(which "$EMAIL_PROGRAM") && ( "$EMAIL_PROGRAM" != "$EMAIL_EXTENSION_PROGRAM" ) ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MAILPROGRAM_NOT_INSTALLED "$EMAIL_PROGRAM"
			exitError "$RC_EMAILPROG_ERROR"
		fi
		if [[ "$EMAIL_PROGRAM" == "$EMAIL_SSMTP_PROGRAM" || "$EMAIL_PROGRAM" == "$EMAIL_MSMTP_PROGRAM" ]] && (( $APPEND_LOG )); then
			if ! which mpack &>/dev/null; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_MPACK_NOT_INSTALLED
				APPEND_LOG=0
			fi
		fi
	fi

	local co
	co="$(tr -d "$COLORING_VALID_OPTIONS" <<< "$COLORING")"
	if [[ -n "$COLORING" && -n "$co" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_COLORING_OPTION "$co"
			exitError "$RC_PARAMETER_ERROR"
	fi

	logExit

}

# retrieve various information for a partition, e.g. /dev/mmcblk0p1 or /dev/sda2
#
# 1: device (mmcblk0 or sda)
# 2: partition number (1 or 2)
#

function deviceInfo() { # device, e.g. /dev/mmcblk1p2 or /dev/sda3 or /dev/nvme0n1p1 or /dev/nvme0n1p1, returns 0:device (mmcblk0), 1: partition number

	logEntry "$1"
	local r=""

	if [[ $1 =~ ^/dev/([^0-9]+)([0-9]+)$ || $1 =~ ^/dev/([^0-9]+[0-9]+)p([0-9]+)$ || $1 =~ ^/dev/([^0-9]+[0-9]+n[0-9])+p([0-9]+)$ ]]; then
		r="${BASH_REMATCH[1]} ${BASH_REMATCH[2]}"
	else
		assertionFailed $LINENO "Unable to extract device info from $1"
	fi

	echo "$r"
	logExit "$r"
}

function inspect4Backup() {

	logEntry

	logCommand "ls -1 /dev/mmcblk*"
	logCommand "ls -1 /dev/sd*"
	logCommand "ls -1 /dev/nvme*"

	if mount | grep -q "^overlay.* on / type"; then
		writeToConsole $MSG_LEVEL_MINIMAL $OVERLAY_FILESYSTEM_NOT_SUPPORTED
		exitError $RC_NOT_SUPPORTED
	fi

	if ! isMounted "/boot"; then
		if ! isMounted "/boot/firmware"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_BOOTPARTITION_MOUNTED			# otherwise an empty bootpartition will be saved
			exitError $RC_NO_BOOT_FOUND
		fi
	fi

	if [[ -n "$BOOT_DEVICE" ]]; then
		local updatedBootdeviceName=${BOOT_DEVICE#"/dev/"}
		BOOT_DEVICE="$updatedBootdeviceName"
		logItem "Using configured bootdevice $BOOT_DEVICE"
	elif (( $REGRESSION_TEST )); then
		[[ -e /dev/vda ]] && BOOT_DEVICE="vda"
		[[ -e /dev/sda ]] && BOOT_DEVICE="sda"
		[[ -e /dev/mmcblk0 ]] && BOOT_DEVICE="mmcblk0"
		[[ -e /dev/nvme0n1 ]] && BOOT_DEVICE="nvme0n1"
		logItem "Force BOOT_DEVICE to $BOOT_DEVICE"
	elif (( $RESTORE )); then
		BOOT_DEVICE="mmcblk0"
		logItem "Force BOOT_DEVICE to $BOOT_DEVICE"
	elif [[ -z $BOOT_DEVICE ]]; then

		logItem "Starting boot discovery"

		# test whether boot device is mounted
		local bootMountpoint="/boot"
		local bootPartition
		bootPartition=$(findmnt "$bootMountpoint" -o source -n) # /dev/mmcblk0p1, /dev/loop01p or /dev/sda1 or /dev/nvme0n1p1
		logItem "bootMountpoint1: $bootMountpoint mounted? $bootPartition"

		if [[ -z "$bootPartition" ]]; then
			bootMountpoint="/boot/firmware"
			local bootPartition
			bootPartition=$(findmnt $bootMountpoint -o source -n) # /dev/mmcblk0p1, /dev/loop01p or /dev/sda1 or /dev/nvme0n1p1
			logItem "bootMountpoint2: $bootMountpoint mounted? $bootPartition"
		fi

		# test whether some other /boot path is mounted
		if [[ -z $bootPartition ]]; then
			bootPartition=$(mount | grep "\s/boot" | cut -f 1 -d ' ')
			bootMountpoint=$(mount | grep "\s/boot" | cut -f 3 -d ' ')
			logItem "Some path in /boot mounted? $bootPartition on $bootMountpoint"
		fi

		logItem "bootMountpoint: $bootMountpoint, bootPartition: $bootPartition"

		logItem "Starting root discovery"

		# find root partition
		local rootPartition rp

		rootPartition=$(findmnt / -o source -n) # /dev/root or /dev/sda1 or /dev/mmcblk1p2 or /dev/nvme0n1p2
		logItem "rootPartition: / mounted? $rootPartition"
		if [[ $rootPartition == "/dev/root" ]]; then
			rp=$(grep -E -o "root=[^ ]+" /proc/cmdline)
			rootPartition=${rp#/root=/}
			logItem "/ mounted as /dev/root: $rootPartition"
		fi

		# check for /boot on root partition
		if [[ -z "$bootPartition" ]]; then
			if ! find "$bootMountpoint" -name cmdline.txt &>/dev/null; then
				logItem "No cmdline.txt found in $bootMountpoint"
				# no RaspbianOS
				if [[ -n $rootPartition ]] && (( UNSUPPORTED_ENVIRONMENT )) && (( IS_UBUNTU )); then	# for example ubuntu on orange
					bootPartition="$rootPartition"
					logItem "Assuming bootpartition is located on rootpartition $rootPartition"
				else
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_BOOTDEVICE_FOUND
					exitError $RC_MISC_ERROR
				fi
			else
				bootPartition="$rootPartition"
				logItem "Bootpartition is located on rootpartition $bootPartition"
			fi
		fi

		mapfile -d " " -t boot < <( deviceInfo "$bootPartition" )
		mapfile -d " " -t root < <( deviceInfo "$rootPartition" )

		logItem "boot: ${boot[0]} - ${boot[1]}"
		logItem "root: ${root[0]} - ${root[1]}"

		if (( "${#boot[@]}" == 0 || "${#root[@]}" == 0 )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_BOOT_DEVICE_DISOVERED
			exitError $RC_NO_BOOT_FOUND
		fi

		BOOT_DEVICE="${boot[0]}"

		#Arrays implicitly concatenate in [[ ]]. Use a loop (or explicit * instead of @)
		#shellcheck disable=SC2199
		if [[ "${boot[@]}" == "${root[@]}" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SHARED_BOOT_DEVICE "/dev/$BOOT_DEVICE"
			SHARED_BOOT_DIRECTORY=1
		fi
	fi

	if [[ ! "$BOOT_DEVICE" =~ ^mmcblk[0-9]+$|^(s|v)d[a-z]$|^loop[0-9]+|^nvme[0-9]+n[0-9]+$ ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_BOOT_DEVICE "$BOOT_DEVICE"
		exitError $RC_INVALID_BOOTDEVICE
	fi

	if (( ! $FAKE )); then	# make sure boot partition is mounted. Otherwise an empty bootpartition will be created in the backup :-(
		local bootPref
		bootPref="$(getPartitionPrefix $BOOT_DEVICE)"

		logItem "bootPref: $bootPref - /dev/${bootPref}${boot[1]}"

		if ! findmnt "/dev/${bootPref}1" &>/dev/null; then
			if ! mount | grep "^/dev/${bootPref}${boot[1]}" &>/dev/null; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_BOOTDEVICE_MOUNTED "/dev/${bootPref}${boot[1]}"
				exitError $RC_INVALID_BOOTDEVICE
			fi
		fi
	fi

	logItem "BOOT_DEVICE: $BOOT_DEVICE"
	BACKUP_BOOT_DEVICE="$BOOT_DEVICE"

	BOOT_DEVICENAME="/dev/$BOOT_DEVICE"
	logItem "BOOT_DEVICENAME: $BOOT_DEVICENAME"
	BACKUP_BOOT_DEVICENAME="$BOOT_DEVICENAME"

	BOOT_PARTITION_PREFIX="$(getPartitionPrefix $BOOT_DEVICE)" # mmcblk0p - sda
	logItem "BOOT_PARTITION_PREFIX: $BOOT_PARTITION_PREFIX"
	BACKUP_BOOT_PARTITION_PREFIX="$BOOT_PARTITION_PREFIX"

	logExit
}

function inspect4Restore() {

	logEntry

	if [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
		SF_FILE=$(ls -1 "$RESTOREFILE/${HOSTNAME}-backup.sfdisk")
		if [[ -z "$SF_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$RESTOREFILE/${HOSTNAME}-backup.sfdisk"
			exitError "$RC_MISSING_FILES"
		fi

		MBR_FILE=$(ls -1 "$RESTOREFILE/${HOSTNAME}-backup.mbr")
		if [[ -z "$MBR_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$RESTOREFILE/${HOSTNAME}-backup.mbr"
			exitError "$RC_MISSING_FILES"
		fi
	fi

	if (( $PARTITIONBASED_BACKUP )); then
		BLKID_FILE=$(ls -1 "$RESTOREFILE/${HOSTNAME}-backup.blkid")
		if [[ -z "$BLKID_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$RESTOREFILE/${HOSTNAME}-backup.blkid"
			exitError "$RC_MISSING_FILES"
		fi

		PARTED_FILE=$(ls -1 "$RESTOREFILE/${HOSTNAME}-backup.parted")
		if [[ -z "$PARTED_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$RESTOREFILE/${HOSTNAME}-backup.parted"
			exitError "$RC_MISSING_FILES"
		fi

		FDISK_FILE=$(ls -1 "$RESTOREFILE/${HOSTNAME}-backup.fdisk")
		if [[ -z "$FDISK_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$RESTOREFILE/${HOSTNAME}-backup.fdisk"
			exitError "$RC_MISSING_FILES"
		fi
	fi

#sfdisk from util-linux 2.25.2
## partition table of /dev/mmcblk0
#unit: sectors
#
#/dev/mmcblk0p1 : start=     8192, size=    83968, Id= c
#/dev/mmcblk0p2 : start=    92160, size= 31330304, Id=83
#/dev/mmcblk0p3 : start=        0, size=        0, Id= 0
#/dev/mmcblk0p4 : start=        0, size=        0, Id= 0

#sfdisk from util-linux 2.27.1
#label: dos
#label-id: 0x6c96114a
#device: /dev/sdb
#unit: sectors
#
#/dev/sdb1 : start=          63, size=  1953520002, type=83

	if [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then

		BACKUP_BOOT_DEVICE=$(grep "partition table" -m 1 "$SF_FILE" | cut -f 5 -d ' ' | sed 's#/dev/##')
		if [[ -z $BACKUP_BOOT_DEVICE ]]; then
			BACKUP_BOOT_DEVICE=$(grep "^device" -m 1 "$SF_FILE" | cut -f 2 -d ':' | sed 's#[[:space:]]*/dev/##')
		fi

		if [[ -z $BACKUP_BOOT_DEVICE ]]; then
			logCommand"cat $SF_FILE"
			assertionFailed $LINENO "Unable to discover boot device from $SF_FILE"
		fi

		logItem "BACKUP_BOOT_DEVICE: $BACKUP_BOOT_DEVICE"

		BACKUP_BOOT_DEVICENAME="/dev/$BACKUP_BOOT_DEVICE"
		logItem "BACKUP_BOOT_DEVICENAME: $BACKUP_BOOT_DEVICENAME"

		BACKUP_BOOT_PARTITION_PREFIX="$(getPartitionPrefix $BACKUP_BOOT_DEVICE)"
		logItem "BACKUP_BOOT_PARTITION_PREFIX: $BACKUP_BOOT_PARTITION_PREFIX"
	fi

	logExit

}

function reportNews() {

	logEntry

	isUpdatePossible

	if (( ! $IS_BETA )); then
		local betaVersion
		betaVersion=$(isBetaAvailable)
		if [[ -n "$betaVersion" && "$VERSION" != "$betaVersion" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_BETAVERSION_AVAILABLE "$betaVersion"
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_VISIT_VERSION_HISTORY_PAGE "$(getMessage $MSG_VERSION_HISTORY_PAGE)"
			NEWS_AVAILABLE=1
			BETA_AVAILABLE=1
		fi
	fi

	logExit

}

function doitBackup() {

	logEntry "$PARTITIONBASED_BACKUP"

	checkImportantParameters

	inspect4Backup

	if ! checkSfdiskOK "$BOOT_DEVICENAME"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITIONS_EXTEND_DISK_SIZE
		exit $RC_COLLECT_PARTITIONS_FAILED
	fi

	commonChecks

	if hasSpaces "$BACKUPPATH"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_CONTAINS_SPACES "$BACKUPPATH"
		exitError $RC_MISC_ERROR
	fi

	if [[ ! -d "$BACKUPPATH" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_DIR_TO_BACKUP_DOESNOTEXIST "$BACKUPPATH"
		exitError $RC_MISSING_FILES
	fi

	if [[ $(getFsType "$BACKUPPATH") == "vfat" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MAX_4GB_LIMIT "$BACKUPPATH"
	fi

	if (( ! $EXCLUDE_DD )); then

		if [[ ! -b $BOOT_DEVICENAME ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_SDCARD_FOUND "$BOOT_DEVICENAME"
			exitError "$RC_PARAMETER_ERROR"
		fi

		if ! fdisk -l $BOOT_DEVICENAME | grep "${BOOT_PARTITION_PREFIX}1" > /dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_BOOT_PARTITION
			exitError "$RC_SDCARD_ERROR"
		fi

		local partitionsFound
		partitionsFound=$(fdisk -l "$BOOT_DEVICENAME" | grep "^/dev/$BOOT_PARTITION_PREFIX" | wc -l)
		logItem "Found partitions on $BOOT_DEVICENAME: $partitionsFound"
		if (( $partitionsFound > 2 )) && [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
			if ! (( $PARTITIONBASED_BACKUP || $IGNORE_ADDITIONAL_PARTITIONS )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_MULTIPLE_PARTITIONS_FOUND
				exitError $RC_SDCARD_ERROR
			fi
			if (( $IGNORE_ADDITIONAL_PARTITIONS && ! $PARTITIONBASED_BACKUP )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_MULTIPLE_PARTITIONS_FOUND_BUT_2_PARTITIONS_SAVED_ONLY
			fi
		fi
	fi

	if [[ ! "$KEEPBACKUPS" =~ ^-?[0-9]+$ ]] || (( $KEEPBACKUPS < -1 || $KEEPBACKUPS > 365 || $KEEPBACKUPS == 0 )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_KEEPBACKUP_INVALID "$KEEPBACKUPS" "-k"
			mentionHelp
			exitError "$RC_PARAMETER_ERROR"
	fi

	local t
	local keepBackups
	for t in "${POSSIBLE_TYPES_ARRAY[@]}"; do
		local bt="${t^^}"
		local v="KEEPBACKUPS_${bt}"
		local keepOverwrite="${!v}"

		if [[ ! $keepOverwrite =~ ^-?[0-9]+$ ]] || (( $keepOverwrite < -1 || $keepOverwrite > 365 )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_KEEPBACKUP_INVALID "$keepOverwrite" "$v"
			mentionHelp
			exitError "$RC_PARAMETER_ERROR"
		fi
	done

	if (( $SMART_RECYCLE )); then
		if [[ ! "$SMART_RECYCLE_OPTIONS" =~ ^[0-9]+[[:space:]]*+[0-9]+[[:space:]]+[0-9]+[[:space:]]+[0-9]+$ ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_PARM_INVALID "" "$SMART_RECYCLE_OPTIONS"
			mentionHelp
			exitError "$RC_PARAMETER_ERROR"
		fi

		eval "SMART_RECYCLE_PARMS=( $SMART_RECYCLE_OPTIONS )"
		logItem "SMART_RECYCLE_PARMS: ${SMART_RECYCLE_PARMS[*]}"
		logItem "smart recycle parms: ${#SMART_RECYCLE_PARMS[@]}"

		local sb
		if (( $SMART_RECYCLE )); then
			for sb in "${SMART_RECYCLE_PARMS[@]}"; do
				if (( $sb > 365 )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_SMART_RECYCLE_PARM_INVALID "$sb" "$SMART_RECYCLE_OPTIONS"
					mentionHelp
					exitError $RC_PARAMETER_ERROR
				fi
			done
		fi
	fi

	logItem "Backuptype selected: $BACKUPTYPE"

	if [[ ! $BACKUPTYPE =~ ^(${POSSIBLE_TYPES})$ ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNKNOWN_BACKUPTYPE "$BACKUPTYPE"
			mentionHelp
			exitError $RC_PARAMETER_ERROR
	fi

	if [[ -n $TAR_COMPRESSION_TOOL ]]; then

		if [[ "$BACKUPTYPE" != "$BACKUPTYPE_TAR" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_OPTION_TAR_COMPRESS_TOOL_NOT_SUPPORTED "$BACKUPTYPE"
			mentionHelp
			exitError $RC_PARAMETER_ERROR
		fi

		local i
		i=$(getIndexInArray "$TAR_COMPRESSION_TOOL" "${TAR_COMPRESSION_TOOLS_SUPPORTED[@]}")
		if (( $? )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_TAR_COMPRESS_TOOL "$TAR_COMPRESSION_TOOL"
			exitError $RC_PARAMETER_ERROR
		else
			logItem "tar compression of $TAR_COMPRESSION_TOOL is supported. Using extension $TAR_COMPRESSION_EXTENSION ($i)"
		fi
		if ! which "$TAR_COMPRESSION_TOOL" &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL "$MSG_TAR_COMPRESS_TOOL_NOT_FOUND" "$TAR_COMPRESSION_TOOL"
			exitError $RC_MISSING_COMMANDS
		fi
	fi

	if [[ -n "$TELEGRAM_CHATID" && -z "$TELEGRAM_TOKEN" ]] || [[ -z "$TELEGRAM_CHATID" && -n "$TELEGRAM_TOKEN" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_OPTIONS_INCOMPLETE
		exitError $RC_PARAMETER_ERROR
	fi

	if [[ -n "$TELEGRAM_CHATID" && -n "$TELEGRAM_TOKEN" ]]; then
		if ! which jq &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "jq" "jq"
			exitError $RC_MISSING_COMMANDS
		fi
		local invalidNotification
		invalidNotification="$(tr -d "$TELEGRAM_POSSIBLE_NOTIFICATIONS" <<< "$TELEGRAM_NOTIFICATIONS")"
		if [[ -n "$invalidNotification" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_TELEGRAM_INVALID_NOTIFICATION "$invalidNotification" "$TELEGRAM_POSSIBLE_NOTIFICATIONS"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if [[ -n "$PUSHOVER_USER" && -z "$PUSHOVER_TOKEN" ]] || [[ -z "$PUSHOVER_USER" && -n "$PUSHOVER_TOKEN" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_PUSHOVER_OPTIONS_INCOMPLETE
		exitError $RC_PARAMETER_ERROR
	fi

	if [[ -n "$PUSHOVER_USER" && -n "$PUSHOVER_TOKEN" ]]; then
		if ! which jq &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "jq" "jq"
			exitError $RC_MISSING_COMMANDS
		fi
		local invalidNotification
		invalidNotification="$(tr -d "$PUSHOVER_POSSIBLE_NOTIFICATIONS" <<< "$PUSHOVER_NOTIFICATIONS")"
		if [[ -n "$invalidNotification" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_PUSHOVER_INVALID_NOTIFICATION "$invalidNotification" "$PUSHOVER_POSSIBLE_NOTIFICATIONS"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
		local invalidNotification
		invalidNotification="$(tr -d "$SLACK_POSSIBLE_NOTIFICATIONS" <<< "$SLACK_NOTIFICATIONS")"
		if [[ -n "$invalidNotification" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SLACK_INVALID_NOTIFICATION "$invalidNotification" "$SLACK_POSSIBLE_NOTIFICATIONS"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" || "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
		(( $DD_WARNING )) && writeToConsole $MSG_LEVEL_MINIMAL $MSG_DD_WARNING
	fi

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" ]]; then
		if ! which rsync &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "rsync" "rsync"
			exitError $RC_MISSING_COMMANDS
		fi

		disableACLsIfRequested

		if ! supportsHardlinks "$BACKUPPATH"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_HARDLINK_ERROR "$BACKUPPATH" "$RC_MISC_ERROR"
			exitError $RC_MISC_ERROR
		fi

		local fs
		fs="$(getFsType "$BACKUPPATH")"
		logItem "Filesystem: $fs"
		if ! supportsFileAttributes "$BACKUPPATH"; then
			if [[ $fs =~ ^nfs* ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_FILEATTRIBUTE_RIGHTS "$(findMountPath "$BACKUPPATH")" "$fs"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_FILEATTRIBUTESUPPORT "$fs" "$(findMountPath "$BACKUPPATH")"
			fi
			exitError $RC_MISC_ERROR
		fi

		if ! supportsSymlinks "$BACKUPPATH"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILESYSTEM_INCORRECT "$(findMountPath "$BACKUPPATH")" "softlinks"
			exitError $RC_MISC_ERROR
		fi

		if hasDefaultACLs "$BACKUPPATH"; then
			logItem "DEFAULT ACLs detected on $BACKUPPATH"
		fi
#		if (( ! $RSYNC_BACKUP_OPTION_EXCLUDE_ACLS )); then
#			if hasDefaultACLs "$BACKUPPATH"; then
#				writeToConsole $MSG_LEVEL_MINIMAL $MSG_BACKUP_DIRECTORY_HAS_DEFAULT_ACLS "$(findMountPath "$BACKUPPATH")"
#				exitError $RC_MISC_ERROR
#			fi
#		fi

		local rsyncVersion
		rsyncVersion=$(rsync --version | head -n 1 | awk '{ print $3 }')
		logItem "rsync version: $rsyncVersion"
		# Decimals are not supported. Either use integers only, or use bc or awk to compare.
		#shellcheck disable=SC2072
		if (( $PROGRESS && $INTERACTIVE )) && [[ "$rsyncVersion" < "3.1" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS "$rsyncVersion"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if [[ -z "$STARTSERVICES" && -z "$STOPSERVICES" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_START_STOP
		exitError $RC_PARAMETER_ERROR
	fi
	if [[ -z "$STARTSERVICES" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_START_OR_STOP "-a"
		exitError $RC_PARAMETER_ERROR
	fi
	if [[ -z "$STOPSERVICES" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_START_OR_STOP "-o"
		exitError $RC_PARAMETER_ERROR
	fi

	if [[ ( -n "$STARTSERVICES" || -n "$STOPSERVICES" ) && ! ( -n "$STARTSERVICES" && -n "$STOPSERVICES" ) ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_START_OR_STOP
		exitError $RC_PARAMETER_ERROR
	fi

	if (( $PROGRESS && $INTERACTIVE )); then
		if ! which pv &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "pv" "pv"
			exitError ""RC_MISSING_COMMANDS
		fi
	fi

	if (( $PARTITIONBASED_BACKUP )); then
		if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" || "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_DD_BACKUP_NOT_POSSIBLE_FOR_PARTITIONBASED_BACKUP
			exitError "$RC_PARAMETER_ERROR"
		fi
		if (( $TAR_BOOT_PARTITION_ENABLED )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_TAR_BOOT_BACKUP_NOT_POSSIBLE
			exitError "$RC_PARAMETER_ERROR"
		fi
		if (( ! $FAKE )); then
			collectPartitions
			checksForPartitionBasedBackup
		fi
	fi

	if (( $LINK_BOOTPARTITIONFILES )) &&  [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" ]] && [[ "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
		touch "$BACKUPPATH/47.$$"
		cp -l "$BACKUPPATH/47.$$" "$BACKUPPATH/11.$$" &>/dev/null
		local rc=$?
		rm "$BACKUPPATH/47.$$" &>/dev/null
		rm "$BACKUPPATH/11.$$" &>/dev/null
		if [[ $rc != 0 ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_USE_HARDLINKS "$BACKUPPATH" "$rc"
			exitError "$RC_LINK_FILE_FAILED"
		fi
	fi

	if (( $SYSTEMSTATUS )) && ! which lsof &>/dev/null; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "lsof" "lsof"
		exitError "$RC_MISSING_COMMANDS"
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_USING_BACKUPPATH "$BACKUPPATH" "$(getFsType "$BACKUPPATH")"

	if (( ! $SKIPLOCALCHECK )); then
		if ! isPathMounted "$BACKUPPATH"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_DEVICEMOUNTED "$BACKUPPATH"
			exitError "$RC_MISC_ERROR"
		fi
		# check if backup partition is a local mount
		logItem "BOOT_DEVICENAME: $BOOT_DEVICENAME"
		local lsblkResult
		lsblkResult="$(lsblk -l -o name,mountpoint | grep "${BACKUPPATH}" | grep "$BOOT_DEVICENAME")"
		logItem "lsblkResult: $lsblkResult"
		if [[ -n "$lsblkResult" ]]; then
			local di
			mapfile -d " " -t di < <( deviceInfo "/dev/$lsblkResult" )
			logItem "di: ${di[*]}"
			if [[ "$BOOT_DEVICE" == "${di[0]}" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_DEVICEMOUNTED "$BACKUPPATH"
				exitError $RC_MISC_ERROR
			fi
		fi
	fi

# all tests succeeded

	BACKUPPATH_PARAMETER="$BACKUPPATH"
	BACKUPPATH="$BACKUPPATH/$HOSTNAME"
	if [[ ! -d "$BACKUPPATH" ]]; then
		if ! mkdir -p "${BACKUPPATH}" &>>"$LOG_FILE"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "$BACKUPPATH"
			exitError "$RC_CREATE_ERROR"
		fi
	fi

	logCommand "ls -1 ${BACKUPPATH}"
	# Note: The new optional part (@.*?)* in the regex below saves possible older backups without the OS release in the name from being deleted as nonRaspiGeneratedDirs!
	local nonRaspiGeneratedDirs
	# Double quote to prevent globbing and word splitting.
	# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
	#shellcheck disable=SC2010,SC2086
	nonRaspiGeneratedDirs=$(ls -1 ${BACKUPPATH} | grep -Ev "$HOSTNAME(@.*?)*\-($POSSIBLE_BACKUP_TYPES_REGEX)\-backup\-([0-9]){8}.([0-9]){6}" | grep -E "\-backup\-" | wc -l)
	logItem "nonRaspiGeneratedDirs: $nonRaspiGeneratedDirs"

	if (( $nonRaspiGeneratedDirs > 0 )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_BACKUPNAMES_DETECTED "$nonRaspiGeneratedDirs" "$BACKUPPATH"
		exitError "$RC_BACKUP_DIRNAME_ERROR"
	fi

	# just inform about options enabled

	if  [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
		if (( $LINK_BOOTPARTITIONFILES )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_LINK_BOOTPARTITIONFILES
		fi
	fi

	if  [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" || "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
		if (( $DD_BACKUP_SAVE_USED_PARTITIONS_ONLY )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_SAVING_USED_PARTITIONS_ONLY
		fi
	fi

	if (( ! $RESTORE && $REBOOT_SYSTEM && ! $FAKE )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_REBOOT_SYSTEM
	fi

	# now either execute a SR dryrun or start backup

	if (( $SMART_RECYCLE_DRYRUN && $SMART_RECYCLE )); then # just apply backup strategy to test smart recycle
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_APPLYING_BACKUP_STRATEGY_ONLY "$BACKUPPATH"
		applyBackupStrategy
		rc=0
	else
		if (( $SMART_RECYCLE && !$SMART_RECYCLE_DRYRUN )); then
			writeToConsole $MSG_LEVEL_DETAILED $MSG_SMART_RECYCLE_WILL_BE_APPLIED
		fi
		backup
	fi

	logExit

}

function listDeviceInfo() { # device (/dev/sda)

	logEntry "$1"
	local result
	result="$(IFS='' lsblk $1 --tree -o NAME,SIZE,FSTYPE,LABEL)"
	echo "$result"
	logExit
}

function getPartitionTable() { # device

	logEntry "$1"
	local result table

	# Possible results of partprobe
	# See https://stackoverflow.com/questions/26873289/how-to-check-a-disk-for-partitions-for-use-in-a-script-in-linux
	# /dev/sdb: gpt partitions 1 -> partition table exists and one partition
	# /dev/sdb: gpt partitions -> partition table exists but no partition
	# <empty> -> no partition table

	if [[ -n "$(partprobe -d -s "$1" | cut -f 4 -d ' ')" ]]; then
		table="$(IFS='' parted "$1" unit MB p 2>>"$LOG_FILE" | sed -r '/^($|[MSDP])/d')"
		if (( $(wc -l <<< "$table") < 2 )); then
			result=""
		else
			result="$table"
		fi
	else
		result=""
	fi
	echo "$result"

	logExit "$result"
}

function checkAndSetBootPartitionFiles() { # directory extension

	logEntry "$1 - $2"

	local prefix="$1/$2"

	DD_FILE="$prefix.$BOOT_DD_EXT"
	logItem "DD_FILE: $DD_FILE"
	TAR_FILE="$prefix.$BOOT_TAR_EXT"
	logItem "TAR_FILE: $TAR_FILE"
	SF_FILE="$prefix.sfdisk"
	logItem "SF_FILE: $SF_FILE"
	MBR_FILE="$prefix.mbr"
	logItem "MBR_FILE: $MBR_FILE"

	local errorCnt=0
	if [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
		if [[ ! -e "$SF_FILE" ]]; then
			logItem "$SF_FILE not found"
			(( errorCnt++ ))
		else
			logItem "$(<"$SF_FILE")"
		fi
		if [[ ! -e "$DD_FILE" && ! -e "$TAR_FILE" ]]; then
			logItem "$DD_FILE/$TAR_FILE not found"
			(( errorCnt++ ))
		fi
		if [[ ! -e "$MBR_FILE" ]]; then
			logItem "$MBR_FILE not found"
			(( errorCnt++ ))
		fi
	fi

	logExit "$errorCnt"

	return $errorCnt

}

function findNonpartitionBackupBootAndRootpartitionFiles() {

	logEntry

#	search precedence for root files
#	1) if directory search corresponding file in directory
#	2) if file passed just use this file

	if [[ -f "$RESTOREFILE" || $BACKUPTYPE == "$BACKUPTYPE_RSYNC" ]]; then
		ROOT_RESTOREFILE="$RESTOREFILE"
	else
		logItem "${RESTOREFILE}/${HOSTNAME}*-*-backup*"
		# Double quote to prevent globbing and word splitting.
		#shellcheck disable=SC2086
		ROOT_RESTOREFILE="$(ls ${RESTOREFILE}/${HOSTNAME}*-*-backup*)"
		logItem "ROOT_RESTOREFILE: $ROOT_RESTOREFILE"
		if [[ -z "$ROOT_RESTOREFILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_ROOTBACKUPFILE_FOUND "$BACKUPTYPE"
			exitError $RC_MISC_ERROR
		fi
	fi

	writeToConsole $MSG_LEVEL_DETAILED $MSG_USING_ROOTBACKUPFILE "$ROOT_RESTOREFILE"

#	search precedence for boot files
#	1) individual backup dir and no date (added in this version)
#	2) backup dir and date (added when boot backup all the time was added in 0.6.1.1)
#	3) backup dir and no date (initial location when ony one single backup was created, pre 0.6.1.1)

	local bootpartitionDirectory=( "$RESTOREFILE" "$BASE_DIR"  "$BASE_DIR" )
	local bootpartitionExtension=( "$HOSTNAME-backup" "$HOSTNAME-backup-$DATE" "$HOSTNAME-backup" )

	local i=0

	for (( i=0; i<${#bootpartitionDirectory[@]}; i++ )); do

		checkAndSetBootPartitionFiles "${bootpartitionDirectory[$i]}" "${bootpartitionExtension[$i]}"
		local errorCnt=$?

		if [[ $errorCnt == 0 ]]; then
			writeToConsole $MSG_LEVEL_DETAILED $MSG_BOOTPATITIONFILES_FOUND "${bootpartitionDirectory[$i]}" "${bootpartitionExtension[$i]}"
			logExit
			return
		fi
	done

	for (( i=0; i<${#bootpartitionDirectory[@]}; i++ )); do
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_BOOTPATITIONFILES_NOT_FOUND "${bootpartitionDirectory[$i]}" "${bootpartitionExtension[$i]}"
	done
	logExit
	exitError "$RC_MISC_ERROR"

}

function initRestoreVariables () {

	logEntry

	if [[ -z $(fdisk -l "$RESTORE_DEVICE" 2>/dev/null) ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_RESTOREDEVICE_FOUND "$RESTORE_DEVICE"
		exitError "$RC_PARAMETER_ERROR"
	fi

	BOOT_PARTITION="$(createPartitionName "$RESTORE_DEVICE" 1)"

	logItem "BOOT_PARTITION : $BOOT_PARTITION"

	ROOT_PARTITION_DEFINED=1
	if [[ -z "$ROOT_PARTITION" ]]; then
		ROOT_PARTITION="$(createPartitionName "$RESTORE_DEVICE" 2)"
		ROOT_PARTITION_DEFINED=0
	else
		if [[ ! -e "$ROOT_PARTITION" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_ROOT_PARTTITION_NOT_FOUND "$ROOT_PARTITION"
			exitError "$RC_PARAMETER_ERROR"
		fi
	fi

	logItem "ROOT_PARTITION : $ROOT_PARTITION"

	logExit
}

function restoreNonPartitionBasedBackup() {

	logEntry

	initRestoreVariables

	if (( ! $SKIP_SFDISK )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_REPARTITION_WARNING "$RESTORE_DEVICE"
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_CREATING_PARTITIONS
	fi

	if (( ! $ROOT_PARTITION_DEFINED )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_WARN_RESTORE_DEVICE_OVERWRITTEN "$RESTORE_DEVICE"
		current_partition_table="$(listDeviceInfo "$RESTORE_DEVICE")"
		if [[ -n "$current_partition_table" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_PARTITION_TABLE "$RESTORE_DEVICE"
			logItem "$current_partition_table"
			echo "$current_partition_table"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_PARTITION_TABLE_DEFINED "$RESTORE_DEVICE"
		fi
	else
		if isSpecialBlockDevice "$ROOT_DEVICE"; then
			ROOT_DEVICE=$(sed -E 's/p[0-9]+$//' <<< "$ROOT_PARTITION")
		else
			ROOT_DEVICE=$(sed -E 's/[0-9]+$//' <<< "$ROOT_PARTITION")
		fi

		if [[ $ROOT_DEVICE != "$RESTORE_DEVICE" ]]; then
			current_partition_table="$(listDeviceInfo "$ROOT_DEVICE")"
			if [[ -n "$current_partition_table" ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_PARTITION_TABLE "$ROOT_DEVICE"
				logItem "$current_partition_table"
				echo "$current_partition_table"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_PARTITION_TABLE_DEFINED "$ROOT_DEVICE"
				if (( $SKIP_SFDISK )); then
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_PARTITION "$ROOT_DEVICE"
					exitError $RC_MISSING_PARTITION
				fi
			fi
		fi
	fi
	if (( ! $SKIP_SFDISK )); then
		if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" ||  "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_REPARTITION_WARNING "$BOOT_PARTITION"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_WARN_BOOT_PARTITION_OVERWRITTEN "$BOOT_PARTITION"
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_WARN_ROOT_PARTITION_OVERWRITTEN "$ROOT_PARTITION"
		fi
	fi

	if ! askYesNo; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
		exitError $RC_RESTORE_FAILED
	fi

	restoreNormalBackupType

	logExit "$rc"

}

function restorePartitionBasedBackup() {

	logEntry

	local partition sourceSDSize targetSDSize

	if [[ "${RESTOREFILE: -1}" != "/" ]]; then
		RESTOREFILE="$RESTOREFILE/"
	fi

	if mount | grep -q "$RESTORE_DEVICE"; then
		logItem "Umounting partitions on $RESTORE_DEVICE"
		logItem "$(mount | grep "$RESTORE_DEVICE")"
		local dev
		while read -r dev; do echo "$dev" | cut -d ' ' -f 1; done < <(mount | grep "$RESTORE_DEVICE")  | xargs umount
		logItem "$(mount | grep "$RESTORE_DEVICE")"
	fi

	current_partition_table="$(listDeviceInfo "$RESTORE_DEVICE")"
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_PARTITION_TABLE "$RESTORE_DEVICE"
	logItem "$current_partition_table"
	echo "$current_partition_table"

	if [[ "${PARTITIONS_TO_RESTORE}" == "$PARTITIONS_TO_BACKUP_ALL" ]]; then
		local partitions
		partitions=( "$(collectAvailableBackupPartitions "$RESTOREFILE" )" )
		local partitionsString="${partitions[*]}"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_PARTITIONS "\"$partitionsString\"" "$RESTORE_DEVICE"
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_PARTITIONS "\"$PARTITIONS_TO_RESTORE\"" "$RESTORE_DEVICE"
	fi

	if ! askYesNo; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_ABORTED
		exitError "$RC_RESTORE_FAILED"
	fi

	if (( $NO_YES_QUESTION )); then
		echo "Y"
	fi

	initRestoreVariables

	MNT_POINT="$TEMPORARY_MOUNTPOINT_ROOT"

	if isMounted "$MNT_POINT"; then
		logItem "$MNT_POINT mounted - unmouting"
		if ! umount -f "$MNT_POINT" &>>"$LOG_FILE"; then
			assertionFailed $LINENO "Unable to unmount $MNT_POINT"
		fi
	fi

	START_TIME="$(date +%s)"

	logItem "Creating mountpoint $MNT_POINT"

	if ! mkdir -p "$MNT_POINT" &>>"$LOG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "$MNT_POINT"
		exitError "$RC_CREATE_ERROR"
	fi

	# handle partitions

	local partitionsToRestore=("${PARTITIONS_TO_RESTORE[@]}")

	if (( ${#partitionsToRestore[@]} > 0 )); then
		if [[ ! -e "$SF_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$SF_FILE"
			exitError $RC_MISSING_FILES
		fi
		logItem "SF_FILE: $SF_FILE$NL$(<"$SF_FILE")"
		if [[ ! -e "$MBR_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$MBR_FILE"
			exitError $RC_MISSING_FILES
		fi
		if [[ ! -e "$BLKID_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$BLKID_FILE"
			exitError $RC_MISSING_FILES
		fi
		logItem "BLKID_FILE: $BLKID_FILE$NL$(<"$BLKID_FILE")"
		if [[ ! -e "$PARTED_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$PARTED_FILE"
			exitError $RC_MISSING_FILES
		fi
		logItem "PARTED_FILE: $PARTED_FILE$NL$(<"$PARTED_FILE")"

		partitionRestoredeviceIfRequested

		local partitionBackupFile
		# Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
		#shellcheck disable=SC2206
		local partitionsToRestore=(${PARTITIONS_TO_RESTORE[@]})
		local partitionsRestored=()

		logItem "RESTOREFILE_BACKUP_BOOT_PARTITION_PREFIX: ${RESTOREFILE}${BACKUP_BOOT_PARTITION_PREFIX}"
		for partitionBackupFile in "${RESTOREFILE}${BACKUP_BOOT_PARTITION_PREFIX}"*; do
			logItem "partitionBackupFile: $partitionBackupFile"
			local partitionNo
			partitionNo="$(grep -Eo "[0-9]+(\.($BACKUPTYPE_TAR|$BACKUPTYPE_TGZ|$TAR_COMPRESSION_EXTENSIONS_SUPPORTED_GREP))?$" <<< "$partitionBackupFile" | sed -E 's/(\.tar)?\..+$//' )"  # delete trailing extension and optional .tar
			logItem "Found partition no: $partitionNo"
			if [[ -z "$partitionNo" ]]; then
				assertionFailed $LINENO "Unable to retrieve partition number from $partitionBackupFile"
			fi
			if [[ "${PARTITIONS_TO_RESTORE}" == "$PARTITIONS_TO_BACKUP_ALL" ]] ||  containsElement "$partitionNo" "${partitionsToRestore[@]}"; then
				restorePartitionBasedPartition "$partitionBackupFile"
				partitionsRestored+=("$partitionNo")
			else
				local skippedPartition="${RESTORE_DEVICE}${partitionNo}"
				if isSpecialBlockDevice "${RESTORE_DEVICE}"; then
					skippedPartition="${RESTORE_DEVICE}p${partitionNo}"
				fi
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_PARTITION_RESTORE "$skippedPartition"
			fi
		done

		updateUUIDs
		synchronizeCmdlineAndfstab

		if ! containsElement "1" "${partitionsRestored[@]}" || ! containsElement "2" "${partitionsRestored[@]}"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITION_RESTORE_NO_BOOT_POSSIBLE
		fi

	fi

	END_TIME="$(date +%s)"

	logCommand "fdisk -l $RESTORE_DEVICE"

	logExit

}

# MBR partition blkid examples:
# /dev/mmcblk0p1: LABEL="RECOVERY" UUID="B383-E246" TYPE="vfat"
# /dev/mmcblk0p3: LABEL="SETTINGS" UUID="9b35a9e6-d81f-4eff-9096-633297a5410b" TYPE="ext4"
# /dev/mmcblk0p5: LABEL="boot0" UUID="035A-9F64" TYPE="vfat"
# /dev/mmcblk0p6: LABEL="root" UUID="53df0f2a-3f9c-4b76-afc9-17c60989988d" TYPE="ext4"
# /dev/mmcblk0p7: LABEL="boot" UUID="56A8-F127" TYPE="vfat"
# /dev/mmcblk0p8: LABEL="root0" UUID="aa2fec4f-70ac-49b5-bc59-be0cf74b76d7" TYPE="ext4"
# GPT partition blkid examples:
# /dev/mmcblk0p1: LABEL_FATBOOT="bootfs" LABEL="bootfs" UUID="EC36-4DE1" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="Microsoft basic data" PARTUUID="df06e23f-4069-4fb4-a5f2-65bd5c9ac229"
function getBackupPartitionLabel() { # partition

	logEntry "$1"

	local partition=$1
	local blkid
	local label=""

	blkid=$(grep "$partition" "$BLKID_FILE")
	logItem "BLKID: $1 - $blkid"

	regexFormatLineLabel="^.* LABEL=\"([^\"]+)\".*$"

	if [[ $blkid =~ $regexFormatLineLabel ]]; then
		label=${BASH_REMATCH[1]}
#	else
#		label=$(sed -E 's/\/dev\///' <<< $partition)	# strip /dev/
	fi

	echo "$label"

	logExit "$label"

}

# parted -l -m
#BYT;
#/dev/mmcblk0:7969MB:sd/mmc:512:512:msdos:SD SD08G;
#1:1049kB:857MB:856MB:fat32::lba;
#2:860MB:7936MB:7076MB:::;
#5:1845MB:1895MB:49.3MB:fat32::lba;
#6:1896MB:3899MB:2003MB:::;
#7:3901MB:4438MB:537MB:ext4::;
#8:4442MB:4505MB:62.9MB:fat16::lba;
#9:4509MB:7926MB:3417MB:ext4::;
#3:7936MB:7969MB:33.6MB:ext4::;

function extractDataFromBackupPartedFile() { # partition fieldnumber

	logEntry "$1 $2"

	local partitionNo
	partitionNo=$(sed -E "s%${BACKUP_BOOT_PARTITION_PREFIX}%%" <<< "$1")
	logItem "PartitionNo: $partitionNo"
	local parted element
	logItem "PARTED: $1 - $(<"$PARTED_FILE")"

	parted=$(grep "^$partitionNo" "$PARTED_FILE")
	logItem "PARTED: $1 - $parted"

	element=$(cut -d ":" -f "$2" <<< "$parted")

	echo "$element"

	logExit "$element"
}

function getBackupPartitionFilesystemUsed() { # partition

	logEntry "$1"

	mount $1 /mnt
	local used
	used=$(df "$1" -B 1 | tail -1 | awk '{ printf "%.0f\n", $3 }')
	umount /mnt
	echo "$used"

	logExit "$used"

}

function getBackupPartitionFilesystemSize() { # partition

	logEntry "$1"

	local size
	size=$(df "$1" -B 1 | tail -1 | awk '{ printf "%.0f\n", $3 + $4 }')
	echo "$size"

	logExit "$size"

}

function getBackupPartitionFilesystem() { # partition

	logEntry "$1"

	local fileSystem
	fileSystem=$(extractDataFromBackupPartedFile "$1" "5")
	echo "$fileSystem"

	logExit "$fileSystem"

}

function getPartitionBootFilesystem() { # partition_no

	logEntry "$1"

	local partitionNo=$1

	logItem "BOOT_DEVICENAME: $BOOT_DEVICENAME"

	local parted format
	logItem "PARTED: $1 - $(parted -m "$BOOT_DEVICENAME" print 2>/dev/null)"
	parted=$(grep "^${partitionNo}:" <(parted -m "$BOOT_DEVICENAME" print 2>/dev/null))
	logItem "PARTED: $1 - $parted"

	format=$(cut -d ":" -f 5 <<< "$parted")

	echo "$format"

	logExit "$format"

}

function lastUsedPartitionByte() { # device

	logEntry "$1"

	local partitionregex="/dev/.*[p]?([0-9]+).*start=[^0-9]*([0-9]+).*size=[^0-9]*([0-9]+).*(Id|type)=[^0-9a-z]*([0-9a-z]+)"
	local lastUsedPartitionByte=0

	local line
	while read -r line; do
		if [[ -z $line ]]; then
			continue
		fi

		logItem "$line"

		if [[ $line =~ $partitionregex ]]; then
			local p=${BASH_REMATCH[1]}
			local start=${BASH_REMATCH[2]}
			local size=${BASH_REMATCH[3]}
			local id=${BASH_REMATCH[5]}

			logItem "$p - $start - $size - $id"
			if [[ $id == 85 || $id == 5 ]]; then
				continue
			fi
			if (( $start > 0 )); then
				lastUsedPartitionByte=$((start+size))
			fi
		fi

	done < <(sfdisk -d "$1" 2>>"$LOG_FILE")

	(( lastUsedPartitionByte*=512 ))

	echo "$lastUsedPartitionByte"

	logExit "$lastUsedPartitionByte"

}

function makeFilesystemAndLabel() { # partition filesystem label

	logEntry "$1 $2"

	local partition="$1"
	local partitionFilesystem="$2"
	local partitionLabel="$3"

	if [[ ! "$partitionFilesystem" =~ $SUPPORTED_PARTITIONBACKUP_PARTITIONTYPE_REGEX ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_FILESYSTEM_FORMAT "$partitionFilesystem" "$partition"
		exitError $RC_MISC_ERROR
	fi

	logItem "partitionFilesystem: \"$partitionFilesystem\""

	local fs="$partitionFilesystem"
	local fatSize=""
	local fatCmd=""

	local swapDetected=0
	if [[ "$partitionFilesystem" =~ ^fat.* ]]; then
		fs="vfat"
		# See if you can use ${variable//search/replace} instead
		#shellcheck disable=SC2001
		fatSize=$(sed 's/fat//' <<< "$partitionFilesystem")
		fatCmd="-I -F $fatSize"
		logItem "fs: $fs - fatSize: $fatSize - fatCmd: $fatCmd"
		cmd="mkfs -t $fs $fatCmd"
	elif [[ "$partitionFilesystem" =~ swap ]]; then
		cmd="mkswap"
		swapDetected=1
		logItem "Swap partition"
	else
		logItem "Normal partition with $partitionFilesystem"
		if [[ $partitionFilesystem == "btrfs" ]]; then
			check4RequiredCommands btrfs
			cmd="mkfs.btrfs -f"
		elif [[ $partitionFilesystem == "f2fs" ]]; then
			check4RequiredCommands f2fs
			if [[ -n $partitionLabel ]]; then
				cmd="mkfs.f2fs -f -l $partitionLabel "
			else
				cmd="mkfs.f2fs -f"
			fi
		else
			cmd="mkfs -t $fs"
		fi
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_FORMATTING "$partition" "$partitionFilesystem"
	logItem "$cmd $partition"

	$cmd "$partition" &>>"$LOG_FILE"

	rc=$?
	if (( $rc )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MKFS_FAILED "$cmd $partition" "$rc"
		exitError $RC_MISC_ERROR
	fi

	if (( ! $swapDetected )); then

		# Keep SUPPORTED_PARTITIONBACKUP_PARTITIONTYPE_REGEX in sync

		if [[ -n $partitionLabel ]]; then
			writeToConsole $MSG_LEVEL_DETAILED $MSG_LABELING "$partition" "$partitionLabel"

			case $partitionFilesystem in
				ext2|ext3|ext4) cmd="e2label"
					;;
				fat16|fat32) cmd="dosfslabel"
					;;
				btrfs) cmd="btrfs filesystem label"
					;;
				f2fs) cmd=": noop until f2fs 1.5 is available on Raspberries # <f2fs label command>"
					 ;;
			esac

			logItem "$cmd $partition $partitionLabel"
			$cmd "$partition" "$partitionLabel" &>>"$LOG_FILE"
			rc=$?
			if (( $rc )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_LABELING_FAILED "$cmd $partition $partitionLabel" "$rc"
				exitError "$RC_LABEL_ERROR"
			fi
		else
			logItem "Partition $partition not labeled"
		fi
	fi

	logExit

}

function restorePartitionBasedPartition() { # restorefile

	logEntry "$1"

	rc=0
	local verbose zip partitionLabel cmd restoreFile restorePartition

	restoreFile="$1"
	restorePartition="$(basename "$restoreFile")"

	restorePartition="$(sed -E 's%(\.tar)?\..+$%%' <<< ${restorePartition})"		# remove backup extension and optional .tar
	logItem "RestorePartition: $restorePartition"

	local partitionNumber
	partitionNumber="$(sed -E 's%.+([0-9]+)$%\1%' <<< "$restorePartition")"			# extract partition number
	logItem "Partitionnumber: $partitionNumber"

	partitionLabel=$(getBackupPartitionLabel "$restorePartition")
	partitionFilesystem=$(getBackupPartitionFilesystem "$restorePartition")

	logItem "Label: $partitionLabel - Filesystem: $partitionFilesystem"

	local restoreDevice
	restoreDevice=${RESTORE_DEVICE%dev%%}
	restoreDevice="$(createPartitionName "$restoreDevice")"
	logItem "RestoreDevice: $restoreDevice"

	local mappedRestorePartition
	# See if you can use ${variable//search/replace} instead
	#shellcheck disable=SC2001
	mappedRestorePartition=$(sed "s%${BACKUP_BOOT_PARTITION_PREFIX}%${restoreDevice}%" <<< "$restorePartition")

	if [[ ! "$partitionFilesystem" =~ $SUPPORTED_PARTITIONBACKUP_PARTITIONTYPE_REGEX ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_FILESYSTEM_FORMAT "$partitionFilesystem" "$mappedRestorePartition"
		exitError "$RC_MISC_ERROR"

	elif [[ -n "$partitionFilesystem" ]]; then
		logItem "partitionFilesystem: \"$partitionFilesystem\""

		if (( ! $SKIP_FORMAT )); then
			makeFilesystemAndLabel "$mappedRestorePartition" "$partitionFilesystem" "$partitionLabel"
		fi

		if [[ ! "$partitionFilesystem" =~ swap ]]; then
			logItem "mount $mappedRestorePartition $MNT_POINT"
			mount "$mappedRestorePartition" "$MNT_POINT"

			logItem "Restoring file $restoreFile"
			if (( $SKIP_FORMAT )); then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_SYNCING_PARTITIONFILE "$mappedRestorePartition"
			else
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORING_PARTITIONFILE "$mappedRestorePartition"
			fi

			(( $VERBOSE )) && verbose="v" || verbose=""

			logItem "Backuptype: $BACKUPTYPE"

			rc=$RC_NATIVE_BACKUP_FAILED

			case $BACKUPTYPE in

				"$BACKUPTYPE_TAR"|"$BACKUPTYPE_TGZ")
					local archiveFlags=""

					if [[ -n $fatSize  ]]; then
						local archiveFlags="--same-owner --same-permissions --numeric-owner ${TAR_RESTORE_ADDITIONAL_OPTIONS}"	# fat32 doesn't know about this
					fi

					if ! pushd "$MNT_POINT" &>>"$LOG_FILE"; then
						assertionFailed $LINENO "push to $MNT_POINT failed"
					fi
					[[ "$BACKUPTYPE" == "$BACKUPTYPE_TGZ" ]] && zip="z" || zip=""

					if (( $PROGRESS && $INTERACTIVE )); then
						cmd="pv -f $restoreFile | tar ${archiveFlags} -x${verbose}${zip}f -"
					else
						cmd="tar ${archiveFlags} -x${verbose}${zip}f \"$restoreFile\""
					fi
					executeTar "$cmd"
					rc=$?
					popd &>>"$LOG_FILE"
					;;

				"$BACKUPTYPE_RSYNC")
					local archiveFlags="aH"						# -a <=> -rlptgoD, H = preserve hardlinks
					[[ -n $fatSize  ]] && archiveFlags="rltD"	# no Hopg flags for fat fs
					cmdParms="--numeric-ids ${RSYNC_BACKUP_OPTIONS} -${archiveFlags}X$verbose \"$restoreFile/\" $MNT_POINT"
					if (( $PROGRESS && $INTERACTIVE )); then
						cmd="rsync --info=progress2 $cmdParms"
					else
						cmd="rsync $cmdParms"
					fi
					executeRsync "$cmd"
					rc=$?
					;;

				*)  logItem "Invalid backupo type $BACKUPTYPE found"
					assertionFailed $LINENO "Invalid backup type $BACKUPTYPE detected"
					;;

			esac

			if [[ $rc != 0 ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_PROGRAM_ERROR "$BACKUPTYPE" "$rc"
				exitError "$RC_NATIVE_RESTORE_FAILED"
			fi

			sleep 1s					# otherwise umount fails

			umountPartition "$mappedRestorePartition"

			if isMounted "$MNT_POINT"; then
				logItem "umount $MNT_POINT"
				if ! umount -f "$MNT_POINT" &>>"$LOG_FILE"; then
					assertionFailed $LINENO "Unable to umount $MNT_POINT"
				fi
			fi

			writeToConsole $MSG_LEVEL_DETAILED $MSG_RESTORING_FILE_PARTITION_DONE "$mappedRestorePartition"

			executeFilesystemCheck "$mappedRestorePartition"

		fi # is not swap partition
	else
		assertionFailed $LINENO "This error should not occur"
	fi

	logExit

}

function executeFilesystemCheck { # partition
	logEntry "$1"
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITION_CHECK_EXECUTED "$1"
	fsck -fpv "$1" &>>"$LOG_FILE"
	rc_fsck=$?
	logItem "fsck rc: $rc_fsck"
	if (( $rc_fsck > 1 )); then # 1: => Filesystem errors corrected
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_PARTITION_CHECK_FAILED "$1" "$rc_fsck"
		exitError $RC_NATIVE_RESTORE_FAILED
	fi
	logExit
}

function doitRestore() {

	logEntry

	local current_partition_table

	logCommand "blkid"

	commonChecks

	if hasSpaces "$RESTOREFILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_CONTAINS_SPACES "$RESTOREFILE"
		exitError $RC_MISC_ERROR
	fi

	if [[ ! -d "$RESTOREFILE" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_DIRECTORY_NO_DIRECTORY "$RESTOREFILE"
		exitError $RC_MISSING_FILES
	fi

	if [[ ! -b "$RESTORE_DEVICE" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_DEVICE_NOT_VALID "$RESTORE_DEVICE"
		exitError $RC_RESTORE_IMPOSSIBLE
	fi

	logItem "ls $RESTOREFILE$NL$(ls "$RESTOREFILE")"

	local regex=""
	for type in $POSSIBLE_TYPES; do
		[[ -z $regex ]] && regex="$type" || regex="$regex|$type"
	done
	regex="\-($regex)\-backup\-"
	logItem "Basename: $(basename "$RESTOREFILE")"
	logItem "regex: $regex"

	if [[ ! $(basename "$RESTOREFILE") =~ $regex ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_DIRECTORY_INVALID "$RESTOREFILE"
		exitError $RC_MISSING_FILES
	fi

	if isMounted "$RESTORE_DEVICE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_DEVICE_MOUNTED "$RESTORE_DEVICE"
		exitError $RC_MISC_ERROR
	fi

	logItem "Checking for partitionbasedbackup in $RESTOREFILE/*"
	logCommand "ls -1 $RESTOREFILE*"

	# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
	#shellcheck disable=SC2010
	if  ls -1 "$RESTOREFILE"* | grep -E "\.blkid$" &>>"$LOG_FILE" ; then
		PARTITIONBASED_BACKUP=1
		if [[ -n $ROOT_PARTITION ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_DEVICE_NOT_ALLOWED
			exitError $RC_MISSING_FILES
		fi
	else
		PARTITIONBASED_BACKUP=0
	fi

	if (( ! $PARTITIONBASED_BACKUP && $OPTION_T_USED )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_OPTION_T_NOT_ALLOWED
			exitError $RC_PARAMETER_ERROR
	fi

	logItem "PartitionbasedBackup detected? $PARTITIONBASED_BACKUP"

	if [[ -z $RESTORE_DEVICE ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_RESTOREDEVICE_DEFINED
		exitError $RC_PARAMETER_ERROR
	fi

	if (( $PROGRESS && $INTERACTIVE )); then
		if ! which pv &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "pv" "pv"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if ! (( $FAKE )); then
		RESTORE_DEVICE=${RESTORE_DEVICE%/} # delete trailing /
		if [[ ! ( $RESTORE_DEVICE =~ ^/dev/mmcblk[0-9]+$ ) && ! ( $RESTORE_DEVICE =~ /dev/loop[0-9]+ ) && ! ( $RESTORE_DEVICE =~ /dev/nvme[0-9]+n[0-9]+ )]]; then
			if ! [[ "$RESTORE_DEVICE" =~ ^/dev/[a-zA-Z]+$ ]] ; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTOREDEVICE_IS_PARTITION "$RESTORE_DEVICE"
				exitError $RC_PARAMETER_ERROR
			fi
		fi

		if [[ -z $(fdisk -l "$RESTORE_DEVICE" 2>/dev/null) ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_RESTOREDEVICE_FOUND "$RESTORE_DEVICE"
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if (( $ROOT_PARTITION_DEFINED )); then
		if ! [[ "$ROOT_PARTITION" =~ ^/dev/[a-z]+[0-9]$ ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_INVALID_RESTORE_ROOT_PARTITION "$ROOT_PARTITION"
			exitError $RC_DEVICES_NOTFOUND
		fi

		if ! [[ -e "$ROOT_PARTITION" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_ROOT_PARTITION_NOT_FOUND "$ROOT_PARTITION"
			exitError $RC_DEVICES_NOTFOUND
		fi

		local rc rr
		rd=$(sed -E 's#/dev/([a-z]+)(.+)?#\1#' <<< "$RESTORE_DEVICE")
		rr=$(sed -E 's#/dev/([a-z]+)(.+)?#\1#' <<< "$ROOT_PARTITION")

		logItem "Restore devices: -d: $rd - -R: $rr"

		if [[ "$rd" == "$rr" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_ROOT_PARTITION_NOT_DIFFERENT "$RESTORE_DEVICE"
			exitError $RC_DEVICES_NOTFOUND
		fi
	fi

	if mount | grep "^${RESTORE_DEVICE%/}"; then # delete trailing / if it's present
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_PARTITION_MOUNTED "$RESTORE_DEVICE"
		current_partition_table="$(listDeviceInfo "$RESTORE_DEVICE")"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_PARTITION_TABLE "$RESTORE_DEVICE"
		echo "$current_partition_table"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UMOUNT_MOUNTED_PARTITIONS "$RESTORE_DEVICE"
		if ! askYesNo; then
			exitError $RC_RESTORE_FAILED
		else
			umount ${RESTORE_DEVICE}* &>>"$LOG_FILE"
			if mount | grep "^${RESTORE_DEVICE%/}"; then # delete trailing / if it's present
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UMOUNT_MOUNTED_PARTITIONS_FAILED "$RESTORE_DEVICE"
				exitError $RC_RESTORE_IMPOSSIBLE
			fi
		fi
	fi

	BASE_DIR=$(dirname "$RESTOREFILE")
	logItem "Basedir: $BASE_DIR"
	# Note: Handle old (without) and new (with OS release info) backup directory names
	HOSTNAME=$(basename "$RESTOREFILE" | sed -r 's/(.*)(@[A-Za-z0-9]+)*-[A-Za-z]+-backup-[0-9]+-[0-9]+.*/\1/')
	HOSTNAME=${HOSTNAME%@*}
	logItem "Hostname: $HOSTNAME"
	BACKUPTYPE=$(basename "$RESTOREFILE" | sed -r 's/.*-([A-Za-z]+)-backup-[0-9]+-[0-9]+.*/\1/')
	logItem "Backuptype: $BACKUPTYPE"
	DATE=$(basename "$RESTOREFILE" | sed -r 's/.*-[A-Za-z]+-backup-([0-9]+-[0-9]+).*/\1/')
	logItem "Date: $DATE"

	if (( $SKIP_FORMAT )); then
		if [[ "$BACKUPTYPE" != "$BACKUPTYPE_RSYNC" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_SKIP_FORMAT_POSSIBLE
			exitError $RC_PARAMETER_ERROR
		fi
	fi

	if (( $PROGRESS && $INTERACTIVE )); then
		if ! which pv &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "pv" "pv"
			exitError $RC_MISSING_COMMANDS
		fi
	fi

	if [[ "$BACKUPTYPE" == "$BACKUPTYPE_RSYNC" ]]; then
		if ! which rsync &>/dev/null; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "rsync" "rsync"
			exitError $RC_MISSING_COMMANDS
		fi
		local rsyncVersion
		rsyncVersion=$(rsync --version | head -n 1 | awk '{ print $3 }')
		logItem "rsync version: $rsyncVersion"
		# Decimals are not supported. Either use integers only, or use bc or awk to compare.
		#shellcheck disable=SC2072
		if (( $PROGRESS && $INTERACTIVE )) && [[ "$rsyncVersion" < "3.1" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_RSYNC_DOES_NOT_SUPPORT_PROGRESS "$rsyncVersion"
			exitError $RC_PARAMETER_ERROR
		fi

		disableACLsIfRequested
	fi

	if ! which dosfslabel &>/dev/null; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_INSTALLED_FILE "dosfslabel" "dosfstools"
		exitError $RC_MISSING_COMMANDS
	fi

	if (( ! $PARTITIONBASED_BACKUP	 )); then
		findNonpartitionBackupBootAndRootpartitionFiles
	fi

	inspect4Restore

	if (( $FORCE_SFDISK )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FORCE_SFDISK "$RESTORE_DEVICE"
	fi

	if (( $SKIP_SFDISK )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SKIP_SFDISK "$RESTORE_DEVICE"
	fi

	#if [[ "$BACKUPTYPE" == "$BACKUPTYPE_DD" ]]; then
	#	local sdSize="$(fdisk -l "$RESTORE_DEVICE" | grep "Disk.*${RESTORE_DEVICE}" | cut -d ' ' -f 5)"
	#	local imgSize="$(stat -c "%s" "$ROOT_RESTOREFILE")"
	#	if [[ $sdSize < $imgSize ]]; then
	#		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SD_TOO_SMALL "$RESTORE_DEVICE" "$sdSize" "$imgSize"
	#		exitError $RC_RESTORE_FAILED
	#	fi
	#elif [[ "$BACKUPTYPE" == "$BACKUPTYPE_DDZ" ]]; then
	#	local c
	#	read c sdSize r < <(gzip -l "$RESTOREFILE" | tail -n 1)
	#	imgSize="$(stat -c "%s" "$ROOT_RESTOREFILE")"
	#	if [[ $sdSize < $imgSize ]]; then
	#		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SD_TOO_SMALL "$RESTORE_DEVICE" "$sdSize" "$imgSize"
	#		exitError $RC_RESTORE_FAILED
	#	fi
	#fi

	rc=0

	if ! (( $PARTITIONBASED_BACKUP )); then
		restoreNonPartitionBasedBackup
		if [[ "$BACKUPTYPE" != "$BACKUPTYPE_DD" && "$BACKUPTYPE" != "$BACKUPTYPE_DDZ" ]]; then
			synchronizeCmdlineAndfstab
		fi
	else
		restorePartitionBasedBackup
	fi

	mapfile -d " " -t RESTORE_TIME < <( duration "$START_TIME" "$END_TIME" )
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORE_TIME "${RESTORE_TIME[1]}" "${RESTORE_TIME[2]}" "${RESTORE_TIME[3]}"

	logCommand "blkid"

	logExit

}

# calculate diff in months of two dates (yyyymm)
function calculateMonthDiff() { # fromDate toDate

	local y1=${1:0:4}
	local m1=${1:4:2}

	local y2=${2:0:4}
	local m2=${2:4:2}

	m1=${m1/#0}
	m2=${m2/#0}

	local diff=$(( ($y2 - $y1) * 12 + ($m2 - $m1) ))
	echo $diff
}

function updateRestoreReminder() {

	logEntry

	local reminder_file="$VAR_LIB_DIRECTORY/$RESTORE_REMINDER_FILE"

	if (( $RESTORE_REMINDER_INTERVAL > 0 )); then

		# create directory to save state
		if [[ ! -d "$VAR_LIB_DIRECTORY" ]]; then
			if ! mkdir -p "$VAR_LIB_DIRECTORY" &>>"$LOG_FILE"; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "$VAR_LIB_DIRECTORY"
				exitError "$RC_CREATE_ERROR"
			fi
		fi

		# initialize reminder state
		if [[ ! -e "$reminder_file" ]]; then
			echo "$(date +%Y%m) 0" > "$reminder_file"
			return
		fi

		# retrieve reminder state
		local now
		now=$(date +%Y%m)
		local rf
		# Double quote to prevent globbing and word splitting.
		#shellcheck disable=SC2086
		rf="$(<$reminder_file)"
		if [[ -z "${rf}" ]]; then				# issue #316: reminder file exists but is empty
			echo "$(date +%Y%m) 0" > "$reminder_file"
			return
		fi

		# Prefer mapfile or read -a to split command output (or quote to avoid splitting).
		#shellcheck disable=SC2207
		rf=( $(<$reminder_file) )

		local diffMonths
		diffMonths=$(calculateMonthDiff "$now" "${rf[0]}" )

		# check if reminder should be send
		if (( $diffMonths <= -$RESTORE_REMINDER_INTERVAL )); then
			if (( ${rf[1]} < $RESTORE_REMINDER_REPEAT )); then
				# update reminder state
				local nr=$(( ${rf[1]} + 1 ))
				echo "${rf[0]} $nr" > "$reminder_file"
				local left=$(( $RESTORE_REMINDER_REPEAT - $nr ))
				NEWS_AVAILABLE=1
				RESTORETEST_REQUIRED=1
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_RESTORETEST_REQUIRED $left
			else
				logItem "Reset reminder"
				# reset reminder state
				echo "$(date +%Y%m) 0" > "$reminder_file"
			fi
		fi
	fi

	logExit

}

function mountAndCheck() { # device mountpoint

	logEntry "$1 - $2"

	umountPartition "$2"

	mount "$1" "$2" &>>"$LOG_FILE"
	local rc=$?
	if (( $rc )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MOUNT_CHECK_ERROR "$1" "$2" "$rc"
		logExit $rc
		exitError $RC_MISC_ERROR
	fi
	logCommand "findmnt $2"
	logExit $rc
}

function remount() { # device mountpoint

	logEntry "$1 - $2"

	if isMounted "$1"; then
		logItem "$1 mounted - unmouting"
		umount "$1" &>>"$LOG_FILE"
	else
		logItem "$1 not mounted"
	fi

	logItem "Creating mountpoint $2"
	if ! mkdir -p "$2" &>>"$LOG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNABLE_TO_CREATE_DIRECTORY "$2"
		exitError "$RC_CREATE_ERROR"
	fi
	mountAndCheck "$1" "$2" &>>"$LOG_FILE"
	logExit $rc

}

function updateConfig() {

	logEntry "$CUSTOM_CONFIG_FILE"

	local customFile="$CUSTOM_CONFIG_FILE"
	local etcConfigFileVersion="$ETC_CONFIG_FILE_VERSION"

	# use fileparameter as new config file
	if [[ -n $customFile ]]; then
		if [[ -f $customFile ]]; then
			logItem "Using config file $customFile"
			# See if you can use ${variable//search/replace} instead
			#shellcheck disable=SC2001
			NEW_CONFIG="$(sed -e "s@$ORIG_CONFIG@$customFile@" <<< "$NEW_CONFIG")"
			# See if you can use ${variable//search/replace} instead
			#shellcheck disable=SC2001
			MERGED_CONFIG="$(sed -e "s@$ORIG_CONFIG@$customFile@" <<< "$MERGED_CONFIG")"
			# See if you can use ${variable//search/replace} instead
			#shellcheck disable=SC2001
			BACKUP_CONFIG="$(sed -e "s@$ORIG_CONFIG@$customFile@" <<< "$BACKUP_CONFIG")"
			etcConfigFileVersion="$CUSTOM_CONFIG_FILE_VERSION"
			# See if you can use ${variable//search/replace} instead
			#shellcheck disable=SC2001
			ORIG_CONFIG="$(sed -e "s@$ORIG_CONFIG@$customFile@" <<< "$ORIG_CONFIG")"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$NEW_CONFIG"
			exitError $RC_MISSING_FILES
		fi
	fi

	if [[ ! -e $ORIG_CONFIG ]]; then
		logItem "$ORIG_CONFIG does not exist"
		logExit
		return
	fi

	logItem "Current config version: $etcConfigFileVersion - Required config version: $VERSION_SCRIPT_CONFIG"		# VERSION_SCRIPT_CONFIG is from updated script

	if (( $(compareVersions "$etcConfigFileVersion" "$VERSION_SCRIPT_CONFIG") >= 0 )) ; then 						# ETC_CONFIG >= SCRIPT_CONFIG
		logExit "Config version ok"
		if (( $UPDATE_CONFIG )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_CONFIGUPDATE_REQUIRED "$VERSION_SCRIPT_CONFIG"
		fi
		logExit
		return
	fi

	# lang appears unused. Verify use (or export if used externally). ... lang used in following eval for late binding of config files to use the correct language !!!
	# shellcheck disable=SC2034
	local lang=${LANGUAGE,,}

	if grep -iqE "alpha|beta" <<< "$VERSION"; then
		eval "DL_URL=$BETA_CONFIG_URL"
	else
		eval "DL_URL=$CONFIG_URL"
	fi

	# download new config file
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_DOWNLOADING "$NEW_CONFIG" "$DL_URL"

	local dlHttpCode dlRC
	dlHttpCode="$(downloadFile "$DL_URL" "$NEW_CONFIG")"
	dlRC=$?
	if (( $dlRC != 0 )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_DOWNLOAD_FAILED "$DL_URL" "$dlHttpCode" $dlRC
		exitError $RC_DOWNLOAD_FAILED
	fi

	# make sure new config file is readable by owner only
	if ! chmod 600 "$NEW_CONFIG" &>>"$LOG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CHMOD_FAILED "$NEW_CONFIG"
		exitError $RC_FILE_OPERATION_ERROR
	fi

	local newConfigVersion
	newConfigVersion="$(extractVersionFromFile "$NEW_CONFIG" "$VERSION_CONFIG_VARNAME")"

	logItem "New config version of downloaded file: $newConfigVersion"

	# Should not occure but make sure config is not downgraded for some reasons
	if (( $(compareVersions "$newConfigVersion" "$VERSION_SCRIPT_CONFIG") < 0 )); then					# newConfigVersion < SCRIPT_CONFIG
		if (( $UPDATE_CONFIG )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_CONFIGUPDATE_REQUIRED "$VERSION_SCRIPT_CONFIG"
			logExit
			return
		fi
	fi

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_CURRENT_CONFIGURATION_UPDATE_REQUIRED "$etcConfigFileVersion" "$VERSION_SCRIPT_CONFIG"

	rm -f "$MERGED_CONFIG" &>/dev/null

	# process NEW CONFIG FILE
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_MERGING_VERSION  "v$etcConfigFileVersion" "v$VERSION_SCRIPT_CONFIG" "$MERGED_CONFIG"
	local merged=0
	local deleted=0

	# make sure config file is readable by owner only
	if ! chmod 600 "$ORIG_CONFIG" &>>"$LOG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CHMOD_FAILED "$ORIG_CONFIG"
		exitError $RC_FILE_OPERATION_ERROR
	fi

	# process new config file and merge old options

	logItem "Merging $NEW_CONFIG and $ORIG_CONFIG"
	while read -r line; do
		if [[ -n "$line" && ! "$line" =~ ^[[:space:]]*# ]]; then			# skip comment or empty lines
			local KW VAL CONFIG_VERSION
			KW="$(cut -d= -f1 <<< "$line")"					# retrieve keyword
			VAL="$(cut -d= -f2 <<< "$line" )"	# retrieve value

			logItem "KW: $KW - VAL: $VAL"
			if [[ "$KW" =~ VERSION_.*CONF ]]; then					# add new version number
				echo "$line" >> "$MERGED_CONFIG"
				CONFIG_VERSION="$VAL"
				continue
			fi

			local OC_line r
			OC_line="$(grep "^$KW=" "$ORIG_CONFIG")"					# retrieve old option line
			r=$?
			logItem "grep old file rc:$s - contents: $OC_line"
			if (( ! $r )); then											# new option found
				local OW
				OW="$(cut -d= -f2- <<< "$OC_line" )"				# retrieve old option value
				echo "$KW=$OW" >> "$MERGED_CONFIG"						# use old option value
			else
				printf "$NEW_OPTION_TRAILER\n" "$CONFIG_VERSION" >> $MERGED_CONFIG
				echo "$line" >> $MERGED_CONFIG						# add new option
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_ADDED_CONFIG_OPTION "$KW" "$VAL"
				(( merged ++ ))
			fi
		else
			echo "$line" >> "$MERGED_CONFIG"							# copy comment  or empty line
		fi
	done < "$NEW_CONFIG"

	# check in old config file which options were deleted in new config file

	logItem "Checking for deleted options"
	while read -r line; do
		if [[ -n "$line" && ! "$line" =~ ^.*# ]]; then			# skip comment or empty lines
			local KW VAL
			KW="$(cut -d= -f1 <<< "$line")"							# retrieve keyword
			VAL="$(cut -d= -f2 <<< "$line" )"	# retrieve value

			if [[ "$KW" =~ VERSION_.*CONF ]]; then					# skip version number
				continue
			fi

			local r
			grep -q "^$KW=" "$NEW_CONFIG"					# check if it's still the new config file
			r=$?
			logItem "grep old file for deleted $KW rc:$r - contents: $OC_line"
			if (( $r )) && [[ $KW != "UUID" ]]; then				# option not found, it was deleted
				{
					echo ""
					printf "$DELETED_OPTION_TRAILER\n" "$CONFIG_VERSION"
					echo "# $line" 										# insert deleted config line as comment
				}  >> "$MERGED_CONFIG"
				(( deleted ++ ))
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_DELETED_CONFIG_OPTION "$KW" "$VAL"
			fi
		fi
	done < "$ORIG_CONFIG"

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_MERGE_SUCCESSFULL

	if ! chmod 600 "$MERGED_CONFIG" &>>"$LOG_FILE"; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_CHMOD_FAILED "$MERGED_CONFIG"
		exitError $RC_FILE_OPERATION_ERROR
	fi

	logItem "Merged: $merged - deleted: $deleted"

	rm -f "$NEW_CONFIG" &>/dev/null

	if askYesNo "$MSG_UPDATE_CONFIG" "$BACKUP_CONFIG"; then
		local new_file
		# save old config
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_SAVING_CURRENT_CONFIGURATION  "$ORIG_CONFIG" "$BACKUP_CONFIG"
		new_file=$(createBackupVersion "$ORIG_CONFIG")
		local r=$?
		if (( $rc )); then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_CONFIG_BACKUP_FAILED "$ORIG_CONFIG"
			exitError $RC_FILE_OPERATION_ERROR
		fi

		if ! chmod 600 "$new_file" &>>"$LOG_FILE"; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_CHMOD_FAILED "$new_file"
			exitError $RC_FILE_OPERATION_ERROR
		fi

		mv "$MERGED_CONFIG" "$ORIG_CONFIG"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_COPIED_FILE "$MERGED_CONFIG" "$ORIG_CONFIG"
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_ACTIVATE_CONFIG "$MERGED_CONFIG" "$ORIG_CONFIG"
	fi

	logExit

}

function synchronizeCmdlineAndfstab() {

	logEntry

	local CMDLINE FSTAB newPartUUID oldPartUUID BOOT_MP ROOT_MP newUUID oldUUID BOOT_PARTITION oldLABEL

	BOOT_PARTITION="$(createPartitionName "$RESTORE_DEVICE" 1)"

	if (( $PARTITIONBASED_BACKUP )); then
		# See if you can use ${variable//search/replace} instead
		#shellcheck disable=SC2001
		ROOT_PARTITION="$(sed 's/1$/2/' <<< "$BOOT_PARTITION")"
	fi

	logEntry "BOOT_PARTITION: $BOOT_PARTITION - ROOT_PARTITION: $ROOT_PARTITION"

	ROOT_MP="$TEMPORARY_MOUNTPOINT_ROOT/root"
	BOOT_MP="$TEMPORARY_MOUNTPOINT_ROOT/boot"
	logEntry "ROOT_MP: $ROOT_MP - BOOT_MP: $BOOT_MP"
	remount "$BOOT_PARTITION" "$BOOT_MP"
	remount "$ROOT_PARTITION" "$ROOT_MP"

	CMDLINE="$BOOT_MP/cmdline.txt" 	# absolute path in mount, don't use firmware subdir for Ubuntu, boot partition is mounted there at ubuntu startup
	FSTAB="$ROOT_MP/etc/fstab" 		# absolute path in mount

	local cmdline # path for message
	[[ -d $TEMPORARY_MOUNTPOINT_ROOT/root/boot/firmware ]] && cmdline="/boot/firmware/cmdline.txt"  || cmdline="/boot/cmdline.txt"

	local fstab="/etc/fstab" # path for message

	logEntry "CMDLINE: $CMDLINE - FSTAB: $FSTAB"

	partprobe "$BOOT_PARTITION"		# reload partition table
	partprobe "$ROOT_PARTITION"		# reload partition table

	logCommand "blkid -o udev $ROOT_PARTITION"

	local rootLabelCreated=0

	writeToConsole $MSG_LEVEL_MINIMAL $MSG_SYNC_CMDLINE_FSTAB "$cmdline" "$fstab"

	if [[ -f "$CMDLINE" ]]; then

		logItem "Org $CMDLINE"
		logCommand "cat $CMDLINE"

		if [[ $(cat "$CMDLINE") =~ root=PARTUUID=([a-z0-9\-]+) ]]; then
			local oldPartUUID=${BASH_REMATCH[1]}
			local newPartUUID
			newPartUUID=$(blkid -o udev "$ROOT_PARTITION" | grep ID_FS_PARTUUID= | cut -d= -f2)
			logItem "CMDLINE - newPartUUID: $newPartUUID, oldPartUUID: $oldPartUUID"
			if [[ -z $newPartUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$cmdline" "root="
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldPartUUID" != "$newPartUUID" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "PARTUUID" "$oldPartUUID" "$newPartUUID" "$cmdline"
				sed -i "s/$oldPartUUID/$newPartUUID/" "$(realpath "$CMDLINE")" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$CMDLINE") =~ root=UUID=([a-z0-9\-]+) ]]; then
			local oldUUID
			oldUUID=${BASH_REMATCH[1]}
			local newUUID
			newUUID=$(blkid -o udev "$ROOT_PARTITION" | grep ID_FS_UUID= | cut -d= -f2)
			logItem "CMDLINE - newUUID: $newUUID, oldUUID: $oldUUID"
			if [[ -z $newUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$cmdline" "root="
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldUUID" != "$newUUID" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "UUID" "$oldUUID" "$newUUID" "$cmdline"
				sed -i "s/$oldUUID/$newUUID/" "$(realpath "$CMDLINE")" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$CMDLINE") =~ root=LABEL=([a-z0-9\-]+) ]]; then
			local oldLABEL=${BASH_REMATCH[1]}
			logItem "Writing label $oldLABEL on $ROOT_PARTITION"
			writeToConsole $MSG_LEVEL_DETAILED $MSG_LABELING "$ROOT_PARTITION" "$oldLABEL"
			e2label "$ROOT_PARTITION" "$oldLABEL" &>> "$LOG_FILE"
			local rc=$?
			if (( $rc )); then
				local cmd="e2label $ROOT_PARTITION $oldLABEL"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_LABELING_FAILED "$cmd" "$rc"
				exitError "$RC_LABEL_ERROR"
			else
				rootLabelCreated=1
			fi
		elif grep "root=/dev/" "$CMDLINE"; then
			logItem "/dev detected in $CMDLINE"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$cmdline" "root="
		fi
	else
		logCommand "ls -la $BOOT_MP"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$cmdline"
		exitError $RC_UUID_UPDATE_IMPOSSIBLE
	fi

	if [[ -f "$FSTAB" ]]; then
		logItem "Org $FSTAB"
		# Double quote to prevent globbing and word splitting.
		#shellcheck disable=SC2086
		logItem "$(cat $FSTAB)"

		if [[ $(cat "$FSTAB") =~ PARTUUID=([a-z0-9\-]+)[[:space:]]+/[[:space:]] ]]; then
			local oldPartUUID=${BASH_REMATCH[1]}
			local newPartUUID
			newPartUUID=$(blkid -o udev "$ROOT_PARTITION" | grep ID_FS_PARTUUID= | cut -d= -f2)
			logItem "FSTAB root - newRootPartUUID: $newPartUUID, oldRootPartUUID: $oldPartUUID"
			if [[ -z $newPartUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_PARTUUID_SYNCHRONIZED "$fstab" "/"
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldPartUUID" != "$newPartUUID" ]]; then
				local oldpartuuidID
				oldpartuuidID="$(sed -E 's/-[0-9]+//' <<< "$oldPartUUID")"
				local newpartuuidID
				newpartuuidID="$(sed -E 's/-[0-9]+//' <<< "$newPartUUID")"
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "PARTUUID" "$oldPartUUID" "$newPartUUID" "$fstab"
				sed -i "s/$oldpartuuidID/$newpartuuidID/g" "$FSTAB" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$FSTAB") =~ UUID=([a-z0-9\-]+)[[:space:]]+/[[:space:]] ]]; then
			local oldUUID=${BASH_REMATCH[1]}
			local newUUID
			newUUID=$(blkid -o udev "$ROOT_PARTITION" | grep ID_FS_UUID= | cut -d= -f2)
			logItem "FSTAB root - newRootUUID: $newUUID, oldRootUUID: $oldUUID"
			if [[ -z $newUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/"
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldUUID" != "$newUUID" ]]; then
				local olduuidID
				olduuidID="$(sed -E 's/-[0-9]+//' <<< "$oldUUID")"
				local newuuidID
				newuuidID="$(sed -E 's/-[0-9]+//' <<< "$newUUID")"
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "PARTUUID" "$olduuidID" "$newuuidID" "$fstab"
				sed -i "s/$olduuidID/$newuuidID/g" "$FSTAB" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$FSTAB") =~ LABEL=([a-z0-9\-]+)[[:space:]]+/[[:space:]] ]]; then
			if (( ! $rootLabelCreated )) ; then
				local oldLABEL=${BASH_REMATCH[1]}
				logItem "Writing label $oldLABEL on $ROOT_PARTITION"
				writeToConsole $MSG_LEVEL_DETAILED $MSG_LABELING "$ROOT_PARTITION" "$oldLABEL"
				e2label "$ROOT_PARTITION" "$oldLABEL" &>> "$LOG_FILE"
				local rc=$?
				if (( $rc )); then
					local cmd="e2label $ROOT_PARTITION $oldLABEL"
					writeToConsole $MSG_LEVEL_MINIMAL $MSG_LABELING_FAILED "$cmd" "$rc"
					exitError "$RC_LABEL_ERROR"
				else
					rootLabelCreated=1
				fi
			fi
		elif grep "^/dev/" "$FSTAB"; then
			logItem "/dev detected in $FSTAB"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/"
		fi
	else
		logCommand "ls -la $ROOT_MP"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_NOT_FOUND "$fstab"
		exitError $RC_UUID_UPDATE_IMPOSSIBLE
	fi

	if [[ -f "$FSTAB" ]]; then
		logItem "Org $FSTAB"
		logItem "$(cat "$FSTAB")"

		if [[ $(cat "$FSTAB") =~ PARTUUID=([a-z0-9\-]+)[[:space:]]+/boot ]]; then
			local oldPartUUID=${BASH_REMATCH[1]}
			local newPartUUID
			newPartUUID=$(blkid -o udev "$BOOT_PARTITION" | grep ID_FS_PARTUUID= | cut -d= -f2)
			logItem "FSTAB boot - newPartUUID: $newPartUUID, oldPartUUID: $oldPartUUID"
			if [[ -z $newPartUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/boot"
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldPartUUID" != "$newPartUUID" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "PARTUUID" "$oldPartUUID" "$newPartUUID" "$fstab"
				sed -i "s/$oldPartUUID/$newPartUUID/" "$FSTAB" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$FSTAB") =~ UUID=([a-z0-9\-]+)[[:space:]]+/boot ]]; then
			local oldUUID=${BASH_REMATCH[1]}
			local newUUID
			newUUID=$(blkid -o udev "$BOOT_PARTITION" | grep ID_FS_UUID= | cut -d= -f2)
			logItem "FSTAB boot - newBootUUID: $newUUID, oldBootUUID: $oldUUID"
			if [[ -z $newUUID ]]; then
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/boot"
				exitError $RC_UUID_UPDATE_IMPOSSIBLE
			elif [[ "$oldUUID" != "$newUUID" ]]; then
				writeToConsole $MSG_LEVEL_DETAILED $MSG_UPDATING_UUID "PARTUUID" "$oldUUID" "$newUUID" "$fstab"
				sed -i "s/$oldUUID/$newUUID/" "$FSTAB" &>> "$LOG_FILE"
			fi
		elif [[ $(cat "$FSTAB") =~ LABEL=([a-z0-9\-]+)[[:space:]]+/boot ]]; then
			local oldLABEL=${BASH_REMATCH[1]}
			logItem "Writing label $oldLABEL on $BOOT_PARTITION"
			writeToConsole $MSG_LEVEL_DETAILED $MSG_LABELING "$BOOT_PARTITION" "$oldLABEL"
			dosfslabel "$BOOT_PARTITION" "$oldLABEL" &>> "$LOG_FILE"
			local rc=$?
			if (( $rc )); then
				local cmd="dosfslabel $BOOT_PARTITION $oldLABEL"
				writeToConsole $MSG_LEVEL_MINIMAL $MSG_LABELING_FAILED "$cmd" "$rc"
				exitError "$RC_LABEL_ERROR"
			fi
		elif grep "^/dev/" "$FSTAB"; then
			logItem "/dev detected in $FSTAB"
		else
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/boot"
		fi
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_NO_UUID_SYNCHRONIZED "$fstab" "/boot"
	fi

	if [[ -f "$CMDLINE" ]]; then
		logItem "Upd $CMDLINE"
		logCommand "cat $CMDLINE"
	fi

	if [[ -f "$FSTAB" ]]; then
		logItem "Upd $FSTAB"
		logCommand "cat $FSTAB"
	fi

	umount "$BOOT_MP" &>>"$LOG_FILE"
	umount "$ROOT_MP" &>>"$LOG_FILE"

	rmdir "$BOOT_MP" &>>"$LOG_FILE"
	rmdir "$ROOT_MP" &>>"$LOG_FILE"

	logExit
}

# count number of lines in string and return 0 if line is empty (wc -l will return 1 :-( )
function countLines() { # string
	logEntry "$1"
	local c
	if [[ -z "$1" ]]; then
		c=0
	else
		c=$(wc -l <<< "$1")
	fi
	echo "$c"
	logExit "$c"
}

# Smart recycle strategy was inspired by Manuel Dewalds excelent article "Automating backups on a Raspberry Pi NAS"
# on https://opensource.com/article/18/8/automate-backups-raspberry-pi

function SR_listYearlyBackups() { # directory
	logEntry "$SR_YEARLY" "$1"
	if (( $SR_YEARLY > 0 )); then
		local i d
		for ((i=0;i<=$(( $SR_YEARLY-1 ));i++)); do
			# today is 20191117
			# date +%Y -d "0 year ago" -> 2019
			d=$(date +%Y -d "${i} year ago")
			# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
			# shellcheck disable=SC2155,SC2010,SC1087
			ls -1 "$1" | grep -E "${HOSTNAME_OSR}\-${BACKUPTYPE}\-backup\-$d[0-9]{2}[0-9]{2}" | grep -Ev "_" | sort -ur | tail -n 1 # find earliest yearly backup
		done
	fi
	logExit
}

function SR_listMonthlyBackups() { # directory
	logEntry "$SR_MONTHLY" "$1"
	if (( $SR_MONTHLY > 0 )); then
		local i d
		for ((i=0;i<=$(( $SR_MONTHLY-1 ));i++)); do
			# ... error in date ... see http://bashworkz.com/linux-date-problem-1-month-ago-date-bug/
			# ls ${BACKUPPATH} | egrep "\-backup\-$(date +%Y%m -d "${i} month ago")[0-9]{2}" | sort -u | head -n 1
			# today is 20191117
			# date -d "$(date +%Y%m15) -0 month" +%Y%m -> 201911
			d=$(date -d "$(date +%Y%m15) -${i} month" +%Y%m) # get month
			# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
			# shellcheck disable=SC2155,SC2010,SC1087
			ls -1 "$1" | grep -E "${HOSTNAME_OSR}\-${BACKUPTYPE}\-backup\-$d[0-9]{2}" | grep -Ev "_" | sort -ur | tail -n 1 # find earliest monthly backup
		done
	fi
	logExit
}

function SR_listWeeklyBackups() { # directory
	logEntry "$SR_WEEKLY" "$1"
	local d
	if (( $SR_WEEKLY > 0 )); then
		local i mon
		for ((i=0;i<=$(( $SR_WEEKLY-1));i++)); do
			# assume today is 20191119 (tue) or wed-sun
			# last monday is date +%Y%m%d -d "last monday -1...n-1 weeks" -> 20191111
			local last="last"
			# assume today is 20191118 (mon)
			# last monday is date +%Y%m%d -d "monday -1...n-1 weeks" -> 20191111
			if (( $(date +"%u") == 1 )); then
				last=""
			fi
			mon=$(date +%Y%m%d -d "$last monday -${i} weeks") # calculate monday of week
			local dl=""
			for ((d=0;d<=6;d++)); do	# now build list of week days of week (mon-sun)
				dl="${HOSTNAME_OSR}\-${BACKUPTYPE}\-backup\-$(date +%Y%m%d -d "$mon + $d day") $dl"
			done
			# Double quote to prevent globbing and word splitting.
			# shellcheck disable=SC2155,SC2010,SC2086
			ls -1 "$1" | grep -e "$(echo -n $dl | sed "s/ /\\\|/g")" | grep -Ev "_" | sort -ur | tail -n 1 # use earliest backup of this week
		done
	fi
	logExit
}

function SR_listDailyBackups() { # directory
	logEntry "$SR_DAILY" "$1"
	if (( $SR_DAILY > 0 )); then
		local i
		for ((i=0;i<=$(( $SR_DAILY-1));i++)); do
			# today is 20191117
			# date +%Y%m%d -d "-1 day" -> 20191116
			local d
			d=$(date +%Y%m%d -d "-${i} day") # get day
			# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
			# shellcheck disable=SC2155,SC2010
			ls -1 "$1" | grep "${HOSTNAME_OSR}\-${BACKUPTYPE}\-backup\-$d" | grep -Ev "_" | sort -ur | head -n 1 # find most current backup of this day
		done
	fi
	logExit
}

function SR_getAllBackups() { # directory
	logEntry "$1"

	local yb mb wb db

	yb="$(SR_listYearlyBackups "$1")"
	logItem "$yb"
	#local ybc="$(countLines "$yb")"
	[[ -n "$yb" ]] && echo "$yb"

	# shellcheck disable=SC2155
	mb="$(SR_listMonthlyBackups "$1")"
	logItem "$mb"
	#local mbc="$(countLines "$mb")"
	[[ -n "$mb" ]] && echo "$mb"

	# shellcheck disable=SC2155
	wb="$(SR_listWeeklyBackups "$1")"
	logItem "$wb"
	#local wbc="$(countLines "$wb")"
	[[ -n "$wb" ]] && echo "$wb"

	# shellcheck disable=SC2155
	db="$(SR_listDailyBackups "$1")"
	logItem "$db"
	#local dbc="$(countLines "$db")"
	[[ -n "$db" ]] && echo "$db"

	logExit
}

function SR_listUniqueBackups() { #directory
	logEntry "$1"
	local r
	r="$(SR_getAllBackups "$1" | grep -Ev "_" | sort -u )"
	local rc
	rc="$(countLines "$r")"
	logItem "$r"
	echo "$r"
	logExit "$rc"
}

function SR_listBackupsToDelete() { # directory
	logEntry "$1"
	local r
	# Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
	# shellcheck disable=SC2155,SC2010
	r="$(ls -1 "$1" | grep -v "$(echo -n "$(SR_listUniqueBackups "$1")" )" | sed "s/ /\\\|/g" | grep "${HOSTNAME_OSR}\-${BACKUPTYPE}\-backup\-" | grep -v "_" )" # make sure to delete only backup type files and no snapshots
	local rc
	rc="$(countLines "$r")"
	logItem "$r"
	echo "$r"
	logExit "$rc"
}

function check4RequiredCommands() { # btrfs | f2fs

	logEntry

	local missing_commands missing_packages

	if [[ -z $1 ]]; then
		for cmd in "${!REQUIRED_COMMANDS[@]}"; do
			if ! hash "$cmd" 2>/dev/null; then
				missing_commands="$cmd $missing_commands "
				missing_packages="${REQUIRED_COMMANDS[$cmd]} $missing_packages "
			fi
		done
	elif [[ "$1" == "btrfs" ]]; then
		for cmd in "${!REQUIRED_COMMANDS_BTRFS[@]}"; do
			if ! hash "$cmd" 2>/dev/null; then
				missing_commands="$cmd $missing_commands "
				missing_packages="${REQUIRED_COMMANDS_BTRFS[$cmd]} $missing_packages "
			fi
		done
	elif [[ "$1" == "f2fs" ]]; then
		for cmd in "${!REQUIRED_COMMANDS_F2FS[@]}"; do
			if ! hash "$cmd" 2>/dev/null; then
				missing_commands="$cmd $missing_commands "
				missing_packages="${REQUIRED_COMMANDS_F2FS[$cmd]} $missing_packages "
			fi
		done
	else
			assertionFailed $LINENO "Invalid arg: '$1'"
	fi

	if [[ -n "$missing_commands" ]]; then
		shopt -s extglob
		missing_commands="${missing_commands%%*( )}"
		missing_packages="${missing_packages%%*( )}"
		shopt -u extglob
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_COMMANDS "$missing_commands"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_PACKAGES "$missing_packages"
		exitError $RC_MISSING_COMMANDS
	fi

	logExit

}

function lockingFramework() {

	# Copyright (C) 2009 Przemyslaw Pawelczyk <przemoc@gmail.com>
	# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
	# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
	# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

	LOCKFILE="/var/lock/$MYNAME"
	LOCKFD=99

# PRIVATE
# Double quote to prevent globbing and word splitting.
# shellcheck disable=SC2086
	_lock()             { flock -$1 $LOCKFD; }
	_no_more_locking()  { _lock u; _lock xn && rm -f "$LOCKFILE" ; }
#	_prepare_locking()  { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; }
	_prepare_locking()  { eval "exec $LOCKFD>\"$LOCKFILE\"" ; }

# ON START
	_prepare_locking

# PUBLIC
	exlock_now()        { _lock xn; }  # obtain an exclusive lock immediately or fail
	exlock()            { _lock x; }   # obtain an exclusive lock
	shlock()            { _lock s; }   # obtain a shared lock
	unlock()            { _lock u; }   # drop a lock
}

function usageEN() {

	echo "$GIT_CODEVERSION"
	echo "Usage: $MYSELF [option]* {backupDirectory}"
	echo ""
	echo "-General options-"
	[ -z "$DEFAULT_EMAIL" ] && DEFAULT_EMAIL="no"
	echo "-b {dd block size} (Default: $DEFAULT_DD_BLOCKSIZE)"
	[ -z "$DEFAULT_DD_PARMS" ] && DEFAULT_DD_PARMS="no"
	echo "-D {additional dd parameters} (Default: $DEFAULT_DD_PARMS)"
	echo "-e {email address} (Default: $DEFAULT_EMAIL)"
	[ -z "$DEFAULT_EMAIL_PARMS" ] && DEFAULT_EMAIL_PARMS="no"
	echo "-E {additional email call parameters} (Default: $DEFAULT_EMAIL_PARMS)"
	echo "-f {config filename}"
	echo "-g Display progress bar"
	echo "-G {message language} (${SUPPORTED_LANGUAGES[*]}) (Default: $LANGUAGE)"
	echo "-h display this help text"
	echo "-l {log level} ($POSSIBLE_LOG_LEVELs) (Default: ${LOG_LEVELs[$DEFAULT_LOG_LEVEL]})"
	echo "-L {log targetdirectory} ($POSSIBLE_LOG_OUTPUTs) (Default: ${LOG_OUTPUTs[$DEFAULT_LOG_OUTPUT]})"
	echo "-m {message level} ($POSSIBLE_MSG_LEVELs) (Default: ${MSG_LEVELs[$DEFAULT_MSG_LEVEL]})"
	echo "-M {backup description of snapshot}"
	echo "-s {email program to use} ($SUPPORTED_MAIL_PROGRAMS) (Default: $DEFAULT_MAIL_PROGRAM)"
	echo "--timestamps Prefix messages with timestamps (Default: ${NO_YES[$DEFAULT_TIMESTAMPS]})"
	echo "-u {excludeList} List of directories to exclude from tar and rsync backup"
	echo "-U current script version will be replaced by the most recent version. Current version will be saved and can be restored with parameter -V"
	echo "-v verbose output of backup tools (Default: ${NO_YES[$DEFAULT_VERBOSE]})"
	echo "-V restore a previous version"
	echo ""
	echo "-Backup options-"
	[ -z "$DEFAULT_STARTSERVICES" ] && DEFAULT_STARTSERVICES="no"
	echo "-a {commands to execute after Backup} (Default: $DEFAULT_STARTSERVICES)"
	echo "-B Save bootpartition in tar file (Default: $DEFAULT_TAR_BOOT_PARTITION_ENABLED)"
	echo "-F Backup is simulated"
	echo "--ignoreAdditionalPartitions (Default: ${NO_YES[$DEFAULT_IGNORE_ADDITIONAL_PARTITIONS]}) - Partitionnumbers > 2 will not be saved"
	echo "--ignoreMissingPartitions (Default: ${NO_YES[$DEFAULT_IGNORE_MISSING_PARTITIONS]}) - Allow to backup not all previously saved paritions"
	echo "-k {backupsToKeep} (Default: $DEFAULT_KEEPBACKUPS)"
	[ -z "$DEFAULT_STOPSERVICES" ] && DEFAULT_STOPSERVICES="no"
	echo "-o {commands to execute before Backup} (Default: $DEFAULT_STOPSERVICES)"
	echo "-P use partitionoriented backup mode to backup the first two partitions (Default: ${DEFAULT_PARTITIONS_TO_BACKUP})"
	echo "-t {backupType} ($ALLOWED_TYPES) (Default: $DEFAULT_BACKUPTYPE)"
	echo "-T {List of partitions to backup in partition oriented mode} (Partition numbers, e.g. \"1 2 3\" or \"*\" for all) (Default: ${DEFAULT_PARTITIONS_TO_BACKUP})"
	echo "--tarCompressionTool {tar Comressiontool} ($TAR_COMPRESSION_TOOLS_SUPPORTED_LIST)"
	echo "--tarCompressionToolOptions {Options for tar compressiontool}"
	echo "-z compress DD and TAR backup file with gzip (Default: ${NO_YES[$DEFAULT_ZIP_BACKUP]})"
	echo ""
	echo "-Restore options-"
	echo "-0 Restore device will not be partitioned"
	echo "-00 Restored partitions will not be formatted (only for backup type rsync)"
	echo "-1 Formatting errors on restore device will be ignored"
	[ -z "$DEFAULT_RESTORE_DEVICE" ] && DEFAULT_RESTORE_DEVICE="no"
	echo "-C Formating of the restorepartitions will check for badblocks (Default: ${NO_YES[$DEFAULT_CHECK_FOR_BAD_BLOCKS]})"
	echo "-d {restoreDevice} (Default: $DEFAULT_RESTORE_DEVICE) (Example: /dev/sda)"
	echo "-R {rootPartition} (Default: restoreDevice) (Example: /dev/sdb1)"
	echo "-T {List of partitions to restore from a partition oriented backup} (Partition numbers, e.g. \"1 2 3\" or \"*\" for all) (Default: ${DEFAULT_PARTITIONS_TO_RESTORE})"
	echo "--resizeRootFS|resizeLastPartitionFS (Default: ${NO_YES[$DEFAULT_RESIZE_ROOTFS]})"
}

function usageDE() {

	echo "$GIT_CODEVERSION"
	echo "Aufruf: $MYSELF [Option]* {Backupverzeichnis}"
	echo ""
	echo "-Allgemeine Optionen-"
	[ -z "$DEFAULT_EMAIL" ] && DEFAULT_EMAIL="nein"
	echo "-b {dd Blockgröße} (Standard: $DEFAULT_DD_BLOCKSIZE)"
	[ -z "$DEFAULT_DD_PARMS" ] && DEFAULT_DD_PARMS="nein"
	echo "-D {Zusätzliche dd Parameter} (Standard: $DEFAULT_DD_PARMS)"
	echo "-e {eMail Addresse} (Standard: $DEFAULT_EMAIL)"
	[ -z "$DEFAULT_EMAIL_PARMS" ] && DEFAULT_EMAIL_PARMS="nein"
	echo "-E {Zusätzliche eMail Aufrufparameter} (Standard: $DEFAULT_EMAIL_PARMS)"
	echo "-f {Konfig Dateiname}"
	echo "-g Anzeige des Fortschritts"
	echo "-G {Meldungssprache} (${SUPPORTED_LANGUAGES[*]}) (Standard: $LANGUAGE)"
	echo "-h Anzeige dieses Hilfstextes"
	echo "-l {log Genauigkeit} ($POSSIBLE_LOG_LEVELs) (Standard: ${LOG_LEVELs[$DEFAULT_LOG_LEVEL]})"
	echo "-L {log Zielverzeichnis} ($POSSIBLE_LOG_OUTPUTs) (Standard: ${LOG_OUTPUTs[$DEFAULT_LOG_OUTPUT]})"
	echo "-m {Meldungsgenauigkeit} ($POSSIBLE_MSG_LEVELs) (Standard: ${MSG_LEVELs[$DEFAULT_MSG_LEVEL]})"
	echo "-M {Backup Beschreibung des Snapshots}"
	echo "-s {Benutztes eMail Program} ($SUPPORTED_MAIL_PROGRAMS) (Standard: $DEFAULT_MAIL_PROGRAM)"
	echo "--timestamps Meldungen werden mit einen Zeitstempel ausgegeben (Standard: ${NO_YES[$DEFAULT_TIMESTAMPS]})"
	echo "-u {excludeList} Liste von Verzeichnissen, die vom tar und rsync Backup auszunehmen sind"
	echo "-U Scriptversion wird durch die aktuelle Version ersetzt. Die momentane Version wird gesichert und kann mit dem Parameter -V wiederhergestellt werden"
	echo "-v Detailierte Ausgaben der Backup Tools (Standard: ${NO_YES[$DEFAULT_VERBOSE]})"
	echo "-V Aktivierung einer älteren Skriptversion"
	echo ""
	echo "-Backup Optionen-"
	[ -z "$DEFAULT_STARTSERVICES" ] && DEFAULT_STARTSERVICES="keine"
	echo "-a {Befehle die nach dem Backup ausgeführt werden} (Standard: $DEFAULT_STARTSERVICES)"
	echo "-B Sicherung der Bootpartition als tar file (Standard: $DEFAULT_TAR_BOOT_PARTITION_ENABLED)"
	echo "-F Backup wird nur simuliert"
	echo "--ignoreAdditionalPartitions (Standard: ${NO_YES[$DEFAULT_IGNORE_ADDITIONAL_PARTITIONS]}) - Partitionsnummern > 2 werden nicht gesichert"
	echo "--ignoreMissingPartitions (default: ${NO_YES[$DEFAULT_IGNORE_MISSING_PARTITIONS]}) - Es können weniger als die vorher gesicherten Partitionen gesichert werden"
	echo "-k {Anzahl Backups} (Standard: $DEFAULT_KEEPBACKUPS)"
	[ -z "$DEFAULT_STOPSERVICES" ] && DEFAULT_STOPSERVICES="keine"
	echo "-o {Befehle die vor dem Backup ausgeführt werden} (Standard: $DEFAULT_STOPSERVICES)"
	echo "-P Nutzung des partitionsorientierten Backupmode"
	echo "-t {Backuptyp} ($ALLOWED_TYPES) (Standard: $DEFAULT_BACKUPTYPE)"
	echo "-T Liste der Partitionen die im partitionsorientierten Mode zu sichern sind} (Partitionsnummern, z.B. \"1 2 3\" oder \"*\" für alle). (Standard: ${DEFAULT_PARTITIONS_TO_BACKUP})"
	echo "--tarCompressionTool {tar Kompressionstool} ($TAR_COMPRESSION_TOOLS_SUPPORTED_LIST)"
	echo "--tarCompressionToolOptions {Optionen für das tar Kompressionstool}"
	echo "-z DD und TAR Backup verkleinern mit gzip (Standard: ${NO_YES[$DEFAULT_ZIP_BACKUP]})"
	echo ""
	echo "-Restore Optionen-"
	echo "-0 Keine Partitionierung des Restoregerätes"
	echo "-00 Keine Formatierung der restorten Partitionen (nur bei Backuptyp rsync)"
	echo "-1 Fehler bei der Formatierung des Restoregerätes werden ignoriert"
	[ -z "$DEFAULT_RESTORE_DEVICE" ] && DEFAULT_RESTORE_DEVICE="keiner"
	echo "-C Beim Formatieren der Restorepartitionen wird auf Badblocks geprüft (Standard: ${NO_YES[$DEFAULT_CHECK_FOR_BAD_BLOCKS]})"
	echo "-d {restoreGerät} (Standard: $DEFAULT_RESTORE_DEVICE) (Beispiel: /dev/sda)"
	echo "-R {rootPartition} (Standard: restoreDevice) (Beispiel: /dev/sdb1)"
	echo "-T {Liste der Partitionen die vom partitionsorientierten Backup zu restoren sind} (Partitionsnummern, z.B. \"1 2 3\" oder \"*\" für alle). (Standard: ${DEFAULT_PARTITIONS_TO_BACKUP})"
	echo "--resizeRootFS|resizeLastPartitionFS (Standard: ${NO_YES[$DEFAULT_RESIZE_ROOTFS]})"
}

function usageFI() {
	echo "$GIT_CODEVERSION"
	echo "Käyttö: $MYSELF [valinta]* {varmuuskopionPolku}"
	echo ""
	echo "-Yleiset asetukset-"
	[ -z "$DEFAULT_EMAIL" ] && DEFAULT_EMAIL="ei"
	echo "-b {dd lohkon koko} (oletus: $DEFAULT_DD_BLOCKSIZE)"
	[ -z "$DEFAULT_DD_PARMS" ] && DEFAULT_DD_PARMS="ei"
	echo "-D {dd lisäparametrit} (oletus: $DEFAULT_DD_PARMS)"
	echo "-e {sähköpostiosoite} (oletus: $DEFAULT_EMAIL)"
	[ -z "$DEFAULT_EMAIL_PARMS" ] && DEFAULT_EMAIL_PARMS="ei"
	echo "-E {sähköpostitoiminnon lisäparametrit} (oletus: $DEFAULT_EMAIL_PARMS)"
	echo "-f {asetustiedoston tiedostonimi}"
	echo "-g Näytä edistymispalkki"
	echo "-G {viestien kieli} (${SUPPORTED_LANGUAGES[*]}) (oletus: $LANGUAGE)"
	echo "-h Näytä tämä ohje"
	echo "-l {lokitaso} ($POSSIBLE_LOG_LEVELs) (oletus: ${LOG_LEVELs[$DEFAULT_LOG_LEVEL]})"
	echo "-m {viestitaso} ($POSSIBLE_MSG_LEVELs) (oletus: ${MSG_LEVELs[$DEFAULT_MSG_LEVEL]})"
	echo "-M {varmuuskopion selite}"
	echo "-s {käytettävä sähköpostiohjelma} ($SUPPORTED_MAIL_PROGRAMS) (oletus: $DEFAULT_MAIL_PROGRAM)"
	echo "--timestamps Lisää aikaleima viestien alkuun (oletus: ${NO_YES[$DEFAULT_TIMESTAMPS]})"
	echo "-u {excludeList} Lista hakemistoista, jotka ohitetaan tar- ja rsync-varmuuskopioissa"
	echo "-U Nykyinen skriptin versio korvataan uusimmalla versiolla. Nykyinen versio varmuuskopioidaan ja sen voi palauttaa parametrillä -V"
	echo "-v Sanallista varmuuskopiotyökalujen tilatiedot (oletus: ${NO_YES[$DEFAULT_VERBOSE]})"
	echo "-V Palauta skriptin edellinen versio"
	echo "-z Pakkaa varmuuskopiotiedosto käyttäen gzip:iä (oletus: ${NO_YES[$DEFAULT_ZIP_BACKUP]})"
	echo ""
	echo "-Varmuuskopioinnin valinnat-"
	[ -z "$DEFAULT_STARTSERVICES" ] && DEFAULT_STARTSERVICES="ei"
	echo "-a {varmuuskopion jläkeen suoritettavat komennot} (oletus: $DEFAULT_STARTSERVICES)"
	echo "-B Tee käynnistysosiosta kopio tar tiedostoon (oletus: $DEFAULT_TAR_BOOT_PARTITION_ENABLED)"
	echo "-F Varmuuskopioinnin simulointi"
	echo "-k {säilytettävien varmuuskopioiden lkm} (oletus: $DEFAULT_KEEPBACKUPS)"
	[ -z "$DEFAULT_STOPSERVICES" ] && DEFAULT_STOPSERVICES="ei"
	echo "-o {ennen varmuuskopiointia suoritettavat komennot} (oletus: $DEFAULT_STOPSERVICES)"
	echo "-t {varmuuskopion tyyppi} ($ALLOWED_TYPES) (oletus: $DEFAULT_BACKUPTYPE)"
	echo "-T {Lista kopioitavista osioista} (Osionumerot, esim. \"1 2 3\"). Valinta käytettävissä vain parametrin -P kanssa (oletus: ${DEFAULT_PARTITIONS_TO_BACKUP})"
	echo ""
	echo "-Palautuksen valinnat-"
	echo "-0 SD-korttia ei alusteta"
	echo "-1 SD-kortin alustuksen virheet ohitetaan"
	[ -z "$DEFAULT_RESTORE_DEVICE" ] && DEFAULT_RESTORE_DEVICE="ei"
	echo "-C Tarkistetaan palautettavien osioiden epäkelvot lohkot (oletus: $DEFAULT_CHECK_FOR_BAD_BLOCKS)"
	echo "-d {palautuslaite} (oletus: $DEFAULT_RESTORE_DEVICE) (Esimerkki: /dev/sda)"
	echo "-R {juuriosio} (oletus: restoreDevice) (Esimerkki: /dev/sdb1)"
	echo "--resizeRootFS|resizeLastPartitionFS (oletus: ${NO_YES[$DEFAULT_RESIZE_ROOTFS]})"
}

function mentionHelp() {
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_MENTION_HELP "$MYSELF"
}

# there is an issue when a parameter starts with "-" which may a new option
# Workaround1: if parameter contains at least one space it's considered as a parameter and not an option even the string starts with '-'
# Workaround2: prefix parameter with \ (has to be \\ in bash commandline)

function checkOptionParameter() { # option parameter

	logEntry "$@"

	local nospaces="${2/ /}"
	if [[ "$nospaces" != "$2" ]]; then
		echo "$2"
		logExit "$2"
		return 0
	fi

	if [[ "${2:0:1}" == "\\" ]]; then
		echo "${2:1}"
		logExit "${2:1}"
		return 0
	elif [[ "$2" =~ ^(\-|\+|\-\-|\+\+) || -z "$2" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_OPTION_REQUIRES_PARAMETER "$1"
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_MENTION_HELP "$MYSELF"
		echo ""
		logExit ""
		return 1
	fi
	echo "$2"
	logExit "$2"
	return 0
}

# -x and -x+ enables, -x- disables flag
# --opt and --opt+ enables, --opt- disables flag
# 0 -> disabled, 1 -> enabled
function getEnableDisableOption() { # option
	case "$1" in
		-*-) echo 0;;
		-*+|-*) echo 1;;
		*) writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNKNOWN_OPTION "$1"
			mentionHelp
			exitError $RC_PARAMETER_ERROR
			;;
	esac
}

# misc other vars

BACKUP_DIRECTORY_NAME=""
BACKUPFILE=""
CUSTOM_CONFIG_FILE_INCLUDED=0
DEPLOY=0
DYNAMIC_MOUNT_EXECUTED=0
EXCLUDE_DD=0
FAKE=0
FORCE_SFDISK=0
FORCE_UPDATE=0
[[ "${BASH_SOURCE[0]}" -ef "$0" ]]
INCLUDE_ONLY=$?
IS_SNAPSHOT=0
IS_UBUNTU=0
NO_YES_QUESTION=0
OPTION_T_USED=0
PROGRESS=0
REGRESSION_TEST=0
RESTORE=0
RESTOREFILE=""
RESTORETEST_REQUIRED=0
REVERT=0
ROOT_PARTITION_DEFINED=0
SHARED_BOOT_DIRECTORY=0
SKIP_SFDISK=0
SKIP_FORMAT=0
UPDATE_MYSELF=0
UPDATE_POSSIBLE=0
VERSION_DEPRECATED=0
WARNING_MESSAGE_WRITTEN=0
CLEANUP_RC=0
UPDATE_CONFIG=0
UNSUPPORTED_ENVIRONMENT="${UNSUPPORTED_ENVIRONMENT:=0}"
rc=0

PARAMS=""

# initialize default config
initializeDefaultConfigVariables
# assign default config to variables
copyDefaultConfigVariables

##### Now do your job

ARG_BAK=("$@")				# save invocation options

# handle options which don't require root access, use system language
if containsElement "-h" "${ARG_BAK[@]}" || containsElement "--help" "${ARG_BAK[@]}" || containsElement "-?" "${ARG_BAK[@]}" || containsElement "--version" "${ARG_BAK[@]}"; then
	case "$1" in
		--version)
			echo "Version: $VERSION CommitSHA: $GIT_COMMIT_ONLY CommitDate: $GIT_DATE_ONLY CommitTime: $GIT_TIME_ONLY"
			exitNormal
			;;
		*)	usage
			exitNormal
		;;
	esac
fi

logEnable

if (( $UID != 0 && ! INCLUDE_ONLY )); then
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_RUNASROOT "$0" "$INVOCATIONPARMS"
	exitError $RC_MISC_ERROR
fi

lockingFramework

trapWithArg cleanupStartup SIGINT SIGTERM EXIT

INVOCATIONPARMS=""			# save passed opts for logging
for (( i=1; i<=$#; i++ )); do
	p=${!i}
	INVOCATIONPARMS="$INVOCATIONPARMS $p"
done

readConfigParameters				# overwrite defaults with settings in config files
copyDefaultConfigVariables			# and update variables with config file contents

logOptions "Standard option files"

# check if language was overwritten by config option
if [[ -n $DEFAULT_LANGUAGE ]]; then
	if ! containsElement "${DEFAULT_LANGUAGE}" "${SUPPORTED_LANGUAGES[@]}"; then
		DEFAULT_LANGUAGE="$MSG_LANG_FALLBACK"	# unsupported language, fall back to English
	else
		DEFAULT_LANGUAGE="${DEFAULT_LANGUAGE^^*}"
	fi
	LANGUAGE=$DEFAULT_LANGUAGE			# redefine language now
fi

while (( "$#" )); do		# check if option -f was used
  case "$1" in
	-f)
		if ! o=$(checkOptionParameter "$1" "$2"); then
			exitError $RC_PARAMETER_ERROR
		fi
		CUSTOM_CONFIG_FILE="$o"; shift 2
		if [[ ! -f "$CUSTOM_CONFIG_FILE" ]]; then
			writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_ARG_NOT_FOUND "$CUSTOM_CONFIG_FILE"
			exitError $RC_MISSING_FILES
		fi
		CUSTOM_CONFIG_FILE="$(readlink -f "$CUSTOM_CONFIG_FILE")"
		set -e
# Can't follow non-constant source. Use a directive to specify location
# shellcheck disable=SC1090
		. "$CUSTOM_CONFIG_FILE"
		set +e
		CUSTOM_CONFIG_FILE_INCLUDED=1
		CUSTOM_CONFIG_FILE_VERSION="$(extractVersionFromFile "$CUSTOM_CONFIG_FILE" "$VERSION_CONFIG_VARNAME" )"
		logItem "Read config ${CUSTOM_CONFIG_FILE} : ${CUSTOM_CONFIG_FILE_VERSION}$NL$(grep -E -v '^\s*$|^#' "$CUSTOM_CONFIG_FILE")"

		copyDefaultConfigVariables		# update variables with custom file contents
		logOptions "Custome option file"
		;;
	*)	shift									# skip option
		;;
	esac
done

set -- "${ARG_BAK[@]}"		# restore all options for second options pass

while (( "$#" )); do

  case "$1" in
	-0|-0[-+])
	  SKIP_SFDISK=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-00|-00[-+])
	  SKIP_FORMAT=$(getEnableDisableOption "$1"); shift 1
	  SKIP_SFDISK=$SKIP_FORMAT
	  ;;

	-1|-1[-+])
	  FORCE_SFDISK=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-a)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  STARTSERVICES="$o"; shift 2
	  ;;

	-A|-A[-+])
	  APPEND_LOG=$(getEnableDisableOption "$1"); shift 1
	  writeToConsole $MSG_LEVEL_MINIMAL $MSG_DEPRECATED_OPTION "-A"
	  ;;

	-b)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  DD_BLOCKSIZE="$o"; shift 2
	  ;;

	-B|-B[-+])
	  TAR_BOOT_PARTITION_ENABLED=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--bootDevice)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  BOOT_DEVICE="$o"; shift 2
	  ;;

	-c|-c[-+])
	  SKIPLOCALCHECK=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-C|-C[-+])
	  CHECK_FOR_BAD_BLOCKS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--coloring)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  COLORING="$o"; shift 2
	  ;;

	-d)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  RESTORE_DEVICE="$o"; RESTORE=1; shift 2
	  ;;

	-D)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  DD_PARMS="$o"; shift 2
	  ;;

	--dynamicMount)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  DYNAMIC_MOUNT="$o"; shift 2
	  ;;

	-e)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EMAIL="$o"; shift 2
	  ;;

	-E)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EMAIL_PARMS="$o"; shift 2
	  ;;

	--eMailColoring)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EMAIL_COLORING="${o^^}"; shift 2
	  ;;

	-f) shift 2
	  ;;

	-F|-F[-+])
	  FAKE=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--forceEmail|--forceEmail[+-])
	  FORCE_EMAIL=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-g|-g[-+])
	  PROGRESS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-G)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  LANGUAGE="$o"; shift 2
  	  LANGUAGE=${LANGUAGE^^*}
	  if ! containsElement "${LANGUAGE^^*}" "${SUPPORTED_LANGUAGES[@]}"; then
		  writeToConsole $MSG_LEVEL_MINIMAL $MSG_LANGUAGE_NOT_SUPPORTED "$LANGUAGE"
		  exitError $RC_PARAMETER_ERROR
	  fi
	  ;;

	--ignoreAdditionalPartitions|--ignoreAdditionalPartitions[+-])
	  IGNORE_ADDITIONAL_PARTITIONS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--ignoreMissingPartitions)
	  IGNORE_MISSING_PARTITIONS=1; shift 1
	  ;;

	--include|--include[+-])
	  INCLUDE_ONLY=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-k)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS="$o"; shift 2
	  ;;

	--keep_dd)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS_DD="$o"; shift 2
	  ;;

	--keep_ddz)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS_DDZ="$o"; shift 2
	  ;;

	--keep_tar)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS_TAR="$o"; shift 2
	  ;;

	--keep_tgz)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS_TGZ="$o"; shift 2
	  ;;

	--keep_rsync)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  KEEPBACKUPS_RSYNC="$o"; shift 2
	  ;;

	-l)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  LOG_LEVEL="$o"; shift 2
	  checkImportantParameters
	  ;;

	-L)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  LOG_OUTPUT="$o"; shift 2
	  checkImportantParameters
	  ;;

	-m)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  MSG_LEVEL="$o"; shift 2
	  checkImportantParameters
	  ;;

	-M)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  BACKUP_DIRECTORY_NAME="$o"; shift 2
  	  BACKUP_DIRECTORY_NAME=${BACKUP_DIRECTORY_NAME//[ \/\\\:\.\-]/_}
  	  BACKUP_DIRECTORY_NAME=${BACKUP_DIRECTORY_NAME//[\"]/}
  	  IS_SNAPSHOT=1
  	  ;;

	-N)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EXTENSIONS="$o"; shift 2
	  ;;

	--notifyStart|--notifyStart[-+])
	  NOTIFY_START=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-o)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  STOPSERVICES="$o"; shift 2
	  ;;

	-p)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  BACKUPPATH="$o"; shift 2
	  if [[ ! -d "$BACKUPPATH" ]]; then
		  writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_ARG_NOT_FOUND "$BACKUPPATH"
		  exitError $RC_MISSING_FILES
	  fi
	  BACKUPPATH="$(readlink -f "$BACKUPPATH")"
	  ;;

	-P|-P[-+])
	  PARTITIONBASED_BACKUP=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-r)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  RESTOREFILE="$o"; shift 2
	  if [[ ! -d "$RESTOREFILE" && ! -f "$RESTOREFILE" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_ARG_NOT_FOUND "$RESTOREFILE"
		exitError $RC_MISSING_FILES
	  fi
	  RESTOREFILE="$(readlink -f "$RESTOREFILE")"
	  ;;

	-R)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  ROOT_PARTITION="$o"; shift 2
	  ROOT_PARTITION_DEFINED=1
  	  ;;

	--resizeRootFS|--resizeRootFS[+-]|--resizeLastPartitionFS|--resizeLastPartitionFS[+-])
	  RESIZE_ROOTFS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--rebootSystem|--rebootSystem[+-])
	  REBOOT_SYSTEM=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-s)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EMAIL_PROGRAM="$o"; shift 2
	  ;;

	-S|-S[-+])
	  FORCE_UPDATE=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--smartRecycle|--smartRecycle[+-])
	  SMART_RECYCLE=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--smartRecycleDryrun|--smartRecycleDryrun[+-])
	  SMART_RECYCLE_DRYRUN=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--smartRecycleOptions)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  SMART_RECYCLE_OPTIONS="$o"; shift 2
	  ;;

	--systemstatus|--systemstatus[+-])
	  SYSTEMSTATUS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-t)
	  if ! o=$(checkOptionParameter "$1" "$2"); then
		exitError $RC_PARAMETER_ERROR
	  fi
	  BACKUPTYPE="$o"; shift 2
	  ;;

	--timestamps|--timestamps[+-])
	  TIMESTAMPS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-T)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  # Variable was used as an array but is now assigned a string.
	  # shellcheck disable=SC2178
	  PARTITIONS_TO_BACKUP="$o"; shift 2
	  # Expanding an array without an index only gives the first element.
	  # shellcheck disable=SC2128
	  PARTITIONS_TO_RESTORE=$PARTITIONS_TO_BACKUP
	  PARTITIONBASED_BACKUP=1
	  OPTION_T_USED=1
	  ;;

	--tarCompressionTool|--tct)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TAR_COMPRESSION_TOOL="$o"; shift 2
	  ;;

	--tarCompressionToolOptions|--tcto)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TAR_COMPRESSION_TOOL_OPTIONS="$o"; shift 2
	  ;;

	--telegramToken)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TELEGRAM_TOKEN="$o"; shift 2
	  ;;

	--telegramChatID)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TELEGRAM_CHATID="$o"; shift 2
	  ;;

	--telegramThreadID)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TELEGRAM_THREADID="$o"; shift 2
	  ;;

	--telegramNotifications)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  TELEGRAM_NOTIFICATIONS="$o"; shift 2
	  ;;

	-u)
	  if ! o="$(checkOptionParameter "$1" "$2")"; then
		exitError $RC_PARAMETER_ERROR
	  fi
	  EXCLUDE_LIST="$o"; shift 2
	  ;;

	-U)
	  UPDATE_MYSELF=1; shift 1
	  ;;

	--unsupportedEnvironment|--use)
	  UNSUPPORTED_ENVIRONMENT=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--updateConfig|--updateConfig[+-])
	  UPDATE_CONFIG=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--updateUUIDs|--updateUUIDs[+-])
	  UPDATE_UUIDS=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-v|-v[-+])
	  VERBOSE=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-V)
	  REVERT=1; shift 1
	  ;;

	-x|-x[-+])
	  EXCLUDE_DD=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-y|-y[-+])
	  DEPLOY=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-Y)
	  NO_YES_QUESTION=1; shift 1
	  ;;

	-z|-z[-+])
	  ZIP_BACKUP=$(getEnableDisableOption "$1"); shift 1
	  ;;

	-Z|-Z[-+]) # flag to enable regession test pathes
	  REGRESSION_TEST=$(getEnableDisableOption "$1"); shift 1
	  ;;

	--) # end argument parsing
	  shift
	  break
	  ;;

	-*|+*) # unknown option
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNKNOWN_OPTION "$1"
		mentionHelp
		exitError $RC_PARAMETER_ERROR
	  ;;

	*) # preserve positional arguments
	  [[ -z "$PARAMS" ]] && PARAMS="$1" || PARAMS="$PARAMS $1"
	  shift
	  ;;
  esac
done

if (( ! $INCLUDE_ONLY )); then

# set positional arguments in argument list $@
set -- "$PARAMS"

if (( $RESTORE )); then
	rstFileName="${LOG_FILE/$LOGFILE_EXT/$LOGFILE_RESTORE_EXT}"
	LOG_FILE="$rstFileName"
	LOGFILE_EXT="$LOGFILE_RESTORE_EXT"
	rstFileName="${MSG_FILE/$MSGFILE_EXT/$MSGFILE_RESTORE_EXT}"
	MSG_FILE="$rstFileName"
	MSGFILE_EXT="$MSGFILE_RESTORE_EXT"
fi

if (( ! $RESTORE )); then
	exlock_now
	# Check exit code directly with e.g. if mycmd;, not indirectly with $?
	#shellcheck disable=SC2181
	if (( $? )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_INSTANCE_ACTIVE
		exitError $RC_MISC_ERROR
	fi
fi

fileParameter="$1"
if hasSpaces "$fileParameter"; then
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_CONTAINS_SPACES "$fileParameter"
	exitError $RC_MISC_ERROR
fi

if [[ -n "$1" ]]; then
	shift 1
	if [[ ! -d "$fileParameter" && ! -f "$fileParameter" ]]; then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_FILE_ARG_NOT_FOUND "$fileParameter"
		exitError $RC_MISSING_FILES
	else
		fileParameter="$(readlink -f "$fileParameter")"
	fi
fi

unusedParms="$*"

if [[ -n "$unusedParms" ]]; then
	usage
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNUSED_PARAMETERS "$unusedParms"
	exitError $RC_PARAMETER_ERROR
fi

if ! isSupportedEnvironment; then
	if (( $UNSUPPORTED_ENVIRONMENT )); then
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_ENVIRONMENT_CONFIRMED
	else
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_UNSUPPORTED_ENVIRONMENT
		exitError $RC_UNSUPPORTED_ENVIRONMENT
	fi
fi

if (( $DEPLOY )); then
	deployMyself
	exitNormal
fi

if (( $REVERT )); then
	revertScriptVersion
	exitNormal
fi

if (( $UPDATE_MYSELF )); then
	downloadPropertiesFile FORCE
	updateScript
	if (( $? )); then
		updateConfig
	fi
	exitNormal
fi

if (( $RESTORE && $NO_YES_QUESTION )); then				# WARNING: dangerous option !!!
	if [[ ! $RESTORE_DEVICE =~ $YES_NO_RESTORE_DEVICE ]]; then	# make sure we're not killing a disk by accident
		writeToConsole $MSG_LEVEL_MINIMAL $MSG_YES_NO_DEVICE_MISMATCH "$RESTORE_DEVICE" "$YES_NO_RESTORE_DEVICE"
		exitError $RC_MISC_ERROR
	fi
fi

check4RequiredCommands

if (( $UPDATE_CONFIG )); then
	updateConfig
	exitNormal
fi

logItem "RESTORE: $RESTORE - fileParameter: $fileParameter"
if [[ -n $fileParameter ]]; then
	if (( $RESTORE )); then
		RESTOREFILE="$(readlink -f "$fileParameter")"
	else
		BACKUPPATH="$(readlink -f "$fileParameter")"
	fi
fi

if ( (( $RESTORE )) && [[ -z "$RESTOREFILE" ]] ) || ( (( ! $RESTORE )) && [[ -z "$BACKUPPATH" ]] ); then
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_FILEPARAMETER
	mentionHelp
	exitError $RC_MISSING_FILES
fi

if [[ -z $RESTORE_DEVICE ]] && (( $ROOT_PARTITION_DEFINED )); then
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_MISSING_RESTOREDEVICE_OPTION
	exitError $RC_PARAMETER_ERROR
fi

_prepare_locking
logItem "Enabling trap handler"
trapWithArg cleanup SIGINT SIGTERM EXIT
lockMe

writeToConsole $MSG_LEVEL_MINIMAL $MSG_STARTED "$HOSTNAME" "$MYSELF" "$VERSION" "$GIT_DATE_ONLY" "$GIT_COMMIT_ONLY" "$(date)"
logger -t "$MYSELF" "Started $VERSION ($GIT_COMMIT_ONLY)"

(( $IS_BETA )) && writeToConsole $MSG_LEVEL_MINIMAL $MSG_INTRO_BETA_MESSAGE
(( $IS_DEV )) && writeToConsole $MSG_LEVEL_MINIMAL $MSG_INTRO_DEV_MESSAGE
(( $IS_HOTFIX )) && writeToConsole $MSG_LEVEL_MINIMAL $MSG_INTRO_HOTFIX_MESSAGE

setupEnvironment

if (( $NOTIFY_START )); then
	if (( ! $INTERACTIVE || $FAKE || $FORCE_EMAIL )); then
		msg="$(getMessage $MSG_TITLE_STARTED "$HOSTNAME")"
		if [[ -n "$EMAIL"  ]]; then
			sendEMail "" "$msg"
		fi
		if [[ -n "$TELEGRAM_TOKEN"  ]]; then
			sendTelegramm "$msg"
		fi
		if [[ -n "$PUSHOVER_USER"  ]]; then
			sendPushover "$msg"
		fi
		if [[ -n "$SLACK_WEBHOOK_URL"  ]]; then
			sendSlack "$msg"
		fi

		callNotificationExtension $rc

	fi
fi


if (( $ETC_CONFIG_FILE_INCLUDED )); then
	writeToConsole $MSG_LEVEL_DETAILED $MSG_INCLUDED_CONFIG "$ETC_CONFIG_FILE" # "$ETC_CONFIG_FILE_VERSION"
	logItem "Read config ${ETC_CONFIG_FILE} : ${ETC_CONFIG_FILE_VERSION}$NL$(grep -E -v '^\s*$|^#' "$ETC_CONFIG_FILE")"
fi
if (( $HOME_CONFIG_FILE_INCLUDED )); then
	writeToConsole $MSG_LEVEL_DETAILED $MSG_INCLUDED_CONFIG "$HOME_CONFIG_FILE" # "$HOME_CONFIG_FILE_VERSION"
	logItem "Read config ${HOME_CONFIG_FILE} : ${HOME_CONFIG_FILE_VERSION}$NL$(grep -E -v '^\s*$|^#' "$HOME_CONFIG_FILE")"
fi
if (( $CURRENTDIR_CONFIG_FILE_INCLUDED )); then
	writeToConsole $MSG_LEVEL_DETAILED $MSG_INCLUDED_CONFIG "$CURRENTDIR_CONFIG_FILE" # "$CURRENTDIR_CONFIG_FILE_VERSION"
	logItem "Read ${CURRENTDIR_CONFIG_FILE} : ${CURRENTDIR_CONFIG_FILE_VERSION}$NL$(grep -E -v '^\s*$|^#' "$CURRENTDIR_CONFIG_FILE")"
fi

if (( $CUSTOM_CONFIG_FILE_INCLUDED )); then
	writeToConsole $MSG_LEVEL_DETAILED $MSG_INCLUDED_CONFIG "$CUSTOM_CONFIG_FILE" # "$CUSTOM_CONFIG_FILE_VERSION"
	logItem "Read ${CUSTOM_CONFIG_FILE} : ${CUSTOM_CONFIG_FILE_VERSION}$NL$(grep -E -v '^\s*$|^#' "$CUSTOM_CONFIG_FILE")"
fi

logItem "INTERACTIVE: $INTERACTIVE"
logOptions "Invocation options"
logSystem

downloadPropertiesFile

updateRestoreReminder

reportNews

if isVersionDeprecated "$VERSION"; then
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_IS_DEPRECATED "$VERSION"
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_IS_DEPRECATED "$VERSION"
	writeToConsole $MSG_LEVEL_MINIMAL $MSG_SCRIPT_IS_DEPRECATED "$VERSION"
	VERSION_DEPRECATED=1
	NEWS_AVAILABLE=1
fi

doit # no return

fi # ! INCLUDE_ONLY
