#!/bin/bash
#
# Copyright (c) 2018 Ejner Fergo efer@dtu.dk
#
# License: This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version. This program is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#

# Main Variables
SCRIPTNAME="comp-backup"
VERSION=7
LOGNAME="backup_logfile"
TARGETNODE="backup.compute.dtu.dk"
HOST=$(hostname -s)
SERIAL=/etc/dtuserial
H=$HOME
BIN_DIR="$H/bin"

# Banner
clear
echo "#-------------------------------#"
echo "#   DTU Compute backup script   #"
echo "#-------------------------------#"
echo
echo "This script will setup a backup routine for you"
echo "Backup server is: $TARGETNODE"
echo

# User Specific Variables
USER=$(whoami)
echo "Enter your DTU username [$USER]:"
read ANS
case $ANS in
    "")
        RUSER=$USER ;;
    *)
        RUSER=$ANS ;;
esac
RHOME=/home/$RUSER
SCRIPTNAME="$SCRIPTNAME-$RUSER"

# PC Specific Variables
echo "Enter the hostname (eg. comp-nbXXXX) [$HOST]:"
read ANS
case $ANS in
    "")
        HOST=$HOST ;;
    *)
        HOST=$ANS ;;
esac

# SUDO
chksudo() {
    echo "Check sudo"
    sudo -l &>/dev/null
    if [ $? -ne 0 ]; then
        echo "You need sudo rights to continue."
        exit 1
    fi
    echo "[sudo] OK"
    }

# Platform Specific Variables
HOST_OS=$(uname -s)
if [ $HOST_OS = 'Darwin' ]; then
    UNIT_DIR="$H/Library/LaunchAgents"
    [ ! -d $UNIT_DIR ] && mkdir -p $UNIT_DIR
    CONF_DIR="$H/Library/$SCRIPTNAME"
    $(which osascript &>/dev/null)
    if [ $? -eq 0 ]; then
        NOTIFY0='osascript -e "display notification \"Backup done\" with title \"FYI\""'
        NOTIFY1='osascript -e "display notification \"Backup did not complete\" with title \"FYI\""'
    fi
    pexcl=($H/Movies
          $H/.Trash
          $H/Library
          *.dmg
          .DS_Store)
elif [ $HOST_OS = 'Linux' ]; then
    CONF_DIR="$H/.config/$SCRIPTNAME"
    $(which notify-send &>/dev/null)
    if [ $? -eq 0 ]; then
        NOTIFY0='notify-send "Backup done"'
        NOTIFY1='notify-send "Backup did not complete"'
    fi
    pexcl=($H/Videos
    	   $H/.dbus)
    # SYSTEMD
    $(which systemctl &>/dev/null)
    if [ $? -ne 0 ]; then
        SYSTEMD=0
        echo "No systemd - Backup will need to be run manually"
    else
        SYSTEMD=1
	# look for 3 digits with a space before and/or after
        sysd_ver=$(systemctl --version |grep -o '\s[[:digit:]]\{3\}\s\{,1\}')
        if [ $sysd_ver -lt 220 ]; then
            echo "No 'systemctl --user' capability"
            echo "Installing system wide"
            chksudo
            dosudo="sudo"
            UNIT_DIR="/etc/systemd/system"
        else
            UNIT_DIR="$H/.config/systemd/user"
            [ ! -d $UNIT_DIR ] && mkdir -p $UNIT_DIR
            douser="--user"
        fi
    fi
else
    echo "OS not supportet"
    exit 1
fi
incl=($H/)
excl=(
     $H/Downloads
     $H/Music
     $H/anaconda*
     $H/.conda
     $H/.cache
     $H/.local
     $H/.viminfo
     *.vdi
     *.vmdk
     *.iso
     )

# Initial Setup
if [ -x $BIN_DIR/$SCRIPTNAME ]; then
    ver=$(grep -o [0-9]$ $BIN_DIR/$SCRIPTNAME)
    if [ $ver -lt $VERSION ]; then
        echo "New version will be installed"
        if [ $HOST_OS = 'Linux' ]; then
            if [ $SYSTEMD = 1 ]; then
                $dosudo systemctl $douser stop $SCRIPTNAME.timer &>/dev/null
                $dosudo systemctl $douser disable $SCRIPTNAME.timer &>/dev/null
            fi
        fi
    else
        echo "Backup script already installed"
        exit 0
    fi
elif [ ! -d $BIN_DIR ]; then
    mkdir $BIN_DIR 
fi
$(echo $PATH | grep -o $BIN_DIR &>/dev/null)
if [ $? -ne 0 ]; then
    if [ $SHELL == '/bin/bash' ]; then
        echo -e "\nexport PATH=$PATH:$BIN_DIR" >> $H/.bash_profile
        source $H/.bash_profile
    elif [ $SHELL == '/bin/zsh' ]; then
        echo -e "\nexport PATH=$PATH:$BIN_DIR" >> $H/.zprofile
        source $H/.zprofile
    else
        echo -e "\nexport PATH=$PATH:$BIN_DIR" >> $H/.profile
        source $H/.profile
    fi
