|
|
|
@ -1,17 +1,16 @@
|
|
|
|
|
#!/usr/bin/env zsh
|
|
|
|
|
set -e
|
|
|
|
|
self_name=$0
|
|
|
|
|
default_cfg='/usr/local/etc/backup.cfg'
|
|
|
|
|
default_postfix=$(date +%F-%H%M)
|
|
|
|
|
|
|
|
|
|
function err
|
|
|
|
|
{
|
|
|
|
|
[[ -n $2 ]] && echo $2 >&2
|
|
|
|
|
return $1
|
|
|
|
|
[[ -n $1 ]] && echo $1 >&2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cfg_err
|
|
|
|
|
{
|
|
|
|
|
[[ -n $1 ]] && echo "$1 is not set in configuration, but is required by $0 to work." >&2
|
|
|
|
|
return 5
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function usage
|
|
|
|
@ -19,50 +18,35 @@ function usage
|
|
|
|
|
echo "usage: $self_name [--help|--config]
|
|
|
|
|
--help -h - show this message
|
|
|
|
|
--config -c - use config from the specified path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Default config path /usr/local/etc/backup.cfg will be used if invoked without options"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function read_config
|
|
|
|
|
# function to read the configuration file and spit out some exceptions if stuff is missing
|
|
|
|
|
function apply_config
|
|
|
|
|
{
|
|
|
|
|
source $cfg || err 15 'Config file does not exist'
|
|
|
|
|
[[ -z $source_dir ]] && cfg_err 'Backup source'
|
|
|
|
|
[[ -z $remote_host ]] && cfg_err 'Remote host'
|
|
|
|
|
[[ -z $protocol ]] && cfg_err 'Backup protocol'
|
|
|
|
|
[[ -z $backup_dir && $protocol != 'ssh' ]] && cfg_err 'Target directory'
|
|
|
|
|
[[ -z $source_dirs ]] && { cfg_err 'Backup source'; exit 5 }
|
|
|
|
|
[[ -z $remote_host ]] && { cfg_err 'Remote host'; exit 5 }
|
|
|
|
|
[[ -z $protocol ]] && { cfg_err 'Backup protocol'; exit 5 }
|
|
|
|
|
[[ -z $backup_dir && $protocol != 'ssh' ]] && { cfg_err 'Target directory'; exit 5 }
|
|
|
|
|
if [[ -z $local_host ]]; then
|
|
|
|
|
local_host=$HOST
|
|
|
|
|
fi
|
|
|
|
|
src_basename=${source_dir:t}
|
|
|
|
|
src_basedir=${source_dir:h}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generate_fullpath
|
|
|
|
|
{
|
|
|
|
|
local backup_type
|
|
|
|
|
local postfix
|
|
|
|
|
# date postfix
|
|
|
|
|
if [[ -z $outfile_postfix ]]; then
|
|
|
|
|
postfix=$default_postfix
|
|
|
|
|
else
|
|
|
|
|
postfix=$outfile_postfix
|
|
|
|
|
fi
|
|
|
|
|
if [[ -s $snap_file ]]; then
|
|
|
|
|
backup_type='incr'
|
|
|
|
|
else
|
|
|
|
|
backup_type='full'
|
|
|
|
|
fi
|
|
|
|
|
if [[ -z $backup_filename ]]; then
|
|
|
|
|
outfile="$backup_dir/${local_host}-${src_basename}_${postfix}_${backup_type}.t${compress_format:-'ar'}"
|
|
|
|
|
else
|
|
|
|
|
outfile=$backup_filename
|
|
|
|
|
if [[ -z $remote_port ]]; then
|
|
|
|
|
case $protocol in
|
|
|
|
|
('ftp'|'ftps') remote_port='21';;
|
|
|
|
|
('sftp'|'ssh') remote_port='22';;
|
|
|
|
|
('local') unset remote_port;;
|
|
|
|
|
(*) err 1 "$protocol is not a valid value for the protocol option.";;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compress # compress to stdout
|
|
|
|
|
{
|
|
|
|
|
local compress_flag
|
|
|
|
|
local exclude_option
|
|
|
|
|
local snapshot_option
|
|
|
|
|
case $compress_format in
|
|
|
|
|
('xz') compress_flag='J' ;;
|
|
|
|
|
('bz2') compress_flag='j' ;;
|
|
|
|
@ -84,19 +68,32 @@ function compress # compress to stdout
|
|
|
|
|
err 1 "Snapshot file $snap_file cannot be written."
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# generate the full backup path
|
|
|
|
|
function generate_fullpath
|
|
|
|
|
{
|
|
|
|
|
local backup_type
|
|
|
|
|
# increment or full backup
|
|
|
|
|
if [[ -s $snap_file ]]; then
|
|
|
|
|
backup_type='incr'
|
|
|
|
|
else
|
|
|
|
|
backup_type='full'
|
|
|
|
|
fi
|
|
|
|
|
if [[ -z $backup_filename ]]; then
|
|
|
|
|
outfile="$backup_dir/${local_host}-${src_basename}_${postfix}_${backup_type}.t${compress_format:-'ar'}"
|
|
|
|
|
else
|
|
|
|
|
outfile=$backup_filename
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compress # compress to stdout
|
|
|
|
|
{
|
|
|
|
|
tar cf$compress_flag - -C $src_basedir $src_basename $snapshot_option $snapshot_file $exclude_option $exclude_list --ignore-failed-read
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function store # store to local or remote
|
|
|
|
|
{
|
|
|
|
|
if [[ -z $remote_port ]]; then
|
|
|
|
|
case $protocol in
|
|
|
|
|
('ftp'|'ftps') remote_port='21';;
|
|
|
|
|
('sftp'|'ssh') remote_port='22';;
|
|
|
|
|
('local') unset remote_port;;
|
|
|
|
|
(*) err 1 "$protocol is not a valid value for the protocol option.";;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
case $protocol in
|
|
|
|
|
('local') dd of=$outfile ;;
|
|
|
|
|
('ssh') ssh -p$remote_port $remote_user@$remote_host "dd of=$outfile" ;;
|
|
|
|
@ -105,7 +102,7 @@ function store # store to local or remote
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function main
|
|
|
|
|
function parse_opts
|
|
|
|
|
{
|
|
|
|
|
while [[ -n $1 ]]; do
|
|
|
|
|
case $1 in
|
|
|
|
@ -113,11 +110,25 @@ function main
|
|
|
|
|
('--config'|'-c') shift; opt_cfg=$1; shift;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
cfg=${opt_cfg:-'/usr/local/etc/backup.cfg'}
|
|
|
|
|
default_postfix=$(date +%F-%H%M)
|
|
|
|
|
read_config
|
|
|
|
|
generate_fullpath
|
|
|
|
|
compress | store
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function main
|
|
|
|
|
{
|
|
|
|
|
parse_opts
|
|
|
|
|
if [[ -z $opt_cfg ]]; then
|
|
|
|
|
cfg=$default_cfg
|
|
|
|
|
else
|
|
|
|
|
cfg=$opt_cfg
|
|
|
|
|
fi
|
|
|
|
|
apply_config
|
|
|
|
|
for i in $source_dirs; do
|
|
|
|
|
unset src_basename src_basedir outfile
|
|
|
|
|
IFS=':' read source_dir snap_file <<< $i
|
|
|
|
|
src_basename=${source_dir:t}
|
|
|
|
|
src_basedir=${source_dir:h}
|
|
|
|
|
generate_fullpath
|
|
|
|
|
compress | store
|
|
|
|
|
done
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|