git.lucas.co / cce-display-manager
login greeter
git clone https://git.lucas.co/cce-display-manager.git

commit84f5cb5cad9d8f50d0ba05d65032cd408da61eac
parentbf21a222a1
authorLucas Galante <lsgalante12@gmail.com>
date2026-09-25 15:29
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