#!/usr/bin/bash
#
# dmal-run-session
# this hook is called as user and is expected to run the session
# it will call pre-session hooks before

set -o errexit
set -o pipefail
set -o nounset
set -o errtrace

function cleanup() {
    trap - ERR
    trap - EXIT
}

# shellcheck disable=SC2329,SC2317
function err_exit_trap() {
    local _status=$?
    local _traptype="$1"

    cleanup

    echo "${FUNCNAME[0]-?}: unexpected exit/error" \
         "near '$BASH_COMMAND', status=$_status, trap=$_traptype"
    exit 1
}

# sourcall_with_log <mode> <tag> <file> [<arg> [..]]
function sourcall_with_log() {
    local _mode="$1"
    local _tag="$2"
    shift 2

    local _retval=0

    # setup custom stdout/stderr
    exec 3>&1 4>&2
    exec 1> >(systemd-cat -t "$_tag" -p info) \
         2> >(systemd-cat -t "$_tag" -p err)

    # shellcheck disable=SC1090
    case "$_mode" in
        source) source "$@" || _retval="$?";;
        call) "$@" || _retval="$?";;
        *)
            exec 1>&3 2>&4
            exec 3>&- 4>&-
            fatal "sourcall_with_log: internal error: unknown mode: $_mode"
    esac

    # restore old stdout/stderr
    exec 1>&3 2>&4
    exec 3>&- 4>&-

    return "$_retval"
}

function source_hooks() {
    local _hook_type="$1"
    local _hook_subdir

    case "$_hook_type" in
        prefix|postfix)
            _hook_subdir="$DMAL_HOOK_DIR/session-wrapper-${_hook_type}.d"
            ;;
        *) fatal "internal error: unknown hook type: $_hook_type"
    esac

    local _hook
    if [ -d "$_hook_subdir" ]
    then
        shopt -s nullglob
        for _hook in "$_hook_subdir"/*
        do
            echo "sourcing $1: $_hook"
            if sourcall_with_log \
                   source "dmal-session-wrapper-$1:${_hook##*/}" "$_hook"
            then
                echo "$1 $_hook finished successfully"
            else
                case "$1" in
                    prefix)
                        echo "$1 $_hook failed with $? - aborting session"
                        cleanup
                        exit 1
                        ;;
                    postfix)
                        echo "$1 hook $_hook failed with $? -" \
                             "continuing postfix.."
                        ;;
                esac
            fi
        done
        shopt -u nullglob
    else
        echo "hook subdir ($_hook_subdir) not found, not sourcing any hooks"
    fi
}

function start_session() {
    local _retval=0

    echo "starting session: $*"

    sourcall_with_log call "dmal-session:${USER-}" "$@" &
    DM_SESSION_PID="$!"

    trap 'kill $DM_SESSION_PID' TERM
    wait "$DM_SESSION_PID" || _retval="$?"
    trap - TERM

    return "$_retval"
}

trap 'err_exit_trap "ERR"' ERR
trap 'err_exit_trap "EXIT"' EXIT

exec > \
     >(systemd-cat -t "dmal-session-wrapper:${USER-}" -p info) \
     2> >(systemd-cat -t "dmal-session-wrapper:${USER-}" -p err)

function fatal() {
    echo "FATAL ERROR: $*" >&2
    exit 1
}

# default values
DMAL_DM_BIN=/usr/sbin/lightdm
DMAL_HOOK_DIR=/etc/dmal/hooks
DMAL_RUN_DIR=/var/run/dmal
DMAL_EXIT_ON_ERROR=
DMAL_SESSIONS_DIR=

DMAL_SESSION_PID=

if [ -f /etc/default/dmal ]
then
    # shellcheck disable=SC1091
    source /etc/default/dmal || fatal "failed to source /etc/default/dmal"
else
    echo "WARNING: /etc/default/dmal not found, using hardcoded values"
fi

echo "called for $USER (id=$(id))"

source_hooks prefix

while true
do
    if start_session "$@"
    then
        echo "seesion stopped clean"
    else
        echo "session stopped with error($?)"
    fi

    [[ "${DMAL_SESSION_LOOP-}" == "yes" ]] || break
    echo "session look was requested, restarting in 5s.."
    sleep 5
done

source_hooks postfix

cleanup
exit 0
