Skip to content

systemd user services, pam, and environment variables

danshick edited this page Oct 20, 2020 · 6 revisions

...or, why xdg-desktop-portal-wlr doesn't work out of the box

TL;DR

You probably need to put

XDG_CURRENT_DESKTOP=sway

into either ~/.config/environment.d/*.conf for your local user or /etc/environment.d/*.conf for a system-wide fix (where * is a file name of your choosing). It is not enough to set that environment variable in profile or {shell}rc configs.

First, some background

xdg-desktop-portal (xdp) is the program that keeps track of different portal implementations, their capabilities, and proxies the appropriate messages between them and other applications that use them.

xdg-desktop-portal-wlr (xdpw) is one specific portal implementation that provides screenshot and screencast implementations for wlroots compositors.

xdp looks for the environment variable XDG_CURRENT_DESKTOP and tries to find a corresponding portal implementation by looking at the installed *.portal files. Those files should all have a line that potentially matches the value of that environment variable (e.g., UseIn=sway). If no environment variable is present, xdp chooses a default implementation for each interface from the collection of all installed portals. xdg needs to be able to see this environment variable in order to choose xdpw as the implementation for the screenshot and screencast interfaces, or a different portal implementation may be used instead (and will fail, often in the form of an all black screenshot or screencast, possibly showing only the cursor).

So what is the problem then?

xdp is meant to start as a systemd user service. Those services are not forked from your login shell and thus, don't inherit environment variables set in your .profile, .{shell}_profile, or .{shell}rc files. Instead, you need to use one of the configs specific to the "user service environment" as documented here. This is explained in even more detail in the ArchWiki and in the Gnome documentation.

This is extra confusing, because if you try to run xdp/xdpw manually from a terminal after logging in, and you've set XDG_CURRENT_DESKTOP in one of the profile or rc config files, it will likely work correctly.

That's annoying, why are user services not forked from my login shell?

It has to do with pam, and how pam is used to initialize systemd user sessions.

For example, on a default Arch Linux install, the /etc/pam.d/login file includes /etc/pam.d/system-local-login, which includes /etc/pam.d/system-login, which contains the lines:

-session   optional   pam_systemd.so
session    required   pam_env.so           user_readenv=1

You can find the pam.d config file documentation here, but in short, the first line invokes the pam_systemd.so module if present. One of the documented purposes of that pam module is to launch "[a]n instance of the system service user@.service, which runs the systemd user manager instance". It also "registers user sessions with the systemd login manager systemd-logind", which automatically handles gettys. Your getty implementation (agetty on a default Arch installation) ultimately invokes /bin/login.

So how should I set this environment variable?

The environment.d docs list a number of files where you can set XDG_CURRENT_DESKTOP, but those aren't your only choices. You could also set them in /etc/environment, /etc/security/pam_env.conf, or possibly ~/.pam_environment, which are loaded by the pam module, pam_env.so. Its configuration is explained here.

You could also run systemctl --user import-environemnt or dbus-update-activation-environment --systemd --all any time before xdp is started, assuming that XDG_CURRENT_DESKTOP is correctly set when and where that command is run. Many users exec one of those commands in their sway config, which seems to work.

Clone this wiki locally