#!/usr/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
#

. /lib/svc/share/smf_include.sh

APACHE_HOME=/usr/apache2/2.4
APACHE_ETC_ROOT=/etc/pkg/depot
APACHE_BIN=${APACHE_HOME}/bin

HTTPD=${APACHE_BIN}/apachectl


function check_prop {
	if [ -z "$1" ]; then
		echo "ERROR: SMF property for $2 was empty"
		exit $SMF_EXIT_ERR_FATAL
	fi
}

function get_pair {
        NAME=$1
        shift 2
        echo "${NAME}=\"$@\""
        echo "export ${NAME}"
}

# A function to pull in the config properties from the FMRI given
# as the first argument. This allows us to make a single call
# to svcprop, rather than calling svcprop for each value we
# want to retrieve.
function get_smf_props {

	IFS="
"
	SMF_PROPS="$(svcprop -t -p config $1 |\
        	sed -e 's#config/#depot_#g' -e 's/$/,/g')"
	IFS=,
	for line in $SMF_PROPS ; do
        	IFS=' 
'
        	eval $(get_pair $line)
	done
}


function check_failure {
	RESULT=$1
	MESSAGE=$2
	NON_FATAL=$3
	if [ $RESULT -ne 0 ]; then
		echo $MESSAGE
		if [ -n "$NON_FATAL" ]; then
			return
		fi
		exit $SMF_EXIT_ERR_FATAL
	fi
}

function check_apache_failure {
	RESULT=$1
	MESSAGE=$2
	if [ $RESULT -ne 0 ]; then
		echo $MESSAGE
		kill_apache
		exit $SMF_EXIT_ERR_FATAL
	fi
}

function abspath {
	# print a normalized version of a path, needed because
	# many utilities will not dereference non-existent directories
	# in path names, e.g. cat /etc/no-such-dir/../motd will fail.
	echo $1 | /usr/bin/python -c \
    'import os.path ; import sys ; print os.path.normpath(sys.stdin.read())'
}

function run_depot {
        if [ "${depot_https}" == "true" ]; then
                https_cmd="--https"
                smf_fmri_cmd="--smf-fmri ${SMF_FMRI}"
                if ! [ -z "${depot_ssl_cert_file}" ]; then
                        ssl_cert_file_cmd="--cert ${depot_ssl_cert_file}"
                fi
                if ! [ -z "${depot_ssl_key_file}" ]; then
                        ssl_key_file_cmd="--key ${depot_ssl_key_file}"
                fi
                if ! [ -z "${depot_ssl_ca_cert_file}" ]; then
                        ssl_ca_cert_file_cmd="--ca-cert ${depot_ssl_ca_cert_file}"
                fi
                if ! [ -z "${depot_ssl_ca_key_file}" ]; then
                        ssl_ca_key_file_cmd="--ca-key ${depot_ssl_ca_key_file}"
                fi
                if ! [ -z "${depot_ssl_cert_key_dir}" ]; then
                        ssl_cert_key_dir_cmd="--cert-key-dir ${depot_ssl_cert_key_dir}"
                fi
                if ! [ -z "${depot_ssl_cert_chain_file}" ]; then
                        ssl_cert_chain_file_cmd="--cert-chain ${depot_ssl_cert_chain_file}"
                fi
        fi
        /usr/lib/pkg.depot-config \
            -S \
            -c ${depot_cache_dir} \
            -h ${depot_host} \
            -l ${depot_log_dir} \
            -p ${depot_port} \
            -r ${depot_runtime_dir} \
            -s ${depot_cache_max} \
            -T ${depot_template_dir} \
            -t apache2 ${https_cmd} \
            ${smf_fmri_cmd} \
            ${ssl_cert_file_cmd} \
            ${ssl_key_file_cmd} \
            ${ssl_ca_cert_file_cmd} \
            ${ssl_ca_key_file_cmd} \
            ${ssl_cert_key_dir_cmd} \
            ${ssl_cert_chain_file_cmd} \
            ${depot_allow_refresh}
	failure=$?
	if [ ${failure} -ne 0 ] ; then
		# make sure we leave nothing behind
		kill_apache
		kill_htcacheclean
	        check_failure $failure \
	            "pkg.depot-config: failed to create Apache config"
	fi
}

function run_htcacheclean {
	# if we dropped to maintenance and are in the process of
	# clearing that state,  we may have htcacheclean processes
	# hanging around.
	kill_htcacheclean
	if [ "${depot_cache_max}" != "0" ] ; then
		# Start a cache cleaning daemon, scanning every 2 weeks,
		# being intelligent about only running if the cache has
		# changed, limiting the cache to ${depot_cache_max}
		# megabytes, being nice about scheduling and removing
		# empty directories if necessary.
	       interval=$((60 * 24 * 14))
               /usr/apache2/2.4/bin/htcacheclean \
                       -d${interval} -i -l ${depot_cache_max}M -n \
                       -p ${depot_cache_dir} \
                       -P ${depot_cache_dir}/../depot_htcacheclean.pid \
                       -t
               check_failure $? "htcacheclean failed to run cleanly"
       fi
}

