summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVon Random <von@vdrandom.org>2015-01-05 18:41:59 +0300
committerVon Random <von@vdrandom.org>2015-01-05 18:41:59 +0300
commit0aabfe44bfc7eddab5167f644a6db8e9dbe12f84 (patch)
tree5a175d8d552d5fbd9e3b4a428918f094d3dcac38
parentffe5c9ac16b73ee429f853494c9b355b296e6cb4 (diff)
more refactoring and fixing, now fully functional and with a documented config
-rw-r--r--backup.cfg57
-rwxr-xr-xbackup.zsh94
2 files changed, 102 insertions, 49 deletions
diff --git a/backup.cfg b/backup.cfg
index a676cf2..982df09 100644
--- a/backup.cfg
+++ b/backup.cfg
@@ -1,11 +1,50 @@
-protocol=ssh # ftp, sftp, ftps, ssh or local
-remote_host=hostname.tld
-backup_dir=relative_or_full_path
-#snap_file=/var/backup/snapshot.list
-#exclude_list=/usr/local/etc/backup/excludes.list
-compress_format=xz # gz, bz2, xz or empty for non-compressed
-remote_user=username
-remote_pass=PassWd
-source_dirs=( '/home/user/source1:/var/backup/snapshot.list' )
+#### general options ####
+## The protocol we want to use to store our backups.
+## Can be ftp, sftp, ftps, ssh or local.
+protocol='ssh'
+
+## The directory store backups in, locally or remotely.
+backup_dir='relative_or_full_path'
+
+## The list of patterns to exclude from backups, for
+## more details look into tar -X option.
+#exclude_list='/usr/local/etc/backup/excludes.list'
+
+## The compression algorithm for backups.
+## Can be gz, bz2, xz or empty (for non-compressed).
+compress_format='xz'
+
+## An array with the set of directories within it.
+## Optionally snapshot file can be added to store
+## incremental diffs (tar -g option used).
+## You'll have to deal with snapshots on your own:
+## backup.zsh only handles backups (i.e. you can remove
+## snapshot via cron on regular basis to ensure that
+## full backups are created from time to time.)
+source_dirs=( '/home/user/source1:/var/backup/snapshot.list'
+ '/etc' '/var/spool/mail:/var/backup/spool_snapshot.list' )
+
+## Use with caution, the file existance is not checked
+## on execution.
+## Since this config is sourced, I advise adding some
+## logic for that, or you can handle filename collisions
+## externally.
+#backup_filename='somebackup'
+
+#### remote options ####
+## Remote host.
+remote_host='hostname.tld'
+
+## Remote user.
+remote_user='username'
+
+## Password, due to how openssh handles security it only
+## works for *ftp* protocols; backups via ssh protocol
+## work interactively. Later versions will have support
+## for ssh keys.
+remote_pass='PassWd'
+
+## Port is optional, the defaults are hardcoded.
+#remote_port='443'
# vim: ft=zsh
diff --git a/backup.zsh b/backup.zsh
index 77a8980..e99edbb 100755
--- a/backup.zsh
+++ b/backup.zsh
@@ -1,6 +1,6 @@
#!/usr/bin/env zsh
self_name=$0
-default_cfg='/usr/local/etc/backup.cfg'
+default_cfg='/etc/backup.zsh.cfg'
default_postfix=$(date +%F-%H%M)
default_ftp_port='21'
default_ssh_port='22'
@@ -12,35 +12,51 @@ function err
function cfg_err
{
- [[ -n $1 ]] && echo "$1 is not set in configuration, but is required by $0 to work." >&2
+ [[ -n $1 ]] && echo "$1 is not set in configuration, but is required by $self_name to work." >&2
}
function usage
{
- echo "usage: $self_name [--help|--config]
- --help -h - show this message
- --config -c - use config from the specified path
+ echo "usage: $self_name [--help|--conf /path/to/config]
+ --help -h show this message
+ --conf -c use config from the specified path
- Default config path /usr/local/etc/backup.cfg will be used if invoked without options"
+ Default config path $default_cfg will be used if invoked without options"
}
# 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'
+ function test_remote_settings
+ {
+ if [[ -z $remote_host ]]; then
+ cfg_err 'remote_host'
+ return 5
+ fi
+ if [[ -z $remote_user ]]; then
+ cfg_err 'remote_user'
+ return 5
+ fi
+ if [[ -z $remote_pass ]]; then
+ cfg_err 'remote_pass'
+ return 5
+ fi
+ if [[ -n $port && ! $port =~ ^[0-9]+$ ]]; then
+ err 'Remote port is not a numeric value.'
+ return 5
+ fi
+ }
+ source $cfg || { err "Config file $cfg is unreadable or does not exist"; return 15 }
if [[ -z $source_dirs ]]; then
- cfg_err 'Backup source'
- exit 5
- fi
- if [[ -z $remote_host ]]; then
- cfg_err 'Remote host'
- exit 5
+ cfg_err 'source_dirs'
+ return 5
fi
if [[ -z $backup_dir && $protocol != 'ssh' ]]; then
- cfg_err 'Target directory'
- exit 5
+ cfg_err 'backup_dir'
+ return 5
fi
if [[ -z $local_host ]]; then
+ err 'local_host is not set, using hostname.'
local_host=$HOST
fi
# date postfix
@@ -50,20 +66,17 @@ function apply_config
postfix=$outfile_postfix
fi
case $protocol in
- ('ftp'|'ftps') port=${remote_port:-$default_ftp_port};;
- ('sftp'|'ssh') port=${remote_port:-$default_ssh_port};;
+ ('ftp'|'ftps') port=${remote_port:-$default_ftp_port}; test_remote_settings; return $?;;
+ ('sftp'|'ssh') port=${remote_port:-$default_ssh_port}; test_remote_settings; return $?;;
('local') unset remote_port;;
- (*) cfg_err 'Backup protocol'; exit 5;;
+ (*) cfg_err 'protocol'; return 5;;
esac
- if [[ ! $remote_port =~ ^[0-9]+$ ]]; then
- err 'Remote port is not a numeric value.'
- fi
case $compress_format in
('xz') compress_flag='J' ;;
('bz2') compress_flag='j' ;;
('gz') compress_flag='z' ;;
('') unset compress_flag; unset compress_format ;;
- (*) err "$compress_format is not a valid value for the compression format option."; exit 5;;
+ (*) err "$compress_format is not a valid value for the compression format option."; return 5;;
esac
if [[ -n $exclude_list ]]; then
if [[ -r $exclude_list ]]; then
@@ -72,13 +85,6 @@ function apply_config
err "Exclusion list $exclude_list is either unreadable or does not exist."
fi
fi
- if [[ -n $snap_file ]]; then
- if printf '' >> $snap_file; then
- snapshot_option='-g'
- else
- err "Snapshot file $snap_file cannot be written."
- fi
- fi
}
# generate the full backup path
@@ -86,7 +92,7 @@ function generate_fullpath
{
local backup_type
# increment or full backup
- if [[ -s $snap_file ]]; then
+ if [[ -s $snapshot_file ]]; then
backup_type='incr'
else
backup_type='full'
@@ -100,7 +106,14 @@ function generate_fullpath
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
+ if [[ -n $snapshot_file ]]; then
+ if printf '' >> $snapshot_file; then
+ snapshot_option='-g'
+ else
+ err "Snapshot file $snapshot_file cannot be written."
+ fi
+ fi
+ tar -c$compress_flag $snapshot_option $snapshot_file $exclude_option $exclude_list --ignore-failed-read -C $src_basedir $src_basename
}
function store # store to local or remote
@@ -116,27 +129,28 @@ function parse_opts
{
while [[ -n $1 ]]; do
case $1 in
- ('--help'|'-h') usage; return 0;;
- ('--config'|'-c') shift; opt_cfg=$1; shift;;
+ ('--help'|'-h') usage; exit 0;;
+ ('--conf'|'-c') shift; opt_cfg=$1; shift;;
+ ('') opt_cfg=$default_cfg;;
+ (*) err "unknown parameter $1"; exit 127;;
esac
done
}
function main
{
- parse_opts
- if [[ -z $opt_cfg ]]; then
- cfg=$default_cfg
- else
- cfg=$opt_cfg
- fi
+ parse_opts $@
+ cfg=${opt_cfg:-$default_cfg}
apply_config
+ local apply_config_returns=$?
+ [[ $apply_config_returns -ne 0 ]] && return $apply_config_returns
for i in $source_dirs; do
unset src_basename src_basedir outfile
- IFS=':' read source_dir snap_file <<< $i
+ IFS=':' read source_dir snapshot_file <<< $i
src_basename=${source_dir:t}
src_basedir=${source_dir:h}
generate_fullpath
+ echo "Creating a backup of $source_dir. Using protocol $protocol to store it in $outfile."
compress | store
done
return 0