#+TITLE: TIL: The TTYPath= setting to starting an interactive program on boot For =$WORK= I had to setup a Linux machine (a Raspberry Pi) so that right after boot, an interactive CLI tool would start, ready to receive input and show information. Of course if you start a script at boot, its =stdin= is closed and =stdout= goes to the Journal. There exists [[https://manpages.debian.org/bookworm/kbd/openvt.1.en.html][openvt(1)]] to launch that script in a new VT (or to take over =tty1=). (But then you have to mind that =openvt= needs to run as root to open a new VT, so it should wrap =sudo= to drop privileges, and that get a bit fiddly.) Then I happened upon the [[https://manpages.debian.org/bookworm/systemd/systemd.exec.5.en.html#:~:text=Sets%20the%20terminal%20device%20node%20to%20use][=TTYPath=]] setting, which does exactly what I need; and of course it combines perfectly fine with settings for =User== or =WorkingDirectory=. I ended up with the following: #+BEGIN_SRC [Unit] Description=Interactive script started on boot [Install] WantedBy=multi-user.target [Service] # The magic to have prompts displayed to the user TTYPath=/dev/tty1 StandardInput=tty StandardOutput=tty User=someuser WorkingDirectory=/opt/software/ ExecStart=/opt/software/bin/start_soft # Always restart on exit, disable restart counter, delay a little bit # the restart to avoid spam in case of repeating error Restart=always StartLimitIntervalSec=0 RestartSec=5s #+END_SRC It only occured to me to have a look at how =getty.service= is configured, and indeed it [[https://github.com/systemd/systemd/blob/e127c66985b9e338fcb79900a88a24848d5d31fb/units/getty%40.service.in#L46][uses the same options]]: #+BEGIN_SRC StandardInput=tty StandardOutput=tty TTYPath=/dev/%I TTYReset=yes # reset $TTYPath before and after execution TTYVHangup=yes # disconnect all clients which have open $TTYPath TTYVTDisallocate=yes # deallocate before and after execution; this ensures screen and scrollback buffer is clear #+END_SRC A inconvenience is that if you start on =tty1=, then messages from systemd or the kernel get mixed up with your program output. If you start on =tty2=, I tried to add =ExecStartPre=chvt 2=, but the VT would switch back to =tty1= depending on exact boot order.