#!/usr/bin/env bash set -e -u . /etc/crypted-backups user_mode="" source_mode="" verbose='' test_source="/tmp/test" test_destination="/home/dave/Downloads/test" function notification_source_to_destination () { local source_directory=$1 local destination_directory=$2 if [ $source_directory != "" -a $destination_directory != "" ];then echo "$source_directory -> $destination_directory" return 0 else echo "Source ($source_directory) or destination ($destination_directory) directory not given!" return 1 fi } function generate_timestamp () { local timestamp="$(date +"%Y%m%d-%H%M%S")-" echo ${timestamp} return 0 } # Adds trailing slash, if missing # Fails when path is not absolute, or not within user home, when not root function sanitize_pathname () { local path=$1 if [ ${#path} -ne 0 ]; then if [ ${path:0:1} = "/" -o ${path:0:2} = "~/" -a $(id -u) -ne 0 ]; then if [ ${path:${#path}-1} != "/" ]; then echo "$path/" return 0 else echo "$path" return 0 fi else echo "Directory must be absolute!" return 1 fi else echo "Directory can not be empty!" return 1 fi } function check_directory_exists () { local destination=$1 if [ ! -d $destination ]; then echo "Directory \"$destination\" does not exist yet. Creating..." mkdir -p $destination else return 0 fi } function check_directory_permission_root () { if [ -w $1 ]; then return 0 else echo "Directory not writable: $1." return 1 fi } function check_directory_writable_user () { if [ -w $1 ]; then return 0 else echo "Directory not writable: $1." return 1 fi } function check_directory_owner_user() { if [ ! -O $1 ]; then echo "Directory not owned by user $(whoami): $1" return 1 else return 0 fi } function check_user_directory () { local directory=$1 check_directory_exists $directory check_directory_writable_user $directory return 0 } function check_root_directory () { local directory=$1 check_directory_exists $directory check_directory_permission_root $directory return 0 } function get_parent_directory () { local directory=$1 local parent="" parent=$(dirname $directory) parent=$(sanitize_pathname $parent) echo "$parent" return 0 } function get_basename_directory () { local directory=$1 local base=$(basename $directory) echo "$base" return 0 } function compress_directory () { local source_directory=$1 local tmp_file=$2 echo "Compressing source directory ($source_directory) to temporary file ($tmp_file)." case $tar_suffix in ".tar.tbz") tar cfj "$tmp_file" $source_directory ;; ".tar.tgz") tar cfz "$tmp_file" $source_directory ;; ".tar.tlz") tar --lzma -cf "$tmp_file" $source_directory ;; ".tar.xz") tar cfJ "$tmp_file" $source_directory ;; *) echo "Using \"$tar_suffix\" as \$tar_suffix is not supported." return 1 ;; esac return 0 } function encrypt_tmp_file () { local tmp_file=$1 local destination_file=$2 echo "Encrypting $tmp_file to $destination_file." gpg -e \ -r "$gpg_public_key" \ -o "$destination_file" \ "$tmp_file" echo "Removing $tmp_file." rm -f "$tmp_file" return 0 } function backup_single_directory () { local source_directory=$1 local source_directory_basename=$(get_basename_directory $source_directory) local source_parent_directory=$(get_parent_directory $source_directory) local tmp_directory=$(sanitize_pathname $tmp) local destination_directory=$(sanitize_pathname $2) local timestamp=$(generate_timestamp) local tmp_file="$tmp_directory$timestamp$source_directory_basename$tar_suffix" local destination_file="$destination_directory$timestamp$source_directory_basename$tar_suffix$gpg_suffix" notification_source_to_destination "$source_parent_directory$source_directory_basename" $destination_file echo "Going to $source_directory_basename's parent directory: $source_parent_directory." cd $source_parent_directory #TODO: check if directory, not for existence? check_directory_exists $source_directory "check_"$user_mode"_directory" $tmp_directory "check_"$user_mode"_directory" $destination_directory compress_directory $source_directory_basename $tmp_file encrypt_tmp_file $tmp_file $destination_file } function backup_multiple_directories () { local source_directory=$(sanitize_pathname $1) local destination_directory=$(sanitize_pathname $2) local layered=0 if [ ${#@} -gt 2 ]; then layered=$3 echo "Multi-layered" fi "check_"$user_mode"_directory" $destination_directory for sub_directory in $source_directory* do if [ -d $sub_directory ];then "check_"$user_mode"_directory" $sub_directory if [ $layered -eq 1 ];then backup_multiple_directories $sub_directory $destination_directory$(get_basename_directory $sub_directory) else backup_single_directory $sub_directory $destination_directory fi fi done } function set_user_mode () { if [ $(id -u) -eq 0 ]; then user_mode="root" else user_mode="user" fi return 0 } function check_gpg_set () { if [ -z "$gpg_public_key" ];then echo "Error. \"gpg_public_key\" not set!" exit 1 fi } function print_help () { echo "help" exit 0 } #TODO: Add function to delete compressed data in working directory (also after fail) #TODO: Add function for database backups #TODO: Add function to cleanup backups #TODO: Add function to mirror backups #TODO: Add function to automatically add key to keyring, if not found #TODO: Create logic to distinguish between different backups #TODO: Add verbose flag check_gpg_set set_user_mode if [ ${#@} -gt 0 ]; then while getopts 'c:hr:s:v' flag; do case "${flag}" in c) echo "Cleanup" ;; h) print_help ;; r) echo "recall" ;; s) source_mode="${OPTARG}" ;; v) verbose='true' ;; *) echo "Error. Unrecognized option: ${flag}." exit 1 ;; esac done else print_help fi if [ -n "$source_mode" ];then case $source_mode in aura) backup_single_directory $aura_source $aura_destination ;; bitlbee) backup_single_directory $bitlbee_source $bitlbee_destination ;; etc) backup_single_directory $etc_source $etc_destination ;; git) backup_multiple_directories $git_source $git_destination ;; mail) if [ "$mail_domains_as_folders" = "yes" ]; then backup_multiple_directories $mail_source $mail_destination "1" elif [ "$mail_domains_as_folders" = "no" ]; then backup_multiple_directories $mail_source $mail_destination else echo "Setting \"mail_domains_as_folders\" to $mail_domains_as_folders is not supported!" exit 1 fi ;; mailman) backup_single_directory $mailman_source $mailman_destination ;; mariadb) ;; logs) backup_single_directory $logs_source $logs_destination ;; websites) backup_multiple_directories $websites_source $websites_destination ;; firefox) backup_single_directory $firefox_source $firefox_destination ;; thunderbird) backup_single_directory $thunderbird_source $thunderbird_destination ;; weechat) backup_single_directory $weechat_source $weechat_destination ;; *) echo "Error. $source_mode is not a valid backup option." exit 1 esac fi exit 0