How Can I Write to Console During Shutdown?
Standard output and error of services under service management — be it s6, runit, perp, daemontools, nosh service management, or systemd — is not the console. It is a pipe connected to some form of log writer.
For a systemd service you need a TTYPath=/dev/console
and a StandardOutput=tty
in the .INI file to change this, StandardInput=tty
if you want to read (but you do not) as well as write. Witness systemd's pre-supplied debug-shell.service
.
This is a general principle that is not systemd specific. Dæmon context involves (amongst other things) not having a controlling terminal and not having open file descriptors for terminals, and under proper service management (such as all of the daemontools family) this is where one starts from, the state that a service process begins in when the supervisor/service manager forks it. So to use the console the service has to explicitly open it.
In systemd, the aforementioned TTYPath
and StandardInput
settings cause the forked child process to open the console before it executes the service program proper. This is hidden inside systemd and you do not really get to see it. In the run
program of a similar nosh service, the run
program explicitly uses some of the nosh toolset chain-loading tools to do the same thing before executing the main program (emergency-login
in this case):
% cat /etc/service-bundles/services/emergency-login@console/service/run #!/bin/nosh #Emergency super-user login on console setsid vc-get-tty console open-controlling-tty vc-reset-tty --hard-reset line-banner "Emergency mode log-in." emergency-login %
Ironically, you do not need the logger
command, or any syslog dependencies. There is no point in writing this interactive prompt to a log. But you really should run this service unprivileged, on principle. It does not need superuser privileges, for anything that it does.
On another principle, don't make your script use #!/bin/bash
unless you really are going to use Bashisms. One of the greatest speedups to system bootstrap/shutdown in the past couple of decades on Debian Linux and Ubuntu Linux was the switch of /bin/sh
from the Bourne Again shell to the Debian Almquist shell. If you are going to write a script as simple as this, keep it POSIX-conformant and use #!/bin/sh
anyway, even if you are not using Debian/Ubuntu, and on Debian/Ubuntu you'll get the Debian Almquist shell benefit as a bonus.
Moreover, if you decide to have more than a glass TTY message, with a tool like dialog
, you will need to set the TERM
environment variable so that your programs can look up the right escape and control sequences to emit in the terminfo database. Again, witness debug-shell.service
. (In the aforegiven run
program, for comparison, the vc-get-tty
tool sets TERM
.)
Similarly, you will want script errors to be logged. So standard error should be left pointing at the journal with StandardError=journal
. Here's a nosh service run
program that illustrates the equivalent of this, and also shows dropping user privileges for a program that really does not need them, which in a systemd .INI file would be User=daemon
:
% cat /etc/service-bundles/services/monitor-fsck-progress/service/run #!/bin/nosh #local socket used for monitor-fsck-progress local-stream-socket-listen --systemd-compatibility --backlog 2 --mode 0644 /run/fsck.progress setsid setlogin -- daemon vc-get-tty console fdmove -c 4 2 open-controlling-tty fdmove 2 4 setuidgid -- daemon ./service %
The program run by ./service
in this case presents a full-screen TUI on the console, whilst its errors are sent to the logging service. This is the stuff that one needs to do, under service managers in general, in order to run such programs as services, talking to the console.
Of course, any such full-screen TUI program will conflict with systemd's "A stop job is running", also written to the console. But that is your problem. ☺
Further reading
- https://unix.stackexchange.com/a/468457/5132
- https://unix.stackexchange.com/a/250965/5132
- https://unix.stackexchange.com/a/499148/5132
- https://unix.stackexchange.com/a/233855/5132
- whiptail or dialog