#!/bin/bash
# backup - backup support
set -e
lib_load 'net/tool/rsync'
lib_load 'sys/tool/tar'
######
# Settings
sys_backup_config_init() {
lib_setting_arrays backup_targets
lib_setting_arrays -ro backup_targets_supported backup_modes
lib_setting_arrays -ro backup_rsync_opts
lib_setting_vars -ro backup_datadir
lib_setting_vars -ro backup_storedir
lib_setting_vars -ro backup_stagedir backup_script_stagedir
# backup_modes - supported modes of operation
backup_modes=( backup restore )
# backup_targets_supported - targets supported by all backup modes
backup_targets_supported=( full config data )
# backup_datadir - location of all mcsh backup data
backup_datadir="$datadir/backups"
# backup_dir - Path to all staged backup data
backup_stagedir="$backup_datadir/stage"
# backup_script_stagedir - Path to script's staged backup data
backup_script_stagedir="$backup_stagedir/$script_name"
# backup_dir - Path to all staged backup data
backup_storedir="$backup_datadir/store"
# backup_rsync_opts - options to pass to rsync
backup_rsync_opts=( --archive )
}
######
# Internal functions
backup_target_add() {
local var=$1
local target=$2
if in_list targets $target; then
warn "$target: ignoring duplicate target"
else
list_insert $var $target
fi
}
backup_file() {
local src=$1
[ -f "$src" ] || error "$src: does not exist"
local dst="${backup_script_stagedir}${src}"
file_mkdir "$dst"
run_rsync "${backup_rsync_opts[@]}" "$src" "$dst"
}
restore_file() {
local dst=$1
local src="${backup_script_stagedir}${dst}"
[ ! -f "$dst" ] || warn "$dst: exists, overwriting..."
file_mkdir "$src"
run_rsync "${backup_rsync_opts[@]}" "$src" "$dst"
}
backup_exec() {
min_args 1 "$@"
local mode=$1
shift
debug "$mode: starting..."
for target in "${backup_targets[@]}"; do
local cmd="${mode}_${target}"
if script_cmd_exists $cmd; then
debug "$mode $target: starting ..."
script_cmd_exec $cmd "$@"
debug "$mode $target: ... done"
elif lib_cmd_exists backup $cmd; then
debug "$mode $target: built-in: starting ..."
lib_cmd_exec backup $cmd "$@"
debug "$mode $target: built-in: ... done"
else
debug "$mode $target: not supported"
fi
done
debug "$mode: ... done!"
}
######
# Backup archives
backup_pack() {
min_args 2 "$@"
local archive=$1
[ ! -f "$archive" ] || error "$archive: archive exists"
shift
file_mkdir "$archive"
local tardir="$backup_stagedir"
tar_create "$archive" "$@"
}
backup_unpack() {
has_args 1 "$@"
local file=$1
[ -f "$file" ] || error "$file: archive does not exist"
file_mkdir "$archive"
local tardir="$backup_stagedir"
tar_extract "$file"
}
######
# Built-in backup methods
backup_config_file() {
local src=$1
if [ -f "$src" ]; then
${backup_mode}_file "$src"
else
# local/user configuration files may not exist
debug "$src: does not exist; skipping..."
fi
}
backup_config() {
for_each backup_config_file "${sys_configs[@]}"
}
backup_backup_config() { local backup_mode=backup; backup_config "$@"; }
backup_restore_config() { local backup_mode=restore; backup_config "$@"; }
######
# Tool backup/restore
backup_tool_tarfile() { echo "$backup_stagedir/$1.tar"; }
backup_tool() {
local tool=$1
shift
run $tool backup "$@"
local archive
archive=$(backup_tool_tarfile "$tool")
run rm -f "$archive"
backup_pack "$archive" $tool
}
restore_tool() {
local tool=$1
shift
local archive
archive=$(backup_tool_tarfile "$tool")
backup_unpack "$archive"
run "$tool" restore "$@"
}
######
# Host backup/restore interface
# backup_host_storedir - Path to stored backup data for host ($1).
backup_host_storedir() { echo "$backup_storedir/$1"; }
backup_host() {
has_args 2 "$@"
local name=$1
local target=$2
info "host backup: starting ..."
# secure archive name before starting
local aname
aname="$target-$(date +%y%m%d-%H%M%S).tar.xz"
for_each_tool _backup_host_tool $target
local files=( "${package_apps[@]}" )
list_map tar_filename files
local archive
archive="$(backup_host_storedir "$name")/$aname"
backup_pack "$archive" "${files[@]}"
info "host backup: ... done."
}
_backup_host_tool() {
local target=$1
local tool=$2
debug "host $name: $tool: backing up $archive"
backup_tool "$tool" "$target"
}
restore_host() {
has_args 2 "$@"
local name=$1
local archive=$2
debug "host $name: unpacking $archive"
backup_unpack "$archive"
for_each_tool _restore_host_tool
}
_restore_host_tool() {
local tool=$1
local archive
archive=$(backup_tool_tarfile "$tool")
debug "host $name: $tool: restoring $archive"
restore_tool "$tool" "$archive"
}
######
# Backup CLI support
backup_dispatch() {
min_args 2 "$@"
local mode=$1
shift
local -a backup_targets
local got_opt=true
while $got_opt; do
local target=$1
case "$target" in
(data|config)
backup_target_add backup_targets "$target"
shift
;;
(full)
backup_target_add backup_targets config
backup_target_add backup_targets data
shift
;;
('')
got_opt=false
;;
(*)
error_usage "$target: unknown target"
;;
esac
done
[ "${backup_targets[*]}" ] || error "$mode: no targets specified"
backup_exec "$mode" "$@"
}
backup_usage() {
cat <<USAGE
<cmd>
Backup Commands:
full Saves all script-related files
config Saves script configuration files
data Saves script data files
Archive Commands
pack <file> Pack staging directory into archive
USAGE
}
restore_usage() {
cat <<USAGE
<cmd> <file>
Restore Commands:
full <file> Perform a full restore
config <file> Restore script configuration files
data <file> Restore script data files
Archive Commands
unpack <file> Unpack archive to staging directory
USAGE
}
Generated on Tue Apr 25 21:21:14 PDT 2017 by mcsh i7 v0.18.0.