4

EnvironmentFile is not an option as per this answer.

I am trying to understand the recommended way of using and passing environment variables.

I have a urxvtd.socket:

[Unit]
Description=urxvt deamon (socket activation)
Documentation=man:urxvtd(1) man:urxvt(1)

[Socket]
ListenStream=%t/urxvt/urxvtd-%H

[Install]
WantedBy=sockets.target

Now a urxvtd.socket with a Requires dependency on that urxvtd.socket:

[Unit]
Description=Urxvt Terminal Daemon
Requires=urxvtd.socket

[Service]
# Needs to know socket file location RXVT_SOCKET environment variable.
# Where will it come from?
ExecStart=/usr/bin/urxvtd -o -q

[Install]
WantedBy=default.target

Now I need RXVT_SOCKET to be set before starting i3 as i3 will have a key binding to start urxvtc (urxvt client).

If I start i3/Xorg without systemd (i.e with xinitrc), and put in .zshenv (user specific environment file loaded always.):

export RXVT_SOCKET=${XDG_RUNTIME_DIR}/urxvt/urxvtd-machinename

Then urxvtc launched by i3 will correctly infer the RXVT_SOCKET variable and look for the socket at that path.

However, the urxvtd.service launches urxvtd (the daemon), so it also needs RXVT_SOCKET.

The Archwiki recommends setting the environment in urxvtd.service:

...
Environment=RXVT_SOCKET=%t/urxvtd-%H
...

But therein the problem lies. Why should the environment variable be set again in urxvtd.service, when the initial user urxvtd.socket should set it?

Note, it is set again in .zshenv for i3 to get it. This is a case of multiple sources of truth for one simple environment variable..

Did we notice that urxvtd.service example above has the incorrect path for RXVT_SOCKET set in .zshenv? Reiterates my multiple source of truth argument.

What is the best way to deal with this?

I was thinking maybe I can set the RXVT_SOCKET in urxvtd.socket as so:

[Socket]
Environment=RXVT_SOCKET
ListenStream=%t/urxvt/urxvtd-%H

And since urxvtd.service is a dependency then there should be a way to import environment variable. But there isn't. So urxvtd daemon will behave as if RXVT_SOCKET is not set, but the socket will be created correctly due to urxvtd.socket.

Then I dug a bit deeper, and systemctl --user import-environment RXVT_SOCKET should import the variable across systemd units. Would that really be the way? Then I also need to ensure that the import happens before urxvtd.service runs. How would that work?

If I do use Xorg/i3 with systemd, I believe there should be a way to transfer the environment variable across systemd units.

At this point I am likely to believe there is no pure systemd solution to such requirement for propagation of environment variables

I ended up using a shell to wrap the ExecStart command since the shell will inherit the environment correctly.

  • In an ideal world, you wouldn't be worrying about this environment variable in the first place and urxvtd would employ the listening socket that is being passed to it as an already-open file descriptor. – JdeBP Nov 1 '18 at 14:56
  • You have a socket unit. systemd is, right now, setting up a file descriptor to the designated socket, and the urxvtd program is starting execution with that file descriptor open and a LISTEN_FDS environment variable telling it how many such already-open file descriptors for listening sockets it has (1 in this case). In an ideal world, urxvtd wouldn't be repeating all of this work and you wouldn't be worrying about the RXVT_SOCKET environment variable. – JdeBP Nov 1 '18 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.