#!/bin/bash

# depends: at bash bsdmainutils cron sed
# depends: if ({mysql,postgresql} database specified) {mysql,postgresql}-client

declare -A CONFIG
export CONFIG
ETC=/etc
export PRE=/usr/local
export ETCDIR=$ETC/snapsched
export CFGFILE=$ETCDIR/config
export INTCRONFILE_BASE=snapsched
export CRONTAB=$ETC/cron.d/$INTCRONFILE_BASE
export CRONPROG=$PRE/lib/snapsched/scheduled
export TMPBASE=/tmp/ssched

# uber snapsched command
export SSCHED_UBER=y

CMD=$1
shift

if [ -z "$CMD" ] ; then
	CMD=help
fi

# load the library routines
 . $PRE/lib/snapsched/snapsched-funcs

init_config_help()
{
	echo "init_config  :   Initialize the snapsched config file.  All previous"
	echo "                 data in config file is erased."
}

print_config_help()
{
	echo "print_config :   Print out the contents of the config file"
}

add_source_help()
{
	echo "add_source   :   Add a btrfs filesystem subvolume to the config file "
	echo "                 for scheduled snapshots.  Snapshot times and dates"
	echo "                 will be the defaults."
	echo "                 Arguments: <filesystem-name> h d w m [db1 ...]"
	echo "                 The basename of the filesystem must be specified"
	echo "                    in <filesystem-name>"
	echo "                 h, d, w and m are a single integer 0-99, indicating"
	echo "                    the maximum number of snapshots for the interval"
	echo "                    period of hourly, daily, weekly and monthly."
	echo "                    When the maximum number is reached, no more"
	echo "                    snapshots for the enclosing period will be"
	echo "                    performed.  So, if if the 'h' number is 20,"
	echo "                    hourly snapshots will stop being performed after"
	echo "                    20 hours.  A number of 25 means that one hourly"
	echo "                    be left undeleted when a new day, and a new batch"
	echo "                    of hourlies is started."
	echo "                    Do not specify > +1 for the enclosing period"
	echo "                 Optional db arguments can be one or more of"
	echo "                    'mysql' or 'postgresql'.  postgresql can be"
	echo "                    suffixed by '-M.m' where M is the major version,"
	echo "                    and m is minor version number.  snapsched will"
	echo "                    attempt to pause just that version of postgres."
	echo
	echo "           NOTE: for the foreseeable future, postgresql pausing"
	echo "                 is not implemented."
}

list_sources_help()
{
	echo "list_sources :   List all the sources in the config file as words"
	echo "                 Option -l lists sources one per line along with the"
	echo "                 snapshot interval and scheduling options for that"
	echo "                 source."
	echo "                 Option -d lists sources one per line along with the"
	echo "                 database flags for that source."
	echo "                 D or 'def' in the listing means using the default."
}

remove_source_help()
{
	echo "remove_source :  Remove a filesystem from the config file"
	echo "                 Argument: <filesystem-name>"
}

create_cronjobs_help()
{
	echo "create_cronjobs : Create cron entries for <filesystem-name>"
	echo "                  Create or replace pre-existing cron entries for"
	echo "                  <filesystem-name> source."
}

delete_cronjobs_help()
{
	echo "delete_cronjobs : Remove all cronjob files from"
	echo "                  /etc/cron.{hourly,daily,weekly,monthly}"
	echo "                  Called with no arguments, deletes them ALL."
	echo "                  Called with one argument <filesystem-name> deletes"
	echo "                      just the cron jobs for that filesystem."
}

lssnap_help()
{
	echo "lssnap          : list snapsched snapshots"
	echo "                  Called with no arguments, lists all snapshots for"
	echo "                    all configured sources."
	echo "                  Called with one argument <filesystem-name>, lists"
	echo "                    all snapshots for that source."
	echo "                  Called with two arguments <filesystem-name> <interval-list>"
	echo "                    lists all snapshots for that source/interval pairing."
	echo "                    interval-list may be a comma separated list"
	echo "                    from h[ourly], d[aily], w[eekly], m[onthly]"
}

