#!/usr/bin/bash

build() {
    SD_RETARD_SECONDS="${SD_RETARD_SECONDS:-20}"
    if (( SD_RETARD_SECONDS < 1 || SD_RETARD_SECONDS > 600 )) && [[ "$SD_RETARD_SECONDS" != "infinity" ]]; then
        error "Illegal value SD_RETARD_SECONDS=$SD_RETARD_SECONDS"
        return 1
    fi

    if [[ -z "$SD_RETARD_SSH_SERVICE" ]]; then
        local hook
        for hook in "${HOOKS[@]}"; do
            case "$hook" in
                ( sd-tinyssh )
                    SD_RETARD_SSH_SERVICE="tinyssh"
                    break ;;
                ( sd-dropbear )
                    SD_RETARD_SSH_SERVICE="dropbear"
                    break ;;
                ( sd-openssh )
                    SD_RETARD_SSH_SERVICE="sshd"
                    break ;;
            esac
        done
    fi
    [[ "$SD_RETARD_SSH_SERVICE" == "openssh" ]] && SD_RETARD_SSH_SERVICE=sshd
    local -r unit_name_pattern='^[-a-zA-Z0-9:_.]+$'
    if [[ ! "$SD_RETARD_SSH_SERVICE" =~ $unit_name_pattern ]]; then
        error "Illegal value SD_RETARD_SSH_SERVICE=$SD_RETARD_SSH_SERVICE"
        return 1
    fi
    case "$SD_RETARD_SSH_SERVICE" in
        ( tinyssh | dropbear | sshd ) ;;
        ( * )
            warning "SD_RETARD_SSH_SERVICE=$SD_RETARD_SSH_SERVICE not one of:"
            warning "    tinyssh, dropbear, openssh, sshd"
    esac

    declare -F add_busybox >/dev/null || . /usr/lib/initcpio/functions.d/systemd-extras

    add_busybox || return $?

    local unit=(
        "[Unit]"
        "Description=Retarder (Started means retardation finished)"
        "DefaultDependencies=no"
	"Before=sysinit.target"
        ""
        "[Service]"
        "Type=forking"
        "ExecStart=sh -c 'mkfifo /tmp/retarder.fifo; cat </tmp/retarder.fifo >/dev/null; rm /tmp/retarder.fifo'"
        "TimeoutStartSec=infinity"
    )
    printf "%s\n" "${unit[@]}" > "${BUILDROOT}/usr/lib/systemd/system/retarder.service"
    add_symlink /etc/systemd/system/sysinit.target.requires/retarder.service /usr/lib/systemd/system/retarder.service

    local check_ssh_sessions=(
        "systemctl show \"${SD_RETARD_SSH_SERVICE}@*.service\" |"
        "grep -q \"^ActiveState=active\$\" ||"
        "echo >/tmp/retarder.fifo"
    )
    local drop_in=(
        "[Service]"
        "ExecStopPost=sh -c '${check_ssh_sessions[*]}'"
    )
    printf "%s\n" "${drop_in[@]}" | add_systemd_drop_in "${SD_RETARD_SSH_SERVICE}@.service" check-ssh-sessions

    if [[ "$SD_RETARD_SECONDS" != "infinity" ]]; then
        unit=(
            "[Unit]"
            "Description=Check for SSH sessions ${SD_RETARD_SECONDS}s after boot"
            "DefaultDependencies=no"
            "Before=sysinit.target"
            ""
            "[Timer]"
            "OnBootSec=$SD_RETARD_SECONDS"
        )
        printf "%s\n" "${unit[@]}" > "${BUILDROOT}/usr/lib/systemd/system/check-ssh-sessions.timer"
        add_symlink /etc/systemd/system/sysinit.target.wants/check-ssh-sessions.timer /usr/lib/systemd/system/check-ssh-sessions.timer

        unit=(
            "[Unit]"
            "Description=Check for SSH sessions ${SD_RETARD_SECONDS}s after boot"
            "DefaultDependencies=no"
            ""
            "[Service]"
            "ExecStart=sh -c '${check_ssh_sessions[*]}'"
        )
        printf "%s\n" "${unit[@]}" > "${BUILDROOT}/usr/lib/systemd/system/check-ssh-sessions.service"
    fi
}

help() {
    cat <<__EOF_HELP__
This hook delays (retards) boot

 o  until all SSH sessions have been terminated or

 o  until a certain period of time (default 20 seconds) has elapsed (provided
    no SSH sessions are active at the end of this period).

This way it is possible to automatically boot to the regular Linux system
without user intervention, while still being able to log into the preliminary
Linux of initramfs and perform arbitrary actions (e.g. backup, decryption).

By default the duration of the initramfs phase is extended to approx. 20
seconds.  This value can be set by SD_RETARD_SECONDS. When specifying
"infinity" the boot process proceeds only when the last SSH session has been
terminated.

The SSH servers supported are TinySSH and Dropbear. TinySSH is default.
Dropbear can be used by setting SD_RETARD_SSH_SERVICE=dropbear. Any service
name other than dropbear or tinyssh is tolerated but produces a warning. Your
mileage may vary.

See https://github.com/wolegis/mkinitcpio-systemd-extras/wiki/Retarder for
details.
__EOF_HELP__
}
