On error just print error, but do not reset env vars, if this is done on verify error the init afterwards will store all settings in the wrong path
674 lines
20 KiB
Bash
674 lines
20 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
if [ -z "${MODULE}" ]; then
|
|
echo "Script cannot be run on its own";
|
|
exit 1;
|
|
fi;
|
|
|
|
set -ETu #-e -o pipefail
|
|
trap cleanup SIGINT SIGTERM ERR
|
|
trap error_trap ERR
|
|
|
|
cleanup() {
|
|
# script cleanup here
|
|
echo "Script abort: $? @LINE: $(caller)";
|
|
# unset exported vars
|
|
unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK;
|
|
# end trap
|
|
trap - SIGINT SIGTERM
|
|
}
|
|
error_trap() {
|
|
echo "Some part of the script failed with an error: $? @LINE: $(caller)";
|
|
trap - ERR
|
|
}
|
|
# on exit unset any exported var
|
|
trap "unset BORG_BASE_DIR BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK BORG_RELOCATED_REPO_ACCESS_IS_OK" EXIT;
|
|
# for version compare
|
|
function version {
|
|
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';
|
|
}
|
|
|
|
# version for all general files
|
|
VERSION="4.5.4";
|
|
|
|
# borg version and borg comamnd
|
|
BORG_VERSION="";
|
|
BORG_COMMAND="borg";
|
|
# default log folder if none are set in config or option
|
|
_LOG_FOLDER="/var/log/borg.backup/";
|
|
# log file name is set based on BACKUP_FILE, .log is added
|
|
LOG_FOLDER="";
|
|
# should be there on everything
|
|
TEMPDIR="/tmp/";
|
|
# HOSTNAME (as set on server)
|
|
HOSTNAME=$(hostname);
|
|
# creates borg backup based on the include/exclude files
|
|
# if base borg folder (backup files) does not exist, it will automatically init it
|
|
# base folder
|
|
BASE_FOLDER="/usr/local/scripts/borg/";
|
|
# base settings and init flag
|
|
SETTINGS_FILE="borg.backup.settings";
|
|
# include files
|
|
INCLUDE_FILE="";
|
|
EXCLUDE_FILE="";
|
|
# backup folder initialzed verify
|
|
BACKUP_INIT_FILE="";
|
|
BACKUP_INIT_DATE="";
|
|
# file with last compact date
|
|
BACKUP_COMPACT_FILE="";
|
|
# file with last check timestamp
|
|
BACKUP_CHECK_FILE="";
|
|
# one time backup prefix tag, if set will use <tag>.<prefix>-Y-M-DTh:m:s type backup prefix
|
|
ONE_TIME_TAG="";
|
|
DELETE_ONE_TIME_TAG="";
|
|
# check command prefix/glob
|
|
CHECK_PREFIX="";
|
|
# debug/verbose/other flags
|
|
VERBOSE=0;
|
|
LIST=0;
|
|
DEBUG=0;
|
|
DRYRUN=0;
|
|
INFO=0;
|
|
VERIFY=0;
|
|
CHECK=0;
|
|
CHECK_VERIFY_DATA=0;
|
|
COMPACT=0;
|
|
INIT=0;
|
|
EXIT=0;
|
|
PRINT=0;
|
|
# flags, set to no to disable
|
|
_BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK="yes";
|
|
_BORG_RELOCATED_REPO_ACCESS_IS_OK="yes";
|
|
# compatible settings
|
|
# NOTE: to keep the old .borg repository name for file module set this to true
|
|
# if set to false (future) it will add -file to the repository name like for other
|
|
# modules
|
|
FILE_REPOSITORY_COMPATIBLE="false";
|
|
# other variables
|
|
TARGET_SERVER="";
|
|
REGEX="";
|
|
REGEX_COMMENT="^[\ \t]*#";
|
|
REGEX_GLOB='\*';
|
|
REGEX_NUMERIC="^[0-9]{1,2}$";
|
|
REGEX_ERROR="^Some part of the script failed with an error:";
|
|
PRUNE_DEBUG="";
|
|
INIT_REPOSITORY=0;
|
|
FOLDER_OK=0;
|
|
TMP_EXCLUDE_FILE="";
|
|
# printf strings
|
|
PRINTF_INFO_STRING="%-23s: %s\n";
|
|
PRINTF_MASTER_BLOCK="=== [%-8s: %19s] ==[%s]====================================>\n";
|
|
PRINTF_SUB_BLOCK="|-- [%-8s: %19s] --[%s]------------------------------------>\n";
|
|
PRINTF_SUBEXT_BLOCK="|-- [%-8s: %s: %19s] --[%s]------------------------------------>\n";
|
|
PRINTF_DB_SUB_BLOCK="|>- [%-8s: %s] ==[%s]=======================>\n";
|
|
PRINTF_DB_RUN_TIME_SUB_BLOCK=">>- [%-8s: %s] ==[%s]==[Run time: %s]=======================>\n";
|
|
# opt flags
|
|
OPT_VERBOSE="";
|
|
OPT_PROGRESS="";
|
|
OPT_LIST="";
|
|
OPT_REMOTE="";
|
|
OPT_LOG_FOLDER="";
|
|
OPT_EXCLUDE="";
|
|
OPT_CHECK_VERIFY_DATA="";
|
|
# config variables (will be overwritten from .settings file)
|
|
TARGET_USER="";
|
|
TARGET_HOST="";
|
|
TARGET_PORT="";
|
|
TARGET_BORG_PATH="";
|
|
TARGET_FOLDER="";
|
|
BACKUP_FILE="";
|
|
SUB_BACKUP_FILE="";
|
|
# OPT is for options set
|
|
OPT_BORG_EXECUTEABLE="";
|
|
# which overrides BORG_EXECUTABLE that can be set in the settings file
|
|
BORG_EXECUTEABLE="";
|
|
# lz4, zstd 1-22 (3), zlib 0-9 (6), lzma 0-9 (6)
|
|
DEFAULT_COMPRESSION="zstd";
|
|
DEFAULT_COMPRESSION_LEVEL=3;
|
|
COMPRESSION="";
|
|
COMPRESSION_LEVEL="";
|
|
SUB_COMPRESSION="";
|
|
SUB_COMPRESSION_LEVEL="";
|
|
# encryption settings
|
|
DEFAULT_ENCRYPTION="keyfile";
|
|
ENCRYPTION="";
|
|
# force verify always
|
|
DEFAULT_FORCE_VERIFY="false";
|
|
FORCE_VERIFY="";
|
|
FORCE_CHECK=""; # Deprecated name, use FORCE_VERIFY
|
|
# compact
|
|
DEFAULT_COMPACT_INTERVAL="1";
|
|
LAST_COMPACT_DATE="";
|
|
COMPACT_INTERVAL="";
|
|
SUB_COMPACT_INTERVAL="";
|
|
# check
|
|
# default interval is none
|
|
DEFAULT_CHECK_INTERVAL="";
|
|
LAST_CHECK_DATE="";
|
|
CHECK_INTERVAL="";
|
|
SUB_CHECK_INTERVAL="";
|
|
# backup set names
|
|
BACKUP_SET="";
|
|
SUB_BACKUP_SET="";
|
|
# for database backup only
|
|
DATABASE_FULL_DUMP="";
|
|
DATABASE_USER="";
|
|
# only for mysql old config file
|
|
MYSQL_DB_CONFIG="";
|
|
MYSQL_DB_CONFIG_PARAM="";
|
|
# gitea module
|
|
GIT_USER="";
|
|
GITEA_WORKING_DIR="";
|
|
GITEA_TEMP_DIR="";
|
|
GITEA_BIN="";
|
|
GITEA_CONFIG="";
|
|
GITEA_EXPORT_TYPE="";
|
|
# zabbix module
|
|
ZABBIX_DUMP_BIN="";
|
|
ZABBIX_CONFIG="";
|
|
ZABBIX_DATABASE="";
|
|
ZABBIX_UNKNOWN_TABLES="";
|
|
ZABBIX_DB_PORT="";
|
|
OPT_ZABBIX_DUMP="";
|
|
OPT_ZABBIX_CONFIG="";
|
|
OPT_ZABBIX_UNKNOWN_TABLES="";
|
|
OPT_ZABBIX_DB_PORT="";
|
|
# default keep 7 days, 4 weeks, 6 months, 1 year
|
|
# if set 0, ignore/off
|
|
# note that for last/hourly it is needed to create a different
|
|
# BACKUP SET that includes hour and minute information
|
|
# IF BACKUP_SET is empty, this is automatically added
|
|
# general keep last, if only this is set only last n will be kept
|
|
DEFAULT_KEEP_LAST=0;
|
|
DEFAULT_KEEP_HOURS=0;
|
|
DEFAULT_KEEP_DAYS=7;
|
|
DEFAULT_KEEP_WEEKS=4;
|
|
DEFAULT_KEEP_MONTHS=6;
|
|
DEFAULT_KEEP_YEARS=1;
|
|
KEEP_LAST="";
|
|
KEEP_HOURS="";
|
|
KEEP_DAYS="";
|
|
KEEP_WEEKS="";
|
|
KEEP_MONTHS="";
|
|
KEEP_YEARS="";
|
|
# in the format of nY|M|d|h|m|s
|
|
KEEP_WITHIN="";
|
|
# sub override init to empty
|
|
SUB_KEEP_LAST="";
|
|
SUB_KEEP_HOURS="";
|
|
SUB_KEEP_DAYS="";
|
|
SUB_KEEP_WEEKS="";
|
|
SUB_KEEP_MONTHS="";
|
|
SUB_KEEP_YEARS="";
|
|
SUB_KEEP_WITHIN="";
|
|
|
|
function usage()
|
|
{
|
|
cat <<- EOT
|
|
Usage: ${0##/*/} [-c <config folder>] [-v] [-d]
|
|
|
|
-c <config folder>: if this is not given, ${BASE_FOLDER} is used
|
|
-L <log folder>: override config set and default log folder
|
|
-T <tag>: create one time stand alone backup prefixed with tag name
|
|
-D <tag backup set>: remove a tagged backup set, full name must be given
|
|
-b <borg executable>: override default path
|
|
-Z: run compress after prune/backup. Only for borg 1.2 or newer
|
|
-C: run borg check if repository is ok
|
|
-y: in combination with -C: add --verify-data
|
|
-p <archive prefix|glob>: in combinatio with -C: only check archives with prefix or glob
|
|
-P: print list of archives created
|
|
-V: verify if repository exists, if not abort
|
|
-e: exit after verify
|
|
-I: init repository (must be run first)
|
|
-i: print out only info
|
|
-l: list files during backup
|
|
-v: be verbose
|
|
-d: debug output all commands
|
|
-n: only do dry run
|
|
-h: this help page
|
|
|
|
Version : ${VERSION}
|
|
Module Version: ${MODULE_VERSION}
|
|
Module : ${MODULE}
|
|
EOT
|
|
}
|
|
|
|
# set options
|
|
while getopts ":c:L:T:D:b:p:vldniCVeIPyZh" opt; do
|
|
case "${opt}" in
|
|
c|config)
|
|
BASE_FOLDER=${OPTARG};
|
|
;;
|
|
L|Log)
|
|
OPT_LOG_FOLDER=${OPTARG};
|
|
;;
|
|
T|Tag)
|
|
ONE_TIME_TAG=${OPTARG};
|
|
;;
|
|
D|Delete)
|
|
DELETE_ONE_TIME_TAG=${OPTARG};
|
|
;;
|
|
b|borg)
|
|
OPT_BORG_EXECUTEABLE=${OPTARG};
|
|
;;
|
|
Z|Compact)
|
|
# will run compact alone
|
|
COMPACT=1;
|
|
;;
|
|
C|Check)
|
|
# will run borg check
|
|
# alt modes --repository-only, --archives-only,
|
|
# add mode --verify-data
|
|
# note that --repair has to be called manually is it might damange backups
|
|
CHECK=1;
|
|
;;
|
|
y|Verify-Data)
|
|
CHECK_VERIFY_DATA=1;
|
|
;;
|
|
p|prefix-glob)
|
|
CHECK_PREFIX=${OPTARG};
|
|
;;
|
|
V|Verify)
|
|
# will verify if repo is there and abort if not
|
|
VERIFY=1;
|
|
;;
|
|
e|exit)
|
|
# exit after verify or init (default off)
|
|
EXIT=1;
|
|
;;
|
|
I|Init)
|
|
# will check if there is a repo and init it
|
|
# previoous this was default
|
|
VERIFY=1;
|
|
INIT=1;
|
|
;;
|
|
P|Print)
|
|
# use borg list to print list of archves
|
|
PRINT=1;
|
|
;;
|
|
v|verbose)
|
|
VERBOSE=1;
|
|
;;
|
|
l|list)
|
|
LIST=1;
|
|
;;
|
|
i|info)
|
|
INFO=1;
|
|
;;
|
|
d|debug)
|
|
DEBUG=1;
|
|
;;
|
|
n|dryrun)
|
|
DRYRUN=1;
|
|
;;
|
|
h|help)
|
|
usage;
|
|
exit;
|
|
;;
|
|
:)
|
|
echo "Option -$OPTARG requires an argument."
|
|
;;
|
|
\?)
|
|
echo -e "\n Option does not exist: ${OPTARG}\n";
|
|
usage;
|
|
exit 1;
|
|
;;
|
|
esac;
|
|
done;
|
|
|
|
# add trailing slasd for base folder
|
|
[[ "${BASE_FOLDER}" != */ ]] && BASE_FOLDER=${BASE_FOLDER}"/";
|
|
# must have settings file there, if not, abort early
|
|
if [ ! -f "${BASE_FOLDER}${SETTINGS_FILE}" ]; then
|
|
echo "No settings file could be found: ${BASE_FOLDER}${SETTINGS_FILE}";
|
|
exit 1;
|
|
fi;
|
|
if [ ! -w "${BASE_FOLDER}" ]; then
|
|
echo "Cannot write to BASE_FOLDER ${BASE_FOLDER}";
|
|
echo "Is the group set to 'backup' and is this group allowed to write?"
|
|
echo "If run as sudo, is this user in the 'backup' group?"
|
|
echo "chgrp -R backup ${BASE_FOLDER}";
|
|
echo "chmod -R g+rwX ${BASE_FOLDER}";
|
|
echo "chmod g+s ${BASE_FOLDER}";
|
|
exit 1;
|
|
fi;
|
|
|
|
# info -i && -C/-I cannot be run together
|
|
if [ ${VERIFY} -eq 1 ] || [ ${INIT} -eq 1 ] && [ ${INFO} -eq 1 ]; then
|
|
echo "Cannot have -i info option and -V verify or -I initialize option at the same time";
|
|
exit 1;
|
|
fi;
|
|
# print -P cannot be run with -i/-C/-I together
|
|
if [ ${PRINT} -eq 1 ] && { [ ${INIT} -eq 1 ] || [ ${VERIFY} -eq 1 ] || [ ${INFO} -eq 1 ]; }; then
|
|
echo "Cannot have -P print option and -i info, -V verify or -I initizalize option at the same time";
|
|
exit 1;
|
|
fi;
|
|
# if tag is set, you can't have init, verify, info, etc
|
|
if [ -n "${ONE_TIME_TAG}" ] && { [ ${PRINT} -eq 1 ] || [ ${INIT} -eq 1 ] || [ ${VERIFY} -eq 1 ] || [ ${INFO} -eq 1 ]; }; then
|
|
echo "Cannot have -T '${ONE_TIME_TAG}' option with -i info, -V verify, -I initialize or -P print option at the same time";
|
|
exit 1;
|
|
fi;
|
|
# verify only alphanumeric, no spaces, only underscore and dash
|
|
if [ -n "${ONE_TIME_TAG}" ] && ! [[ "${ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+$ ]]; then
|
|
echo "One time tag '${ONE_TIME_TAG}' must be alphanumeric with dashes and underscore only.";
|
|
exit 1;
|
|
elif [ -n "${ONE_TIME_TAG}" ]; then
|
|
# all ok, attach '.' at the end
|
|
ONE_TIME_TAG=${ONE_TIME_TAG}".";
|
|
fi;
|
|
# if -D, cannot be with -T, -i, -C, -I, -P
|
|
if [ -n "${DELETE_ONE_TIME_TAG}" ] && { [ -n "${ONE_TIME_TAG}" ] || [ ${PRINT} -eq 1 ] || [ ${INIT} -eq 1 ] || [ ${VERIFY} -eq 1 ] || [ ${INFO} -eq 1 ]; }; then
|
|
echo "Cannot have -D delete tag option with -T one time tag, -i info, -V verify, -I initialize or -P print option at the same time";
|
|
exit 1;
|
|
fi;
|
|
# -D also must be in valid backup set format
|
|
# ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]]
|
|
if [ -n "${DELETE_ONE_TIME_TAG}" ] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},([A-Za-z0-9_-]+-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$ ]] && ! [[ "${DELETE_ONE_TIME_TAG}" =~ ^[A-Za-z0-9_-]+\.${MODULE},(\*-)?[0-9]{4}-[0-9]{2}-[0-9]{2}T\*$ ]]; then
|
|
echo "Delete one time tag '${DELETE_ONE_TIME_TAG}' is in an invalid format."
|
|
echo "Please verify existing tags with -P option."
|
|
echo "For a globing be sure it is in the format of: TAG.MODULE,*-YYYY-MM-DDT*";
|
|
echo "Note the dash (-) after the first *, also time (T) is a globa (*) must."
|
|
exit 1;
|
|
fi;
|
|
# -y can't be set without -C
|
|
if [ ${CHECK_VERIFY_DATA} -eq 1 ] && [ ${CHECK} -eq 0 ]; then
|
|
echo "-y (verify-data) cannot be run without -C (Check) option";
|
|
exit 1;
|
|
fi;
|
|
# -p can't be set without -C
|
|
if [ -n "${CHECK_PREFIX}" ] && [ ${CHECK} -eq 0 ]; then
|
|
echo "-p (pattern|glob) for check cannot be run without -C (Check) options";
|
|
exit 1;
|
|
fi;
|
|
# can't have -e if VERIFY or INIT is not set
|
|
if [ ${EXIT} -eq 1 ] && [ ${VERIFY} -eq 0 ] && [ ${INIT} -eq 0 ]; then
|
|
echo "-e (exit) can only be used with -V (Verify) and -I (Init)";
|
|
exit 1;
|
|
fi;
|
|
|
|
# verbose & progress
|
|
if [ ${VERBOSE} -eq 1 ]; then
|
|
OPT_VERBOSE="-v";
|
|
OPT_PROGRESS="-p";
|
|
fi;
|
|
# list files
|
|
if [ ${LIST} -eq 1 ]; then
|
|
OPT_LIST="--list";
|
|
fi;
|
|
# If dry run, the stats (-s) option cannot be used
|
|
if [ ${DRYRUN} -eq 1 ]; then
|
|
DRY_RUN_STATS="-n";
|
|
else
|
|
DRY_RUN_STATS="-s";
|
|
fi;
|
|
if [ ${CHECK_VERIFY_DATA} -eq 1 ] && [ ${CHECK} -eq 1 ]; then
|
|
OPT_CHECK_VERIFY_DATA="--verify-data";
|
|
fi;
|
|
|
|
# read config file
|
|
. "${BASE_FOLDER}${SETTINGS_FILE}";
|
|
|
|
# if OPTION SET overrides ALL others
|
|
if [ -n "${OPT_BORG_EXECUTEABLE}" ]; then
|
|
BORG_COMMAND="${OPT_BORG_EXECUTEABLE}";
|
|
if [ ! -f "${BORG_COMMAND}" ]; then
|
|
echo "borg command not found with option -b: ${BORG_COMMAND}";
|
|
exit;
|
|
fi;
|
|
# if in setting file, use this
|
|
elif [ -n "${BORG_EXECUTEABLE}" ]; then
|
|
BORG_COMMAND="${BORG_EXECUTEABLE}";
|
|
if [ ! -f "${BORG_COMMAND}" ]; then
|
|
echo "borg command not found with setting: ${BORG_COMMAND}";
|
|
exit;
|
|
fi;
|
|
elif ! command -v borg &> /dev/null; then
|
|
# elif [ -z ($command -v borg) ]; then
|
|
echo "borg backup seems not to be installed, please verify paths";
|
|
exit;
|
|
fi;
|
|
# verify that this is a borg executable, no detail check
|
|
_BORG_COMMAND_VERIFY=$(${BORG_COMMAND} -V | grep "borg");
|
|
if [[ "${_BORG_COMMAND_VERIFY}" =~ ${REGEX_ERROR} ]]; then
|
|
echo "Cannot extract borg info from command, is this a valid borg executable?: ${BORG_COMMAND}";
|
|
exit;
|
|
fi;
|
|
# extract actually borg version from here
|
|
# alt sed to get only numbes: sed -e 's/.* \([0-9]*\.[0-9]*\.[0-9]*\)$/\1/g'
|
|
# or use cut -d " " -f 2 and assume NO space in the first part
|
|
BORG_VERSION=$(${BORG_COMMAND} -V | sed -e 's/borg.* //') 2>&1 || echo "[!] Borg version not estable";
|
|
|
|
# load default settings for fileds not set
|
|
if [ -z "${COMPRESSION}" ]; then
|
|
COMPRESSION="${DEFAULT_COMPRESSION}";
|
|
fi;
|
|
if [ -z "${COMPRESSION_LEVEL}" ]; then
|
|
COMPRESSION_LEVEL="${DEFAULT_COMPRESSION_LEVEL}";
|
|
fi;
|
|
if [ -z "${ENCRYPTION}" ]; then
|
|
ENCRYPTION="${DEFAULT_ENCRYPTION}";
|
|
fi;
|
|
# check interval override
|
|
if [ -z "${COMPACT_INTERVAL}" ]; then
|
|
COMPACT_INTERVAL="${DEFAULT_COMPACT_INTERVAL}";
|
|
fi;
|
|
if [ -z "${CHECK_INTERVAL}" ]; then
|
|
CHECK_INTERVAL="${DEFAULT_CHECK_INTERVAL}";
|
|
fi;
|
|
# deprecated name FORCE_CHECK, use FORCE_VERIFY instead
|
|
if [ -n "${FORCE_CHECK}" ]; then
|
|
FORCE_VERIFY="${FORCE_CHECK}";
|
|
fi;
|
|
if [ -z "${FORCE_VERIFY}" ]; then
|
|
FORCE_VERIFY="${DEFAULT_FORCE_VERIFY}";
|
|
fi;
|
|
if [ -z "${KEEP_LAST}" ]; then
|
|
KEEP_LAST="${DEFAULT_KEEP_LAST}";
|
|
fi;
|
|
if [ -z "${KEEP_HOURS}" ]; then
|
|
KEEP_HOURS="${DEFAULT_KEEP_HOURS}";
|
|
fi;
|
|
if [ -z "${KEEP_DAYS}" ]; then
|
|
KEEP_DAYS="${DEFAULT_KEEP_DAYS}";
|
|
fi;
|
|
if [ -z "${KEEP_WEEKS}" ]; then
|
|
KEEP_WEEKS="${DEFAULT_KEEP_WEEKS}";
|
|
fi;
|
|
if [ -z "${KEEP_MONTHS}" ]; then
|
|
KEEP_MONTHS="${DEFAULT_KEEP_MONTHS}";
|
|
fi;
|
|
if [ -z "${KEEP_YEARS}" ]; then
|
|
KEEP_YEARS="${DEFAULT_KEEP_YEARS}";
|
|
fi;
|
|
# ** SUB LOAD
|
|
# a settings file always end in .settings, replace that with lower case MODULE.settings
|
|
SETTINGS_FILE_SUB=$(echo "${SETTINGS_FILE}" | sed -e "s/\.settings/\.${MODULE,,}\.settings/");
|
|
# if mysql/pgsql run, load sub settings
|
|
if [ -f "${BASE_FOLDER}${SETTINGS_FILE_SUB}" ]; then
|
|
. "${BASE_FOLDER}${SETTINGS_FILE_SUB}";
|
|
# if SUB_ set override master
|
|
if [ -n "${SUB_BACKUP_FILE}" ]; then
|
|
BACKUP_FILE=${SUB_BACKUP_FILE}
|
|
fi;
|
|
# if sub backup set it set, override current
|
|
if [ -n "${SUB_BACKUP_SET}" ]; then
|
|
BACKUP_SET=${SUB_BACKUP_SET};
|
|
fi;
|
|
# ovrride compression
|
|
if [ -n "${SUB_COMPRESSION}" ]; then
|
|
COMPRESSION=${SUB_COMPRESSION};
|
|
fi;
|
|
if [ -n "${SUB_COMPRESSION_LEVEL}" ]; then
|
|
COMPRESSION_LEVEL=${SUB_COMPRESSION_LEVEL};
|
|
fi;
|
|
# compact interval override
|
|
if [ -n "${SUB_COMPACT_INTERVAL}" ]; then
|
|
COMPACT_INTERVAL="${SUB_COMPACT_INTERVAL}";
|
|
fi;
|
|
# override check interval
|
|
if [ -n "${SUB_CHECK_INTERVAL}" ]; then
|
|
CHECK_INTERVAL="${SUB_CHECK_INTERVAL}";
|
|
fi;
|
|
# check override for keep time
|
|
if [ -n "${SUB_KEEP_LAST}" ]; then
|
|
KEEP_LAST=${SUB_KEEP_LAST};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_HOURS}" ]; then
|
|
KEEP_HOURS=${SUB_KEEP_HOURS};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_DAYS}" ]; then
|
|
KEEP_DAYS=${SUB_KEEP_DAYS};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_WEEKS}" ]; then
|
|
KEEP_WEEKS=${SUB_KEEP_WEEKS};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_MONTHS}" ]; then
|
|
KEEP_MONTHS=${SUB_KEEP_MONTHS};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_YEARS}" ]; then
|
|
KEEP_YEARS=${SUB_KEEP_YEARS};
|
|
fi;
|
|
if [ -n "${SUB_KEEP_WITHIN}" ]; then
|
|
KEEP_WITHIN=${SUB_KEEP_WITHIN};
|
|
fi;
|
|
fi;
|
|
# add module name to backup file, always
|
|
# except if FILE module and FILE_REPOSITORY_COMPATIBLE="true"
|
|
if [ "${FILE_REPOSITORY_COMPATIBLE}" != "true" ] || [ "${MODULE,,}" != "file" ]; then
|
|
BACKUP_FILE=${BACKUP_FILE/.borg/-${MODULE,,}.borg};
|
|
fi;
|
|
# backup file must be set
|
|
if [ -z "${BACKUP_FILE}" ]; then
|
|
echo "No BACKUP_FILE set";
|
|
exit;
|
|
fi;
|
|
# backup file (folder) must end as .borg
|
|
# BACKUP FILE also cannot start with / or have / inside or start with ~
|
|
# valid file name check, alphanumeric, -,._ ...
|
|
if ! [[ "${BACKUP_FILE}" =~ ^[A-Za-z0-9,._-]+\.borg$ ]]; then
|
|
echo "BACKUP_FILE ${BACKUP_FILE} can only contain A-Z a-z 0-9 , . _ - chracters and must end with .borg";
|
|
exit 1;
|
|
fi;
|
|
# error if the repository file still has the default name
|
|
# This is just for old sets
|
|
REGEX="^some\-prefix\-";
|
|
if [[ "${BACKUP_FILE}" =~ ${REGEX} ]]; then
|
|
echo "[DEPRECATED] The repository name still has the default prefix: ${BACKUP_FILE}";
|
|
exit 1;
|
|
fi;
|
|
|
|
# check LOG_FOLDER, TARGET_BORG_PATH, TARGET_FOLDER must have no ~/ as start position
|
|
if [[ ${LOG_FOLDER} =~ ^~\/ ]]; then
|
|
echo "LOG_FOLDER path cannot start with ~/. Path must be absolute: ${LOG_FOLDER}";
|
|
exit 1;
|
|
fi;
|
|
if [[ ${TARGET_BORG_PATH} =~ ^~\/ ]]; then
|
|
echo "TARGET_BORG_PATH path cannot start with ~/. Path must be absolute: ${TARGET_BORG_PATH}";
|
|
exit 1;
|
|
fi;
|
|
if [[ ${TARGET_FOLDER} =~ ^~\/ ]]; then
|
|
echo "TARGET_FOLDER path cannot start with ~/. Path must be absolute: ${TARGET_FOLDER}";
|
|
exit 1;
|
|
fi
|
|
|
|
# COMPACT_INTERVAL must be a number from -1 to 365
|
|
# CHECK_INTERVAL must be a number from -1 to 365
|
|
|
|
# log file set and check
|
|
# option folder overrides all other folders
|
|
if [ -n "${OPT_LOG_FOLDER}" ]; then
|
|
LOG_FOLDER="${OPT_LOG_FOLDER}";
|
|
fi;
|
|
# if empty folder set to default folder
|
|
if [ -z "${LOG_FOLDER}" ]; then
|
|
LOG_FOLDER="${_LOG_FOLDER}";
|
|
fi;
|
|
# if folder does not exists create it
|
|
if [ ! -d "${LOG_FOLDER}" ]; then
|
|
mkdir "${LOG_FOLDER}";
|
|
fi;
|
|
# set the output log folder
|
|
# LOG=$(printf "%q" "${LOG_FOLDER}/${BACKUP_FILE}.log");
|
|
LOG="${LOG_FOLDER}/${BACKUP_FILE}.log";
|
|
# fail if not writeable to folder or file
|
|
if [[ -f "${LOG}" && ! -w "${LOG}" ]] || [[ ! -f "${LOG}" && ! -w "${LOG_FOLDER}" ]]; then
|
|
echo "Log folder or log file is not writeable: ${LOG}";
|
|
echo "Is the group set to 'backup' and is this group allowed to write?"
|
|
echo "If run as sudo, is this user in the 'backup' group?"
|
|
echo "chgrp -R backup ${LOG}";
|
|
echo "chmod -R g+rwX ${LOG}";
|
|
echo "chmod g+s ${LOG}";
|
|
exit 1;
|
|
fi;
|
|
|
|
# if ENCRYPTION is empty or not in the valid list fall back to none
|
|
# NOTE This is currently set in default and doesn't need to be set on empty
|
|
# only ivalid should be checked
|
|
if
|
|
[ "${ENCRYPTION}" = "authenticated" ] ||
|
|
[ "${ENCRYPTION}" = "repokey" ] ||
|
|
[ "${ENCRYPTION}" = "authenticated-blake2" ] ||
|
|
[ "${ENCRYPTION}" = "repokey-blake2" ] ;
|
|
then
|
|
# if "authenticated" or "repokey" a password must be set
|
|
if [[ ! -v BORG_PASSPHRASE ]] && [[ ! -v BORG_PASSCOMMAND ]] && [[ ! -v BORG_PASSPHRASE_FD ]]; then
|
|
echo "Encryption method '${ENCRYPTION}' requires a BORG_PASSPHRASE, BORG_PASSCOMMAND or BORG_PASSPHRASE_FD to be set.";
|
|
exit 1;
|
|
fi;
|
|
elif [ "${ENCRYPTION}" = "keyfile" ] || [ "${ENCRYPTION}" = "keyfile-blake2" ]; then
|
|
# if no password, set empty password
|
|
if [[ ! -v BORG_PASSPHRASE ]] && [[ ! -v BORG_PASSCOMMAND ]] && [[ ! -v BORG_PASSPHRASE_FD ]]; then
|
|
export BORG_PASSPHRASE="";
|
|
fi;
|
|
elif [ "${ENCRYPTION}" != "none" ]; then
|
|
echo "Encryption method '${ENCRYPTION}' is not valid.";
|
|
exit 1;
|
|
fi;
|
|
|
|
## FUNCTIONS
|
|
|
|
# METHOD: convert_time
|
|
# PARAMS: timestamp in seconds or with milliseconds (nnnn.nnnn)
|
|
# RETURN: formated string with human readable time (d/h/m/s)
|
|
# CALL : var=$(convert_time $timestamp);
|
|
# DESC : converts a timestamp or a timestamp with float milliseconds
|
|
# to a human readable format
|
|
# output is in days/hours/minutes/seconds
|
|
function convert_time
|
|
{
|
|
timestamp=${1};
|
|
# round to four digits for ms
|
|
timestamp=$(printf "%1.4f" "$timestamp");
|
|
# get the ms part and remove any leading 0
|
|
ms=$(echo "${timestamp}" | cut -d "." -f 2 | sed -e 's/^0*//');
|
|
timestamp=$(echo "${timestamp}" | cut -d "." -f 1);
|
|
timegroups=(86400 3600 60 1); # day, hour, min, sec
|
|
timenames=("d" "h" "m" "s"); # day, hour, min, sec
|
|
output=( );
|
|
time_string=;
|
|
for timeslice in "${timegroups[@]}"; do
|
|
# floor for the division, push to output
|
|
output[${#output[*]}]=$(awk "BEGIN {printf \"%d\", ${timestamp}/${timeslice}}");
|
|
timestamp=$(awk "BEGIN {printf \"%d\", ${timestamp}%${timeslice}}");
|
|
done;
|
|
|
|
for ((i=0; i<${#output[@]}; i++)); do
|
|
if [ "${output[$i]}" -gt 0 ] || [ -n "$time_string" ]; then
|
|
if [ -n "${time_string}" ]; then
|
|
time_string=${time_string}" ";
|
|
fi;
|
|
time_string=${time_string}${output[$i]}${timenames[$i]};
|
|
fi;
|
|
done;
|
|
if [ -n "${ms}" ] && [ "${ms}" != "nan" ] && [ "${ms}" -gt 0 ]; then
|
|
time_string="${time_string} ${ms}ms";
|
|
fi;
|
|
# just in case the time is 0
|
|
if [ -z "${time_string}" ]; then
|
|
time_string="0s";
|
|
fi;
|
|
echo -n "${time_string}";
|
|
}
|
|
|
|
# __END__
|