94 lines
3.4 KiB
Bash
94 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared by the watcher and recovery helper. Config is trusted user-owned Bash.
|
|
|
|
log() {
|
|
printf '%s: %s\n' "$LOGTAG" "$*" >&2
|
|
}
|
|
|
|
# These settings are consumed by scripts sourcing this library and via ${!name}.
|
|
# shellcheck disable=SC2034
|
|
load_config() {
|
|
MONITOR=HDMI-A-2
|
|
DEBOUNCE_SECONDS=30
|
|
HDMI_SETTLE_SECONDS=5
|
|
VT_SWITCH_DELAY_SECONDS=1
|
|
VT_RETURN_SETTLE_SECONDS=2
|
|
local config="${XDG_CONFIG_HOME:-$HOME/.config}/revive-monitor/config.env"
|
|
if [[ -r "$config" ]]; then
|
|
# shellcheck disable=SC1090
|
|
source "$config" || return 1
|
|
fi
|
|
if [[ ! "$MONITOR" =~ ^[a-zA-Z0-9_-]+$ ]]; then
|
|
log 'Invalid MONITOR: expected an output name such as HDMI-A-2'
|
|
return 1
|
|
fi
|
|
local name value limit
|
|
for name in DEBOUNCE_SECONDS HDMI_SETTLE_SECONDS VT_SWITCH_DELAY_SECONDS VT_RETURN_SETTLE_SECONDS; do
|
|
value="${!name}"
|
|
limit=300
|
|
[[ "$name" == DEBOUNCE_SECONDS ]] && limit=3600
|
|
if [[ ! "$value" =~ ^[0-9]{1,4}$ ]] || (( 10#$value > limit )); then
|
|
log "Invalid $name: expected an integer between 0 and $limit"
|
|
return 1
|
|
fi
|
|
printf -v "$name" '%d' "$((10#$value))"
|
|
done
|
|
}
|
|
|
|
require_commands() {
|
|
local command_name
|
|
for command_name in "$@"; do
|
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
|
log "Required command not found: $command_name"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
prepare_runtime() {
|
|
# No shared /tmp fallback: locks must live in a private per-user directory.
|
|
local runtime="${XDG_RUNTIME_DIR:-}"
|
|
if [[ "$runtime" != /* || ! -d "$runtime" || -L "$runtime" || ! -O "$runtime" ]] ||
|
|
[[ "$(stat -c %a -- "$runtime" 2>/dev/null)" != 700 ]]; then
|
|
log 'XDG_RUNTIME_DIR must be an existing, user-owned directory with mode 0700'
|
|
return 1
|
|
fi
|
|
STATE_DIR="$runtime/revive-monitor"
|
|
if [[ -L "$STATE_DIR" ]]; then
|
|
log 'Refusing a symlink as runtime state directory'
|
|
return 1
|
|
fi
|
|
(umask 077; mkdir -p -- "$STATE_DIR") || return 1
|
|
if [[ ! -O "$STATE_DIR" || "$(stat -c %a -- "$STATE_DIR")" != 700 ]]; then
|
|
log 'Runtime state directory must be user-owned with mode 0700'
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
get_active_wayland_session() {
|
|
local sessions sid rest properties key value uid type active vt seat desktop
|
|
sessions="$(timeout 5 loginctl list-sessions --no-legend --no-pager 2>/dev/null)" || return 1
|
|
while read -r sid rest; do
|
|
[[ -n "$sid" ]] || continue
|
|
properties="$(timeout 5 loginctl show-session "$sid" -p User -p Type -p Active -p VTNr -p Seat -p Desktop 2>/dev/null)" || continue
|
|
uid='' type='' active='' vt='' seat='' desktop=''
|
|
while IFS='=' read -r key value; do
|
|
case "$key" in
|
|
User) uid="$value" ;;
|
|
Type) type="$value" ;;
|
|
Active) active="$value" ;;
|
|
VTNr) vt="$value" ;;
|
|
Seat) seat="$value" ;;
|
|
Desktop) desktop="${value,,}" ;;
|
|
esac
|
|
done <<< "$properties"
|
|
[[ "$uid" == "$UID" && "$type" == wayland && "$active" == yes && "$seat" == seat0 ]] || continue
|
|
[[ -z "$desktop" || "$desktop" == *hyprland* ]] || continue
|
|
if [[ "$vt" =~ ^[1-9][0-9]?$ ]] && (( vt <= 63 )); then
|
|
printf '%s:%s\n' "$sid" "$vt"
|
|
return 0
|
|
fi
|
|
done <<< "$sessions"
|
|
return 1
|
|
}
|