bare/bare.sh

1508 lines
38 KiB
Bash
Executable File

#!/bin/bash
VALIDCOMMANDS="go ls init repos stats diff forget get check"
RCFILE=${HOME}/.backup/config
DEF_AUTHFILE=${HOME}/.backup/auth
REPOFILE=${HOME}/.backup/repos
STATFILE=${HOME}/.backup/stats
LOGFILE=/var/log/backup.log
FULLLOGFILE_BASE=/tmp/full_backup_log
RESTIC=/usr/local/bin/restic
RCLONE=/usr/local/bin/rclone
RSYNC=/usr/local/bin/rsync
USMB=/usr/local/bin/usmb
#RCLONEOPTS="--cache-chunk-no-memory --buffer-size=10M --progress"
RCLONEOPTS="--progress --buffer-size 10M --cache-chunk-no-memory"
SPEED=""
RESTOREDIRBASE="/mnt/restore"
CRONMODE=0
CONNECTIONS=""
LOG=/dev/stdout
DATE=/bin/date
DOALL=0
REPO_LIST=""
TESTMODE=0
TELEGRAM=0
VERBOSE=0
function cecho() {
local col
col="$1"
shift 1
echo -e "${col}$*${PLAIN}"
}
function error() {
cecho "$RED" "Error: $*"
}
function action() {
cecho "$CYAN" "$*"
}
function log() {
local now col lowrer
now=`${DATE} +%Y/%m/%d-%H:%M:%S`
lower=$(echo "$*" | tr '[:upper:]' '[:lower:]')
if [[ $lower == *error* ]]; then
col="$RED"
elif [[ $lower == *fail* ]]; then
col="$RED"
elif [[ $lower == *success* ]]; then
col="$GREEN"
elif [[ $lower == *starting* ]]; then
col="$BOLD"
elif [[ $lower == *created* ]]; then
col="$BOLD"
elif [[ $lower == *creating* ]]; then
col="$BOLD"
elif [[ $lower == *finished* ]]; then
col="$BOLD"
else
col="$CYAN"
fi
if [[ $TELEGRAM -eq 1 ]]; then
echo -e "__${now}__ **<${mode}>** \`$*\`" >>${LOG}
else
echo -e "$CYAN${now} <${mode}> $col$*$PLAIN" >>${LOG}
fi
}
function updatestats() {
local repo cmd stamp code
repo=$1
cmd=$2
code=$3
stamp=`date +%s`
if [[ -f $STATFILE ]]; then
sed -i "/${repo}:${cmd}/d" $STATFILE
fi
echo "${repo}:${cmd}:${code}:${stamp}" >> $STATFILE
}
function usage-repo() {
echo " reponame1;/path/to/files1/;tag1,tag2,...,tagX;repo_url;repo_passfile;repo_excludefile"
echo " reponame2;/path/to/files2/;tag1,tag2,...,tagX;repo_url;repo_passfile;repo_excludefile"
echo " ..."
echo " reponameX;/path/to/filesX/;tag1,tag2,...,tagX;repo_url;repo_passfile;repo_excludefile"
echo ""
echo " Default password file is: $DEF_AUTHFILE"
echo ""
echo "Backup method tags:"
echo " restic Backup using restic (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
echo " rclone Backup using rclone (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
echo " rsync Backup using rsync (default repo is \$DEF_RSYNC_USER@\$DEF_RSYNC_SERVER:\$DEF_RSYNC_DIR/<reponame>)"
echo " postgres Dump postgres databases. Instead of local file path, specify database name to backup. If empty, all dbs are backed up."
echo " mysql Dump mysql databases. Instead of local file path, specify database name to backup. If empty, all dbs are backed up."
echo ""
echo "Pre-backup commands to access local files:"
echo " nfs Mount \$DEF_NFS_SERVER:\$DEF_NFS_SERVER_BASE/<sharename> to <repopath>"
echo " before running. Sharename determined by stripping \$NFS_PREFIX"
echo " from start of repo path."
echo " usmb Run 'usmb reponame' to mount \$USMB_PREFIX/<sharename> before running."
echo " Sharename determined by stripping \$NFS_PREFIX from start of <repopath>."
echo " localmount Run 'mount reponame' to mount <path_to_files> before running."
echo
echo "Pre-backup commands to access repo:"
echo " premount=x Run 'mount <x>' before command and 'umount x' afterwards."
}
function usage-rc() {
echo " export B2_ACCOUNT_ID=xxx # Backblaze B2 credentials"
echo " export B2_ACCOUNT_KEY=xxx # Backblaze B2 credentials"
echo " export B2_APP_ID=xxx # Backblaze B2 bucket details"
echo " export B2_APP_KEY=xxx # Backblaze B2 bucket auth"
echo " export B2_BUCKET_PREFIX=xxx # Prefix to append to create unique B2 bucket name"
echo ""
echo " # Binary paths (optional, below are defualts):"
echo " #export RESTIC=/usr/local/bin/restic"
echo " #export RCLONE=/usr/local/bin/rclone"
echo " #export RSYNC=/usr/local/bin/rsync"
echo " #export USMB=/usr/local/bin/usmb"
echo ""
echo " export RESTIC_KEEPDAYS=31 # Days to keep restic backups for"
echo " export RESTICOPTS=\"--one-file-system\" # Extra args to pass to restic"
echo ""
echo " export PGUSER=postgres # Postgresql username"
echo ""
echo " export DEF_RSYNC_SERVER=xxx # Server used for repos with 'rsync' tag"
echo " export DEF_RSYNC_USER=backups # Username for rsync server"
echo " export DEF_RSYNC_DIR=/home/backups/backups # Remote directory on rsync server"
echo " export RSYNC_OPTIONS=-Pavz # Options to pass to rsync"
echo ""
echo " export USMB_PREFIX=/DataVolume/shares # Strip this from repo path to get USMB share name"
echo ""
echo " export DEF_NFS_SERVER=nfs.yourdomain.com # NFS server where local files for 'nfs' repos are found"
echo " export DEF_NFS_SERVER_BASE=/remote/nfs/share/base # Path on local NFS server to prefix to repo names"
echo " export NFS_PREFIX=/local/nfs/mountpoint # Where to mount NFS exports locally before backing them up"
}
function usage() {
echo "usage: $0 command reponame"
echo ""
echo " -a Run on all repos defined as 'auto'"
echo " -d dir Restore mode: specify where to put restored files (default: $RESTOREDIRBASE)"
echo " -h Show this usage text"
echo " -s num Limit speed to 'num' Mbps (default: unlimited)"
echo " -x num Use 'num' simultaneous connections (default: 20)"
echo " -c Cron mode - log to ${LOGFILE}"
echo " -t Test mode - dump what would be done then exit."
echo " -T Telegram formatting mode"
echo ""
echo "Valid commands are:"
echo " $VALIDCOMMANDS"
echo ""
echo "${RCFILE} should look like this:"
usage-rc
echo ""
echo "${REPOFILE} should look like this:"
usage-repo
echo ""
}
function getdatapath() {
local DATAPATH REPO x
REPO="$1"
DATAPATH=""
for x in ${REPODEFS[@]}; do
match="^${REPO}\;"
if [[ $x =~ $match ]]; then
DATAPATH=`echo $x | sed -e s/${match}//`
fi
done
DATAPATH=`echo $DATAPATH | sed -e s/\;.*//`
echo "$DATAPATH"
}
function getmode() {
local mode
checktag "$1" rclone
if [[ $? -eq 0 ]]; then
mode=rclone
else
checktag "$1" rsync
if [[ $? -eq 0 ]]; then
mode=rsync
else
mode=restic
fi
fi
echo "$mode"
}
function getrepoexcludefile() { # output path
local res rv
res=`getrepotok $1 6`
rv=$?
echo "$res"
return $rv
}
function getrepopath() { # output path
local res rv mode def repobase
res=`getrepotok $1 4`
rv=$?
if [[ -z $res ]]; then
mode=`getmode $1`
repobase=`getreponame $1`
if [[ $mode == "restic" ]]; then
def="b2:${B2_BUCKET_PREFIX}-${repobase}"
elif [[ $mode == "rclone" ]]; then
def="remote:${B2_BUCKET_PREFIX}-${repobase}"
elif [[ $mode == "rsync" ]]; then
def="${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER}:${DEF_RSYNC_DIR}/$repobase"
else
def="(no default repo for mode $mode)"
fi
res="$def"
fi
echo "$res"
return $rv
}
function getrepopassfile() { # output path
local res rv
res=`getrepotok $1 5`
rv=$?
echo "$res"
return $rv
}
function getrepotags() { # output path
local res rv
res=`getrepotok $1 3`
rv=$?
echo "$res"
return $rv
}
function getrepotok() { # output given token from repo def
local def res rv code idx
def=`getrepodef "$1"`
idx=$2
code="{ print \$${idx} }"
res=`echo "$def" | awk -F';' "$code"`
echo "$res"
if [[ -z $res ]]; then
rv=1
else
rv=0
fi
return $rv
}
function getreponame() {
local reponame
reponame="$1"
if [[ $reponame =~ ^.*\;.*$ ]]; then
# if we were given a repo def, return just the name
reponame=`echo "$reponame" | sed -e 's/\;.*//g'`
fi
echo "$reponame"
}
function getrepodef() {
local reponame match repodef x
reponame="$1"
if [[ $reponame =~ ^.*\;.*$ ]]; then
repodef="$reponame"
else
# if we were just given a repo name, look up the def
repodef=""
for x in ${REPODEFS[@]}; do
match="^${reponame};"
if [[ $x =~ $match ]]; then
repodef="$x"
fi
done
fi
echo "$repodef"
}
function gettagval() { # return 0 if tag matches
local reponame lookfor justtags x t val
reponame="$1"
lookfor="$2"
justtags=`getrepotags "$reponame"`
val=""
IFS=',' read -ra t <<< "$justtags"
for x in ${t[@]}; do
if [[ $x == ${lookfor}=* ]]; then
val=`echo "$x" | cut -d= -f2`
break
fi
done
if [[ ! -z ${val} ]]; then
echo "$val"
return 0
fi
return 1
}
function checktag() { # return 0 if tag matches
local reponame lookfor justtags
reponame="$1"
lookfor="$2"
justtags=`getrepotags "$reponame"`
if [[ $justtags =~ ^.*${lookfor}.*$ ]]; then
return 0
fi
return 1
}
function do_mount() {
local msg
if [[ $USEUSMB -eq 1 ]]; then
[[ $VERBOSE -eq 1 ]] && log "debug: mounting $DATAPATH via smb"
mount | grep -q ${DATAPATH}
if [[ $? -ne 0 ]]; then
# try mounting it.
${USMB} ${USMBNAME} >/dev/null
if [[ $? -eq 0 ]]; then
log "Mount usmb volume '$USMBNAME': success"
else
log "Mount usmb volume '$USMBNAME': FAILED"
return 1
fi
fi
elif [[ $USENFS -eq 1 ]]; then
[[ $VERBOSE -eq 1 ]] && log "debug: mounting $DATAPATH via nfs"
mount | grep -q ${DATAPATH}
if [[ $? -ne 0 ]]; then
# try mounting it.
mkdir -p $DATAPATH
mount_nfs -R 1 ${NFSPATH} ${DATAPATH} >/dev/null
if [[ $? -eq 0 ]]; then
log "Mount nfs volume '$NFSPATH' to $DATAPATH: success"
else
log "Mount nfs volume '$NFSPATH' to $DATAPATH: FAILED"
return 1
fi
fi
elif [[ $USELOCALMOUNT -eq 1 ]]; then
[[ $VERBOSE -eq 1 ]] && log "debug: mounting $DATAPATH via fstab"
mount | grep -q ${DATAPATH}
if [[ $? -ne 0 ]]; then
# try mounting it.
mkdir -p $DATAPATH
mount ${DATAPATH} >/dev/null
if [[ $? -eq 0 ]]; then
log "Mount $DATAPATH: success"
else
log "Mount $DATAPATH: FAILED"
return 1
fi
fi
fi
# datapath is used for sql filename in pgsql/mysql backups
if checktag "$f" postgres; then
# Make sure the db exists
if ! [[ -z ${DATAPATH} ]]; then
psql -lqt | cut -d \| -f 1 | grep -qw ${DATAPATH}
if [[ $? -ne 0 ]]; then
log "Error: PostgreSQL database '${DATAPATH}' doesn't exist"
return 1
fi
fi
elif checktag "$f" mysql; then
# Make sure the db exists
if ! [[ -z ${DATAPATH} ]]; then
mysql -e 'show databases' | grep -v "^Database$" | grep -qw ${DATAPATH}
if [[ $? -ne 0 ]]; then
log "Error: MySQL database '${DATAPATH}' doesn't exist"
return 1
fi
fi
else
if ! [[ -e ${DATAPATH} ]]; then
log "Error: ${DATAPATH} doesn't exist"
return 1
fi
count=`ls ${DATAPATH} | wc -l`
if [ $count -le 2 ]; then
log "Error: ${DATAPATH} exists but appears to be empty"
return 1
fi
fi
return 0
}
function do_umount() {
if is_mounted $DATAPATH; then
if [[ $USEUSMB -eq 1 ]]; then
log "Unmounting usmb volume '$USMBNAME'"
usmb -u $USMBNAME
elif [[ $USENFS -eq 1 ]]; then
log "Unmounting nfs volume '$NFSPATH' from $DATAPATH"
umount $DATAPATH
elif [[ $USELOCALMOUNT -eq 1 ]]; then
log "Unmounting dir $DATAPATH"
umount $DATAPATH
fi
fi
}
function updatedir() {
local temp r tempwd
tempwd=$(echo "$wd" | sed -e 's-/\{1,\}-/-g')
temp=$( ${RESTIC} $AUTHOPTS $CONNECTIONSOPTS -q ls -l $RESTORESNAPID $tempwd 2>/dev/null )
r=$?
if [[ $r -ne 0 || -z $temp ]]; then
return 1
fi
wd="$tempwd"
contents=$( echo "$temp" | awk -v wd=$wd '{ sub(wd,""); sub(wd "/", ""); print $0; }')
subdirs=$( echo "${contents}" | grep "^d" | awk '{ print $NF}' | sed -e 's,^/,,')
subfiles=$( echo "${contents}" | awk '{ print $NF}' | sed -e 's,^/,,')
return 0
}
function showrestoreinfo() {
cecho "$YELLOW$BOLD" "Repo to restore from:"
cecho "$YELLOW" " $f (snapshot $RESTORESNAPID)"
echo
cecho "$YELLOW$BOLD" "Files to restore:"
if [[ -z $RESTORELIST ]]; then
cecho "$YELLOW" " (none)"
else
cecho "$YELLOW" "$RESTORELIST" | sed -e 's/^ //' | tr ' ' '\n' | sed -e 's/^/ /g'
fi
echo
}
function restorecmd_help() {
echo
echo "x Abort"
echo "q Abort"
echo "lcd dir Change local restore dir"
echo "ls Show files in current repo dir"
echo "cd Change current repo dir"
echo "dirs Start subdirectories of current repo dir"
echo "go Start restore of marked file"
echo "w List files marked for restore"
echo "a file Mark file to be restored"
echo "d file Un-mark file from restore list"
echo
}
function is_mounted() {
local dir dev1 dev2 rv formatarg
dir="$1"
if [[ $(uname -s) == "Linux" ]]; then
formatarg="-c"
else
formatarg="-f"
fi
dev1=$(stat $formatarg %d $dir 2>/dev/null)
dev2=$(stat $formatarg %d $dir/.. 2>/dev/null)
if [[ $dev1 == $dev2 ]]; then
rv=1
else
rv=0
fi
return $rv
}
function check_repomount_needed() {
local path
path=`gettagval "$f" premount`
if [[ $? -eq 0 ]]; then
grep -q $path /etc/fstab
if [[ $? -ne 0 ]]; then
log "Error: repo '$REPO' has premount tag but $path not in fstab."
return 1
fi
MOUNTREPO=1
else
MOUNTREPO=0
fi
return 0
}
function check_datamount_needed() {
if [[ $CMD == "go" ]]; then
NEEDMOUNT=1
elif [[ $CMD == "get" ]]; then
NEEDMOUNT=1
elif [[ $CMD == "diff" ]]; then
NEEDMOUNT=1
else
NEEDMOUNT=0
fi
}
# Handle args
ARGS="acd:hs:tTvx:"
while getopts "$ARGS" i; do
case "$i" in
a)
DOALL=1
;;
d)
RESTOREDIRBASE="$OPTARG";
;;
h)
usage;
exit 1
;;
s)
SPEED="$OPTARG";
;;
x)
CONNECTIONS="$OPTARG";
;;
c)
CRONMODE=1;
LOG=${LOGFILE}
;;
t)
TESTMODE=1
;;
T)
TELEGRAM=1
;;
v)
VERBOSE=1
;;
*)
echo "ERROR: invalid argument: $i";
usage;
;;
esac
done
shift $((OPTIND - 1))
if [[ $CRONMODE -eq 0 ]]; then
BOLD="\033[1m"
PLAIN="\033[0m"
UNDERLINE="\033[4m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
BLUE="\033[34m"
CYAN="\033[36m"
LINK="$BLUE$UNDERLINE"
fi
if ! [ -e ${RCFILE} ]; then
error "can't find ${RCFILE}"
echo ""
usage-rc
exit 1
fi
if ! [ -e ${REPOFILE} ]; then
error "can't find ${REPOFILE}"
echo ""
usage-repo
exit 1
fi
which bc >/dev/null 2>&1
if [ $? -ne 0 ]; then
error "can't find bc in path"
echo ""
exit 1
fi
. ${RCFILE}
if [[ -z $RESTIC_KEEPDAYS ]]; then
error "\$RESTIC_KEEPDAYS not set."
exit 1
fi
# Convert speed from Mbps to KBps
if ! [[ -z $SPEED ]]; then
KSPEED=$(echo "scale=2; $SPEED * 125" | bc)
else
KSPEED=""
fi
CMD="$1"
shift 1
# command synonyms
if [[ $CMD == "repolist" ]]; then
CMD="repos"
elif [[ $CMD == "restore" ]]; then
CMD="get"
elif [[ $CMD == "snapshots" ]]; then
CMD="ls"
fi
if (echo "$VALIDCOMMANDS" | grep -wq $CMD) ; then
true
else
error "invalid command $CMD. Should one of: $VALIDCOMMANDS"
exit 1
fi
# Get list of defined repos
idx=0
for f in `cat $REPOFILE | grep ";" | grep -v "^#"`; do
REPODEFS[$idx]="$f"
mode=`getmode "$f"`
if [[ $mode == "restic" ]]; then
thisrpath=`getrepopath $f`
if [[ ${thisrpath,,} == *b2* ]]; then
if [[ -z $B2_APP_ID ]]; then
error "\$B2_APP_ID not set."
exit 1
fi
if [[ -z $B2_APP_KEY ]]; then
error "\$B2_APP_KEY not set."
exit 1
fi
fi
fi
if [[ $DOALL -eq 1 ]]; then
checktag "$f" auto
if [[ $? -eq 0 ]]; then
REPO_LIST="$REPO_LIST `echo $f | sed -e 's/\;.*//'`"
fi
fi
idx=$((idx + 1))
done
if [[ $CMD == "get" ]]; then
# one repo + snapshotid/date
err=0
if [[ -z $REPO_LIST ]]; then
if [[ $# -ge 1 ]]; then
REPO_LIST=$1 ;shift 1
else
error "no reponame provided."
exit 1
fi
if [[ $# -ge 1 ]]; then
RESTORESNAPID=$1 ; shift 1
fi
RESTORELIST="$*"
else
echo "restore usage: $0 get repo_name (snapshotid|latest)"
echo " or"
echo " $0 get repo_name (snapshotid|latest) file1 file2 etc"
echo
echo "Files will be restored to $RESTOREDIRBASE/repo_name/"
echo
exit 1
fi
else
# one or more repos
if [[ -z $REPO_LIST ]]; then
REPO_LIST="$*"
fi
fi
if [[ $CMD == "repos" ]]; then
format="%-20s%-20s%-30s%s\n"
cecho "${CYAN}" "Repos defined in $BOLD${RCFILE}$PLAIN$CYAN:"
echo ""
head=$(printf "$format" "Repo" "Path/DB" "Repo path" "Tags")
cecho "$BOLD$YELLOW" "$head"
for x in ${REPODEFS[@]}; do
IFS=';' read -ra tok <<< "$x"
thisrepo=${tok[0]}
thispath=${tok[1]}
if [[ -z ${tok[2]} ]]; then
tags="n/a"
else
tags=`echo "${tok[2]}" | sed -e 's/,/ /g'`
fi
thisrpath=`getrepopath $thisrepo`
[[ -z $thisrpath ]] && thisrpath="(default)"
if [[ $tags == *postgres* && -z $thispath ]]; then
thispath="(all dbs)"
elif [[ $tags == *mysql* && -z $thispath ]]; then
thispath="(all dbs)"
fi
line=$(printf "$format" "$thisrepo" "$thispath" "$thisrpath" "$tags")
cecho "$YELLOW" "$line"
done
exit 0
fi
if [[ -z $REPO_LIST ]]; then
usage
exit 1
fi
# Validate repos
GOODREPOS=""
for f in $REPO_LIST; do
REPO=${f}
DATAPATH=$(getdatapath $f)
REPOPATH=$(getrepopath $f)
mode=`getmode "$REPO"`
checktag "$f" usmb
if [[ $? -eq 0 ]]; then
if [[ -z $USMB_PREFIX ]]; then
USMBNAME=$f
else
if ! [[ $DATAPATH == *${USMB_PREFIX}* ]]; then
log "Error: path '$DATAPATH' of repo '$REPO' does not contain smb prefix '$USMB_PREFIX'."
continue
fi
USMBNAME=`echo "${DATAPATH}" | sed -e "s,${USMB_PREFIX}/\(.*\).*,\1,"`
fi
USEUSMB=1
else
USMBNAME=""
USEUSMB=0
fi
checktag "$f" nfs
if [[ $? -eq 0 ]]; then
if [[ -z $DEF_NFS_SERVER ]]; then
log "Error: repo '$REPO' has nfs tag but \$DEF_NFS_SERVER not defined."
continue
fi
if [[ -z $DEF_NFS_SERVER_BASE ]]; then
log "Error: repo '$REPO' has nfs tag but \$DEF_NFS_SERVER_BASE not defined."
continue
fi
if ! [[ $DATAPATH == *${NFS_PREFIX}* ]]; then
log "Error: path '$DATAPATH' of repo '$REPO' does not contain nfs prefix '$NFS_PREFIX'."
continue
fi
NFSNAME=`echo "${DATAPATH}" | sed -e "s,${NFS_PREFIX}/\(.*\).*,\1,"`
NFSPATH="${DEF_NFS_SERVER}:${DEF_NFS_SERVER_BASE}/${NFSNAME}"
USENFS=1
else
NFSNAME=""
USENFS=0
fi
check_repomount_needed "$f" # sets $MOUNTREPO
[[ $? -ne 0 ]] && continue
checktag "$f" localmount
if [[ $? -eq 0 ]]; then
dir=`echo "$DATAPATH" | sed -e 's,/$,,'`
grep -q $dir /etc/fstab
if [[ $? -ne 0 ]]; then
log "Error: repo '$REPO' has localmount tag but $DATAPATH not in fstab."
continue
fi
USELOCALMOUNT=1
else
USELOCALMOUNT=0
fi
if [[ -z $DATAPATH ]]; then
checktag "$f" postgres
pgrv=$?
checktag "$f" mysql
myrv=$?
if [[ $pgrv -ne 0 && $myrv -ne 0 ]]; then
log "error - can't find matching repo for $f - make sure it is listed in ${REPOFILE}"
continue
fi
fi
check_datamount_needed "$f" # sets $NEEDMOUNT
if [[ $CMD == "go" ]]; then
NEEDMOUNT=1
elif [[ $CMD == "get" ]]; then
NEEDMOUNT=1
elif [[ $CMD == "diff" ]]; then
NEEDMOUNT=1
else
NEEDMOUNT=0
fi
if [[ $NEEDMOUNT -eq 1 ]]; then
do_mount $DATAPATH
if [[ $? -ne 0 ]]; then
continue
fi
fi
if [[ -z $GOODREPOS ]]; then
GOODREPOS="$f"
else
GOODREPOS="$GOODREPOS $f"
fi
done
REPO_LIST="$GOODREPOS"
if [[ -z $REPO_LIST ]]; then
log "Error: errors found with all repos. Aborting."
exit 1
fi
[[ $VERBOSE -eq 1 ]] && log "Processing these repos: $REPO_LIST"
if [[ $TESTMODE -eq 1 ]]; then
action "Would have run '$CMD' on these repos:"
for f in $REPO_LIST; do
DATAPATH=$(getdatapath $f)
echo " $f -> $DATAPATH"
if [[ $NEEDMOUNT -eq 1 ]]; then
do_umount
fi
done
exit 0
fi
errcount=0 # used for 'check' mode
warncount=0 # used for 'check' mode
errtext=""
for f in $REPO_LIST; do
[[ $VERBOSE -eq 1 ]] && log "debug: starting repo $f"
REPO=${f}
DATAPATH=$(getdatapath $REPO)
FULLLOGFILE="${FULLLOGFILE_BASE}_${REPO}.txt"
checktag "$f" usmb
if [[ $? -eq 0 ]]; then
if [[ -z $USMB_PREFIX ]]; then
USMBNAME=$f
else
USMBNAME=`echo "${DATAPATH}" | sed -e "s,${USMB_PREFIX}/\(.*\).*,\1,"`
fi
USEUSMB=1
else
USMBNAME=""
USEUSMB=0
fi
checktag "$f" nfs
if [[ $? -eq 0 ]]; then
NFSNAME=`echo "${DATAPATH}" | sed -e "s,${NFS_PREFIX}/\(.*\).*,\1,"`
NFSPATH="${DEF_NFS_SERVER}:${DEF_NFS_SERVER_BASE}/${NFSNAME}"
USENFS=1
else
NFSNAME=""
USENFS=0
fi
checktag "$f" localmount
if [[ $? -eq 0 ]]; then
USELOCALMOUNT=1
else
USELOCALMOUNT=0
fi
export REPO_PATH=`getrepopath "$f"`
if [[ $? -eq 0 ]]; then
USINGDEFAULT=0
else
USINGDEFAULT=1
fi
check_datamount_needed "$f" # sets $NEEDMOUNT
check_repomount_needed "$f" # sets $MOUNTREPO
if [[ $MOUNTREPO -eq 1 ]]; then
path=`gettagval "$f" premount`
[[ $VERBOSE -eq 1 ]] && log "debug: doing repo premount at $path via fstab"
if is_mounted $path; then
[[ ! $CMD == "check" ]] && log "Pre-mount of '$path': already mounted"
else
mount $path
if [[ $? -eq 0 ]]; then
[[ ! $CMD == "check" ]] && log "Pre-mount of '$path': success"
else
[[ ! $CMD == "check" ]] && log "Pre-mount of '$path': FAILED"
continue
fi
fi
fi
mode=`getmode "$f"`
SPEEDOPTS=""
AUTHOPTS=""
OTHEROPTS=""
CONNECTIONOPTS=""
if [[ $mode == "restic" ]]; then
MYREPO="restic: $REPO_PATH"
export RESTIC_REPOSITORY="$REPO_PATH"
export RESTIC_PASSWORD_FILE=`getrepopassfile "$f"`
if [[ ! -z $RESTIC_PASSWORD_FILE ]]; then
unset RESTIC_PASSWORD
AUTHOPTS="-p ${RESTIC_PASSWORD_FILE}"
else
AUTHOPTS="-p ${DEF_AUTHFILE}"
fi
if [[ -z $KSPEED ]]; then
SPEEDOPTS=""
else
SPEEDOPTS="--limit-upload $KSPEED"
fi
if [[ -z $CONNECTIONS ]]; then
CONNECTIONSOPTS=""
else
CONNECTIONSOPTS="-o b2.connections=${CONNECTIONS}"
fi
checktag "$f" postgres
if [[ $? -eq 0 ]]; then
CONNECTIONSOPTS="$OTHEROPTS --tag postgres"
fi
checktag "$f" mysql
if [[ $? -eq 0 ]]; then
CONNECTIONSOPTS="$OTHEROPTS --tag mysql"
fi
if [[ $VERBOSE -eq 1 ]]; then
OTHEROPTS="$OTHEROPTS -v"
fi
DBOPTS=""
DBDUMPCMD=""
checktag "$f" postgres
if [[ $? -eq 0 ]]; then
DBOPTS="$DBOPTS --clean"
OTHEROPTS="$OTHEROPTS --stdin"
if [[ -z ${DATAPATH} ]]; then
DBDUMPCMD="pg_dumpall"
DBFILENAME="alldbs.sql"
else
DBDUMPCMD="pg_dump"
DBFILENAME="${DATAPATH}.sql"
DBOPTS="$DBOPTS ${DATAPATH}" # Last dbdump option is database name
fi
fi
checktag "$f" mysql
if [[ $? -eq 0 ]]; then
DBOPTS="$DBOPTS --all-databases --master-data --single-transaction"
OTHEROPTS="$OTHEROPTS --stdin"
if [[ -z ${DATAPATH} ]]; then
DBDUMPCMD="mysqldump"
DBFILENAME="mysql_alldbs.sql"
else
DBDUMPCMD="mysqldump"
DBFILENAME="mysql_${DATAPATH}.sql"
DBOPTS="$DBOPTS ${DATAPATH}" # Last dbdump option is database name
fi
fi
export RESTIC_EXCLUDEFILE=`getrepoexcludefile "$f"`
if [[ ! -z $RESTIC_EXCLUDEFILE ]]; then
OTHEROPTS="$OTHEROPTS --exclude-file=${RESTIC_EXCLUDEFILE}"
fi
OTHEROPTS="$OTHEROPTS $RESTICOPTS"
elif [[ $mode == "rsync" ]]; then
# rsync
MYREPO="rsync: $REPO_PATH"
export RSYNC_REPOSITORY="$REPO_PATH"
export RSYNC_FULLDIR="${DEF_RSYNC_DIR}/${REPO}"
if [[ $USINGDEFAULT -eq 1 ]]; then
list="DEF_RSYNC_SERVER DEF_RSYNC_USER DEF_RSYNC_DIR RSYNC_OPTIONS"
else
list="RSYNC_OPTIONS"
fi
for xx in $list; do
eval val='$'$xx
if [[ -z $val ]]; then
error "\$$xx not set. Please update ${RCFILE}."
echo ""
usage-rc
exit 1
fi
done
if [[ -z $KSPEED ]]; then
SPEEDOPTS=""
else
SPEEDOPTS="--bwlimit=${KSPEED}k"
fi
CONNECTIONSOPTS=""
else
# rclone
MYREPO="rclone: $REPO_PATH"
export RCLONE_REPOSITORY="$REPO_PATH"
if [[ -z $KSPEED ]]; then
SPEEDOPTS=""
else
SPEEDOPTS="--bwlimit=${KSPEED}k"
fi
if [[ -z $CONNECTIONS ]]; then
CONNECTIONSOPTS=""
else
CONNECTIONSOPTS="--transfers=${CONNECTIONS}"
fi
# use sizeonly to check, follow symlinks
OTHEROPTS="$OTHEROPTS --size-only -L"
export RESTIC_EXCLUDEFILE=`getrepoexcludefile "$f"`
if [[ -n $RESTIC_EXCLUDEFILE ]]; then
OTHEROPTS="$OTHEROPTS --exclude-from ${RESTIC_EXCLUDEFILE}"
fi
fi
if [[ ! $CMD == "check" ]]; then
text="Starting '$CMD' on repo '$REPO' [$DATAPATH <-> $MYREPO]"
log "$text"
fi
if [[ $CMD == "check" ]]; then
line=`egrep "^$REPO:go:" $STATFILE 2>/dev/null`
if [[ $? -eq 0 ]]; then
# Get result
code=`echo "$line" | cut -d: -f3`
stamp=`echo "$line" | cut -d: -f4`
date --version 2>&1 | grep -q GNU
if [[ $? -eq 0 ]]; then
humanstamp=`date --date="@$stamp"`
else
humanstamp=`date -r $stamp`
fi
now=`date +%s`
age=$( echo "$now - $stamp" | bc )
oneday=$( echo "24 * 60 * 60" | bc)
if [[ $code -eq 0 ]]; then
if [[ $age -le $oneday ]]; then
if [[ $TELEGRAM -eq 1 ]]; then
echo "*OK*: Last backup for _${REPO}_ succeeded on $humanstamp."
else
cecho "$GREEN" "OK: Last backup for $BOLD${REPO}$PLAIN$GREEN succeeded on $humanstamp."
fi
rv=0
else
if [[ $TELEGRAM -eq 1 ]]; then
echo "*CRITICAL*: Last backup for _${REPO}_ succeeded on $humanstamp (age $age not in last 24 hours)."
else
cecho "$RED" "CRITICAL: Last backup for $BOLD${REPO}${PLAIN}${RED} succeeded on $humanstamp (age $age not in last 24 hours)."
fi
errcount=$(( $errcount + 1))
rv=2
fi
else
if [[ $TELEGRAM -eq 1 ]]; then
echo "*CRITICAL*: Last backup for _${REPO}_ failed on $humanstamp."
else
cecho "$RED" "CRITICAL: Last backup for $BOLD${REPO}$PLAIN$RED failed on $humanstamp."
fi
rv=2
errcount=$(( $errcount + 1))
fi
else
if [[ $TELEGRAM -eq 1 ]]; then
echo "*WARNING*: No history found for repo _${REPO}_"
else
cecho "$YELLOW" "WARNING: No history found for repo $BOLD$REPO$PLAIN$YELLOW'"
fi
rv=1
warncount=$(( $warncount + 1))
fi
elif [[ $mode == "restic" ]]; then
if [[ $CMD == "go" ]]; then
if checktag "$f" postgres; then
btype=postgres
elif checktag "$f" mysql; then
btype=mysql
else
btype=normal
fi
if [[ $CRONMODE -eq 1 ]]; then
if [[ $VERBOSE -eq 1 ]]; then
echo "debug: running: [${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH" >>${LOG}
echo "debug: full log is in ${FULLLOGFILE}" >>${LOG}
if [[ $btype == "postgres" || $btype == "mysql" ]] ; then
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 >> ${FULLLOGFILE}
rv=$?
else
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 >> ${FULLLOGFILE}
rv=$?
fi
egrep "^(Added|processed|snapshot)" ${FULLLOGFILE} >>${LOG}
else
if [[ $btype == "postgres" || $btype == "mysql" ]] ; then
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 | egrep "^(Added|processed|snapshot)" >> ${LOG}
rv=${PIPESTATUS[0]}
else
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 | egrep "^(Added|processed|snapshot)" >> ${LOG}
rv=${PIPESTATUS[0]}
fi
fi
else
if [[ $btype == "postgres" || $btype == "mysql" ]] ; then
[[ $VERBOSE -eq 1 ]] && log "debug: running: [$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME"
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 >> ${LOG}
rv=$?
else
[[ $VERBOSE -eq 1 ]] && log "debug: running: [${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH"
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 >> ${LOG}
rv=$?
fi
fi
elif [[ $CMD == "get" ]]; then
RESTOREDIR="$RESTOREDIRBASE/$f/"
snaps=$(${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS 2>&1 | grep -v ID | awk '(NF >= 4) { print }')
if checktag "$f" postgres; then
snaps=$(echo "$snaps" | grep -w postgres)
elif checktag "$f" mysql; then
snaps=$(echo "$snaps" | grep -w mysql)
else
snaps=$(echo "$snaps" | egrep -vw "postgres|mysql")
fi
snapids=$(echo "$snaps" | awk '{ print $1 }')
defsid=$(echo "$snapids" | tail -1)
if [[ -z $RESTORESNAPID ]]; then
cecho "$BOLD$CYAN" "Found these snapshots:"
echo "$snaps"
RESTORESNAPID="xxxxxx"
while [[ ! $snaps == *$RESTORESNAPID* ]]; do
read -p "snapshot [$defsid]: " RESTORESNAPID
if [[ $RESTORESNAPID == "latest" || -z $RESTORESNAPID ]]; then
RESTORESNAPID=$defsid
fi
done
elif [[ $RESTORESNAPID == "latest" ]]; then
RESTORESNAPID=$defsid
elif [[ ! $snaps == *$RESTORESNAPID* ]]; then
error "snapshot '$RESTORESNAPID' not found."
echo
cecho "$RED" "Valid snapshots for repo $f:"
cecho "$RED" "$snaps"
exit 1
fi
if [[ -z $RESTORELIST ]]; then
action "Opening repo for snapshot $BOLD$RESTORESNAPID$PLAIN$CYAN..."
wd=/
updatedir
c="ls"
doit=0
while [[ ! $c == "x" && ! c == "q" ]]; do
if [[ $c == "ls" ]]; then
echo "$contents"
elif [[ $c == "go" ]]; then
if [[ -z $RESTORELIST ]]; then
cecho "$RED" "Nothing to restore!"
else
doit=1
fi
break
elif [[ $c == "x" || $c == "q" ]]; then
doit=0
break
elif [[ $c == "?" || $c == "h" ]]; then
restorecmd_help
elif [[ -z $c ]]; then
true
elif [[ $c == "dirs" ]]; then
echo "subdirs:"
echo "$subdirs" | sed -e 's/^/ /'
elif [[ $c == w* ]]; then
showrestoreinfo
elif [[ $c == a* || $c == mark* ]]; then
file=$(echo "$c" | awk '{ print $2 }')
# remove leading /
file=$(echo $file | sed -e 's,^/,,')
if [[ -z $file ]]; then
error "no file provided"
else
echo "$RESTORELIST" | tr ' ' '\n' | egrep -q "^$wd$file$"
thisrv=$?
if [[ $thisrv -eq 0 ]]; then
error "'$file' already in restore list"
else
if [[ $file == */* ]]; then
# add without checking
if [[ -z $RESTORELIST ]]; then
RESTORELIST="$wd$file"
else
RESTORELIST="$RESTORELIST $wd$file"
fi
action "Added to restore list: $BOLD$file$PLAIN$CYAN (no verify)"
else
echo "$subfiles" | grep -qw "$file"
rv=$?
if [[ $rv -eq 0 ]]; then
RESTORELIST="$RESTORELIST $wd$file"
action "Added to restore list: $BOLD$file"
else
error "'$file' doesn't exist"
fi
fi
fi
fi
elif [[ $c == d* || $c == unmark* ]]; then
file=$(echo "$c" | awk '{ print $2 }')
file="$wd$file"
echo "$RESTORELIST" | tr ' ' '\n' | egrep -q "^$file$"
if [[ $? -eq 0 ]]; then
#RESTORELIST=$(echo "$RESTORELIST" | sed -e 's/^ //' | tr ' ' '\n' | grep -wv $file | tr '\n' ' ' | egrep -v "^$" | sed -e 's/^/ /')
RESTORELIST=$(echo "$RESTORELIST" | sed -e "s, $file,,")
action "Removed from restore list: $BOLD$file"
else
error "Restore list doesn't contain '$file'"
fi
elif [[ $c == cd* ]]; then
newdir=$(echo "$c" | awk '{ print $2 }')
olddir=$wd
needupdate=1
if [[ $newdir == "/" ]]; then
wd=$newdir
rv=0
elif [[ $newdir == /* ]]; then
wd=$newdir/
updatedir
rv=$?
needupdate=0
elif [[ $newdir == */* ]]; then
wd=$wd$newdir/
updatedir
rv=$?
needupdate=0
elif [[ $newdir == ".." ]]; then
wd=$(dirname $wd)
rv=0
else
echo "$subdirs" | grep -qw "$newdir"
rv=$?
if [[ $rv -eq 0 ]]; then
wd=$wd$newdir/
fi
fi
if [[ $rv -eq 0 ]]; then
[[ $needupdate -eq 1 ]] && updatedir
else
error "no such directory '$newdir'"
wd=$olddir
fi
elif [[ $c == lcd* ]]; then
newlocaldir=$(echo "$c" | awk '{ print $2 }')
if [[ -d $newlocaldir ]]; then
RESTOREDIR="$newlocaldir"
elif [[ -e $newlocaldir ]]; then
error "'$newlocaldir' is not a directory"
else
error "'$newlocaldir' does not exist"
fi
else
error "bad command '$c' (? for help)"
fi
echo
action "Restore path: $RESTOREDIR"
echo -en "$CYAN$wd> $PLAIN"
read c
done
else
# restorelist not empty
doit=1
fi
if [[ $doit -eq 1 ]]; then
showrestoreinfo
action "Performing restore..."
echo
RESTOREOPTS=""
for r in $RESTORELIST; do
RESTOREOPTS="$RESTOREOPTS -i $r"
done
[[ $VERBOSE -eq 1 ]] && log "debug: running: ${RESTIC} restore $AUTHOPTS $CONNECTIONSOPTS -t "$RESTOREDIR" $RESTOREOPTS $RESTORESNAPID"
${RESTIC} restore $AUTHOPTS $CONNECTIONSOPTS -t "$RESTOREDIR" $RESTOREOPTS $RESTORESNAPID 2>&1 >> ${LOG}
rv=$?
if [[ $rv -eq 0 ]]; then
# check that we got them all
tried=0
success=0
failed=0
for r in $RESTORELIST; do
tried=$((tried + 1))
if [[ -e $RESTOREDIR/$r ]]; then
success=$((success + 1))
else
failed=$((failed + 1))
fi
done
echo
echo -en "${CYAN}${BOLD}Restored $success / $tried items$PLAIN"
[[ $failed -gt 0 ]] && cecho "$RED" " ($failed failed)" || echo
echo
if [[ $success -eq $tried ]]; then
rv=0
else
rv=1
fi
fi
else
action "${BOLD}Aborting..."
rv=1
fi
elif [[ $CMD == "ls" ]]; then
[[ $VERBOSE -eq 1 ]] && log "debug: running: ${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS $OTHEROPTS "
${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "stats" ]]; then
${RESTIC} stats $AUTHOPTS $CONNECTIONSOPTS 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "diff" ]]; then
log "Error: diff not supported in restic."
rv=1
elif [[ $CMD == "init" ]]; then
# check whether it already exists first!
${RESTIC} stats $AUTHOPTS $CONNECTIONSOPTS >/dev/null 2>&1
if [ $? -eq 0 ]; then
log "ERROR: Repo ${REPO} already exists. Aborting."
rv=1
else
cmdtorun="${RESTIC} init $AUTHOPTS $CONNECTIONSOPTS"
if [[ $VERBOSE -eq 1 ]]; then
log "export RESTIC_REPOSITORY=\"$REPO_PATH\""
log "export RESTIC_PASSWORD_FILE=`getrepopassfile \"$f\"`"
log "will run: [${cmdtorun}]"
fi
errtext=`${RESTIC} init $AUTHOPTS $CONNECTIONSOPTS 2>&1`
rv=$?
fi
elif [[ $CMD == "forget" ]]; then
# age out stuff after RESTIC_KEEPDAYS days
FORGETOPTS="-d ${RESTIC_KEEPDAYS}"
${RESTIC} forget $AUTHOPTS $CONNECTIONSOPTS $FORGETOPTS 2>&1 | awk '($1 == "Applying") { print } ($2 == "snapshots") { show=0 } (show == 1 && $1 != "ID" && NF > 1) { print "Removing: " $0 } ($1 == "remove") { show=1 }' >> ${LOG}
rv=$?
${RESTIC} prune $AUTHOPTS 2>&1 | egrep "^(repository contain|found|will|remove)" >> ${LOG}
else
log "Error: invalid command $CMD"
rv=1
fi
elif [[ $mode == "rsync" ]]; then
REMOTE=""
if checktag "$f" postgres; then
log "Error: postgres backups not supported for rsync mode."
rv=1
elif checktag "$f" mysql; then
log "Error: mysql backups not supported for rsync mode."
rv=1
elif [[ $CMD == "go" ]]; then
${RSYNC} ${RSYNC_OPTIONS} $DATAPATH/ ${RSYNC_REPOSITORY} 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "ls" ]]; then
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} ls ${RSYNC_FULLDIR} 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "stats" ]]; then
action "Size of remote data for ${REPO}:"
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} du -hs ${RSYNC_FULLDIR} 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "diff" ]]; then
${RSYNC} ${RSYNC_OPTIONS} -n $DATAPATH/ ${RSYNC_REPOSITORY} 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "init" ]]; then
# check whether it already exists first!
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} ls -d ${RSYNC_FULLDIR} 2>&1 >> ${LOG}
if [ $? -eq 0 ]; then
log "ERROR: Repo ${REPO} already exists. Aborting."
else
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} mkdir -p ${RSYNC_FULLDIR} 2>&1 >>${LOG}
if [ $? -eq 0 ]; then
log "Created directory ${RSYNC_FULLDIR}..."
else
log "Creation of ${RSYNC_FULLDIR} failed."
fi
fi
elif [[ $CMD == "forget" ]]; then
log "Error: forget not supported for $mode mode."
rv=1
else
log "Error: invalid command $CMD"
rv=1
fi
else
# rclone
REMOTE=""
if checktag "$f" postgres; then
log "Error: postgres backups not supported for $mode mode."
rv=1
elif checktag "$f" mysql; then
log "Error: mysql backups not supported for $mode mode."
rv=1
elif [[ $CMD == "go" ]]; then
${RCLONE} sync $RCLONEOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH $RCLONE_REPOSITORY 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "ls" ]]; then
${RCLONE} ls $RCLONEOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $RCLONE_REPOSITORY 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "stats" ]]; then
${RCLONE} size $RCLONEOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $RCLONE_REPOSITORY 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "diff" ]]; then
${RCLONE} check $RCLONEOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $RCLONE_REPOSITORY 2>&1 >> ${LOG}
rv=$?
elif [[ $CMD == "init" ]]; then
# check whether it already exists first!
${RCLONE} size $RCLONEOPTS $RCLONE_REPOSITORY >/dev/null 2>&1
if [ $? -eq 0 ]; then
log "ERROR: Repo ${REPO} already exists. Aborting."
else
# does 'remote' exist?
${RCLONE} listremotes | grep -q remote: >/dev/null 2>&1
rv=$?
if [ $rv -ne 0 ]; then
log "Rclone remote doesn't exist - creating it..."
${RCLONE} $RCLONEOPTS config create remote b2 account $B2_APP_ID key $B2_APP_KEY >>${LOG}
rv=$?
if [ $rv -ne 0 ]; then
log "Rclone remote init failed."
exit 1
fi
fi
if [ $rv -eq 0 ]; then
log "Creating B2 bucket for $RCLONE_REPOSITORY..."
# create the bucket
${RCLONE} $RCLONEOPTS mkdir $RCLONE_REPOSITORY >>${LOG}
else
log "Rclone bucket creation of $RCLONE_REPOSITORY failed."
fi
fi
elif [[ $CMD == "forget" ]]; then
log "Error: forget not supported for rclone mode."
rv=1
else
log "Error: invalid command $CMD"
rv=1
fi
fi
if [[ ! $CMD == "check" ]]; then
# Record result
updatestats $f $CMD $rv
# did our command succeed?
if [[ $rv -ne 0 ]]; then
log "Error: '$CMD' on repo '$REPO' failed"
if [[ ! -z $errtext ]]; then
log "$errtext"
fi
fi
log "Finished '$CMD' on repo '$REPO'"
fi
done
# Clean up
for f in $REPO_LIST; do
check_datamount_needed "$f" # sets $NEEDMOUNT
if [[ $NEEDMOUNT -eq 1 ]]; then
do_umount
fi
check_repomount_needed "$f" # sets $MOUNTREPO
if [[ $MOUNTREPO -eq 1 ]]; then
path=`gettagval "$f" premount`
if is_mounted $path; then
umount $path
if [[ $? -eq 0 ]]; then
[[ ! $CMD == "check" ]] && log "Un-mount of '$path': success"
else
[[ ! $CMD == "check" ]] && log "Un-mount of '$path': FAILED"
fi
fi
fi
done
if [[ $CMD == "check" ]]; then
if [[ $errcount -ge 1 ]]; then
rv=2
elif [[ $warncount -ge 1 ]]; then
rv=1
else
rv=0
fi
exit $rv
fi