#!/bin/sh
#
# This file is part of OpenMediaVault.
#
# @license   http://www.gnu.org/licenses/gpl.html GPL Version 3
# @author    Volker Theile <volker.theile@openmediavault.org>
# @copyright Copyright (c) 2009-2017 Volker Theile
#
# OpenMediaVault 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
# any later version.
#
# OpenMediaVault 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.
#
# You should have received a copy of the GNU General Public License
# along with OpenMediaVault. If not, see <http://www.gnu.org/licenses/>.

# Documentation/Howto:
# https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files
# http://blog.tjll.net/systemd-for-device-activation-and-media-archiving/
#
# systemctl --all --full -t device

set -e

. /etc/default/openmediavault
. /usr/share/openmediavault/scripts/helper-functions

OMV_USBBACKUP_SCRIPTS_DIR=${OMV_USBBACKUP_SCRIPTS_DIR:-"/var/lib/openmediavault/usbbackup.d"}
OMV_USBBACKUP_SCRIPTS_MASK=${OMV_USBBACKUP_SCRIPTS_MASK:-"755"}
OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX=${OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX:-"rsync-"}
OMV_USBBACKUP_JOBS_SCRIPT_PREFIX=${OMV_USBBACKUP_JOBS_SCRIPT_PREFIX:-"openmediavault-usbbackup-"}
OMV_USBBACKUP_LOGFILE=${OMV_USBBACKUP_LOGFILE:-"/var/log/rsync.log"}
OMV_USBBACKUP_SYSTEMD_SCRIPTS_DIR=${OMV_USBBACKUP_SYSTEMD_SCRIPTS_DIR:-"/lib/systemd/system"}
OMV_USBBACKUP_SYSTEMD_UNITFILE_PREFIX=${OMV_USBBACKUP_SYSTEMD_UNITFILE_PREFIX:-"openmediavault-usbbackup-"}
OMV_USBBACKUP_SYSTEMD_UNITFILE_MASK=${OMV_USBBACKUP_SYSTEMD_UNITFILE_MASK:-"644"}

# Create the backup jobs. Each job is configured in a seperate script.
mkdir -p ${OMV_USBBACKUP_SCRIPTS_DIR}
find "${OMV_USBBACKUP_SCRIPTS_DIR}" -type f -iname "${OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX}*" -print0 | xargs -0r rm -f
find "${OMV_USBBACKUP_SCRIPTS_DIR}" -type f -iname "${OMV_USBBACKUP_JOBS_SCRIPT_PREFIX}*" -print0 | xargs -0r rm -f
find "${OMV_USBBACKUP_SYSTEMD_SCRIPTS_DIR}" -type f -iname "${OMV_USBBACKUP_SYSTEMD_UNITFILE_PREFIX}*" -print0 | xargs -0r rm -f

# Create the scripts regardless if enabled or disabled.
xmlstarlet sel -t \
  -m "//services/usbbackup/jobs/job" \
    -v "uuid" -n \
  -b \
  ${OMV_CONFIG_FILE} | xmlstarlet unesc |
  while read uuid; do
	  filename="${OMV_USBBACKUP_SCRIPTS_DIR}/${OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX}${uuid}"
	  runfile="/var/run/${OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX}${uuid}"

	  xmlstarlet sel -t -m "//services/usbbackup/jobs/job[uuid='${uuid}']" \
		-o "#!/bin/sh" -n \
		-o "# This configuration file is auto-generated." -n \
		-o "# WARNING: Do not edit this file, your changes will be lost." -n \
		-o ". /usr/share/openmediavault/scripts/helper-functions" -n \
		-o "cleanup() {" -n \
		-o "    omv_kill_children \$\$" -n \
		-o "    rm -f ${runfile}" -n \
		-o "    exit" -n \
		-o "}" -n \
		-o "[ -e ${runfile} ] && exit 1" -n \
		-o "# Make sure the storage device is mounted." -n \
		-v "concat('id=\$(omv_md5 ',devicefile,')')" -n \
		-o "mountdir=\$(omv_build_mount_dir \${id})" -n \
		-o "if ! omv_is_mounted \${mountdir} ; then" -n \
		-v "concat('    omv_error \"External storage device <',devicefile,'> not mounted!\"')" -n \
		-o "    exit 1" -n \
		-o "fi" -n \
		-o "trap cleanup 0 1 2 5 15" -n \
		-o "touch ${runfile}" -n \
		-i "mode = 'push' and usesubdir = '1'" \
		  -o "# Create target directory on external storage device." -n \
		  -o "mkdir -p \"\${mountdir}/" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -o "\"" -n \
		  -o "chmod 777 \"\${mountdir}/" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -o "\"" -n \
		-b \
		-o "# Synchronise directories ..." -n \
		-o "omv_log \"Please wait, syncing '" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_PATH} -o "' to '\${mountdir}" -i "usesubdir = '1'" -o "/" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -b -o "' ...\n\"" -n \
		-o "rsync --verbose --log-file=\"${OMV_USBBACKUP_LOGFILE}\"" \
		-i "recursive = '1'" -o " --recursive" -b \
		-i "times = '1'" -o " --times" -b \
		-i "compress = '1'" -o " --compress" -b \
		-i "archive = '1'" -o " --archive" -b \
		-i "delete = '1'" -o " --delete" -b \
		-i "quiet = '1'" -o " --quiet" -b \
		-i "perms = '1'" -o " --perms" -b \
		-i "acls = '1'" -o " --acls" -b \
		-i "xattrs = '1'" -o " --xattrs" -b \
		-i "partial = '1'" -o " --partial" -b \
		-i "string-length(extraoptions) > 0" -v "concat(' ',extraoptions)" -b \
		-i "mode = 'push'" -o " \"" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_PATH} -o "/\" \"\${mountdir}" -i "usesubdir = '1'" -o "/" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -b -o "\"" -b \
		-i "mode = 'pull'" -o " \"\${mountdir}" -i "usesubdir = '1'" -o "/" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -b -o "/\" \"" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_PATH} -o "\"" -b \
		-o " & wait \$!" -n \
		-o "omv_log \"\nThe synchronisation has completed successfully.\"" \
		${OMV_CONFIG_FILE} | xmlstarlet unesc > ${filename}
	  chmod ${OMV_USBBACKUP_SCRIPTS_MASK} ${filename}
  done

