#!/bin/bash ## A user callback for backintime ## Copyright 2021 Fancesco Potortì, released under AGPL 3.0 or later version ## ## Return 0 if everything is alright. ## Any other return code cancels the running snapshot ################################################################ ## User variables PATH=/bin:/sbin:/usr/bin:/usr/sbin ## It is possible to store the backup files on a volume which is mounted before the backup and ## unmounted afterwards. If this is what you do, then set the following variables mount_point= # leave blank if no mounting and unmounting is necessary mount_point=/backup # the mount point for storing the backup files if [ "$mount_point" ]; then ## The device to mount for storing the backup files mount_dev= # leave blank if reading device from fstab mount_dev=$(/usr/sbin/findfs LABEL=backup) ## The options used when mounting the device mount_opts= # leave blank if reading options from fstab mount_opts="-o barrier,compress=zstd:15" fi ## Log maxlogs=40 ## TODO: log options: short or long log, send email, store to /var/log/ ################################################################ ## Internal variables and code ## Parameters profile_id="$1" profile_name="$2" reason="$3" local_dir=$HOME/.local/share/backintime/ # where the log file resides shortlog=$local_dir/shortlog # short log of the backup process tmplog=$local_dir/tmplog-$PPID size_file=$local_dir/init-size-$PPID ((running_under_schedule = (SHLVL == 1))) function print_free_space () { ## Indent df output by two spaces df --sync --human-readable --output=target,ipcent,used,avail,pcent $mount_point | sed 's/^/ /' echo } case $reason in 1) ## Backup process begins if ((running_under_schedule)); then # running under Cron rm --force $tmplog fi ;; esac if ((running_under_schedule)); then # running under Cron exec &>>$tmplog # all output goes to the tmplog file fi case $reason in 1) ## Backup process begins date; echo echo "- Backup process begins" if [ "$mount_point" ]; then ## Store initial filesystem size df --sync --block-size=1M --output=used $mount_point | tail -1 > $size_file print_free_space fi ;; 2) ## Backup process ends echo "- Backup process ends" ## Read takesnapshot_.log, excluding all lines containing 'BACKINTIME' and including ## only lines starting with '[I] ', remove the '[I] ' and indent by two spaces sed -n '/BACKINTIME/d; /Smart remove/d; /^\[I] /s// /p' $local_dir/takesnapshot_.log if [ "$mount_point" ]; then ## Check file system echo -n " Checking file system..." mount -o remount,ro $mount_point fstype=$(df --output=fstype $mount_point | tail -1) device=$(df --output=source $mount_point | tail -1) case $fstype in btrfs) ## --mode lowmem on an SSD 1TB filesystem increases checking time from 8 ## to 180 minutes and decreases resident memory occupancy from 7 to 5 GB #fsck="btrfs check --force --check-data-csum --mode lowmem" fsck="btrfs check --force --check-data-csum" ;; ext*) fsck="fsck -T -pf -t ext2" ;; *) fsck="fsck -T" ;; esac chkout=$($fsck $device 2>&1) chkret=$? if ((chkret == 0)); then echo " success" else if ((chkret == 137)); then echo " FAILED: killed by the oom killer" echo "Not enough memory available at the moment" else echo " FAILED: $fsck $device returned $chkret" echo $chkout fi fi print_free_space ## Compute used space isz=$(cat $size_file) fsz=$(df --block-size=1M --output=used $mount_point | tail -1) echo " ${fsz}-${isz} = *** $((fsz-isz)) MB used ***" rm --force $size_file fi echo; date if ((running_under_schedule)); then # running under Cron if command -v mailx &>/dev/null; then mailx -s backintime $LOGNAME < $tmplog fi if command -v savelog &>/dev/null; then savelog -lc $maxlogs $shortlog fi mv $tmplog $shortlog fi ;; 3) ## A new snapshot was taken snapshot_id="$4" snapshot_name="$5" echo -e "- A new snapshot $snapshot_id was taken" ;; 4) ## There was an error errorcode="$4" echo "- Signaling error code $errorcode" case $errorcode in 1) ## ERROR The application is not configured msg="ERROR The application is not configured" ;; 2) ## ERROR A 'take snapshot' process is already running msg="ERROR A 'take snapshot' process is already running" ;; 3) ## ERROR Can't find snapshots folder (is it on a removable drive ?) msg="ERROR Can't find snapshots folder (is it on a removable drive ?)" ;; 4) ## ERROR A snapshot for 'now' already exist msg="ERROR A snapshot for 'now' already exist" ;; *) ## ERROR Unknown error msg="ERROR Unknown error, probably this callback handler is outdated" ;; esac echo "$msg" ;; 5) ## backintime-qt4 (GUI) started echo "- GUI started" ;; 6) ## backintime-qt4 (GUI) closed echo "- GUI closed" ;; 7) ## Mount drives echo "- Mounting drives" if [ "$mount_point" ]; then echo "Mounting $mount_point" umount $mount_point 2> /dev/null || true mount $mount_opts $mount_dev $mount_point fi ;; 8) ## Unmount the drives echo "- Unmounting drives" if [ "$mount_point" ]; then echo "Unmounting $mount_point" umount $mount_point 2> /dev/null || true fi ;; *) ## Unknown reason echo "- Unknown callback reason, probably this callback handler is outdated" ;; esac