set_btrfspath_help()
{
	echo "set_btrfspath :  Set the main mount point for the btrfs filesystem"
	echo "                 Arg: <btfs-mount-point>"
	echo "                 Changes the mount point in the config file for the
                   subvolid=0 mounting of the btrfs filesystem used
                   for ALL OPERATIONS.  Use carefully.  Default is
                   '/media/btrfs'.  This is sanity checked at run time
                   by attempting to do a mount, hence, the entry in
                   /etc/fstab must already exist to mount the btrfs
                   filesystem at that point with the subvolid=0 mount
                   option.  All scheduled snapshots will be created under
                   this mount point, and all source subvolumes specified
                   in the add_source command must be in this directory
                   (not subdirectories)."
}

set_dailies_help()
{
	echo "set_dailies :  Set the time and day-of-week for daily snapshots"
	echo "                 Args: <fs> <days> [<time-of-day>]"
	echo "                 fs is the file system subvolume to be snapped, as"
	echo "                   already configured with add_source."
	echo "                 days is the day[s] of the week you would like"
	echo "                   this daily snapshot to happen.  Range is 1-7,
                   but some crontab-like strings may be used, such
                   as '1,3,5,7' or 'mon-fri' or 'mon,tue,thu,sat' and so on.
                   Very little validation can be done for such strings, so
                   make sure you get them right.  two aliases are allowed:
                   'weekdays' is equivalent to 'mon-fri', and
                   'weekend' is equivalent to 'sat,sun'.
                   '*' can be used, but it must be double quoted, ie.,
                   like \\\* or '\*'"
	echo "                 ToD is the HH:MM format of the hour and minute to
                   fire the snapshot on the day in question.  default: 00:00
                   You can put '+NN' where NN is number of minutes after
                   00:00 you want the snapshot to fire.  HH and MM both must
                   be TWO DIGITS, so use leading zeroes where necessary."
}

set_weeklies_help()
{
	echo "set_weeklies :  Set the time and day-of-week for weekly snapshots"
	echo "                 Args: <fs> <day> [<time-of-day>]"
	echo "                 fs is the file system subvolume to be snapped, as"
	echo "                   already configured with add_source."
	echo "                 day is the day of the week you would like"
	echo "                   this weekly snapshot to happen.  Range is 1-7,
                   but some crontab-like strings may be used, such
                   as 'mon' or 'sun' and so on.
                   Very little validation can be done for such strings, so
                   make sure you get them right."
	echo "                 ToD is the HH:MM format of the hour and minute to
                   fire the snapshot on the day in question.  default: 00:00
                   You can put '+NN' where NN is number of minutes after
                   00:00 you want the snapshot to fire.  HH and MM both must
                   be TWO DIGITS, so use leading zeroes where necessary."
}

set_monthlies_help()
{
	echo "set_monthlies :  Set the time and day-of-month for monthly snapshots"
	echo "                 Args: <fs> <day-of-month> [<time-of-day>]"
	echo "                 fs is the file system subvolume to be snapped, as"
	echo "                   already configured."
	echo "                 day-of-month is the day of the month you would like"
	echo "                   this monthly snapshot to happen.  Range is 1-31,
                   but some months have fewer days than 31.
                   Some have as few as 28.  Synonyms such as 'last'
                   or 'last-sat' or 'last-weekday' or 'last-weekend'
                   can be used.  last means the last day of each month.
                   last-<day-of-week> means the last day of that week
                   in the month.  Three letter day names as understood
                   by the date/cron commands only, please."
	echo "                 ToD is the HH:MM format of the hour and minute to
                   fire the snapshot on the day in question.  default: 22:00"
}

set_backup_help()
{
	echo "set_backup :  Setup and initiate the backup feature for a src/interval"
	echo "              Args: <fs> <interval> <backup-host> <bfs-dir> [<compress>]"
	echo "              fs is the file system subvolume parent of the snapshots"
	echo "                to be backed up, as already configured."
	echo "              interval is the interval level that will be backed up - all"
	echo "                interval levels above this one will be backed up."
	echo "              backup-host is the hostname/IP-addr of the host that"
	echo "                will receive the snapshot."
	echo "              bfs-dir is the directory on the backup host of the btrfs"
	echo "                file system that will receive the backup snapshot."
	echo "              compression ([off],on) specifies using compression arg"
	echo "                with ssh when doing the xfer.  Compression is generally"
	echo "                much slower on fast (> 100Base-T) connections."
	echo "              If you specify 'daily' as the interval, any interval levels
              you are snapping for the source fs that are larger (above)
              daily will be backed up as well.  So, if you have weekly and
              daily snapshots scheduled, all weekly and daily snaps will
              be backed up.  It is up to the user to delete snapshots
              on the backup server when they are no longer needed.
              A bootstrap process is scheduled for 5 minutes after
              this command is run to send all un-backed up snapshots to
              the backup server.  Use the at(1) command to modify the
              scheduling of that command, but be aware that cron will
              kick off a backup the next time a snapshot of <interval>
              is performed.  The root user will get an email with the
              results of the bootstrap and cron backup efforts, except
              for hourly snapshots unless there is an error."

}

