BetterFrame/deploy/systemd/betterframe-kiosk.service
Mitchell R 1a87c97479
fix(kiosk): piwiz + cursor + migration backfill + artifact cleanup
Cursor: install theme as index.theme (XCursor spec) not just
cursor.theme. Add WLR_XCURSOR_THEME env var for wlroots compat.

Piwiz: broader purge (rpi-first-boot-wizard, raspi-config triggers,
profile.d scripts, firstrun.sh). Mark first-boot done via userconf
marker file.

Migration: add encrypt_key_encrypted, cloud_accounts, and ONVIF event
columns to catch-all backfill so PRAGMA user_version skips can't miss
them.

Artifact cleanup: delete yanked firmware/OS files + prune to 5 most
recent per channel. Runs every 6h. Stops disk from filling up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-23 02:56:56 +02:00

67 lines
2.8 KiB
Desktop File

[Unit]
Description=BetterFrame Kiosk (cage + betterframe-kiosk)
Documentation=https://github.com/BetterCorp/BetterFrame
After=systemd-user-sessions.service plymouth-quit-wait.service network-online.target seatd.service
Wants=network-online.target
Conflicts=getty@tty1.service
After=getty@tty1.service
# After 10 fast restarts in 60s, back off so a broken binary doesn't burn CPU.
StartLimitIntervalSec=60
StartLimitBurst=10
[Service]
Type=simple
User=bfkiosk
Group=bfkiosk
SupplementaryGroups=video render input audio
PAMName=cage
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
StandardInput=tty-fail
StandardOutput=journal
StandardError=journal
UtmpIdentifier=tty1
UtmpMode=user
WorkingDirectory=/home/bfkiosk
EnvironmentFile=-/etc/default/betterframe-kiosk
Environment=XDG_SESSION_TYPE=wayland
Environment=XDG_SESSION_CLASS=user
Environment=GST_DEBUG=1
# Cursor: cage/wlroots draws a sprite in the gap between compositor start
# and first kiosk frame. Collapse to 1px transparent + force software
# fallback so XCURSOR_SIZE actually applies (HW cursors ignore size on
# some GPUs, leaving a default white-arrow visible in the corner).
# Invisible cursor: transparent theme + 1px size + software fallback.
# Three layers because Pi 5 GPU ignores XCURSOR_SIZE for HW cursors.
Environment=XCURSOR_THEME=betterframe-empty
Environment=WLR_XCURSOR_THEME=betterframe-empty
Environment=XCURSOR_SIZE=1
Environment=WLR_NO_HARDWARE_CURSORS=1
# Let the unprivileged kiosk process control the Pi fan PWM sysfs files.
ExecStartPre=+/bin/sh -c 'for d in /sys/class/hwmon/hwmon*; do [ -e "$d/pwm1" ] || continue; chgrp bfkiosk "$d/pwm1" "$d/pwm1_enable" 2>/dev/null || true; chmod g+w "$d/pwm1" "$d/pwm1_enable" 2>/dev/null || true; done'
ExecStartPre=+/usr/local/sbin/betterframe-firmware-rollback.sh
ExecStart=/usr/bin/cage -s -- /opt/betterframe/kiosk/betterframe-kiosk
Restart=always
RestartSec=2
# If cage/kiosk exits or crashes and systemd can't restart it after the
# burst limit (10 in 60s per [Unit]), force a full system reboot. This
# covers scenarios where the app isn't foreground (e.g. cage died, VT
# switched, GPU fault) — the kiosk should NEVER show anything other than
# our app. A reboot is less alarming than a login prompt or blank screen.
FailureAction=reboot-force
StartLimitAction=reboot-force
# WebKitGTK uses bubblewrap for its web-content sandbox. bwrap aborts with
# "Unexpected capabilities but not setuid" when launched from a process that
# still carries CAP_* bits. Strip caps + lock NoNewPrivileges so WebKit's
# sandbox can initialise cleanly. Without this WebKit cells crash on load.
CapabilityBoundingSet=
AmbientCapabilities=
NoNewPrivileges=yes
# Fallback if the above isn't enough on a given distro (disables WebKit sandbox):
#Environment=WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1
[Install]
WantedBy=multi-user.target