Using systemd to execute an interactive (whiptail) script after multi-user.target but before the login screen

6

1

I am trying to run a small interactive configuration script from systemd on Fedora 19. It has to be run as root, and run prior to the user logging in. I have created a service which looks a bit like this:

[Unit]
Description=blah
Before=graphical.target 

[Service]
Type=oneshot
ExecStart=/path/to/script.sh

[Install]
RequiredBy=multi-user.target

and for the sake of simplicity, the script looks like this:

#!/bin/sh
whiptail --msgbox "test" 0 78

But when I load this service and reboot the script output is not displayed and in /var/log/messages it suggest that the TERM variable should be set. But I would have expected the script to be run on the first virtual terminal.

Any suggestions or insight would be greatly appreciated.

pxul

Posted 2013-12-17T18:16:51.793

Reputation: 175

Can you pls post the exact error message? – MariusMatutiae – 2013-12-17T18:35:46.990

Sure, the message I get is:

test.sh[418]: TERM environment variable needs set.

However, setting the environment variable in the service leads to the script output being directed into /var/log/messages. – pxul – 2013-12-17T18:37:00.723

Answers

1

There is a fairly fundamental thing about dæmons that you're missing: As standard they don't have controlling terminals. They don't have open file handles for terminal devices. Anything that expects to talk to "the terminal" won't do so. There is no "the terminal".

No, $TERM doesn't specify "the terminal". It specifies the terminal type, i.e. what escape sequences to send as output and to interpret as input. It is needed here, and you'll have to arrange for it to be set to an appropriate value. But it's not the major factor here. The major factor is that there is no "the terminal".

Yes, the output ends up in /var/log/messages. The standard output of a service goes to the journal by default under systemd, and you've evidently got a syslogd of some sort running. That you saw this only after $TERM was set simply means that your script got further along, past the part where it needed to know the terminal type in order to work out how it was going to output things.

systemd does have the ability to attach dæmons to terminals. It has to have. It runs agetty as a daemon to provide the login sessions on virtual terminals.

What you are looking for are the StandardInput=, StandardOutput=, and TTYPath= settings, to add to that unit file in your question. Have a look in /usr/lib/systemd/system/getty@.service to see them in use.

You don't give enough information in your question as to whether this is precisely the right approach, or whether instead you should be adding an ExecStartPre= to a custom /etc/systemd/system/getty@.service. It all depends from whether this is something to be run once before starting a GUI, or every time before every individual (TUI) login. Before=graphical.target hints at the former, but this could be not what you actually wanted (given the RequiredBy=). ☺

JdeBP

Posted 2013-12-17T18:16:51.793

Reputation: 23 855

As you suspected this was for a run-once script to be executed before starting the display manager. In the end I used /usr/lib/systemd/system/initial-setup-text.service as a template, which incorporated your suggestions. – pxul – 2014-06-25T15:01:47.797

1@JdeBP I was pointed at your answer. Do you mind giving an example of a unit that runs something once right before allowing users to log in? I am using it for a system setup script. Think like a pre-imaged OS. On each system start, it checks if it has been "set up", and if not, asks the user at the console for a few pieces of setup info, sets them and is done. If setup was done in the past, it does nothing. So it may need to interact with the user on "console". – deitch – 2016-04-28T13:49:06.233