rm_backup_help()
{
	echo "rm_backup  :  Remove backup config for src/interval"
	echo "              Args: <fs> <interval>"
	echo "              fs is the file system subvolume parent of the snapshots"
	echo "              to be backed up, as already configured."
	echo "              interval is the interval level that was being backed up."
	echo "              Remove from the config file the backup settings."
}

mod_maxsnapcount_help()
{
	echo "mod_maxsnapcount :  change the max snap count for a particular source filesystem"
	echo "                    and snapshot interval."
	echo "                    args: <fs> <interval> <new max>"
	echo "                    fs is the file system subvolume to be snapped, as"
	echo "                    already configured."
	echo "                    interval is the specific snap interval of fs to change,"
	echo "                    one of hourly, daily, weekly or monthly.  can be abbreviated
                    to single letter or non-pluralized word (day).
                    new-max is the new max snapcount for this fs/interval pair."
}

diff_help()
{
	echo "diff    :  diff a file against version in a scheduled snapshot"
	echo "           args: <snap-src> <int-type> <file-name> [<back-num>]"
	echo "                 <snap-src> - the name of the source fileset"
	echo "                 <int-type> - h[ourly],d[ayly],w[eekly],m[onthly]"
	echo "                 <file-name> - name of file.  relative from PWD for now"
	echo "                 <back-num> - number of snaps to go back. default=1"
	echo "                              max is dependent on config and int-type"
	echo "           env variable SSCHED_DIFF can contain custom diff"
}

get_help()
{
	echo "get     :  get a file from a scheduled snapshot - must have sudo access"
	echo "           args: <snap-src> <int-type> <file-name> <out-filename> [<back-num>]"
	echo "                 <snap-src> - the name of the source fileset"
	echo "                 <int-type> - h[ourly],d[ayly],w[eekly],m[onthly]"
	echo "                 <file-name> - name of file.  relative from PWD for now"
	echo "                 <out-filename> - name of output file. will overwrite"
	echo "                                  existing files.  can use - to specify"
	echo "                                  sending file to stdout"
	echo "                 <back-num> - number of snaps to go back. default=1"
	echo "                              max is dependent on config and int-type"
	echo "           env variable SSCHED_CP can contain custom cp command. args are"
	echo "           full pathname strings of input-file and output-file. output-file"
	echo "           will be null string if '-' was specified.  default cmd is"
	echo "           'cp --reflink-auto'"
}

if [ \( "$CMD" = "--list-funcs" \) -o \
	\( "$CMD" = "-h" \) -o \
	\( "$CMD" = "help" \) -o \
	\( "$CMD" = "--help" \) ] ; then
	echo "snapsched <cmd>"
	echo "List of available commands:"
	init_config_help
	echo
	print_config_help
	echo
	add_source_help
	echo
	list_sources_help
	echo
	remove_source_help
	echo
	create_cronjobs_help
	echo
	delete_cronjobs_help
	echo
	lssnap_help
	echo
	set_btrfspath_help
	echo
	set_dailies_help
	echo
	set_weeklies_help
	echo
	set_monthlies_help
	echo
	set_backup_help
	echo
	rm_backup_help
	echo
	mod_maxsnapcount_help
	echo
	diff_help
	echo
	get_help

	echo

	exit 0
fi

if [ \( "$1" = "-h" \) -o \
	\( "$1" = "--help" \) ] ; then
	${CMD}_help || serr "Sorry, no help available for '$CMD'"
	exit
fi

ssched_$CMD "$@"

