#!/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:
# http://blog.shadypixel.com/monitoring-a-ups-with-nut-on-debian-or-ubuntu-linux/
# http://www.die-welt.net/2011/02/mustek-powemust-1000-usb-on-debian-squeeze/
# http://beeznest.wordpress.com/2008/07/14/howto-setup-nut-network-ups-tools-on-debian/
# http://kiserai.net/blog/2009/03/07/belkin-universal-ups-with-nut-debian
# http://rogerprice.org/NUT.html
# http://linuxman.wikispaces.com/NUT
# http://ifireball.wordpress.com/2011/10/13/configuring-aviem-pro2100-ups-on-debian-6-0-stablesqueeze/
# http://blog.shadypixel.com/monitoring-a-ups-with-nut-on-debian-or-ubuntu-linux
# http://adi.roiban.ro/2011/11/10/monitor-the-ups-in-ubuntu-with-network-ups-tools

set -e

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

OMV_NUT_NUT_CONFIG=${OMV_NUT_NUT_CONFIG:-"/etc/nut/nut.conf"}
OMV_NUT_UPS_CONFIG=${OMV_NUT_UPS_CONFIG:-"/etc/nut/ups.conf"}
OMV_NUT_UPSD_CONFIG=${OMV_NUT_UPSD_CONFIG:-"/etc/nut/upsd.conf"}
OMV_NUT_UPSD_MAXAGE=${OMV_NUT_UPSD_MAXAGE:-"15"}
OMV_NUT_UPSD_MAXCONN=${OMV_NUT_UPSD_MAXCONN:-"1024"}
OMV_NUT_UPSD_PORT=${OMV_NUT_UPSD_PORT:-"3493"}
OMV_NUT_UPSDUSERS_CONFIG=${OMV_NUT_UPSDUSERS_CONFIG:-"/etc/nut/upsd.users"}
OMV_NUT_UPSDUSERS_ADMIN_USER=${OMV_NUT_UPSDUSERS_ADMIN_USER:-"admin"}
OMV_NUT_UPSDUSERS_ADMIN_PASSWORD=${OMV_NUT_UPSDUSERS_ADMIN_PASSWORD:-"$(openssl rand -hex 16)"}
OMV_NUT_UPSDUSERS_ADMIN_INSTCMDS=${OMV_NUT_UPSDUSERS_ADMIN_INSTCMDS:-"ALL"}
OMV_NUT_UPSDUSERS_MONITOR_USER=${OMV_NUT_UPSDUSERS_MONITOR_USER:-"monmaster"}
OMV_NUT_UPSDUSERS_MONITOR_PASSWORD=${OMV_NUT_UPSDUSERS_MONITOR_PASSWORD:-"$(openssl rand -hex 16)"}
OMV_NUT_UPSMON_CONFIG=${OMV_NUT_UPSMON_CONFIG:-"/etc/nut/upsmon.conf"}
OMV_NUT_UPSMON_MINSUPPLIES=${OMV_NUT_UPSMON_MINSUPPLIES:-"1"}
OMV_NUT_UPSMON_SHUTDOWNCMD=${OMV_NUT_UPSMON_SHUTDOWNCMD:-"/sbin/shutdown -h +0"}
OMV_NUT_UPSMON_NOTIFYCMD=${OMV_NUT_UPSMON_NOTIFYCMD:-"/sbin/upssched"}
OMV_NUT_UPSMON_POLLFREQ=${OMV_NUT_UPSMON_POLLFREQ:-"5"}
OMV_NUT_UPSMON_POLLFREQALERT=${OMV_NUT_UPSMON_POLLFREQALERT:-"5"}
OMV_NUT_UPSMON_HOSTSYNC=${OMV_NUT_UPSMON_HOSTSYNC:-"15"}
OMV_NUT_UPSMON_DEADTIME=${OMV_NUT_UPSMON_DEADTIME:-""}
OMV_NUT_UPSMON_POWERDOWNFLAG=${OMV_NUT_UPSMON_POWERDOWNFLAG:-"/etc/killpower"}
OMV_NUT_UPSMON_RBWARNTIME=${OMV_NUT_UPSMON_RBWARNTIME:-"43200"}
OMV_NUT_UPSMON_NOCOMMWARNTIME=${OMV_NUT_UPSMON_NOCOMMWARNTIME:-"300"}
OMV_NUT_UPSMON_FINALDELAY=${OMV_NUT_UPSMON_FINALDELAY:-"5"}
OMV_NUT_UPSSCHED_CONFIG=${OMV_NUT_UPSSCHED_CONFIG:-"/etc/nut/upssched.conf"}
OMV_NUT_UPSSCHED_CMDSCRIPT=${OMV_NUT_UPSSCHED_CMDSCRIPT:-"/usr/bin/upssched-cmd"}
OMV_NUT_UDEV_RULE_CONFIG=${OMV_NUT_UDEV_RULE_CONFIG:-"/etc/udev/rules.d/99-openmediavault-nut-serialups.rules"}
OMV_NUT_UDEV_RULE_GROUP=${OMV_NUT_UDEV_RULE_GROUP:-"nut"}

