#!/bin/sh
# The login screen. greetd runs this as `sggreet` (config/greetd-config.toml).
#
# sg-compositor hosts sg-greet-bridge, which runs the Windows-style greeter
# and relays what it collects to greetd over GREETD_SOCK; PAM decides (ADR
# 0008). On success greetd itself starts the user's session with the command
# given here -- the greeter cannot choose it.
set -u

# No core dumps in the user's home: wlroots starts Xwayland with -core, and
# Xwayland dies at every sign-out -- each left a 20 MB core file in the home
# (now the user's profile, seen in File Explorer). Nobody reads them here.
# shellcheck disable=SC3045 # dash (/bin/sh here) has ulimit -c
ulimit -c 0 2>/dev/null || true
SG_LIB="${SG_LIB:-/usr/lib/stained-glass}"
# shellcheck source=lib/sg-common.sh
. "$SG_LIB/sg-common.sh"
sg_wine_env
unset SG_WINSTATION

LIBEXEC="${SG_LIBEXEC:-/usr/libexec/stained-glass}"
# A live boot (the installation media's "live" entry) shows Setup here instead:
# the machine's first screen is the installer, as with Windows Setup.
# SG_SETUP=0 shows the login screen anyway.
#
# Setup's "Try Stained Glass OS" closes it and leaves "try" in the result
# file; then the live account (made at boot by sg-live-setup, no password) is
# signed in through greetd -- PAM decides, as for anyone. Anything else (Setup
# cancelled, crashed) ends this greeter, and greetd shows Setup again.
if grep -qw systemd.volatile=overlay /proc/cmdline 2>/dev/null && [ "${SG_SETUP:-1}" != 0 ] \
        && [ -x "$LIBEXEC/sg-setup-bridge" ] && [ -f "$LIBEXEC/sg-setup64.exe" ]; then
    result=$(mktemp "${XDG_RUNTIME_DIR:-/tmp}/sg-setup-result.XXXXXX") || exit 1
    SG_SETUP_RESULT="$result" systemd-cat -t sg-setup -- "$SG_COMPOSITOR" -- "$LIBEXEC/sg-setup-bridge" \
        "env -u WAYLAND_DISPLAY SG_SIGN_IN_SCREEN=1 $SG_LIB/sg-ui-scale wine $LIBEXEC/sg-setup64.exe"
    answer=$(cat "$result" 2>/dev/null)
    rm -f "$result"
    if [ "$answer" = try ] && getent passwd live >/dev/null; then
        exec systemd-cat -t sg-login -- env SG_GREET_AUTOLOGIN=live "$LIBEXEC/sg-greet-bridge" /usr/bin/sg-session-start
    fi
    exit 0
fi

# The first boot of an installed machine shows the first-run setup (the OOBE:
# region, keyboard, network, account, privacy, a browser) here, before anyone
# signs in, as Windows' out-of-box experience does. sg-install leaves the
# marker; sg-oobed, behind its socket, applies the choices and removes it.
# Whatever happens, this greeter then ends: greetd starts it again, and it
# shows the login screen (with the keyboard just chosen) or, if the first-run
# setup did not finish, the first-run setup again. SG_OOBE=0 skips it.
#
# It must never keep the machine from its login screen: without its service
# (the socket) it is not shown; if its window has not appeared within
# SG_OOBE_TIMEOUT seconds (300) it is stopped; and after three tries that did
# not finish, this boot shows the login screen instead (a per-boot count in
# /tmp, a tmpfs). The marker stays, so the next boot offers it again.
OOBE_PENDING="${SG_OOBE_PENDING:-/etc/stained-glass/oobe.pending}"
OOBE_SOCK="${SG_OOBED_SOCK:-/run/stained-glass-oobe/oobed.sock}"
OOBE_TRIES="${TMPDIR:-/tmp}/sg-oobe-tries.$(id -u)"
if [ -f "$OOBE_PENDING" ] && [ "${SG_OOBE:-1}" != 0 ] && [ -S "$OOBE_SOCK" ] \
        && [ -x "$LIBEXEC/sg-setup-bridge" ] && [ -f "$LIBEXEC/sg-oobe64.exe" ] \
        && [ "$(cat "$OOBE_TRIES" 2>/dev/null || echo 0)" -lt 3 ]; then
    echo $(( $(cat "$OOBE_TRIES" 2>/dev/null || echo 0) + 1 )) > "$OOBE_TRIES"
    ready="${TMPDIR:-/tmp}/sg-oobe-ready.$(id -u)"
    rm -f "$ready"
    SG_OOBE_READY="$ready" SG_OOBED_SOCK="$OOBE_SOCK" systemd-cat -t sg-oobe -- "$SG_COMPOSITOR" -- \
        "$LIBEXEC/sg-setup-bridge" --oobe "env -u WAYLAND_DISPLAY SG_SIGN_IN_SCREEN=1 $SG_LIB/sg-ui-scale wine $LIBEXEC/sg-oobe64.exe" &
    pid=$!
    waited=0
    while [ ! -e "$ready" ] && kill -0 "$pid" 2>/dev/null; do
        if [ "$waited" -ge "${SG_OOBE_TIMEOUT:-300}" ]; then
            echo "sg-login-ui: the first-run setup did not appear in ${SG_OOBE_TIMEOUT:-300}s; showing the login screen" \
                | systemd-cat -t sg-oobe
            echo 3 > "$OOBE_TRIES"
            kill "$pid" 2>/dev/null
            break
        fi
        sleep 1
        waited=$((waited + 1))
    done
    wait "$pid"
    rm -f "$ready"
    # A crash loop must not hammer the machine: greetd restarts us at once.
    [ -f "$OOBE_PENDING" ] && sleep 2
    exit 0
fi
[ -f "$OOBE_PENDING" ] && [ -f "$OOBE_TRIES" ] && \
    echo "sg-login-ui: the first-run setup did not finish; the login screen instead, this boot" | systemd-cat -t sg-oobe

# Wine prefers its Wayland driver whenever WAYLAND_DISPLAY is set, and the
# compositor always sets it; the greeter is drawn through XWayland like the
# desktop is (ADR 0003), so the greeter command drops it. SG_SIGN_IN_SCREEN:
# wineboot starts no startup program here, and RunOnce waits for a user
# (wine-sg 5937; this is no user's session).
#
# Through systemd-cat so the compositor's and bridge's output -- including the
# compositor's audit lines -- reaches the journal (tag sg-login); greetd does
# not forward a greeter's output anywhere.
# -s: Ctrl+Alt+F1-F9 reach the text consoles from the sign-in screen too
exec systemd-cat -t sg-login -- "$SG_COMPOSITOR" -s -- "$LIBEXEC/sg-greet-bridge" /usr/bin/sg-session-start \
    "env -u WAYLAND_DISPLAY SG_SIGN_IN_SCREEN=1 $SG_LIB/sg-ui-scale wine $LIBEXEC/sg-greeter64.exe"
