Files

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
}