#!/bin/bash
VERSION="2.82.3 [17 Mar 2026]"
LVMDELETESNAPSHOT="$(command -v lvm-delete-snapshot.sh)"
function removesnapshot () {
if [[ -n $BASEFSVOL && -n $BASEFS ]]; then
	if [[ -x $LVMDELETESNAPSHOT ]]; then
		[[ -n $VERBOSE ]] && echo "$(date +%H:%M:%S) Deleting LVM snapshot of $BASEFSVOL at $BASEFSVOL$THIS-$$ (if any)"
		"$LVMDELETESNAPSHOT" -f "$BASEFS$THIS-$$" >/dev/null||{ echo "A problem occurred running $LVMDELETESNAPSHOT, aborting">&2; exit 1; }
	else
		echo "Unable to locate $LVMDELETESNAPSHOT, aborting">&2; exit 1
	fi
fi
}

function set_userdir () {
	[[ -n $USELVM ]] && BASEFSVOL=$(lvs --noheadings|grep -E -m 1 "(root|home)"|awk '{print "/dev/"$2"/"$1}' 2>/dev/null)
	if [[ -n $BASEFSVOL ]]; then
		# we can use LVM snapshot
		BASEFS=$(echo "$BASEFSVOL"|awk -F/ '{print $NF}')
		if [[ $(echo "$BASEFSVOL"|awk -F/ '{print NF}') != 4 ]]; then
			# lv should be in the form /dev/xx/$BASEFS
			echo "$(date +%H:%M:%S) couldn't identify $BASEFS volume name (found '${BASEFSVOL}'), aborting..."
			exit 1
		fi
		removesnapshot
		if [[ -z $QUIET ]]; then echo -n "$(date +%H:%M:%S) Making LVM snapshot of $BASEFSVOL as $BASEFSVOL$THIS-$$"; fi
		lvcreate --permission rw --size 16G --snapshot --name "$BASEFS$THIS-$$" "$BASEFSVOL">/dev/null||{ echo -e "\ncouldn't create logical volume $BASEFSVOL$THIS-$$, aborting..."; exit 1; }
		[[ -z $QUIET ]] && echo -en " - ok\n$(date +%H:%M:%S) Mounting LVM snapshot at /mnt/$BASEFS$THIS-$$"
		mkdir -p "/mnt/$BASEFS$THIS-$$" || { echo -e "\ncouldn't create mountpoint, aborting..."; exit 1; }
		sleep 2s # prevent error 'special device ... does not exist' when mounting
		mount -o ro "$BASEFSVOL$THIS-$$" "/mnt/$BASEFS$THIS-$$"||{ echo -e "\ncouldn't mount $BASEFSVOL$THIS-$$ at mountpoint, aborting..."; exit 1; }
		[[ -z $QUIET ]] && echo " - ok"
		USERDIR="/mnt/$BASEFS$THIS-$$"
		if [[ -d $USERDIR/home ]]; then USERDIR="${USERDIR}/home"; fi
	else
		USERDIR="/home"
		unset BASEFSVOL
	fi
}