# Create the scripts executed by systemd when the USB storage device is
# connected. Process duplicate jobs per filesystem only once (emulate SQL
# 'DISTINCT' to do this).
xmlstarlet sel -t \
  -m "//services/usbbackup/jobs/job[not(devicefile=preceding-sibling::*/devicefile) and enable='1']" \
    -v "devicefile" -n \
  -b \
  ${OMV_CONFIG_FILE} | xmlstarlet unesc |
  while read devicefile; do
	  id=$(omv_md5 ${devicefile})
	  scriptfile="${OMV_USBBACKUP_SCRIPTS_DIR}/${OMV_USBBACKUP_JOBS_SCRIPT_PREFIX}${id}"
	  runfile="/var/run/${OMV_USBBACKUP_JOBS_SCRIPT_PREFIX}${id}"
	  mountdir=$(omv_build_mount_dir ${id})
	  unitfile="${OMV_USBBACKUP_SYSTEMD_SCRIPTS_DIR}/${OMV_USBBACKUP_SYSTEMD_UNITFILE_PREFIX}${id}.service"
	  device=$(systemd-escape --path ${devicefile})

	  xmlstarlet sel -t \
		-o "#!/bin/sh" -n \
		-o "# This configuration file is auto-generated." -n \
		-o "# WARNING: Do not edit this file, your changes will be lost." -n \
		-o ". /usr/share/openmediavault/scripts/helper-functions" -n \
		-o "outfile=$(mktemp)" -n \
		-o "cleanup() {" -n \
		-o "    # Kill all child processes." -n \
		-o "    omv_kill_children \$\$" -n \
		-o "    # Remove temporary files." -n \
		-o "    rm -f ${runfile}" -n \
		-o "    rm -f \${outfile}" -n \
		-o "    # Umount the storage device." -n \
		-o "    umount ${devicefile} || true" -n \
		-o "    rmdir ${mountdir} || true" -n \
		-o "    exit" -n \
		-o "}" -n \
		-o "if [ -e ${runfile} ]; then" -n \
		-o "    omv_error \"The sync job is already running.\"" -n \
		-o "    omv_beep_error" -n \
		-o "    exit 1" -n \
		-o "fi" -n \
		-o "# Check if the storage device exists." -n \
		-o "if [ ! -b \"${devicefile}\" ]; then" -n \
		-o "    omv_error \"External storage device '${devicefile}' not found!\"" -n \
		-o "    omv_beep_error" -n \
		-o "    exit 1" -n \
		-o "fi" -n \
		-o "# Mount the storage device." -n \
		-o "mkdir -p ${mountdir}" -n \
		-o "mount ${devicefile} ${mountdir}" -n \
		-o "# Make sure the storage device is mounted." -n \
		-o "if ! omv_is_mounted ${mountdir} ; then" -n \
		-o "    omv_error \"External storage device '${devicefile}' not mounted!\"" -n \
		-o "    omv_beep_error" -n \
		-o "    exit 1" -n \
		-o "fi" -n \
		-o "trap cleanup 0 1 2 5 15" -n \
		-o "touch ${runfile}" -n \
		-o "# Execute the rsync backup scripts." -n \
		-o "omv_beep_start" -n \
		-m "//services/usbbackup/jobs/job[devicefile='${devicefile}' and enable='1']" \
		  -v "concat('${OMV_USBBACKUP_SCRIPTS_DIR}/${OMV_USBBACKUP_RSYNC_SCRIPT_PREFIX}',uuid,' | tee \${outfile}')" -n \
		  -i "sendemail[. = '1']" \
		    -o "mail -E -s \"USB Backup (shared folder=" ${OMV_XMLSTARLET_GET_SHAREDFOLDER_NAME} -o ", device=" -v devicefile -o ")" \
			-i "string-length(comment) > 0" \
			  -v "concat(' - ',translate(comment,'\

',' '))" \
			-b \
			-o "\" -a \"From: USB Backup <root>\" root <\${outfile}" -n \
		  -b \
		-b \
		-o "omv_beep_ok" \
		${OMV_CONFIG_FILE} | xmlstarlet unesc > ${scriptfile}
	  chmod ${OMV_USBBACKUP_SCRIPTS_MASK} ${scriptfile}

	  cat <<EOF > ${unitfile}
[Unit]
Description=Execute the rsync backup jobs when ${devicefile} is plugged in
BindsTo=${device}.device
After=${device}.device
Requisite=${device}.device

[Service]
Type=oneshot
RemainAfterExit=false
ExecStart=${scriptfile}

[Install]
WantedBy=${device}.device
EOF
	  chmod ${OMV_USBBACKUP_SYSTEMD_UNITFILE_MASK} ${unitfile}
  done
