#!/usr/bin/bash

# This systemd.generator(7) detects if rescue or emergency targets were
# requested from the kernel cmdline; if so, it overrides the respective
# target to set force sulogin, allowing use of rescue/emergency targets
# on systems with locked root password (as is Fedora default).
#
# This does NOT bypass locked root password on a fsck failure, but WILL
# bypass when rescue/emergency targets are chosen from kernel cmdline.
# Since this requires console/grub access, it is assumed to be at least
# as secure as a user reset of the root password using grub to modify
# the kernel cmdline with init=/bin/bash .
#
# NOTE: the SYSTEMD_SULOGIN_FORCE method used here does not bypass any
# assigned password; root password is only bypassed when locked/unset.

export PATH="/usr/bin:/usr/sbin:${PATH}"
if [ -n "$1" ]; then
    # If invoked with arguments (not testing) log to kmsg
    # https://github.com/systemd/systemd/issues/15638
    exec 1>/dev/kmsg; exec 2>&1
fi

# If invoked with no arguments (for testing) write to /tmp
UNIT_DIR="${1:-/tmp}"

set -euo pipefail

have_some_karg() {
    local args=("$@")
    IFS=" " read -r -a cmdline <<< "$(</proc/cmdline)"
    local i
    for i in "${cmdline[@]}"; do
        for a in "${args[@]}"; do
        if [[ "$i" == "$a" ]]; then
            return 0
        fi
        done
    done
    return 1
}

write_dropin() {
    local service="$1"

    local out_dir="${UNIT_DIR}/${service}.service.d"
    mkdir -p "${out_dir}"

    # /tmp isn't r/w yet, and the shell needs to cache the here-document
    TMPDIR=/run
    cat > "${out_dir}/sulogin-force.conf" <<EOF
# Automatically created by coreos-sulogin-force-generator
[Service]
Environment=SYSTEMD_SULOGIN_FORCE=1
EOF
    echo "$(basename ${0}): set SYSTEMD_SULOGIN_FORCE=1 for ${service}.service"
}

# Match kernel command line targets for systemd(1) rescue/emergency
# Ignores 'rd.' prefixed targets since they enter the dracut ramdisk
# environment which does not interact with installed system root user.
if have_some_karg 'systemd.unit=rescue.target' rescue single s S 1; then
    write_dropin rescue
elif have_some_karg 'systemd.unit=emergency.target' emergency '-b' ; then
    write_dropin emergency
fi
