login greeter
git clone https://git.lucas.co/cce-display-manager.git
fix: the unit restarts the display manager after any exit
Ctrl+C at the greeter exits the daemon, and with no Restart= the login
screen stayed gone until a reboot. Restart=always, RestartSec=1, under
systemd's default start limit for a daemon that cannot start at all.
A daemon that dies mid-session cannot bring a greeter up beside a live
session: it leads tty1's session, and the compositor and startcce, in
its foreground process group, take the kernel's SIGHUP with the default
action (neither ignores nor catches it, per /proc/<pid>/status), so the
session has already ended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md | 11 +++++++++--
README.md | 5 ++---
cce-display-manager.service | 10 ++++++++++
cce-display-manager@.service | 10 ++++++++++
4 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 03773ef..63259f4 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -102,6 +102,15 @@ sealed random one) and raced the unit.
file owned by that user (`symlink_metadata`), since anyone can create names
in /tmp.
+**The unit restarts the daemon after any exit** (`Restart=always`, since
+2026-09-25). Ctrl+C at the greeter exits it (130 from the greeter → the daemon
+`exit(0)`), which left no login screen until a reboot. A daemon that dies
+mid-session has already ended the session — it leads tty1's session, and the
+compositor and `startcce`, in its foreground process group, take the kernel's
+SIGHUP with the default action (checked in `/proc/<pid>/status`) — so a
+restart then cannot put a greeter beside a live session. If the compositor
+ever starts ignoring SIGHUP, that reasoning has to be redone.
+
## Installing and verifying
The login runs `/usr/bin/cce-display-manager`, the units in
@@ -131,8 +140,6 @@ Rollback is Ctrl+Alt+F2 (logind's auto-VTs), restore the `.bak`, reboot.
## Known gaps
-- **Ctrl+C at the greeter stops the daemon** (exit 130 → `exit(0)`), and the
- unit has no `Restart=`, so the login screen stays gone until a reboot.
- `WLR_DRM_DEVICES=/dev/dri/card1:/dev/dri/card0` for the greeter's cage is
this machine's card numbering, hard-coded; `startcce` pins card1 the same way.
- `busctl monitor` (the resume watchdog) and `chvt` / `loginctl` are shelled
diff --git a/README.md b/README.md
index 615c90a..2c5eaef 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,8 @@ conflict). The machine's own session list comes from
the two fields.
- **F5** restarts the display manager daemon from `/usr/bin` — how a newly
installed version takes effect without a reboot.
-- **Ctrl+C** stops the display manager altogether. The unit does not restart
- it, so the login screen stays gone until a reboot or
- `sudo systemctl start cce-display-manager@tty1`.
+- **Ctrl+C** exits the display manager; its unit (`Restart=always`) starts it
+ again a second later — a full restart, where F5 only re-execs the daemon.
## How it is put together
diff --git a/cce-display-manager.service b/cce-display-manager.service
index 9bf0774..d809880 100644
--- a/cce-display-manager.service
+++ b/cce-display-manager.service
@@ -21,6 +21,16 @@ TTYVTDisallocate=yes
UtmpIdentifier=tty1
UtmpMode=user
Environment=RUST_LOG=info
+# Come back after ANY exit. Ctrl+C at the greeter exits the daemon (0), and
+# without this the login screen stayed gone until a reboot. A daemon that
+# dies mid-session has already taken the session with it: it leads the tty's
+# session, the compositor is in its foreground process group, and neither the
+# compositor nor startcce handles the SIGHUP the kernel sends them when it
+# exits. So restarting then brings back a login screen, not a second greeter
+# beside a live session. RestartSec paces a daemon that cannot
+# start at all (cage missing); systemd's start limit (5 in 10s) then stops it.
+Restart=always
+RestartSec=1
[Install]
WantedBy=graphical.target
diff --git a/cce-display-manager@.service b/cce-display-manager@.service
index a6dcda0..a1913ee 100644
--- a/cce-display-manager@.service
+++ b/cce-display-manager@.service
@@ -21,6 +21,16 @@ TTYVTDisallocate=yes
UtmpIdentifier=%I
UtmpMode=user
Environment=RUST_LOG=info
+# Come back after ANY exit. Ctrl+C at the greeter exits the daemon (0), and
+# without this the login screen stayed gone until a reboot. A daemon that
+# dies mid-session has already taken the session with it: it leads the tty's
+# session, the compositor is in its foreground process group, and neither the
+# compositor nor startcce handles the SIGHUP the kernel sends them when it
+# exits. So restarting then brings back a login screen, not a second greeter
+# beside a live session. RestartSec paces a daemon that cannot
+# start at all (cage missing); systemd's start limit (5 in 10s) then stops it.
+Restart=always
+RestartSec=1
[Install]
WantedBy=graphical.target