function kill_htcacheclean {
	pid_file=$(abspath ${depot_cache_dir}/../depot_htcacheclean.pid)
	if [ -f $pid_file ]; then
                PID=$(< $pid_file)
                /usr/bin/kill -TERM $PID
                check_failure $? "failed to kill htcacheclean process\
 $PID" "not_fatal"
        fi
}

function kill_apache {
	# We go to lengths to kill remaining httpd processes: if we kill
	# just the pid, then child httpd processes become zombies,
	# hanging onto the server port, which causes problems
	# when trying to start a service that is transitioning from
	# maintenance.
	# This function should only be called when the service is
	# transitioning to maintenance: normal Apache shutdown is
	# preferable.
	pid_file=$(abspath ${depot_runtime_dir}/../depot_httpd.pid)
	if [ -f $pid_file ]; then
		PID=$(< $pid_file)
		/usr/bin/ptree $PID | /usr/bin/awk '{print $1}' | \
		    /usr/bin/xargs /usr/bin/kill -TERM
		check_failure $? "failed to kill apache process $PID" \
		    "not_fatal"
		/usr/bin/rm $pid_file
	fi
}

function server_ping {
	# Ping the service, ensuring the index gets built if does
	# not exist.
	# Since curl --retry uses an exponential backoff algorithm, this
	# can result in us waiting 40 seconds, which ought to be long
	# enough for Apache to come online. (index refreshes are run in
	# the background on the server after it has returned a response)
	url="http://${depot_host}:${depot_port}"
	ipv6=$(echo ${depot_host} | /usr/bin/grep :)
	if [ -n "$ipv6" ] ; then
		url="http://\[${depot_host}\]:${depot_port}"
	fi
	/usr/bin/curl -s --max-time 5 --retry 4 -o /dev/null ${url} \
2> /dev/null
	check_failure $? "Unable to access the server at ${url}. Check\
 the SMF service log or the error log at ${depot_log_dir}/error_log for\
 more information, if any."
}

get_smf_props $SMF_FMRI
check_prop ${depot_host} config/host
check_prop ${depot_port} config/port
check_prop ${depot_log_dir} config/log_dir
check_prop ${depot_template_dir} config/template_dir
check_prop ${depot_runtime_dir} config/runtime_dir
check_prop ${depot_cache_dir} config/cache_dir
check_prop ${depot_cache_max} config/cache_max
check_prop ${depot_https} config/https
check_prop ${depot_allow_refresh} config/allow_refresh
if [ "${depot_allow_refresh}" == "true" ] ; then
	depot_allow_refresh="-A"
else
	depot_allow_refresh=""
fi

FAILED_TO_RUN="Server failed to %s. Check the SMF service log or the\
 error log at ${depot_log_dir}/error_log for more information, if any."


case "$1" in
"start")
	cmd="start"
	run_depot
	# drop privileges now that we've written our configuration
	/usr/bin/ppriv -s E=basic,net_privaddr $$
	run_htcacheclean
        emsg=$(/usr/bin/printf ${FAILED_TO_RUN} start)
	${HTTPD} -f ${depot_runtime_dir}/depot_httpd.conf \
            ${STARTUP_OPTIONS} -k ${cmd} 2>&1
 	check_apache_failure $? $emsg
        server_ping
	;;
"refresh")
	cmd="graceful"
	run_depot
	# drop privileges now that we've written our configuration
	/usr/bin/ppriv -s E=basic,net_privaddr $$
	kill_htcacheclean
	run_htcacheclean
        emsg=$(/usr/bin/printf ${FAILED_TO_RUN} refresh)
	${HTTPD} -f ${depot_runtime_dir}/depot_httpd.conf \
            ${STARTUP_OPTIONS} -k ${cmd} 2>&1
	check_apache_failure $? $emsg
        server_ping
	;;
"stop")
	cmd="stop"
	kill_htcacheclean
        emsg=$(/usr/bin/printf ${FAILED_TO_RUN} stop)
        # If https service is on and user blindly deleted the certificate dir,
        # then the stop method will cause error due to not find certificate
        # and key files. Instead of causing this error, we kill the apache
        # instance manually.
        if [[ "${depot_https}" == "true" && \
            ! ( -f "${depot_ssl_cert_file}" && \
            -f "${depot_ssl_key_file}" ) ]]; then
                kill_apache
        else
	        ${HTTPD} -f ${depot_runtime_dir}/depot_httpd.conf \
                    ${STARTUP_OPTIONS} -k ${cmd} 2>&1
        fi
	check_apache_failure $? $emsg
	;;
*)
	echo "Usage: $0 {start|stop|refresh}"
	exit $SMF_EXIT_ERR_CONFIG
	;;
esac

exit $SMF_EXIT_OK
