Backup/backup.sh
2023-05-22 14:19:45 +03:00

404 lines
10 KiB
Bash
Executable File

#!/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 -e "./backup.sh \e[93m--format=\e[39m/dev/sda"
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 another_instance() {
if [ $(ps | grep backup.sh) ];then
log "[FAIL] another instance is running"
return 1
fi
return 0
}
function mount_smb() {
if mkdir /mnt/${PID}; then
log "[ OK ] creating /mnt/${PID}"
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 sshfs -o ro ${USER}@${HOST}:${SHARE} /mnt/${PID}; then
return 0
else
log "[FAIL] mount ${USER}@${HOST}:${SHARE} to /mnt/${SRC}"
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 --connect-timeout 10 -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_luks() {
for DEV in `ls -1 /dev/disk/by-id/usb*`; do
if /sbin/cryptsetup isLuks ${DEV}; then
USB_DEV=${DEV}
LOGDEV=$(echo $DEV | cut -c21- )
log "[ OK ] find encrypted ${LOGDEV}"
return 0
fi
done
log "[FAIL] to find encrypted disk"
return 1
}
function mount_luks2() {
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 | /sbin/cryptsetup luksOpen $2 crypted_usb
if [ $? = 0 ]; then
log "[ OK ] luksOpen crypted_usb"
return 0
fi
sleep 60
done
log "[FAIL] luksOpen crypted_usb (error)"
return 1
fi
sleep 60
done
log "[FAIL] luksOpen crypted_usb (timeout)"
return 1
}
function mount_luks() {
if [[ -L /dev/mapper/crypted_usb ]]; then
log "[ !! ] founbd old crypted_usb"
dmsetup remove /dev/mapper/crypted_usb
if [ $? = 0 ]; then
log "[ !! ] old crypted_usb removed"
fi
fi
waiting=$(grep 'Dirty\|Writeback' /proc/meminfo | grep Writeback: | awk {'print $2'})
if [[ wating -eq "0" ]]; then
echo $1 | /sbin/cryptsetup luksOpen $2 crypted_usb
if [ $? = 0 ]; then
log "[ OK ] luksOpen crypted_usb"
return 0
fi
fi
}
function mount_usb() {
if mount /dev/mapper/crypted_usb /mnt/usb; then
log "[ OK ] mount crypted_usb to /mnt/usb"
return 0
else
log "[FAIL] to mount crypted_usb to /mnt/usb"
return 1
fi
}
function check_space () {
src_size=$(du -s /mnt/${PID} | awk '{print $1}')
dst_size=$(df /mnt/usb | grep "^/" | awk {'print $4'})
log "USB usage size: $src_size"
log "USB 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="/mnt/${PID}${SOURCE}"
DST="/mnt/usb${DESTINATION}"
log "SOURCE : ${SRC}"
log "DESTINATION : ${DST}"
log "DELETE : ${DELETE:-"No (default)"}"
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}" "${DST}" | 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}" "${DST}" | sed '/sending\ incremental\ file\ list/d' | tee -a $LOG
fi
cd - > /dev/null
log "------------- RSYNC ENDED -----------"
return 0
}
function check_copy () {
cd ${SOURCE}
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 umount_usb() {
if umount /mnt/usb; then
log "[ OK ] umount /mnt/usb"
return 0
else
log "[FAIL] umount /mnt/usb"
return 1
fi
}
function luks_close() {
for n in `seq 1 12`; do
cryptsetup close crypted_usb
if [ $? = 0 ]; then
log "[ OK ] luksClose /dev/mapper/crypted_usb"
return 0
fi
sleep 10
done
log "[FAIL] luksClose (timeout)"
return 1
}
function statistics_usb() {
USBTOTAL=$(df -h | grep /mnt/usb | awk '{print $2}')
USBUSAGE=$(df -h | grep /mnt/usb | awk '{print $5}')
USBUSED=$(df -h | grep /mnt/usb | awk '{print $3}')
USBFREE=$(df -h | grep /mnt/usb | awk '{print $4}')
log "USB DISK Total : ${USBTOTAL}"
log "USB DISK Usage : ${USBUSAGE}"
log "USB DISK Used : ${USBUSED}"
log "USB DISK Free : ${USBFREE}"
}
function debug_mount() {
if get_luks_password; then
if find_luks; then
if mount_luks $LUKS_PASS $USB_DEV; then
if mount_usb; then
ls -l /mnt/usb
fi
fi
fi
fi
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 format() {
if [ -b ${FORMAT} ]; then
if cryptsetup -y -v luksFormat ${FORMAT}; then
log "[ OK ] formating ${FORMAT}"
else
log "[FAIL] formating ${FORMAT}"
fi
else
log "[FAIL] ${FORMAT} not found"
fi
exit
}
function main () {
if another_instance; then
if get_luks_password; then
if find_luks; then
if mount_luks $LUKS_PASS $USB_DEV; then
if mount_usb; then
sync_files
statistics_usb
if umount_usb; then
luks_close
fi
fi
fi
fi
fi
fi
send_mail
}
for i in "$@"
do
case $i in
--help)
usage
;;
--mount)
debug_mount
;;
--umount)
umount_usb && luks_close
;;
--format=*)
FORMAT="${i#*=}"
format
shift
;;
--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 "$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
[ -z "$USER" ] && usage "config \e[92m'USER'\e[39m is missing"
[ -z "$PASS" ] && usage "config \e[92m'PASS'\e[39m is missing"
if mount_smb; then
main
fi
fi
if [ "$PROTO" = "ssh" ]; then
if mount_ssh; then
main
fi
fi
umount_remote
fi
exit
[ -z "$SOURCE" ] && usage "option \e[92m'--src'\e[39m is missing"
[ -z "$DESTINATION" ] && usage "option \e[92m'--dst'\e[39m is missing"
main