#!/bin/sh

DEFAULT_CONFIGFILE=/etc/virtshaus/checkservice.conf
AFTERSERVICES=""
CONFIGFILES=""
PATTERN=".$"
NOPATTERN="\.target$"
VERBOSE=0
DRYRUN=no
FORCETERMINAL=no

usage() {
cat <<EOF 1>&2
usage: $0 [ -e REGEX ][ -c CONFIGFILE ] [ -a SERVICE ][ services... ]
   checks whether (systemd) services are running and restarts them if necessary

   optional arguments:
     -c CONFIGFILE
              check services that are listed in CONFIGFILE.
              (lines starting with '#' are ignored)
              can be given multiple times.
     -a SERVICE
              checks services that are an 'After=' reverse-dependency of SERVICE
              can be given multiple times.
     -e REGEX
              only check services that match this REGEX
              (default: "$PATTERN")
     -x REGEX
              only check services that DO NOT match this REGEX
              (default: "$NOPATTERN")
     -v
              increase verbosity
     -n
              dry-run (use with '-v')
     -t
              force terminal mode (output to stdout/stderr)

   positional arguments:
     [ services ]
              check given services

   if neither <services> not CONFIGFILEs not SERVICEs are given, read
   the default config-file '${DEFAULT_CONFIGFILE}'
EOF
}

OPTIND=1 # Reset is necessary if getopts was used previously in the script.  It is a good idea to make this local in a function.
while getopts ":vntc:a:e:x:" opt; do
    case "${opt}" in
        c)
            CONFIGFILES="${CONFIGFILES} ${OPTARG}"
            ;;
        a)
            AFTERSERVICES="${AFTERSERVICES} ${OPTARG}"
            ;;
        e)
            PATTERN="${OPTARG}"
            ;;
        x)
            NOPATTERN="${OPTARG}"
            ;;
        v)
            VERBOSE=$((VERBOSE+1))
            ;;
        n)
            DRYRUN=yes
            ;;
        t)
            FORCETERMINAL=yes
            ;;
        '?')
            usage
            exit 1
            ;;
    esac
done
shift "$((OPTIND-1))" # Shift off the options and optional --.


if [ "x${FORCETERMINAL}" != "xyes" ]; then
    if [ -t 0 ]; then
        FORCETERMINAL=yes
    fi
fi
if [ "x${FORCETERMINAL}" = "xyes" ]; then
## interactive shell
error() {
 echo "$@" 1>&2
}
else
## non-interactive (e.g. run as daemon)
error() {
 logger -p daemon.warning "$@"
}
fi
verbose() {
    local verbosity=$1
    shift
    if [ "$verbosity" -le "${VERBOSE}" ]; then
        error "$@"
    fi
}

have_loggedin() {
 who | grep . 2>&1 >/dev/null
}

is_broken() {
    systemctl -q is-enabled "$1" && systemctl -q is-failed "$1"
}

restarters=""
do_restart() {
    if have_loggedin; then
        error "$0: not restarting '$1' since users are logged in"
        restarters="${restarters} $1"
    else
        systemctl restart "$1"
    fi
}

check_restart() {
    verbose 1 "checking restart of $1"
    if [ "x${DRYRUN}" = "xyes" ]; then
        is_broken "$1" && do_restart "$1"
    fi
}

if [ "x${AFTERSERVICES}" = "x" -a "x${CONFIGFILES}" = "x" -a "x$#" = "x0" ]; then
    CONFIGFILES="${DEFAULT_CONFIGFILE}"
fi

(
    # services from conf-files
    for c in "${CONFIGFILES}"; do
        if [ -e "${c}" -a -r "${c}" ]; then
            cat "${c}" \
                | sed -e 's/#.*//' -e '/^ *$/d' \
                | while read service; do
                echo ${service}
            done
        fi
    done

    # services as reverse-dependencies
    for a in "${AFTERSERVICES}"; do
        for line in $(/bin/systemctl cat $a 2>/dev/null | egrep "^After=" | sed -e 's|^After=||'); do
            for service in ${line}; do
                echo ${service}
            done
        done
    done

    # services from cmdline
    for service in "$@"; do
        echo ${service}
    done

) \
    | egrep -e "${PATTERN}" \
    | egrep -v -e "${NOPATTERN}" \
    | awk '!a[$0]++' \
    | while read -r u; do
    check_restart "${u}"
done



if [ -t 0 ]; then
    ## interactive shell
    if [  -n "${restarters}" ]; then
        echo "systemctl restart ${restarters}"
    fi
fi