fi
if [ ! -d $CONF_DIR ]; then
    mkdir -p $CONF_DIR 
    echo "# Files to include" > $CONF_DIR/include
    for i in ${incl[*]}; do
        echo $i >> $CONF_DIR/include
    done
    echo "# Files to exclude" > $CONF_DIR/exclude
    for e in ${excl[*]}; do
        echo $e >> $CONF_DIR/exclude
    done
    for p in ${pexcl[*]}; do
        echo $p >> $CONF_DIR/exclude
    done
fi

# SSH
echo "Check ssh"
grep $TARGETNODE $H/.ssh/known_hosts &>/dev/null
if [ $? -ne 0 ]; then
    if [ ! -d ~/.ssh ]; then
        mkdir ~/.ssh
        chmod 700 ~/.ssh
    fi
    ssh-keyscan -H -t ecdsa $TARGETNODE 2>/dev/null|grep ^[^#] >> ~/.ssh/known_hosts
fi

SSHKEY=~/.ssh/$SCRIPTNAME
if [ -f $SSHKEY ]; then
    ssh -o BatchMode=yes -i $SSHKEY $RUSER@$TARGETNODE "grep -o $USER@$HOST .ssh/authorized_keys" &>/dev/null
    if [ $? -ne 0 ]; then
        echo "Installing public key"
        ssh-copy-id -i $SSHKEY $RUSER@$TARGETNODE &>/dev/null
    else
        echo "[ssh] OK"
    fi
else
    echo "Creating SSH keys"
    ssh-keygen -q -f $SSHKEY -N '' &>/dev/null
    ssh-copy-id -i $SSHKEY $RUSER@$TARGETNODE &>/dev/null
fi

# Create Backup Dir
echo "Checking for backup dir..."
ssh -i $SSHKEY $RUSER@$TARGETNODE ls -d $RHOME/$HOST &>/dev/null
if [ $? = 0 ]; then
    ssh -i $SSHKEY $RUSER@$TARGETNODE ls $RHOME/$HOST/$LOGNAME &>/dev/null
    if [ $? = 0 ]; then
        ssh -i $SSHKEY $RUSER@$TARGETNODE mv $RHOME/$HOST/$LOGNAME $RHOME/$HOST/old_install.$(date +%Y-%m-%d)
    fi
    echo "OK"
else
    ssh -i $SSHKEY $RUSER@$TARGETNODE "mkdir $RHOME/$HOST && chmod 700 $RHOME/$HOST"
    if [ $? = 0 ]; then
	if [ -f "$SERIAL" ]; then
	    scp -i $SSHKEY $SERIAL $RUSER@$TARGETNODE:$RHOME/$HOST/ &>/dev/null
	else
	    echo "No Serial file to copy..."
	fi
        echo "Created backup dir"
    else
        echo "Failed to create backup dir"
        exit 1
    fi
fi

# Script & Daemon Files
echo "Writing files"

TMP="$H/.local/tmp"
if [ ! -d $TMP ]; then
    mkdir -p $TMP
fi
LOG=$TMP/$LOGNAME-$RUSER

cat > $BIN_DIR/$SCRIPTNAME << EOF
#!/bin/bash
# version=$VERSION

# Log check
logcheck(){
    lsize=\$(du $LOG|awk '{print \$1}')
    if [ \$lsize -gt 2048 ]; then
        scp -i $SSHKEY $LOG $RUSER@$TARGETNODE:$RHOME/$HOST/$LOGNAME-$RUSER.\$(date +%Y-%m-%d)
        mv $LOG $LOG.\$(date +%Y-%m-%d)
    fi
}

# Main
if [ -f $LOG ]; then
    logcheck
fi
rsync -arRx -e "ssh -i $SSHKEY" \
--files-from=$CONF_DIR/include \
--exclude-from=$CONF_DIR/exclude \
--delete-excluded --delete-before \
--log-file=$LOG \
/ $RUSER@$TARGETNODE:$RHOME/$HOST/

if [ \$? -eq 0 ]; then
    echo "Backup ok"
    $NOTIFY0
else
    echo "Backup failed"
    $NOTIFY1
fi

# Log update
rsync -a -e "ssh -i $SSHKEY" $TMP/$LOGNAME-$RUSER $RUSER@$TARGETNODE:$RHOME/$HOST/$LOGNAME
EOF
chmod +x $BIN_DIR/$SCRIPTNAME

if [ $HOST_OS = 'Darwin' ]; then

cat > $UNIT_DIR/com.dtucompute.backup.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

<dict>
	<key>Label</key>
	<string>com.dtucompute.backup</string>
	<key>ProgramArguments</key>
	<array>
		<string>$BIN_DIR/$SCRIPTNAME</string>
	</array>
	<key>StartInterval</key>
	<integer>10800</integer>
</dict>

</plist>
EOF

elif [ $SYSTEMD = 1 ]; then

$dosudo bash -c "cat > $UNIT_DIR/$SCRIPTNAME.timer" << EOF
[Unit]
Description=$SCRIPTNAME timer

[Timer]
OnBootSec=5min
OnUnitActiveSec=3h
Unit=$SCRIPTNAME.service

[Install]
WantedBy=timers.target
EOF

$dosudo bash -c "cat > $UNIT_DIR/$SCRIPTNAME.service" << EOF
[Unit]
Description=DTU Compute backup script
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=$BIN_DIR/$SCRIPTNAME

[Install]
WantedBy=default.target
EOF

$dosudo systemctl $douser enable $SCRIPTNAME.timer &>/dev/null
fi

# Finish
echo "Backup script installed"
echo