Back in June, I wrote about the difficulty of killing the dbus-monitor subprocess when Bustle is recording the system bus:
But sending SIGKILL from the unprivileged Bustle process to the privileged dbus-monitor process has no effect. Weirdly, if I run pkexec dbus-monitor --system in a terminal, I can hit Ctrl+C and kill it just fine. (Is this something to do with controlling terminals? Please tell me if you know how I could make this work.)
Greetings, past me! I’m just like you, only 6 months older, and I’m here to tell you how to make this work.
When you run a process in a terminal (emulator), its controlling TTY is a pseudoterminal (hereafter PTY) slave ((not my choice of terminology)) device. When you press Ctrl+C, the terminal doesn’t send SIGINT to the running process; it writes the ^C character '\x03'
into the corresponding PTY master. This is intercepted by the kernel’s TTY layer, which eats this character and sends SIGINT to the (foreground) process (group) attached to the PTY slave. It doesn’t matter if that process (group) is owned by another user: being able to write to its controlling terminal is the capability you need.
Armed with this knowledge, and some further reading on how to set the controlling TTY, it was reasonably easy to wire this up in Bustle:
- Before forking the dbus-monitor subprocess, open a PTY master/slave pair and tell GSubprocess to use the slave FD as the subprocess’s stdin
- After forking, but before execing pkexec dbus-monitor, call
setsid ()
to move the process to a new session, thenioctl (STDIN_FILENO, TIOCSCTTY, 0);
to set its controlling TTY - When it comes time to stop the monitor, write
'\x03'
into the PTY master FD
You may wonder how the second step works in the Flatpak case, where the pkexec dbus-monitor process is not spawned directly by Bustle, but by the Flatpak session helper daemon. Well, we don’t get a chance to run our own code between fork()
and exec()
, but that’s okay because the session helper does exactly the same thing for us. (I think this is why Ctrl+C works in a host shell running within Flatpak:d GNOME Builder.)