In the previous entry of this now-a-series series, you’ll of seen me use seatd.service
instead of systemd-logind.service
to acquire a seat for my custom Shoe service. I had avoided using logind
before because it refused to actually allocate a seat to my services, no matter what I did.
I was never sure if logind
didn’t support VT-less setups, if my PAM files were wrong, or if the Arch Linux package for cage
wasn’t compiled with logind
support, but now I know why…
In case you don’t know: A “seat” is a group of input & output devices which can be allocated to a process. This concept enables multi-seat setups, where one physical device has multiple people logged in at same time, with each login getting its own set of devices.
Why it didn’t work
The answer is frustratingly simple: Because I was lazy.
When the VT subsystem is present, it will always try to read user input, and that’s the problem. If some other process tries to read user input, then both the process and the VT subsystem will receive the input.
Therefore, if logind
finds /dev/tty0
(a couple other files are checked too), it will only give seats to processes with a TTY device in its control; the only way to solve the split-input issue is to send the input to a TTY device and then have it redirect the input to the relevant process.
Proper solution
Just, ya know, actually compile out the kernel VT support?
After that, set the XDG_SEAT environment variable to seat0
and use a PAM config containing at least pam_systemd.so
to acquire a session from systemd-logind.service
. Here’s an example of what such a PAM config might look like:
seat0
is the hardcoded seat containing all input devices not allocated to another seat, which for most people (who probably aren’t manually creating seats) is all the available input devices.
Very hacky solution(s)
To avoid needing to touch the /dev/tty[0-63]
devices (among others), or if you’re someone who likes their terrible ideas to have some certainty to them damnit, you can add the following systemd-logind.service
drop-in file to force logind
to allocate a seat anyways:
This is a terrible idea:
systemd-logind.service
will complain that/sys/class/tty/tty0
doesn’t exist while/dev/tty0
does, which ordinarily wouldn’t be possible.- This leaves the split-input problem entirely unsolved and, if you stop the relevant processes and inspect the underlying TTY device (probably
/dev/tty1
), you’re usually able to see everything you’ve typed up to that point.
Similarly, using seatd
(with SEATD_VTBOUND=0
) and logind
simultaneously has the same input problem as described above, only now there’s two seat-managing services involved which is arguably even worse.
Probably hacky solution
Another way of getting logind
to cooperate, while being at least slightly less hacky than the above proposals, is to remove the VT subsystem devices early on in the boot process, which you can accomplish with this hardened service:
Add the
Requires=rm-vt-dev.service
&After=rm-vt-dev.service
lines to the necessary service to pull inrm-vt-dev.service
Additionally, you can set the console=ttynull
kernel cmdline option, which stops /dev/console
(the TTY device used by the /init
process) from redirecting to /dev/tty0
(which in theory redirects to /dev/tty1
, since /dev/tty0
represents the “current” TTY device). You can check what devices redirect where by looking at /sys/class/tty/{console,tty0}/active
and reading the device name.
This is probably a bad idea, mainly because I’m uncertain of two things:
- Does this prevent other processes from accessing the VT subsystem from this point onwards?
- Does the VT subsystem still receive user input if not even
systemd-vconsole-setup.service
has touched the TTY devices?
Without an answer to these questions, I cannot recommend using this method for anything except demonstrations; the proper solution is the only secure method I know of.
The dream solution
In an ideal world, the VT subsystem could be disabled with a runtime toggle (e.g. a kernel cmdline like vt_disabled=1
) and avoid the need for recompiling, but until then, these are the only available methods I’m aware of.