#!/bin/sh
#
# Copyright (C) 2020, Cirrent Inc
#
# All use of this software must be covered by a license agreement signed by Cirrent Inc.
#
# DISCLAIMER. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OR CONDITION,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. LICENSORS HEREBY DISCLAIM
# ALL LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE.
#

### BEGIN INIT INFO
# Provides:          cirrent
# Required-Start:    $local_fs $network $dhcpcd $monit
# Required-Stop:     $local_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: This script manages Cirrent Agent.
# Description:
### END INIT INFO

NAME="cirrent"
PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
APPDIR="/etc/cirrent"
APPBIN="$(which cirrent_agent)"
APPPID="/var/run/cirrent_agent.pid"
CA_CONF="${APPDIR}/cirrent_agent.conf"
STATUS_SCRIPT=Yes
STATUS_SCRIPT_PATH="${APPDIR}/scripts/status.sh"
PRODUCT_ACTION_SCRIPT=No
PRODUCT_ACTION_SCRIPT_PATH="${APPDIR}/scripts/product_action.sh"
DIAGNOSTIC_SCRIPT=Yes
DIAGNOSTIC_SCRIPT_PATH="${APPDIR}/scripts/diagnostic_handler.sh"
INI_CUSTOM_SCRIPT=Yes
INI_CUSTOM_SCRIPT_PATH="${APPDIR}/scripts/ini_custom.sh"
APPARGS="-c $CA_CONF -p $APPPID"
export LD_LIBRARY_PATH=/usr/lib/cirrent

# Include service settings
[ -e /etc/default/${NAME} ] && . /etc/default/${NAME}

# Set device provision credential args
[ -n "$PROVISION_CRED" ] && APPARGS="$APPARGS $PROVISION_CRED"

# Include lsb init functions
[ -e /lib/lsb/init-functions ] && . /lib/lsb/init-functions

# Check utils availability
type start-stop-daemon > /dev/null || {
    echo "start-stop-daemon is not found"
    exit 1
}

type status_of_proc > /dev/null || {
    status_of_proc()
    {
        [ "$1" = "-p" ] && local pid_file="$2" || return 1
        [ -e "$pid_file" ] || {
            echo "$NAME is not started"
            return 3
        }
        read pid < "$pid_file"
        if [ -n "$pid" ] && kill -0 "$pid"
        then
            echo "$NAME is running"
            return 0
        else
            echo "$NAME is not running"
            return 1
        fi
    }
}

type log_action_msg > /dev/null || {
    log_action_msg()
    {
        echo "$@"
    }
}

type log_failure_msg > /dev/null || {
    log_failure_msg()
    {
        echo "FAIL: $@"
    }
}

type log_begin_msg > /dev/null || {
    log_begin_msg()
    {
        echo "$@"
    }
}

type log_end_msg > /dev/null || {
    log_end_msg()
    {
        echo "$@"
    }
}

config_ap_shared_radio()
{
    SOFTAP_SETTING=$(grep -i "SoftAP:" "$CA_CONF" | awk '{print $2}')
    SHARED_RADIO_SETTING=$(grep -i "AP Shared Radio:" "$CA_CONF" | awk '{print $4}')

    if [ "$SOFTAP_SETTING" != "Enabled" -o "$SHARED_RADIO_SETTING" != "Yes" ]; then
        return 0
    fi

    WIFI_IFACE=$(grep -i "^WiFi Interface:" $CA_CONF | awk '{print $3}')
    SOFTAP_IFACE=$(grep -i "^AP WiFi Interface:" "$CA_CONF" | awk '{print $4}')
    printf "Checking if interface %s exists, will create interface if it doesn't\n" "$SOFTAP_IFACE"
    ifconfig "$SOFTAP_IFACE"

    if [ "$?" -ne 0 ]; then
        printf "interface not found. will create interface %s\n" "$SOFTAP_IFACE"
        iw dev "$WIFI_IFACE" interface add "$SOFTAP_IFACE" type __ap
        if [ "$?" -ne 0 ]; then
            printf "Error creating interface!\n"
            exit 2
        fi

        WIFI_IFACE_MAC=$(ifconfig "$WIFI_IFACE" | grep "HWaddr" | awk '{print $5}')
        SOFTAP_IFACE_MAC=$(ifconfig "$SOFTAP_IFACE" | grep "HWaddr" | awk '{print $5}')
        if [ "$WIFI_IFACE_MAC" = "$SOFTAP_IFACE_MAC" ]; then
            printf "MAC address are same, modifying iface %s mac address\n" "$SOFTAP_IFACE"
            SOFTAP_IFACE_MAC_LSB=$(printf "%s" "$SOFTAP_IFACE_MAC" | awk -F: '{print $6}')
            SOFTAP_IFACE_MAC_LSB=$((0x$SOFTAP_IFACE_MAC_LSB+0x2))
            SOFTAP_IFACE_MAC_LSB=$(printf "%x" "$SOFTAP_IFACE_MAC_LSB")
            SOFTAP_IFACE_MAC=$(printf "%s" "$SOFTAP_IFACE_MAC" | awk -v m="$SOFTAP_IFACE_MAC_LSB" 'BEGIN {FS=OFS=":"} {$6=m; print}')
            ifconfig "$SOFTAP_IFACE" hw ether "$SOFTAP_IFACE_MAC"
            if [ "$?" -ne 0 ]; then
                printf "Failed to modify %s to mac address %s\n" "$SOFTAP_IFACE" "$SOFTAP_IFACE_MAC"
            fi
        fi
    fi
}

