/dev/stderr in systemd service

stderrsystemd

I'm writing a service which should start LTE connection.

But the utility I'm using to connect (sakis3g) is writing to /dev/stderr, which is not available in systemd and the log is full of

Cannot create /dev/stderr: No such device or address

Is there some way to work around it?

Changing the utility script/binary is unfortunately not an option.

EDIT: Here is the service:

[Unit]
Description=LTE
After=syslog.target network-online.target
Before=openvpn-client@client
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/mav/LTE/
ExecStartPre=/sbin/ip link set wwan0 down
ExecStart=/opt/mav/LTE/sakis3g connect -g --sudo
ExecStop=/opt/mav/LTE/sakis3g disconnect --sudo

[Install]
WantedBy=multi-user.target

And it works in this state. But when I start sakis3g with -g flag for more verbose debug output, then the stderr errors appear.

Best Answer

If there was no stderr, you wouldn't see the error.

Here, the error is about not being able to open the /dev/stderr file, which on Linux is a symlink to the actual file that is open on the fd 2 (while on other systems, opening /dev/stderr is like doing a dup(2)).

The problem here is likely that fd 2 is open on a socket (inet TCP, Unix stream or other) and you can't open() a socket file.

If you run:

sudo lsof -aU +E -d 2

On a system using systemd you'll notice that fd 2 of most services is a unix domain stream socket to systemd-journald.

As a work around, you may be able to start it as:

bash -o pipefail -c '{ /opt/mav/LTE/sakis3g connect -g --sudo 2>&1 >&3 3>&- | cat >&2 3>&-; } 3>&1'

That is make stderr a pipe (to cat) instead of a socket, cat forwarding what it receives on the pipe to the original stderr (the socket), and make sure we preserve the exit status of the command with the pipefail option.

In any case, the source of that sakis3g is available and that sakis3g init file is a bash script, that happen to do:

echo text >> /dev/stderr

instead of:

echo test >&2

It's even got a few > /dev/stderr instead of >> /dev/stderr which is even more wrong. It has no tee -a /dev/stderr | other cmd which would have been a legitimate use of /dev/stderr and would also not work with stderr on a socket, so it's easily fixable.

You may want to let them know of the problem by raising an issue at https://github.com/Trixarian/sakis3g-source/issues