function verifysession() {
	# param1 - the session number (of the current repo)
	local THIS_SESSION_ERR
	if [[ -n $VERBOSE ]]; then
		echo -en "\n    $(date +%H:%M:%S): $1 $ATTIME: Starting"
	elif [[ -z $QUIET ]]; then
		echo -n "."
	fi
	local SETTEMPDIR
	[[ -n $TEMPORARYDIR ]] && SETTEMPDIR=--tempdir
	# add session to run file so other processes/programs (e.g. remote-verify-compare.sh) can tell this verification is underway
	[[ -n $ALTERNATE ]] && echo -e "# adding $REPO,$ATTIME - at $(date +"%F %T")\n$REPO,$ATTIME" >>"/tmp/$THIS-live-$$.run"
	echo "Verifying $REPO session $1 $ATTIME (start $(date +"%F %T")):" >"/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
	local VERIFY_LOOP
	VERIFY_LOOP=0
	local RDIFFBACKUPERR
	while true; do
		(( VERIFY_LOOP++ ))
		if [[ $RDIFF_BACKUP_VER -le 20500 ]]; then
			# shellcheck disable=SC2086
			COLUMNS=30000 rdiff-backup $SETTEMPDIR $TEMPORARYDIR --verify-at-time "$ATTIME" "$REPO" >"/tmp/$THIS-$$-$REPONUM-$1-errmsg0.txt" 2>&1
			RDIFFBACKUPERR=$?
		else # new CLI [14 Feb 2024]
			# shellcheck disable=SC2086
			COLUMNS=30000 rdiff-backup --api-version 201 $SETTEMPDIR $TEMPORARYDIR verify --at "$ATTIME" "$REPO" >"/tmp/$THIS-$$-$REPONUM-$1-errmsg0.txt" 2>&1
			RDIFFBACKUPERR=$?
		fi
		# retry a few times if it is a segmentation fault 139 or 'futex' 134 [13 Apr 2022]
		[[ $RDIFFBACKUPERR -ne 139 && $RDIFFBACKUPERR -ne 134 ]] || [[ VERIFY_LOOP -gt 3 ]] && break
		echo -e "$(date +"%F %T") rdiff-backup fault $RDIFFBACKUPERR (attempt $VERIFY_LOOP), trying again:\n                    rdiff-backup --verify-at-time $ATTIME $SETTEMPDIR $TEMPORARYDIR \"$REPO\""
	done
	[[ $VERIFY_LOOP -gt 1 ]] && echo "$(date +"%F %T") rdiff-backup verification completed with exit code $RDIFFBACKUPERR"
	if [[ -s "/tmp/$THIS-$$-$REPONUM-$1-errmsg0.txt" ]]; then
		grep -vxFf "/tmp/$THIS-$$-errmsg-excludes.txt" "/tmp/$THIS-$$-$REPONUM-$1-errmsg0.txt" >>"/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
	else
		truncate -s0 "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
	fi
	[[ -z $DEBUG ]] && rm -- "/tmp/$THIS-$$-$REPONUM-$1-errmsg0.txt"
	[[ -n $ALTERNATE ]] && sed -i '/^'"${REPO//\//\\/},$ATTIME"'$/{s/^/# ending /;s/$/ - at '"$(date +"%F %T")"'/}' "/tmp/$THIS-live-$$.run"
	# If exit code is not 0 or 2 we regard it as fatal.
	if [[ $RDIFFBACKUPERR -gt 0 ]]; then
		if [[ $RDIFFBACKUPERR -eq 2 ]]; then
			# error 2 means one or more files could not be verified but we should compare output text against
			# $IGNORESFILE and also certain common messages and see if we are left with anything else
#			grep -vxFf "$IGNORESFILE" "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"|sed '/^$/d;/^WARNING: Server will be called with deprecated command line interface/d;/^Verifying /d;/^Not all files could be verified.$/d;/^Your backup repository may be corrupted!$/d;/^WARNING: Action verify emitted warnings/d;/^ERROR: Verification found/d;/^A regular file was indicated by the metadata, but could not be$/{N;N;N;N;d}' >"/tmp/$THIS-$$-$REPONUM-$1-errmsg2.txt"
			grep -vxFf "$IGNORESFILE" "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"|sed '/^$/d;/^WARNING: Server will be called with deprecated command line interface/d;/^Verifying /d;/^Not all files could be verified.$/d;/^Your backup repository may be corrupted!$/d;/^WARNING: Action verify emitted warnings/d;/^ERROR: Verification found/d;/^A regular file was indicated by the metadata, but could not be$/{d}' >"/tmp/$THIS-$$-$REPONUM-$1-errmsg2.txt"
			# if the only failures are 'ignores', truncate the original error file to prevent them appearing at the end
			[[ -s /tmp/$THIS-$$-$REPONUM-$1-errmsg2.txt && -z $TV_TESTING ]] || truncate -s0 "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
		fi
		if [[ -s "/tmp/$THIS-$$-$REPONUM-$1-errmsg2.txt" || $RDIFFBACKUPERR -ne 2 ]]; then
			echo -e "\n    $(date +%H:%M:%S): $1 $ATTIME: FAILED with error $RDIFFBACKUPERR"
			[[ -s /tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt ]] && cat "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
			echo -e "\n$REPO session $ATTIME failed verification\n">&2
			THIS_SESSION_ERR=1
			# when all verifications are completed, this file will hold one line for each verification error
			echo "rdiffbackup error $RDIFFBACKUPERR on repo $REPO session $ATTIME ($1)" >>"/tmp/$THIS-$$-repo_errs.txt"
			#THIS_REPO_ERR=$((THIS_REPO_ERR+1))
			#echo "$SESSION failed" >>"/tmp/$THIS-$$-failed.txt"
		elif [[ -n $VERBOSE ]]; then
			echo -en "\n    $(date +%H:%M:%S): $1 $ATTIME: Error $RDIFFBACKUPERR treated as ignorable"
		fi
	else
		[[ -n $VERBOSE ]] && echo -en "\n    $(date +%H:%M:%S): $1 $ATTIME: Verified OK"
		if grep -Eq "(All files|Every file) verified successfully" "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt" >/dev/null; then
			#[[ $(<"/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt" wc -l) -eq 2 ]] && rm -- "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
			rm -- "/tmp/$THIS-$$-$REPONUM-$1-errmsg1.txt"
		else
			echo -e "\n    $(date +%H:%M:%S): $1 $ATTIME: but missing '(All files|Every file) verified successfully' text" >&2
		fi
	fi
	if [[ -n $THIS_SESSION_ERR ]]; then
		# delete this repo from the verify list if it was there and if this was a genuine (exit code 2) verification failure
		# (we don't delete if exit code 1 cos it might just be an abort which would have verified successfully if it had
		#  been allowed to run to completion)
		[[ -s "$ORIGD/verified.log" && $RDIFFBACKUPERR -ne 1 ]] && sed -i "/$ATTIME/d" "$ORIGD/verified.log"
	else
		# if completed a successful verification and there were previous faked verifications, add them to the verified.log
		[[ -s "$ORIGD/verified-fake.log" ]] && cat "$ORIGD/verified-fake.log" >>"$ORIGD/verified.log" && rm -- "$ORIGD/verified-fake.log"
		# record successful verification. If it is the most recent session, precede the datetime record with 'R'
		# - when/if this is no longer the most recent session it should be verified again
		[[ $1 -eq $SESSIONS ]] && local GREPADD="R"
		echo "$GREPADD$ATTIME,$(date +"%F %T"),$RDIFFBACKUPERR">>"$ORIGD/verified.log" || echo -e "\nUnable to write to '$ORIGD/verified.log' to '$VNAME'">&2
		local VNAME
		VNAME=$(stat -c %U "$ORIGD")
		if [[ "$VNAME" != "$(stat -c %U "$ORIGD/verified.log")" ]]; then
			chown "$VNAME:" "$ORIGD/verified.log" || echo -e "\nUnable to set ownership of '$ORIGD/verified.log' to '$VNAME'">&2
		fi
	fi
	return $THIS_SESSION_ERR
}

THIS=$(basename "$0")
if test -t 0; then # we are running from a terminal (specifically, using standard input)
  COLUMNS=$(stty size 2>/dev/null||echo 80); COLUMNS=${COLUMNS##* }
else
  COLUMNS=30000
fi
CONCURRENT=1
ACTION="Verify"
INCFAKE="F\?"
ARCHIVENAME_UNMATCH="xyzabcXYZABC"
while getopts ":a:bd:efhilmn:qrst:vu:wx:z:12345:6" optname; do
	case "$optname" in
		"a")	ABORTAT=$(date +%s -d "$OPTARG" || { echo "Invalid -a date format, aborting" >&2; exit 1; });;
		"b")	RDIFFWEBFIX="y";;
		#"c")	CONCURRENT="$OPTARG";;
		"d")	TODATE="$OPTARG";;
		"e")	DEBUG="y";;
		"f")	FULL="y";;
		"h")	HELP="y";;
		"i")	CONTINUE_ON_ERROR="y";;
		"l")	CHANGELOG="y";;
		"m")	USELVM="y";;
		"n")	ARCHIVENAME_MATCH="$OPTARG";;
		"q")	QUIET="y";;
		"r")	RETEST="y"; unset INCFAKE;;
		"s")	SHOWONLY="y";ACTION="Show";;
		"t")	TEMPORARYDIR="$OPTARG";;
		"u")	FORUSER="/$OPTARG";;
		"v")	VERBOSE="y";;
		"w")	COLUMNS="30000";;
		"x")	ARCHIVENAME_UNMATCH="$OPTARG";;
		"z")	DOLAST="$OPTARG";;
		"1")	ONLYOLDEST="y";;
		"2")	SKIPMOSTRECENT="y";;
		"3")	ALTERNATE="y";;
		"4")	SKIPNFAKE="y";;
		"5")	SKIPNFAKE="y";FORCEOLDEST="$OPTARG";;
		"6")	unset INCFAKE;;
		"?")	echo "Unknown option $OPTARG"; exit 1;;
		*)		echo "Unknown error while processing options"; exit 1;;
	esac