check_hostapd()
{(
    local wifi_iface=$1
    local unit_file=/lib/systemd/system/hostapd.service
    local unit_conf=$(grep 'Environment=' $unit_file | sed 's|^Environment=||g')

    [ -n "$unit_conf" ] && eval $unit_conf
    [ -s /etc/default/hostapd ] && . /etc/default/hostapd

    systemctl stop hostapd@${wifi_iface}

    local configured=0
    for conf in $DAEMON_CONF; do
        [ -s $conf ] || continue
        local configured=1
        (
            . $conf
            [ "$interface" = "$wifi_iface" ]
        ) && {
            systemctl stop hostapd
            return 0
        }
    done

    [ $configured = 0 ] && {
        systemctl stop hostapd
        systemctl mask hostapd

        return 1
    }

    return 0
)}

config_interface()
{
    local wifi_iface=$(grep -i "^WiFi Interface:" $CA_CONF | awk '{print $3}')
    local zipkey_setting=$(grep -i "^ZipKey:" $CA_CONF | awk '{print $2}')
    [ "$zipkey_setting" = "Enabled" ] || return 0

    log_action_msg "Prepare interface '$wifi_iface' to be acquired by '$NAME'"

    rfkill unblock wifi
    rfkill unblock bluetooth

    [ -e /run/dhcpcd.sock ] && {
        dhcpcd --denyinterfaces $wifi_iface
        dhcpcd --release $wifi_iface
    }
    pkill -f "dhcpcd.*${wifi_iface}" 2>&1 > /dev/null
    pkill -f "dhclient.*${wifi_iface}" 2>&1 > /dev/null

    check_hostapd "$wifi_iface"
    ifdown "$wifi_iface"
}

enable_monit()
{
    ln -s "/etc/monit/conf-available/${NAME}" "/etc/monit/conf-enabled/${NAME}"
    monit reload
}

disable_monit()
{
    rm "/etc/monit/conf-enabled/${NAME}"
    monit reload
}

enable_ini_custom()
{
    [ -x "$INI_CUSTOM_SCRIPT_PATH" ] || return 0
    echo "* * * * *  root ${INI_CUSTOM_SCRIPT_PATH} > /dev/null" > "/etc/cron.d/${NAME}_ini_custom"
    ${INI_CUSTOM_SCRIPT_PATH} attribute
}

disable_ini_custom()
{
    rm -f "/etc/cron.d/${NAME}_ini_custom"
}

do_start()
{
    config_ap_shared_radio
    config_interface

    start-stop-daemon --start --background --pidfile "$APPPID" \
        --exec "$APPBIN" -- $APPARGS
    status=$?

    if [ $status -ne 0 ]; then
        log_failure_msg "Failed to start '$NAME' with exit code $status"
        return $status
    fi

    sleep 1
    [ -d /etc/monit ] && enable_monit

    if [ "$PRODUCT_ACTION_SCRIPT" = "Yes" ]; then
        log_action_msg "Product action enabled. Register $PRODUCT_ACTION_SCRIPT_PATH"
        cirrent_cli register_prod_action_script "$PRODUCT_ACTION_SCRIPT_PATH"
    fi

    if [ "$DIAGNOSTIC_SCRIPT" = "Yes" ]; then
        log_action_msg "Diagnostic handler enabled. Register $DIAGNOSTIC_SCRIPT_PATH"
        cirrent_cli register_diagnostic_script "$DIAGNOSTIC_SCRIPT_PATH"
    fi

    if [ "${INI_CUSTOM_SCRIPT}" = "Yes" ] ; then
        enable_ini_custom
    fi
}

do_stop()
{
    [ -d /etc/monit ] && disable_monit
    disable_ini_custom
    start-stop-daemon --stop --retry 15 --pidfile "$APPPID" \
        --exec "$APPBIN" -- $APPARGS
}


[ "$STATUS_SCRIPT" = "Yes" ] && APPARGS="$APPARGS -s $STATUS_SCRIPT_PATH"
case "$1" in
    start)
        log_begin_msg "Starting '$NAME'... "

        do_start

        log_end_msg $?
        ;;
    stop)
        log_begin_msg "Stopping '$NAME'... "

        do_stop

        log_end_msg $?
        ;;
    restart)
        log_begin_msg "Restarting '$NAME'... "

        do_stop
        do_start

        log_end_msg $?
        ;;
    status)
        status_of_proc -p "$APPPID" "$APPBIN" "$NAME"
        exit $?
        ;;
    *)
        echo "Usage: $NAME {start|stop|restart|status}" >&2
        exit 1
        ;;
esac

exit 0