mkconf() {
	# Create the '/etc/nut/nut.conf' file.
	xmlstarlet sel -t -m "//services/nut" \
	  -i "remotemonitor[. = '0']" -o "MODE=standalone" -b \
	  -i "remotemonitor[. = '1']" -o "MODE=netserver" -b \
	  ${OMV_CONFIG_FILE} | xmlstarlet unesc > ${OMV_NUT_NUT_CONFIG}

	# Create the '/etc/nut/ups.conf'.
	xmlstarlet sel -t -m "//services/nut" \
	  -v "concat('[',upsname,']')" -n \
	  -v driverconf -n \
	  -i "string-length(comment) > 0" -v "concat('desc = ',comment)" -b \
	  ${OMV_CONFIG_FILE} | xmlstarlet unesc > ${OMV_NUT_UPS_CONFIG}

	# Create the '/etc/nut/upsd.conf' file.
	cat <<EOF > ${OMV_NUT_UPSD_CONFIG}
MAXAGE ${OMV_NUT_UPSD_MAXAGE}
MAXCONN ${OMV_NUT_UPSD_MAXCONN}
EOF

	if [ "1" = "$(omv_config_get "//services/nut/remotemonitor")" ]; then
		# To simplify setup we are listening on ANY network address. To
		# enhance security this can be limited via iptables rules.
		echo "LISTEN 0.0.0.0 ${OMV_NUT_UPSD_PORT}" >> ${OMV_NUT_UPSD_CONFIG}
	else
		# If remote monitoring is disabled then only listen on localhost.
		echo "LISTEN 127.0.0.1 ${OMV_NUT_UPSD_PORT}" >> ${OMV_NUT_UPSD_CONFIG}
	fi

	# Create '/etc/nut/upsd.users'.
	# Note, the password for OMV_NUT_UPSDUSERS_MONITOR_USER
	# is generated randomly each time the config is created.
	xmlstarlet sel -t -m "//services/nut" \
	  -o "[${OMV_NUT_UPSDUSERS_ADMIN_USER}]" -n \
	  -o "password = ${OMV_NUT_UPSDUSERS_ADMIN_PASSWORD}" -n \
	  -o "actions = set" -n \
	  -o "actions = fsd" -n \
	  -o "instcmds = ${OMV_NUT_UPSDUSERS_ADMIN_INSTCMDS}" -n \
	  -n \
	  -o "[${OMV_NUT_UPSDUSERS_MONITOR_USER}]" -n \
	  -o "password = ${OMV_NUT_UPSDUSERS_MONITOR_PASSWORD}" -n \
	  -o "upsmon master" -n \
	  -i "remotemonitor[. = '1']" \
		-n \
		-v "concat('[',remoteuser,']')" -n \
		-v "concat('password = ',remotepassword)" -n \
		-o "upsmon slave" \
	  -b \
	  ${OMV_CONFIG_FILE} | xmlstarlet unesc > ${OMV_NUT_UPSDUSERS_CONFIG}

	# Create the '/etc/nut/upsmon.conf' file.
	if [ -z "${OMV_NUT_UPSMON_DEADTIME}" ]; then
		# Calulate the dead time value: take the larger of the two POLLFREQ
		# values, and multiply by 3.
		# See http://www.networkupstools.org/docs/man/upsmon.conf.html
		pollfreq=${OMV_NUT_UPSMON_POLLFREQ}
		[ ${OMV_NUT_UPSMON_POLLFREQALERT} -gt ${OMV_NUT_UPSMON_POLLFREQ} ] && pollfreq=${OMV_NUT_UPSMON_POLLFREQALERT}
		OMV_NUT_UPSMON_DEADTIME=$((${pollfreq} * 3))
	fi
	xmlstarlet sel -t -m "//services/nut" \
	  -v "concat('MONITOR ',upsname,'@localhost 1 ${OMV_NUT_UPSDUSERS_MONITOR_USER} ${OMV_NUT_UPSDUSERS_MONITOR_PASSWORD} master')" -n \
	  ${OMV_CONFIG_FILE} | xmlstarlet unesc > ${OMV_NUT_UPSMON_CONFIG}
	cat <<EOF >> ${OMV_NUT_UPSMON_CONFIG}
MINSUPPLIES ${OMV_NUT_UPSMON_MINSUPPLIES}
SHUTDOWNCMD "${OMV_NUT_UPSMON_SHUTDOWNCMD}"
NOTIFYCMD "${OMV_NUT_UPSMON_NOTIFYCMD}"
POLLFREQ ${OMV_NUT_UPSMON_POLLFREQ}
POLLFREQALERT ${OMV_NUT_UPSMON_POLLFREQALERT}
HOSTSYNC ${OMV_NUT_UPSMON_HOSTSYNC}
DEADTIME ${OMV_NUT_UPSMON_DEADTIME}
POWERDOWNFLAG ${OMV_NUT_UPSMON_POWERDOWNFLAG}
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC
NOTIFYFLAG NOCOMM SYSLOG+WALL+EXEC
NOTIFYFLAG FSD SYSLOG+WALL+EXEC
RBWARNTIME ${OMV_NUT_UPSMON_RBWARNTIME}
NOCOMMWARNTIME ${OMV_NUT_UPSMON_NOCOMMWARNTIME}
FINALDELAY ${OMV_NUT_UPSMON_FINALDELAY}
EOF

	# Create '/etc/nut/upssched.conf'
	cat <<EOF > ${OMV_NUT_UPSSCHED_CONFIG}
CMDSCRIPT ${OMV_NUT_UPSSCHED_CMDSCRIPT}
PIPEFN /var/run/nut/upssched.pipe
LOCKFN /var/run/nut/upssched.lock
AT COMMOK * EXECUTE notify
AT COMMBAD * EXECUTE notify
AT REPLBATT * EXECUTE notify
AT NOCOMM * EXECUTE notify
AT FSD * EXECUTE forced-shutdown
AT NOPARENT * EXECUTE notify
AT SHUTDOWN * EXECUTE notify
EOF
	if [ "onbatt" = "$(omv_config_get "//services/nut/shutdownmode")" ]; then
		shutdowntimer=$(omv_config_get "//services/nut/shutdowntimer")
		cat <<EOF >> ${OMV_NUT_UPSSCHED_CONFIG}
AT ONLINE * CANCEL-TIMER shutdown
AT ONLINE * EXECUTE resume
AT ONBATT * START-TIMER shutdown ${shutdowntimer}
AT ONBATT * EXECUTE shutdown-warning
AT LOWBATT * START-TIMER shutdown
AT LOWBATT * EXECUTE shutdown-warning
EOF
	else
		cat <<EOF >> ${OMV_NUT_UPSSCHED_CONFIG}
AT ONLINE * EXECUTE notify
AT ONBATT * EXECUTE notify
AT LOWBATT * EXECUTE notify
EOF
	fi

	# Create '/etc/default/upssched-cmd'
	# Using the defaults file is necessary because the script is executed as
	# user 'nut' which does not have the privileges to read the OMV config.xml
	# file to extract necessary informations.
	xmlstarlet sel -t \
	  -o "# This file is auto-generated by OpenMediaVault." -n \
	  -m "//system/email" \
		-i "enable = '1'" \
		  -o "OMV_NUT_UPSSCHEDCMD_EMAIL_ENABLE=\"yes\"" -n \
		-b \
	  -m "//services/nut" \
		-v "concat('OMV_NUT_UPSSCHEDCMD_SHUTDOWNTIMER=\"',shutdowntimer,'\"')" \
	  ${OMV_CONFIG_FILE} | xmlstarlet unesc > /etc/default/upssched-cmd

	# Modify file permissions.
	chown root:nut /etc/nut/*
	chmod 640 /etc/nut/*

	# Create a udev rule for the given port if necessary.
	#port=$(xmlstarlet sel -t -v "//services/nut/driverconf" ${OMV_CONFIG_FILE} | grep -E "^\s*port\s*=.+$" | sed -e 's/^\s*port\s*=\s*\([a-zA-Z0-9\/]*\)\s*$/\1/g')
	port=$(omv_config_get "//services/nut/driverconf" | sed -n -e 's/^.*port\s*=\s*\([a-zA-Z0-9\/]*\)\s*.*$/\1/p')
	if [ "${port}" != "auto" ]; then
		cat <<EOF > ${OMV_NUT_UDEV_RULE_CONFIG}
# This configuration file is auto-generated.
# WARNING: Do not edit this file, your changes will be lost.
KERNEL=="${port##*/}", GROUP="${OMV_NUT_UDEV_RULE_GROUP}"
EOF
	else
		rm -f ${OMV_NUT_UDEV_RULE_CONFIG}
	fi
}

case "$1" in
	mkconf|*)
		mkconf
		;;
esac