done
shift $((OPTIND-1))
[[ -z $QUIET || -n $HELP || -n $CHANGELOG ]] && echo -e "\n$THIS v$VERSION by Dominic (try -h for help)\n${THIS//?/=}\n"
[[ -n $DEBUG ]] && echo "\$COLUMNS: '$COLUMNS'"
if [[ -n $HELP ]]; then
	echo -e "Verifies integrity of rdiff-backup repositories at \
/home/*/[here] and /home/*/*/[here]. \
Unless options -f or -d are used it just verifies the most recent session \
in each repository (this session is held in the clear in the repository). \
With -f or -d options it may take a long time!

If run by root (or with sudo) $THIS checks repositories for all users (as \
restricted by -u, -n and -x options), otherwise it checks only the current \
user's repositories. A non-zero exit code is returned \
if one or more problems were found.

Each successful verification for a repository session is saved in that \
repository's rdiff-backup-data/verified.log file; on a subsequent run \
that session is skipped for verification unless -r option is used. This file \
therefore provides a linear record of successful verifications in the form \
[datetime-of-original-session],[datetime-when-verified],[rdiff-backup exit code].

You can override problem detection (if you have a known reported problem \
which is not in fact such or you do not consider fatal) by adding the \
error text to /opt/$THIS-ignore.txt, any \
whole line matches for such text will be ignored on future runs. Lines \
in this ignore file where the first non-whitespace is a hash (#) are \
disregarded i.e. will not trigger an ignoral and can therefore \
be used for comments.

Normally $THIS will exit immediately if rdiff-backup reports an error \
(unless the error text is matched in /opt/$THIS-ignore.txt), but you \
can override this behaviour with -i option.

Also with -b option (deprecated) it fixes ownership of restore.log files \
(which Rdiffweb may have created and set to root ownership, thus \
causing warning errors upon user trying to retrieve files).

$THIS is part of the TimeDicer Server software suite.

Usage:\t $THIS [options]

Options:
  -a [datetime] - stop (abort) verifications at datetime (with exit code 0) *
  -b - fix ownership of any Rdiffweb-created restore.log files
  -d [datetime] - verify backup sessions back to session on, or next before, \
datetime *
  -e - debug mode (unexpected things may happen)
  -f - verify all sessions in each repository (slowest)
  -h - show this help and quit
  -i - continue after rdiff-backup reports an error (aka 'ignore')
  -l - show changelog and quit
  -m - create and use lvm snapshot of source data (discarded at end)
  -n [name] - check only repositories containing text 'name' (egrep-type \
regex) in their pathname (cf. -x)
  -q - quiet (text output only on error)
  -r - don't skip any repository sessions previously verified as ok
  -s - list backup sessions and date/time of the corresponding previous \
verification session (if any), then quit
  -t [tmpdir] - use tmpdir for temporary storage
  -u [user] - only for named user (ignored unless run by root)
  -v - verbose output
  -x [name] - skip any repositories containing text 'name' (egrep-type regex) \
in their pathname (cf. -n)
  -z [name] - process any repositories with path containing text 'name' (sed-type regex) last
  -1 - verify only the earliest session for each repository that falls \
within the specification (cf. -4,-5)
  -2 - skip verification of the most recent session for each repository
  -3 - skip any verifications that are in progress elsewhere, normally in a \
 different session on the same machine, but with an additional script can \
also detect sessions in progress on another (i.e. mirror) machine
  -4 - skip all verifications that would be performed for each repository \
except the earliest and instead mark them in that repo's verified.log as \
having been performed but with a special 'fake' flag. Sessions thus marked \
will be skipped on any subsequent run of $THIS for this repository \
unless -6 or -r is specified. In effect this is the same as running $THIS -1, \
or running rdiff-backup \
--verify for the earliest verification date, but it affects future runs \
of $THIS. Marking of fake sessions in verified.log only occurs if and after \
successful verification of the earliest session, or confirmation of a \
previous successful verification of the earliest session.
  -5 [datetime] - as -4 but perform an actual verification for the earliest \
session even if it was previously successfully verified but such \
verification was performed before [datetime] *
  -6 - don't skip over 'fake' former verifications (see -4,-5)

* datetime can be but does not have to be in the format used by \
rdiff-backup; it just needs to be understood by the 'date' command \
e.g. yesterday, \"3 July 2022\", \"2 weeks ago\", \
\"2022-05-03 14:26\". See 'man date' for more details.

Why $(basename "$THIS" .sh):
rdiff-backup provides the 'verify --at' (formerly '--verify-at-time') option \
to verify a single \
repository session. However this does not record the successful verification \
nor, more importantly, does it verify any intermediate sessions. \
For instance, a file that did *not* exist at the time of the \
earlier session, *did* exist at the time of an intermediate \
session, but has subsequently been deleted, could prove irrecoverable even \
when the earlier session had been verified. You cannot even be entirely \
confident that a later version of a file that has been verified at an \
earlier date is OK (although it is highly likely).

The only way to be confident about all repository sessions is to use \
rdiff-backup's 'verify --at' option to verify each session individually. \
This is what \
$THIS accomplishes, and although it may be a slow process, by \
keeping a record of successful previous verifications \
and not (unless required by -r or -5 options) rechecking \
them, it becomes manageable. A suggested use is as a weekly cron \
job with -d \"one month ago\" option (sessions earlier than a week ago will \
normally be skipped automatically because they were verified previously).

Dependencies: awk bash column coreutils diff findutils grep lvm(optional) \
$(basename "$LVMDELETESNAPSHOT")(optional) rdiff-backup sed

License: Copyright © 2026 Dominic Raferd. Licensed under the Apache License, \
Version 2.0 (the \"License\"); you may not use this file except in compliance \
with the License. You may obtain a copy of the License at \
https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable \
law or agreed to in writing, software distributed under the License is \
distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY \
KIND, either express or implied. See the License for the specific language \
governing permissions and limitations under the License.
"|fold -sw "$COLUMNS"
fi
if [[ -n $CHANGELOG ]]; then
	# changelog
	[[ -n $HELP ]] && echo "Changelog:"
	echo -e "\
2.82 [14 Mar 2024] - bug fixes
2.81 [08 Mar 2024] - ensure non-breaking report lines from rdiff-backup, add -w option, deprecate -b option
2.80 [21 Feb 2024] - better shellcheck compliance, compatibility added for rdiff-backup v2.2, removed for v1.x and earlier
2.71 [01 Aug 2022] - allow -n and -x options to be combined
2.70 [14 Apr 2022] - further tweaks, try verification again in case of segmentation fault
2.69 [07 Apr 2022] - further tweaks
2.68 [31 Mar 2022] - more bugfixing, remove concurrency option (as it was not reliable)
2.67 [10 Mar 2022] - more concurrency bugfixing (i.e. -c option), was not spotting when a verification failed, mark concurrency as alpha status
2.66 [25 Jan 2022] - concurrency bugfixing (i.e. -c option)
2.65 [29 Jul 2020] - fix for identifying existing instances of $THIS
2.64 [26 Jul 2020] - fix for identification of rdiff-backup version and of some repos latest date
2.63 [05 Jul 2020] - small fix for verification by v2+ of pre-v2 DOS repositories
2.62 [24 Jun 2020] - don't attempt to patch compare.py for rdiff-backup v2+, but warn for v2.0.0
2.61 [03 Jan 2019] - small tweak to help text
2.60 [24 May 2017] - serious bugfix - was not patching rdiff_backup/compare.py
2.54 [29 Mar 2016] - serious bugfix - v2.25-2.53 were failing to detect many verification failures
2.53 [25 Feb 2016] - bugfix unnecessary re-verification of single session repos with -d
2.52 [12 Feb 2016] - bugfix -5 option
2.51 [29 Jan 2016] - add -5 option (renumber previous -5 as -6)
2.50 [13 Jan 2016] - add -4 and -5 options ('fake' verifications)
2.49 [17 Dec 2015] - add automatic patching of rdiff_backup/compare.py
2.48 [16 Dec 2015] - bugfix -z option
2.47 [15 Dec 2015] - add -z option
2.46 [15 Dec 2015] - bugfix -3 option
2.45 [14 Dec 2015] - add -3 option
2.44 [12 Dec 2015] - bugfix -a option
2.43 [09 Dec 2015] - add -a option
2.42 [30 Nov 2015] - bugfix for error detection, depends on modified \
compare.py, bugfix for -1 option
2.41 [19 Nov 2015] - bugfix for -1 option
2.40 [16 Nov 2015] - treat non-zero exitcode <> 2 from rdiff-backup as fatal \
(fix bug whereby killing/aborting process - exit code 1 - set a success \
'flag' for the, in fact incomplete, verification action)
2.30 [08 Nov 2015] - add -1 option
2.26 [29 Oct 2015] - default concurrent sessions = 1
2.25 [21 Oct 2015] - add -e debug mode, bugfix use of /opt/$THIS-ignore.txt
2.24 [04 Oct 2015] - abort if an instance of $THIS is already running as a different process
2.23 [14 Jan 2015] - don't touch verified.log file(s) unless need to be updated
2.22 [08 Dec 2014] - bugfix, was not using exit code >0 when error found in \
repository (except the last)
2.21 [11 Oct 2014] - bugfix, was not counting errors that occurred with rdiff-backup --list-increments
2.20 [27 Mar 2014] - use rdiff-backup --list-increments to \
obtain list - avoid checking null increments
2.15 [10 Oct 2013] - tweak snapshot settings to allow concurrent runs of $THIS
2.14 [09 Oct 2013] - changes to text output, reassign -o option to -x
2.13 [19 Sep 2013] - add (-o ->) -x option
2.12 [19 Feb 2013] - web help layout fix, reassign -w to -b
2.10 [09 Jul 2012] - first public release
2.04 [10 Jun 2012] - improved concurrency
2.03 [09 Jun 2012] - add -c, -m, -n, -t options
2.02 [06 Jun 2012] - bugfixes
2.0105 [05 Jan 2012] - hide lvremove non-error text on removing snapshot
1.1230 [30 Dec 2011] - (create and) use /home/tmp as TMPDIR, add -l option to show this changelog
1.0818 [18 Aug 2011] - add use of LVM snapshot if available (for root only), add -u and -d options
1.0817 [17 Aug 2011] - add non-root usage, add -s option "|fold -sw "$COLUMNS"
fi
[[ -n $HELP$CHANGELOG ]] && exit 0
[[ -n $DEBUG ]] && echo "Debug mode"
if [[ -n $TODATE ]]; then
	[[ -n $FULL ]] && { echo "Incompatible options -f and -d, aborting...">&2; exit 1; }
	TODATEEPOCH=$(date -d "$TODATE" +%s 2>/dev/null)
	# reject invalid dates or dates before 1/1/2005
	[[ $TODATEEPOCH -ge 1104537600 ]] || { echo "Invalid date '$TODATE' on command line, aborting...">&2; exit 1; }
fi
if [[ -n $FORCEOLDEST ]]; then
	FORCEEPOCH=$(date -d "$FORCEOLDEST" +%s 2>/dev/null)
	# reject invalid dates or dates before 1/1/2005
	[[ $FORCEEPOCH -ge 1104537600 ]] || { echo "Invalid date '$FORCEOLDEST' on command line, aborting...">&2; exit 1; }
fi
if [[ "$(id -u)" != "0" ]]; then
	unset FORUSER
	THISUSER="$USER"
	USERDIR="/home/$USER"
	ORIGUSERDIR="$USERDIR"
	USERTEXT="${USER}'s"
else
	THISUSER="root"
	ORIGUSERDIR="/home"
	if [[ -z $FORUSER ]]; then
		USERTEXT="all users'"
	else
		if [[ ! -d /home/$FORUSER ]]; then
			echo "Can't find home directory for user $FORUSER, aborting"
			exit 1
		fi
		USERTEXT="${FORUSER}'s"
	fi
	set_userdir
fi
# historically (and still in Ubuntu 20.04) ps only matches on first 15 chars of the command name, so test for this too
for COMMANDNAME in "$THIS" "${THIS:0:15}"; do
	PRIOR="$(ps --no-headers -wwo "s,pid,ppid,sid,args" -C "$COMMANDNAME" |sed -n "/${THIS:0:1}\\${THIS:1} /{/^[XZ] /d;/ $$ /d;/ $PPID /d;p}")"
	[[ -n $PRIOR ]] && { echo -e "$THIS is already running:\n$PRIOR\nOur PID/PPID: $$,$PPID\nAborting...">&2; exit 1; }
done
SKIPPEDVSESSIONSTOTAL=0; VSESSIONSTOTAL=0
PREVFAKEDVSESSIONSTOTAL=0; FAKEDVSESSIONSTOTAL=0
if [[ -n $VERBOSE ]]; then
	echo "$(date +"%F %T") ${ACTION}ing $USERTEXT rdiff-backup repositories at $ORIGUSERDIR$FORUSER"
elif [[ -z $QUIET ]]; then
	echo -e "Starting $(date +"%F %T")\n${ACTION}ing repositories at $USERDIR"
fi

# retrieve rdiff-backup version as 5+ digit number e.g. 20005 (for 2.0.5) or 10302 for 1.3.2b
< <(rdiff-backup --version 2>/dev/null|sed 's/rdiff-backup\s*//'|awk -F '[^[:digit:]]+' '{printf "%s",$1; for (f=2;f<=3;f++) printf "%02.0f",$f}') read -r RDIFF_BACKUP_VER
[[ $RDIFF_BACKUP_VER =~ ^[1-9][0-9]{4,}$ ]] || { echo "Cannot recognise rdiff-backup version '$RDIFF_BACKUP_VER', aborting...">&2; exit 1; }
[[ -z $QUIET ]] && echo "Using $(rdiff-backup --version)"
[[ $RDIFF_BACKUP_VER -lt 20001 ]] && { echo -e "$THIS requires rdiff-backup v2.0.1 or higher, sorry"; exit 1; }
if [[ -z $QUIET ]]; then
	#echo "Maximum $CONCURRENT concurrent verification operations"
	if [[ -z $SHOWONLY ]]; then
		[[ -n $ARCHIVENAME_MATCH ]] && echo "Checking only repositories with '$ARCHIVENAME_MATCH' in pathname"
		[[ $ARCHIVENAME_UNMATCH != "xyzabcXYZABC" ]] && echo "Checking only repositories without '$ARCHIVENAME_UNMATCH' in pathname"
		if [[ -n $FULL ]]; then
			echo "Verification of all sessions in each repository"
		elif [[ -n $TODATE ]]; then
			echo "Verification of sessions back to $TODATE from each repository"
		else
			echo "Verification of most recent session in each repository"
		fi
		if [[ -n $ONLYOLDEST ]]; then
			echo "  - filtered for only the earliest such session"
		fi
		[[ -n $ABORTAT ]] && echo "Will abort if still running at $(date -d @"$ABORTAT" +"%F %T")"
		[[ -n $ALTERNATE ]] && echo "Skipping verifications that are underway elsewhere"
		[[ -n $SKIPNFAKE ]] && echo "Skipping verifications except the earliest and marking such as 'fake' verified"
		[[ -n $FORCEOLDEST ]] && echo " - forcing verification of earliest if last verified before $FORCEOLDEST"
		[[ -z $INCFAKE ]] && echo "Not skipping any previously 'faked' verifications"
		[[ -n $DOLAST ]] && echo "Repositories with path containing '$DOLAST' will be processed last"
		[[ -n $CONTINUE_ON_ERROR ]] && echo "Continuing with further verifications after any verification failure"
		[[ -n $TEMPORARYDIR ]] && echo -e "Using tempdir $TEMPORARYDIR"
		echo "This may take a long time! Please be patient..."
		if [[ -z $RETEST ]]; then
			echo "Skipping previously verified sessions"
			if [[ -z $VERBOSE ]]; then
				echo -e "  . indicates session that is undergoing/has undergone current verification\n  - indicates session skipped because previously verified"
				[[ -n $ALTERNATE ]] && echo "  ' indicates session skipped because it is being verified elsewhere"
				[[ -n $SKIPMOSTRECENT ]] && echo "  + indicates session skipped because it is the most recent"
				[[ -n $SKIPNFAKE ]] && echo "  F indicates session skipped and 'fake' verified"
				[[ -n $INCFAKE ]] && echo "  f indicates session skipped because previously 'fake' verified"
			fi
		fi
	else
		echo "Note: If 'Most_Recent_Only' shows 'y', then this \
has only been verified as the most recent session and it will be \
retested for full verification when $THIS is re-run after a subsequent \
backup session."|fold -sw "$COLUMNS"
	fi
fi
# if basearchive in TimeDicer configuration file is blank then depth will be 3,
#   i.e. repositories are at /home/[user]/[repository]
# if basearchive is one folder deep (e.g. archives/) then depth will be 4,
#   i.e. repositories are at /home/[user]/[basearchive]/[repository]
# - to cover both possibilities use -mindepth 3 -maxdepth 4
[[ -n $DEBUG ]] && echo -e "MYPID    : $$\nBASEFSVOL: $BASEFSVOL\nBASEFS   : $BASEFS\nSearching $USERDIR$FORUSER for repositories"
[[ -z $SHOWONLY$QUIET ]] && echo -n "$(date +%H:%M:%S) "
[[ -z $QUIET ]] && echo -n "Total repositories found: "
find "$USERDIR$FORUSER" -mindepth 2 -maxdepth 4 -type d -regextype egrep -regex ".*$ARCHIVENAME_MATCH.*/rdiff-backup-data$" ! -regex ".*$ARCHIVENAME_UNMATCH.*/rdiff-backup-data$" 2>/dev/null|sort >"/tmp/$THIS-$$.repos"
#	[[ -n $DEBUG ]] && echo "Doing: find \"$USERDIR$FORUSER\" -mindepth 2 -maxdepth 4 -type d -regextype egrep ! -regex \".*$ARCHIVENAME.*\" -regex \".*/rdiff-backup-data$\" 2>/dev/null|sort"
#	find "$USERDIR$FORUSER" -mindepth 2 -maxdepth 4 -type d -regextype egrep ! -regex ".*$ARCHIVENAME.*" -regex ".*/rdiff-backup-data$" 2>/dev/null|sort >"/tmp/$THIS-$$.repos"
# shellcheck disable=SC2016
[[ -n $DOLAST ]] && sed -i "/${DOLAST//\//\\/}"'/{H;d};${G;s/\n//}' "/tmp/$THIS-$$.repos"
REPOTOTAL=$(<"/tmp/$THIS-$$.repos" wc -l)
REPOERRTOTAL=0
[[ -n $DEBUG ]] && echo "got here 123"
[[ -z $QUIET ]] && { echo -n "$REPOTOTAL"; [[ -n $SHOWONLY ]] && echo; }
REPONUM=0
VSESSIONSABORTED=0
OLDIFS=$IFS; IFS=$'\n'
#WHEN=$(date --rfc-3339=seconds|sed 's/ /T/')
IGNORESFILE="/tmp/$THIS-$$-ignore.txt"
if [[ -s /opt/$THIS-ignore.txt ]]; then
	grep -v '^\s*#' "/opt/$THIS-ignore.txt" >"$IGNORESFILE"
else
	truncate -s0 "$IGNORESFILE"
fi
# create a list of output messages from verification sessions which never indicate a real problem (and will be skipped)
echo -e "WARNING: this command line interface is deprecated and will disappear, start using the new one as described with '--new --help'.\nWARNING: POSIX ACLs file not found\nWARNING: Extended Attributes file not found\nWarning: special_escapes file not found,\nwill assume need to escape DOS devices and trailing spaces based on file systems.\nWarning: Access Control List file not found\nWarning: Extended Attributes file not found" >"/tmp/$THIS-$$-errmsg-excludes.txt"

[[ -n $DEBUG ]] && echo "got here 133"
touch "/tmp/$THIS-$$-repo_errs.txt"
while read -r D; do
	[[ -n $DEBUG ]] && echo "got here 143"
	[[ -s "/tmp/$THIS-$$-repo_errs.txt" && -z $CONTINUE_ON_ERROR ]] && break
	[[ -n $ABORTAT && $(date +%s) -ge $ABORTAT ]] && { [[ -n $VERBOSE ]] && echo -e "\n$(date +%T): abort timeout reached"; break; }
	# shellcheck disable=SC2001
	REPO=$(echo "$D"|sed 's~/[^/]*$~~')
	if [[ -n $BASEFSVOL ]]; then
		ORIGD="/$BASEFS${D:${#USERDIR}}"
		ORIGREPO="/$BASEFS${REPO:${#USERDIR}}"
	else
		ORIGD=$D; ORIGREPO=$REPO
	fi
	[[ -n $DEBUG ]] && echo "got here 153"
	[[ -n $SKIPNFAKE ]] && { [[ -n $DEBUG ]] && echo "got here 154"; echo -n >"$ORIGD/verified-fake.log" || { echo -e "\nUnable to write to '$ORIGD/verified-fake.log'">&2; exit 1; } }
	[[ -n $DEBUG ]] && echo "got here 155"
	REPONUM=$((REPONUM+1))
	[[ -n $DEBUG ]] && echo -e "\nD        : $D\nREPO     : $REPO\nORIGD    : $ORIGD\nORIGREPO : $ORIGREPO\nREPONUM  : $REPONUM"
	if [[ -z $QUIET ]]; then
		echo
		[[ -z $SHOWONLY ]] && echo -en "  $(date +%H:%M:%S) "
		echo -en "$REPONUM/$REPOTOTAL "
	fi
	[[ -n $DEBUG ]] && echo "got here 163"
	[[ -z $QUIET || -n $SHOWONLY ]] && echo -n "\"$ORIGREPO\""
	if [[ $RDIFF_BACKUP_VER -le 20500 ]]; then
		rdiff-backup --list-increments "$REPO" >"/tmp/$THIS-$$.sessions" 2>/dev/null || { (( REPOERRTOTAL++ )); continue; }
	else
		rdiff-backup --api-version 201 list increments "$REPO" >"/tmp/$THIS-$$.sessions" 2>/dev/null || { (( REPOERRTOTAL++ )); continue; }
	fi
	sed -i '/increments\./{s/.*increments\.//;s/\.dir.*//;p};d' "/tmp/$THIS-$$.sessions"
	# add the most recent session using the actual datetime
	find "$REPO/rdiff-backup-data" -maxdepth 1 -type f -name "file_statistics.*.data.gz"|grep -E -o "20[0-9]{2}-[0-9]{2}-[0-9]{2}[^.]*"|sort -r|head -n 1 >>"/tmp/$THIS-$$.sessions"
	SESSIONS=$(wc -l "/tmp/$THIS-$$.sessions"|awk '{print $1}')
	if [[ -z $SHOWONLY ]]; then
		if [[ -n $FULL ]]; then
			[[ -n $ONLYOLDEST ]] && sed -i '2,$d' "/tmp/$THIS-$$.sessions" && SESSIONS=1
			LASTSESSION=1; FIRSTSESSION=$SESSIONS
			[[ -z $QUIET ]] && echo -n " - checking all of $SESSIONS sessions"
		elif [[ -n $TODATEEPOCH ]]; then
			FIRSTSESSION=$SESSIONS
			# to work out the last session we look through the session
			# dates in reverse order and find the first one that is on or
			# before date, this does it in one (rather complex) line:
			COUNTER=0; REVERSELIST=$(tac "/tmp/$THIS-$$.sessions")
			for LINE in $REVERSELIST; do
				(( COUNTER++ ))
				echo -n "$LINE"|sed 's/T/ /'|xargs -I {} date +"%s" -d {}|xargs -I {} test "$TODATEEPOCH" -ge {} && break
			done
			LASTSESSION=$((SESSIONS-COUNTER+1))
			if [[ -n $ONLYOLDEST ]]; then
				FIRSTSESSION=$LASTSESSION
				[[ -z $QUIET ]]  && echo -n " - checking earliest session within the date span"
			elif [[ -z $QUIET ]]; then
				echo -n " - checking most recent $COUNTER of $SESSIONS sessions"
			fi
		else
			LASTSESSION=$SESSIONS; FIRSTSESSION=$LASTSESSION
			[[ -z $QUIET ]] && echo -n " - checking most recent 1 of $SESSIONS sessions"
		fi
	else
		echo
		echo "Num,Backup_Session_When,Verified_When,Most_Recent_Only">"/tmp/$THIS-$$-sessions.csv"
		REVERSELIST=$(tac "/tmp/$THIS-$$.sessions")
		LINENUM=0
		for LINE in $REVERSELIST; do
			(( LINENUM++ ))
			if [[ -s $ORIGD/verified.log ]]; then
				if [[ $LINENUM -eq 1 ]]; then
					LINEFOUND=$(grep "$LINE" "$ORIGD/verified.log")
				else	#skip any 'R' sessions except the most recent cos irrelevant
					LINEFOUND=$(grep --color=NEVER "^$LINE" "$ORIGD/verified.log")
				fi
				if [[ -n $LINEFOUND ]]; then
					LINE="$LINEFOUND"
					if [[ "${LINE:0:1}" == "R" ]]; then
						LINE="${LINE:1:999},y"
					fi
				fi
			fi
			echo "$LINENUM,${LINE/T/ }">>"/tmp/$THIS-$$-sessions.csv"
		done
		column -s, -t "/tmp/$THIS-$$-sessions.csv"
		continue
	fi
	if [[ -z $QUIET ]]; then
		if [[ -s "/tmp/$THIS-$$.sessions" ]]; then
			echo -n " ("
			if [[ -z $VERBOSE ]]; then
				echo -n "$(sed -n "${FIRSTSESSION}p" "/tmp/$THIS-$$.sessions")"
				[[ $LASTSESSION -ne $FIRSTSESSION ]] && echo -n " "
			fi
			[[ $LASTSESSION -ne $FIRSTSESSION ]] && echo -n "to $(sed -n "${LASTSESSION}p" "/tmp/$THIS-$$.sessions")"
			echo -n ")"
		fi
		echo -n ": "
	fi
	# now loop through the sessions for this repository
	for ((SESSION=FIRSTSESSION; SESSION>=LASTSESSION; SESSION--)); do
		# note: we can't test conclusively whether there has been an error on this repo because of (possible) concurrency
		[[ -s "/tmp/$THIS-$$-repo_errs.txt" && -z $CONTINUE_ON_ERROR ]] && break
		# decide whether to skip
		ATTIME=$(sed -n "${SESSION}p" "/tmp/$THIS-$$.sessions")
		# if on most recent session accept a prevous verify session preceded by R
		[[ $SESSION -ne $SESSIONS ]] && GREPPRC="^" || GREPPRC=""
		[[ ! -f "$ORIGD/verified.log" ]] && touch "$ORIGD/verified.log"
		if [[ -z $RETEST && -n $FORCEOLDEST && $SESSION == "$LASTSESSION" ]]; then
			SESSIONT=$(grep "$GREPPRC$ATTIME" "$ORIGD/verified.log" 2>/dev/null|awk -F, '{print $2}'|sort -rn|head -n1)
			if [[ -n $SESSIONT ]]; then
				SESSIONEPOCH=$(date -d "$SESSIONT" +%s 2>/dev/null)
				[[ -n $VERBOSE ]] && LAST_TEXT="last verified $SESSIONT"
			else
				SESSIONEPOCH=0
				[[ -n $VERBOSE ]] && LAST_TEXT="no previous verification found"
			fi
			if [[ $SESSIONEPOCH -lt $FORCEEPOCH ]]; then
				FORCINGOLDEST="y"
				[[ -n $VERBOSE ]] && echo -en "\n    $ATTIME (last session): $LAST_TEXT - re-verifying"
			else
				unset FORCINGOLDEST
			fi
		else
			unset FORCINGOLDEST
		fi
		if [[ $SESSION == "$SESSIONS" && -n $SKIPMOSTRECENT ]]; then
			(( SKIPPEDVSESSIONSTOTAL++ ))
			if [[ -n $VERBOSE ]]; then
				echo -en "\n    $(date +%H:%M:%S): $SESSION $ATTIME: Skipping (most recent session)"
			elif [[ -z $QUIET ]]; then
				echo -n "+"
			fi
		elif [[ -z $RETEST$FORCINGOLDEST && -s "$ORIGD/verified.log" ]] && grep -q "$GREPPRC$ATTIME" "$ORIGD/verified.log"; then
			(( SKIPPEDVSESSIONSTOTAL++ ))
			if [[ -n $VERBOSE ]]; then
				echo -en "\n    $(date +%H:%M:%S): $SESSION $ATTIME: Skipping (last verified $(tac "$ORIGD/verified.log"|grep -m1 "$GREPPRC$ATTIME" "$ORIGD/verified.log"|cut -d, -f2))"
			elif [[ -z $QUIET ]]; then
				echo -n "-"
			fi
		elif [[ -z $RETEST$FORCINGOLDEST && -s "$ORIGD/verified.log" ]] && grep -q "$GREPPRC$INCFAKE$ATTIME" "$ORIGD/verified.log"; then
			(( SKIPPEDVSESSIONSTOTAL++ )); (( PREVFAKEDVSESSIONSTOTAL++ ))
			if [[ -n $VERBOSE ]]; then
				echo -en "\n    $(date +%H:%M:%S): $SESSION $ATTIME: Skipping (previously faked verification)"
			elif [[ -z $QUIET ]]; then
				echo -n "f"
			fi
		elif [[ -z $RETEST$FORCINGOLDEST && -n $SKIPNFAKE && $SESSION != "$LASTSESSION" ]]; then
			(( SKIPPEDVSESSIONSTOTAL++ )); (( FAKEDVSESSIONSTOTAL++ ))
			if [[ -n $VERBOSE ]]; then
				echo -en "\n    $(date +%H:%M:%S): $SESSION $ATTIME: Skipping (faking verification)"
			elif [[ -z $QUIET ]]; then
				echo -n "F"
			fi
			# record fake verification
			echo "F$ATTIME,$(date +"%F %T")">>"$ORIGD/verified-fake.log" || echo -e "\nUnable to write to '$ORIGD/verified-fake.log'">&2
		else
			if [[ -n $ALTERNATE ]]; then
				# search for any other $THIS processes which are running and make sure not to duplicate their current verification
				[[ -n $DEBUG ]] && echo -en "\nDEBUG: ALTERNATE find output: " && find /tmp -maxdepth 1 -name "$THIS-live-*.run" -not -name "$THIS-live-$$.run" -mmin -4 -execdir grep "^$REPO,$ATTIME$" "{}" \+ | awk '{printf $0}'
				ALTERNATEUNDERWAY=$(find /tmp -maxdepth 1 -name "$THIS-live-*.run" -not -name "$THIS-live-$$.run" -mmin -4 -execdir grep "^$REPO,$ATTIME$" "{}" \+ 2>/dev/null)
				[[ -n $DEBUG ]] && echo -e "\nDEBUG: ALTERNATE check: ALTERNATEUNDERWAY='$ALTERNATEUNDERWAY'"
				if [[ -n $ALTERNATEUNDERWAY ]]; then	# we found a match, that means this repo/session is already being verified
					# skip this session
					[[ -n $DEBUG ]] && echo -n "DEBUG: ALTERNATE check: - match found, will skip verification"
					(( SKIPPEDVSESSIONSTOTAL++ ))
					if [[ -n $VERBOSE ]]; then
						echo -en "\n    $(date +%H:%M:%S): $SESSION $ATTIME: Skipping (alternate process)"
					elif [[ -z $QUIET ]]; then
						echo -n "'"
					fi
					continue
				elif [[ -n $DEBUG ]]; then
					echo -n "DEBUG: ALTERNATE check: - match not found, will continue with verification"
				fi
			fi
			if [[ $CONCURRENT -le 1 ]]; then
				verifysession "$SESSION" || break # don't verify earlier sessions in same repo if there was a failure
			else
				# now check if there are already $CONCURRENT sessions in progress, wait if there are
				while true; do
					# for jobs command see 'help jobs'
					read -ra RUNNING < <(jobs -rp)
					[[ "${#RUNNING[@]}" -lt "$CONCURRENT" ]] && break
					# if we have overrun time then get out of here but end all child processes first
					if [[ -n $ABORTAT && $(date +%s) -ge $ABORTAT ]]; then
						# shellcheck disable=SC2068
						for PID in ${RUNNING[@]}; do
							# use kill -- to send TERM, kill -9 to send KILL
							CHILDPID=$(ps --no-headers --ppid "$PID" -o pid)
							[[ -n $VERBOSE ]] && echo -en "\n    $(date +%T): abort timeout reached: killing pid '$PID'\n    "
							kill -- "$PID"
							sleep 15s
							if [[ -n $CHILDPID ]]; then
								[[ -n $VERBOSE ]] && echo -n "    $(date +%T): killing child pid '$CHILDPID'"
								kill -- "$CHILDPID"
								sleep 15s
							fi
							(( VSESSIONSTOTAL-- ))
							(( VSESSIONSABORTED++ ))
							[[ -n $VERBOSE ]] && echo
							break
						done
					fi
					[[ -n $ALTERNATE ]] && touch "/tmp/$THIS-live-$$.run"
					sleep 10s   # this is not optimal, but you can't use wait here
				done
				# start a verify session and return here at once
				verifysession "$SESSION" &
			fi
			(( VSESSIONSTOTAL++ ))
		fi
		[[ -n $ABORTAT && $(date +%s) -ge $ABORTAT ]] && break
	done
	[[ -n $ABORTAT && $(date +%s) -ge $ABORTAT ]] && break
	if [[ -n $RDIFFWEBFIX && "$THISUSER" == "root" ]]; then
		UNAME=$(stat -c %U "$ORIGD")
		# now do the Rdiffweb restore.log ownership fix
		if [[ -O $ORIGD/restore.log ]]; then
			# if restore.log exists and is owned by root, change ownership
			echo -en "\nChanging $ORIGD/restore.log to owned by $UNAME"
			chown "$UNAME:" "$ORIGD/restore.log" && echo ": OK" || echo ": FAILED"
		elif [[ ! -f "$ORIGD/restore.log" ]]; then
			# create restore.log if not existing and set owner
			echo -en "\nCreating $ORIGD/restore.log as owned by $UNAME"
			touch "$ORIGD/restore.log" 2>/dev/null && chown "$UNAME:" "$ORIGD/restore.log" && echo ": OK" || echo ": FAILED"
		else
			ONAME=$(stat -c %U "$ORIGD/restore.log")
			if [[ "$UNAME" != "$ONAME" ]]; then
				echo -en "\nChanging $ORIGD/restore.log to owned by $UNAME instead of $ONAME"
				chown "$UNAME:" "$ORIGD/restore.log" && echo ": OK" || echo ": FAILED"
			elif [[ -n $VERBOSE ]]; then
				echo -en "\n$ORIGD/restore.log is already owned by $UNAME - no change required"
			fi
		fi
	fi
	[[ -s "$ORIGD/verified-fake.log" ]] && { rm -- "$ORIGD/verified-fake.log" || echo "Warning: unable to remove $ORIGD/verified-fake.log" >&2; }
done <"/tmp/$THIS-$$.repos"
IFS=$OLDIFS

# wait until all concurrent verify sessions have finished
# for jobs command see 'help jobs'
[[ -z $QUIET ]] && echo
while true; do # loop added [25 Jan 2022]
	# for jobs command see 'help jobs'
	< <(jobs -rp|wc -l) read -r RUNNING_TOT
	[[ -z $QUIET && "$RUNNING_TOT" != "$PREV_RUNNING_TOT" ]] && echo "$(date +%T) $RUNNING_TOT verifications ongoing"
	[[ $RUNNING_TOT -eq 0 ]] && break
	PREV_RUNNING_TOT=$RUNNING_TOT
	if [[ -n $ABORTAT && $(date +%s) -ge $ABORTAT ]]; then
		# this should never happen...
		[[ -z $QUIET ]] && echo "$(date +%T) Warning! Aborting (timeout) even though $RUNNING_TOT jobs are still in progress"
		break
	fi
	sleep 10s
done
REPOERRTOTAL=$(<"/tmp/$THIS-$$-repo_errs.txt" wc -l)

find /tmp -maxdepth 1 -type f -name "$THIS-$$*errmsg1.txt" -execdir cat {} \+ | grep -vxFf "$IGNORESFILE" | grep -Ev "ERROR: Verification found [1-9][0-9]+ potentially corrupted files" | sed 's/^/  /;$s/$/\n/;1iError messages:'

[[ -z $DEBUG ]] && { removesnapshot; rm -f -- "/tmp/$THIS-$$"* "/tmp/$THIS-live-$$.run"; }
if [[ -z $QUIET ]]; then
	echo -n "$(date +%T) Completed verifications: $VSESSIONSTOTAL actual, $SKIPPEDVSESSIONSTOTAL skipped"
	[[ $PREVFAKEDVSESSIONSTOTAL -ne 0 || $FAKEDVSESSIONSTOTAL -ne 0 ]] && echo -n " (of which $PREVFAKEDVSESSIONSTOTAL were previous fake verifications and $FAKEDVSESSIONSTOTAL were faked on this run)"
	echo ", $VSESSIONSABORTED aborted, $REPOERRTOTAL error(s)"
fi
exit "$REPOERRTOTAL"
