#!/bin/bash SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) cd $SCRIPT_DIR . ./backup.config function log() { echo -e "\e[96m`date +'%d/%m/%Y %H:%M:%S'` \e[39m| $1" echo -e "`date +'%d/%m/%Y %H:%M:%S'` | $1" >> $LOG } function usage() { echo echo -e "./backup.sh \e[93m--help \e[39m" echo -e "./backup.sh \e[93m--mount \e[39m" echo -e "./backup.sh \e[93m--umount \e[39m" echo echo "Local directories" echo -e "./backup.sh \e[92m--src=\e[39m/mnt/data \e[96m--dst=\e[39m/backup" echo -e "./backup.sh \e[92m--src=\e[39m/mnt/vmachines/storage \e[96m--dst=\e[39m/backup/data/VMachines" echo -e "./backup.sh \e[92m--src=\e[39m/mnt/projects \e[96m--dst=\e[39m/backup \e[91m--delete=\e[39myes" echo echo "Remote directories [smb|ssh]" echo -e "./backup.sh \e[35m--config=\e[39m./windows.backup" echo echo -e " $1" echo exit } function mount_smb() { if mkdir /mnt/$PID; then log "[ OK ] creating /mnt/$PID" exit if mount -t cifs //$HOST/$SHARE /mnt/$PID -o username=$USER,password=$PASS; then log "[ OK ] mount //$HOST/$SHARE to /mnt/$PID" return 0 else log "[FAIL] mount //$HOST/$SHARE to /mnt/$PID" return 1 fi else log "[FAIL] to create /mnt/$PID" return 1 fi } function mount_ssh() { if mkdir /mnt/$PID; then if ssh -q -o BatchMode=yes -o ConnectTimeout=10 $USER@$HOST exit; then if ssh $USER@$HOST ls -l $DIR 2> /dev/null; then if sshfs -o ro $USER@$HOST:$SOURCE /mnt/$PID; then return 0 else log "[FAIL] mount $USER@$HOST:$SOURCE to /mnt/$SRC" return 1 fi else log "[FAIL] remote dir $DIR not found" return 1 fi else log "[FAIL] ssh $USER@$HOST" return 1 fi else log "[FAIL] to create /mnt/$PID" return 1 fi } function get_luks_password() { LUKS_PASS=$(curl -s $LUKS_PASS_URL | jq -r ".password") if [ -z "$LUKS_PASS" ]; then log "[FAIL] to get LUKS password" return 1 else log "[ OK ] getting LUKS password" return 0 fi } function find_usb() { for DISK in `ls -l /dev/disk/by-id/usb* | grep -v part | awk -F/ '{print $NF}'`; do DEV="/dev/$DISK" for PARTITION in `ls -1 $DEV* | grep "[0-9]$"`; do /usr/sbin/cryptsetup isLuks $PARTITION if [ $? = 0 ]; then USB_PARTITION=$PARTITION return 0 fi done log "[FAIL] to find encrypted USB partition" return 1 done log "[FAIL] to find encrypted USB disk" return 1 } function mount_luks() { for n in `seq 0 9`; do waiting=$(grep 'Dirty\|Writeback' /proc/meminfo | grep Writeback: | awk {'print $2'}) if [[ wating -eq "0" ]]; then for n in `seq 0 9`; do echo $1 | /usr/sbin/cryptsetup luksOpen $2 crypted_usb if [ $? = 0 ]; then log "[ OK ] created /dev/mapper/crypted_usb" return 0 fi sleep 60 done log "[FAIL] to create /dev/mapper/crypted_usb (error)" return 1 fi sleep 60 done log "[FAIL] to create /dev/mapper/crypted_usb (timeout)" return 1 } function mount_usb() { mount_luks $LUKS_PASS $USB_PARTITION if [ $? = 0 ]; then log "[ OK ] $USB_PARTITION decrypted" /usr/bin/mount /dev/mapper/crypted_usb /mnt/usb if [ $? = 0 ]; then log "[ OK ] $USB_PARTITION mounted" return 0 else log "[FAIL] $USB_PARTITION mounted" return 1 fi else log "[FAIL] $USB_PARTITION decrypted" return 1 fi exit } function check_space () { src_size=$(du -s "$SRC" | awk '{print $1}') dst_size=$(df $MNT | grep "^/" | awk {'print $4'}) log "$SRC usage size: $src_size" log "$MNT$DIR available size: $dst_size" if [ "$dst_size" -gt "$src_size" ]; then log "[ OK ] enought available space" return 0 else log "[FAIL] not enought available space" return 1 fi } function sync_files() { SRC_PATH=`dirname "$SRC"` SRC_DIR=`basename "$SRC"` DST_DIR=$USB_MOUNT$DST log "------------ RSYNC STARTED ---------" cd $SRC_PATH if [ "$DELETE" == "yes" ]; then rsync -av --stats \ --temp-dir=/tmp \ --links \ --human-readable \ --no-owner \ --no-group \ --include ".*" \ --delete \ "$SRC_DIR" "$DST_DIR" | sed '/sending\ incremental\ file\ list/d' | tee -a $LOG else rsync -av \ --stats \ --temp-dir=/tmp \ --include ".*" \ --links \ --human-readable \ --no-owner \ --no-group \ "$SRC_DIR" "$DST_DIR" | sed '/sending\ incremental\ file\ list/d' | tee -a $LOG fi cd /root log "------------ RSYNC ENDED -----------" return 0 } function check_copy () { cd ${SRC} find * -type f -exec ls -s {} \; > /root/backup-src.log cd ${DST_DIR}/${SRC_DIR} find * -type f -exec ls -s {} \; > /root/backup-dst.log cd if diff -r /root/backup-src.log /root/backup-dst.log; then log "[ OK ] files check" else log "[FAIL] files check" fi return 0 } function luks_close() { for n in `seq 1 12`; do /usr/sbin/cryptsetup close crypted_usb if [ $? = 0 ]; then log "[ OK ] luksClose /dev/mapper/crypted_usb" return 0 fi sleep 300 done log "[FAIL] luksClose (timeout)" return 1 } function umount_usb() { if /usr/bin/umount $USB_MOUNT; then log "[ OK ] umount usb disk" return 0 else log "[FAIL] to find mounted usb disk" return 1 fi } function statistics_usb() { USBTOTAL=$(df -h | grep $USB_MOUNT | awk '{print $2}') USBUSAGE=$(df -h | grep $USB_MOUNT | awk '{print $5}') USBUSED=$(df -h | grep $USB_MOUNT | awk '{print $3}') USBFREE=$(df -h | grep $USB_MOUNT | awk '{print $4}') log "USB DISK Total : ${USBTOTAL}" log "USB DISK Usage : ${USBUSAGE}" log "USB DISK Used : ${USBUSED}" log "USB DISK Free : ${USBFREE}" } function mount() { if find_usb; then if get_luks_password; then mount_usb fi fi exit } function umount() { umount_usb exit } function send_mail() { COPIED=$( cat ${LOG} | grep "Number of created files:" | awk {'print $5'} ) DELETED=$( cat ${LOG} | grep "Number of deleted files:" | awk {'print $5'} ) TRANSFERRED=$( cat ${LOG} | grep "Number of regular files transferred:" | awk {'print $6'} ) SUBJECT="${COPIED} files copied, ${DELETED} files deleted, ${TRANSFERRED} files transferred" echo "Backup Report" | mutt -s $SUBJECT -F /etc/muttrc $MAIL_RECIPIENT -a $LOG } function free_to_run() { for n in `seq 0 9`; do if [[ `ps aux | grep backup.sh | grep -v grep` ]]; then return 0 fi sleep 120 done log "[ ] wating another instance to finish" return 1 } function umount_remote() { if umount /mnt/$PID then log "[ OK ] umount /mnt/${PID}" if rmdir /mnt/$PID; then log "[ OK ] rmdir /mnt/${PID}" else log "[FAIL] rmdir /mnt/${PID}" fi else log "[FAIL] umount /mnt/${PID}" fi } function main () { log "SOURCE : $SRC" log "DESTINATION : $USB_MOUNT$DST" log "DELETE : ${DELETE:-"No (default)"}" if get_luks_password; then if find_usb; then if mount_usb; then sync_files statistics_usb if umount_usb; then luks_close fi fi send_mail fi fi } for i in "$@" do case $i in --help) usage ;; --mount) mount ;; --umount) umount ;; --src=*) SRC="${i#*=}" shift ;; --dst=*) DST="${i#*=}" shift ;; --delete=*) DELETE="${i#*=}" shift ;; --config=*) CONFIG="${i#*=}" shift ;; *) usage ;; esac done if [[ -n "$CONFIG" ]]; then PID=$$ source $CONFIG [ -z "$PROTO" ] && usage "config \e[92m'PROTO'\e[39m is missing" [ -z "$SHARE" ] && usage "config \e[92m'SHARE'\e[39m is missing" [ -z "$USER" ] && usage "config \e[92m'USER'\e[39m is missing" [ -z "$PASS" ] && usage "config \e[92m'PASS'\e[39m is missing" [ -z "$SOURCE" ] && usage "config \e[92m'SOURCE'\e[39m is missing" [ -z "$DESTINATION" ] && usage "config \e[92m'DESTINATION'\e[39m is missing" if [ "$PROTO" = "smb" ]; then if mount_smb; then echo "mount_smb" fi fi if [ "$PROTO" = "ssh" ]; then if mount_ssh; then echo "mount_ssh" fi fi umount_remote fi exit [ -z "$SRC" ] && usage "option \e[92m'--src'\e[39m is missing" [ -z "$DST" ] && usage "option \e[92m'--dst'\e[39m is missing" main