#!/bin/bash
#
# Helper script for Ubiquiti UniFi Network
#

. "/usr/sbin/unifi-network-service-common"

# General parameters
NAME="unifi"
BASEDIR="/usr/lib/unifi"
ADDITIONAL_STORAGE_BASE="/srv"

### Helper functions ###

function is_link() {
	[ -L "$1" ] && [ -e "$1" ]
}

function is_mountpoint() {
	mountpoint -q "$1"
}

function is_additional_storage_available() {
	is_mountpoint "$ADDITIONAL_STORAGE_BASE" || is_link "$ADDITIONAL_STORAGE_BASE"
}

function create_additional_storage_dir() {
	if is_additional_storage_available && [ ! -d "$ADDITIONAL_STORAGE_DIR" ]; then
		mkdir "$ADDITIONAL_STORAGE_DIR"
		chown "$USER:$GROUP" "$ADDITIONAL_STORAGE_DIR"
	fi
}

function create_db_dir() {
	if [ ! -d "$DB_DIR" ]; then
		mkdir "$DB_DIR"
		chown "$USER:$GROUP" "$DB_DIR"
	fi
}

function mount_tmpfs_dir() {
	# Support directories
	mkdir -p "$TMPFS_DIR"
	chown -R "$USER:$GROUP" "$TMPFS_DIR"

	# Mount temp filesystem
	mount -t tmpfs -o size=$TMPFS_SIZE tmpfs $TMPFS_DIR || log "Warning: Could not mount tmpfs to $TMPFS_DIR"
}

function unmount_tmpfs_dir() {
	log "tmpfs: $TMPFS_DIR"
	if is_mountpoint "$TMPFS_DIR"; then
		umount "$TMPFS_DIR" || log "Warning: Could not unmount tmpfs from $TMPFS_DIR"
	fi
}

function create_dirs() {
	log "user: $USER, group: $GROUP"
	log "data: $DATADIR, logs: $LOGDIR, run: $RUNDIR, additional storage: $ADDITIONAL_STORAGE_DIR"
	log "tmpfs: $TMPFS_DIR, size: $TMPFS_SIZE"
	link_to_persistent "${DATADIR}" "${BASEDIR}"/data
	link_to_persistent "${LOGDIR}"  "${BASEDIR}"/logs
	link_to_persistent "${RUNDIR}"  "${BASEDIR}"/run
	create_additional_storage_dir
	create_db_dir
	mount_tmpfs_dir

	check_dir_permissions || log "Warning: Wrong permissions for ${DATADIR}, ${LOGDIR}, ${RUNDIR}"

	return 0
}

function check_dir_permissions() {
	local unifi_uid=$(id -u "${USER}")

	local datadir_uid=$(stat ${DATADIR} -Lc %u)
	local logdir_uid=$( stat ${LOGDIR}  -Lc %u)
	local rundir_uid=$( stat ${RUNDIR}  -Lc %u)

	[ "${unifi_uid}" == "${datadir_uid}" ] && \
	[ "${unifi_uid}" == "${logdir_uid}"  ] && \
	[ "${unifi_uid}" == "${logdir_uid}"  ] && \
	\
	sudo -u "${USER}" test -w "${DATADIR}" && \
	sudo -u "${USER}" test -w "${LOGDIR}"  && \
	sudo -u "${USER}" test -w "${RUNDIR}"  && \
	\
		return 0;

	return 1;
}

function link_to_persistent() {
	local persistent_dir="${1}"
	local orig_dir="${2}"
	install -o "${USER}" -dD "${persistent_dir}"
	chown -R "${USER}": "${persistent_dir}"
	if ! [ -L "${orig_dir}" -a "${persistent_dir}" -ef  "${orig_dir}" ]; then
		rm -rf "${orig_dir}"
		ln -sf "${persistent_dir}" "${orig_dir}"
	fi
}

function dir_symlink_fix () {
	local DSTDIR=$1
	local SYMLINK=$2
	local MYUSER=$3
	local MYGROUP=$4
	local MYMODE=$5

	[ -d ${DSTDIR} ] || install -o ${MYUSER} -g ${MYGROUP} -m ${MYMODE} -d ${DSTDIR}
	[ -d ${SYMLINK} -a ! -L ${SYMLINK} ] && mv ${SYMLINK} `mktemp -u ${SYMLINK}.XXXXXXXX`
	[ "$(readlink ${SYMLINK})" = "${DSTDIR}" ] || (rm -f ${SYMLINK} && ln -sf ${DSTDIR} ${SYMLINK})
}

function file_symlink_fix () {
	local DSTFILE=$1
	local SYMLINK=$2

	if [ -f ${DSTFILE} ]; then
		[ -f ${SYMLINK} -a ! -L ${SYMLINK} ] && mv ${SYMLINK} `mktemp -u ${SYMLINK}.XXXXXXXX`
		[ "$(readlink ${SYMLINK})" = "${DSTFILE}" ] || (rm -f ${SYMLINK} && ln -sf ${DSTFILE} ${SYMLINK})
	fi
}

