#! /bin/bash
#
#                         F L A S H B A C K
#                         -----------------
#
#                           by John Walker
#                      http://www.fourmilab.ch/
#
#   Ever accidentally typed something like "rm * .o" after
#   a busy day's productive editing?  FLASHBACK makes
#   snapshots of the directory you're working in (and any
#   subdirectories) to a common backup directory from which
#   you can restore clobbered files as required.  FLASHBACK
#   reports the size of the backup directory after adding
#   the new backup so you'll know when it's time to get rid
#   of old backups.  Command line arguments permit you to
#   back up just the current directory (no subdirectories)
#   or specific files in the current directory or elsewhere.
#
#   WHERE is the directory in which you want backups to be kept.
#   This should ideally be on an NFS (or whatever) mounted
#   location on a different machine than the one you usually
#   work on or, failing that, a file system stored on a
#   different physical device than the one you usually edit
#   within.
#
WHERE=$HOME/FLASHBACK
#
#   WHERE_ELSE is an alternative directory which, if it exists,
#   is used instead of WHERE.  This is usually set to the dynamic
#   mount point of a removable drive, such as a USB flash drive.
#   If plugged in, backups will go to it, otherwise to the usual
#   directory.
#
#WHERE_ELSE=/media/your_name/FLASHBACK
#
#   Unless you want to fiddle with how flashback names its
#   files or creates backups, you shouldn't have to change
#   anything below this comment unless you're using non-GNU
#   versions of "find" and/or "du".
#
#   Working directory translated to backup file name
#
WHAT=`echo $PWD | tr / - | sed s:-::`
#
#   ISO 8601 date and time
#
WHEN=`date +%Y-%m-%d-%H-%M-%S`
#
#   Command (must be a filter) which we use to compress
#   the backup, normally "gzip", "bzip2", or "xz".  You may, if
#   you wish, specify options (for example, compression level)
#   after this command.
#
WHY="gzip"
#WHY="bzip2"
#WHY="xz"
#
#   Extension to append to backup archives to indicate file type.
#   For GZIP backups, use '.tar.gz', for BZIP2 backups '.tar.bz2',
#   for XZ, 'tar.xz'.
#
HOW=".tar.gz"
#HOW=".tar.bz2"
#HOW=".tar.xz"
#
#   Command used to back up files.  Arguments will be appended to
#   this command to select what is backed up.
#
WHO="tar cfv - "
#
#   What we back up by default: the current directory
#
WHOM="."
#
#   Command to obtain the size of the backup directory.
#   This default assumes a System V style "du" with the "-h"
#   option; if you're using a BSD-style system, such as SunOS
#   4.x, you'll have to modify the following command.  "du -s"
#   should work on most systems.
HOWBIG="du -sh"
#
#   If you want to support backup to a remote system,
#   specify the destination host and directory.  Specifying the
#   null string disables remote backups.
#
#REMDEST="cloud:/home/your_name/FLASHBACK"

#   You shouldn't have to change anything below this line

VERSION='1.8'
DATE='2021-07-31'
#
#   Print help text if "-u" option specified.  We also accept
#   "-h", "-help", and "--help" just in case.
#
if [ "x$1" = "x-u" -o "x$1" = "x-h" -o "x$1" = "x-help" -o "x$1" = "x--help" ]
then
    echo "Usage: flashback           Back up current directory and subdirectories"
    echo "       flashback -n        Back up current directory only (no subdirectories)"
    echo "       flashback file...   Back up specified files"
    if [ "x$REMDEST" != "x" ]
    then
        echo "       flashback -r ...    Mirror backup to remote destination $REMDEST"
    fi
    echo "       flashback -u        Print this message"
    echo "Version $VERSION ($DATE)"
    echo "Backup directory: $WHERE"
    echo "The current version is available from http://www.fourmilab.ch/webtools/flashback/"
    echo "This program is in the public domain."
    exit 0
fi
#
#   If the alternative directory exists, use it.
#
if [ -d $WHERE_ELSE ]
then
    WHERE=$WHERE_ELSE
else
    #
    #   If the backup directory doesn't exist, ask if the user
    #   wants to create it.
    #
    if [ ! -d $WHERE ]
    then
        echo Backup directory $WHERE does not exist.
        echo -n "Would you like to create it (y/N) ? "
        read confirm
        if [ "$confirm" = "y" -o "$confirm" = "Y" ]
        then
            echo mkdir $WHERE
            mkdir $WHERE
            if [ ! -d $WHERE ]
            then
                echo Unable to create backup directory $WHERE -- exiting.
                exit 1
            fi
        else
            echo Backup aborted.
            exit 1
        fi
    fi
fi
#
#   If the -r option is specified, back up to the
#   designated remote destination.
#
REM=''
if [ "x$1" = "x-r" ]
then
    shift
    if [ "x$REMDEST" = "x" ]
    then
        echo "No REMDEST configured.  Cannot mirror to remote system."
        exit 1
    fi
    REM='Yes'
fi
#
#   If the "-n" option is specified, back up only
#   regular files in the current directory--do not
#   recurse into subdirectories.
#
if [ "x$1" = "x-n" ]
then
    shift
    WHOM=`find . -maxdepth 1 -type f -print`
fi
#
#   If one or more files are named, specify them as what to back up
#
if [ "x$1" != "x" ]
then
    WHOM=""
    #
    #   Verify all named files exist and are readable by this process
    #
    FILESOK=1
    for file in "$@"
    do
        if [ ! -r "$file" ]
        then
            echo File $file does not exist or is not readable.
            FILESOK=0
    else
        WHOM="$WHOM $(printf '%q' "$file")"
        fi
    done
    if [ $FILESOK -eq 0 ]
    then
        echo Type \"flashback -u\" for usage information.
        exit 1
    fi
fi

#
#   Okay, let 'er rip.  Note that we have to pass the command
#   to a sub-shell in order for escaped file names to be parsed
#   correctly.
#
#echo $SHELL $WHO $WHOM
$SHELL -c "$WHO $WHOM" | $WHY >"$WHERE/$WHAT-$WHEN$HOW"
if [ $? -ne 0 ]
then
    echo $0: Error $? creating backup.
    rm -f "$WHERE/$WHAT-$WHEN$HOW"
    exit 1
fi
#
#   Make the backup read-only to prevent tragedy if you
#   fat-finger "c" for "v" when extracting with tar.
#
chmod 444 "$WHERE/$WHAT-$WHEN$HOW"
#
#   Attempt to flush out everything which may be in file
#   system cache.  Big hammer, small drive, but what 'ya
#   gonna do?
sync "$WHERE/$WHAT-$WHEN$HOW"
#
#   Now obtain the size of the backup directory and let the
#   user know, just in case it's time for some housekeeping.
#
HOWMUCH=`$HOWBIG $WHERE | cut -f1`
echo $0: $HOWMUCH bytes in $WHERE
#
#   If the user specified the -r option, mirror the backup
#   to the specified REMDEST.
#
if [ "x$REM" != "x" ]
then
    scp -p "$WHERE/$WHAT-$WHEN$HOW" $REMDEST
fi

exit 0