function nested_symlinks_fix () {
	# Fix issue with nested symbolic links
	[ -L "${BASEDIR}"/data/data ] && rm "${BASEDIR}"/data/data
	[ -L "${BASEDIR}"/logs/logs ] && rm "${BASEDIR}"/logs/logs
	[ -L "${BASEDIR}"/run/run ] && rm "${BASEDIR}"/run/run
	[ -L "${BASEDIR}"/data/unifi ] && rm "${BASEDIR}"/data/unifi
	[ -L "${BASEDIR}"/logs/unifi ] && rm "${BASEDIR}"/logs/unifi
	[ -L "${BASEDIR}"/run/unifi ] && rm "${BASEDIR}"/run/unifi
}

function remove_old_format_logs () {
	# Remove server logs with old format 'server.log.yyyy-MM-dd.X'
	if [ -d ${LOGDIR} ]; then
		rm -f ${LOGDIR}/server\.log\.[0-9]*-[0-9]*-[0-9]*\.[0-9]*
	fi
}

function init () {
	local UMASK=027
	umask ${UMASK}
	local DIR_MODE=$(printf '%x' $((0x7777 - 0x${UMASK} & 0x0777)))

	nested_symlinks_fix
	dir_symlink_fix ${DATADIR} "${BASEDIR}"/data ${USER} ${GROUP} ${DIR_MODE}
	dir_symlink_fix ${LOGDIR} "${BASEDIR}"/logs ${USER} ${GROUP} ${DIR_MODE}
	dir_symlink_fix ${RUNDIR} "${BASEDIR}"/run ${USER} ${GROUP} ${DIR_MODE}
	[ -z "${UNIFI_SSL_KEYSTORE}" ] || file_symlink_fix ${UNIFI_SSL_KEYSTORE} "${BASEDIR}"/data/keystore
}

function init_uos () {
	nested_symlinks_fix
	create_dirs
	remove_old_format_logs
}

function shutdown_unifi_mongo_service_if_needed() {
	if [ "${UNIFI_MONGODB_SERVICE_ENABLED}" == "true" ] && [ $(systemctl is-active --quiet unifi-mongodb && echo $?) ]; then
		runningMongoDbVersion=$(mongo localhost:27117/ace --quiet --eval "db.version()")
		echo "Running MongoDB version - $runningMongoDbVersion"
		installedMongoDbVersion=$(dpkg-query --showformat="\${VERSION}" --show mongodb-server)
		echo "Installed MongoDB version - $installedMongoDbVersion"
		if [[ $installedMongoDbVersion == *"$runningMongoDbVersion"* ]]; then
			echo "MongoDB version has not changed"
		else
			echo "MongoDB version has changed, shutting down unifi-mongodb.service"
			systemctl stop unifi-mongodb
			echo "Finished shutting down unifi-mongodb.service"
		fi
	fi
}

### Helper functions end ###

# Load variables
[ -f "/etc/default/${NAME}" ] && . "/etc/default/${NAME}"

USER=${UNIFI_USER:-unifi}
UNIFI_GROUP=$(id -gn ${USER})
GROUP=${UNIFI_GROUP:-unifi}
DATADIR=${UNIFI_DATA_DIR:-/var/lib/${NAME}}
LOGDIR=${UNIFI_LOG_DIR:-/var/log/${NAME}}
RUNDIR=${UNIFI_RUN_DIR:-/var/run/${NAME}}
ADDITIONAL_STORAGE_DIR=${UNIFI_ADDITIONAL_STORAGE_DIR:-$ADDITIONAL_STORAGE_BASE/$NAME}
DB_DIR=${UNIFI_DB_DIR:-$DATADIR/db}
TMPFS_DIR=${UNIFI_TMPFS_DIR:-/var/opt/$NAME/tmp}
TMPFS_SIZE=${UNIFI_TMPFS_SIZE:-64m}
STATUS_URL="http://localhost:${UNIFI_HTTP_PORT:-8081}/status"
UNIFI_MONGODB_SERVICE_ENABLED=${UNIFI_MONGODB_SERVICE_ENABLED:-false}

case "$1" in
	init-uos)
		init_uos
	;;
	create-dirs)
		create_dirs
	;;
	cleanup)
		unmount_tmpfs_dir
	;;
	shutdown-unifi-mongo-if-needed)
		shutdown_unifi_mongo_service_if_needed
	;;
	service-started)
		log_unifi_service_cpu_time
	;;
	*)
		log "Usage: $0 {init-uos|create-dirs|cleanup}"
		exit 1
	;;
esac

exit 0
