3

I'm currently using a systemd unit file to configure a service which uses X server display.

The X server instance is launched by the user logged in (currently pi user) but the service is launched at root.

I can successfully launch the service using systemctl start test_graphic_app if I hard code the .Xauthority file location into XAUTHORITY variable from the unit file as follow

[Unit]
Description=Test Graphic App
After=multi-user.target

[Service]
Type=simple

User=root
Group=root

Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/pi/.Xauthority"

ExecStart=/usr/bin/python3 /usr/sbin/test_graphic_app.py

KillSignal=SIGINT
SuccessExitStatus=SIGINT

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=test_graphic_app

Restart=on-failure

[Install]
WantedBy=default.target

However this obviously doesn't work if I log using another user or if I run it locally on my laptop cause the user launching X is not pi

I would like to dynamically get the .Xauthority file location on the system.


I've tried using sudo xauth info | grep Authority | awk '{print $3}' as follow

Environment="XAUTHORITY=$(/usr/bin/xauth info | grep Authority | awk '{print $3}')"

ExecStartPre=/bin/bash -c 'export XAUTHORITY=${XAUTHORITY}'

However if the command works on my laptop, it doesn't on the pi

## On laptop ##
$ sudo xauth info | grep "Authority file" | awk '{print $3}'
/run/user/1000/gdm/Xauthority

## On pi ##
$ sudo xauth info | grep "Authority file" | awk '{print $3}'
xauth:  file /root/.Xauthority does not exist
/root/.Xauthority

I was unable find how to get the .Xauthority file location depending on the user that have launched the X server instance. Also, I don't want to allow any user to use X display doing xhost +

How can I get the location within my systemd unit?

Is there any better solution other than finding the .Xauthority location?

2
  • The easy solution is not to launch your service at boot, but launch it when this particular user logs in. Or use a display manager, which will launch the X server, and launch the service once the X server is up. Trying to start your service before there is any X server it can connect is broken, no matter how many workarounds you try. If the service does anything important which you need at boot, split it into a non-graphical and a graphical part.
    – dirkt
    Sep 17, 2018 at 6:28
  • I'm using autolog on the raspberry pi and default.target is set to graphical runlevel, so the service start after X has been launched.
    – Arkaik
    Sep 18, 2018 at 8:06

2 Answers 2

2

There are more sophisticated versions of xhost +, namely xhost +si:localuser:root which adds only local user root to the list of allowed connections.

You need to find where to put this command so it is run on login, depending on your distribution. Look in /etc/X11/ for an existing file using xhost already. On my pi I found it in /etc/X11/Xsession.d/35x11-common_xhost-local:

if type xhost >/dev/null 2>&1; then
  xhost +si:localuser:$(id -un) || :
fi

On another system it was in /etc/X11/xinit/xinitrc.d/localuser.sh.

5
  • Do you know a way to do it permanently so I just have to run it at install ?
    – Arkaik
    Sep 16, 2018 at 16:24
  • I'm not sure what you mean. Just create a shell script file with a name like 35-add-root-xhost in the appropriate directory, with the new extra xhost command in it, and make sure it is executable. It will be run at each login.
    – meuh
    Sep 16, 2018 at 17:58
  • My issue is that I will deploy the app on several linux systems using an install script so I'm looking for a way to allow root to connect X (with xhost +si:localuser:root for example) but permanently with one command ran at install. The script would be nice if the location were always the same on the system.
    – Arkaik
    Sep 16, 2018 at 20:15
  • @Arkaik Did you find a clean way to "install" this configuration? What did you try next? I'm stuck in the same place you were...
    – Eric Roy
    Apr 24 at 10:17
  • 1
    It's been a very long time since I worked on this project, so I don't really remember everything I did. However I got it to work with different configurations depending on the targeted OS, on my development computer I used ExecStartPre=/usr/bin/xhost +si:localuser:root into the systemd unit file and ran the service as root. On the Pi I ran the service as a specific user/group appuser that was created during the image preparing into a loop device and I used Environment="DISPLAY=:0" and Environment="XAUTHORITY=/home/appuser/.Xauthority" into the unit file. Hope it helps you.
    – Arkaik
    Apr 25 at 15:39
0

Add this to your install script:

sudo mkdir /opt/xauthorityfix
sudo chmod 777 /opt/xauthorityfix
echo "#!/bin/sh" > /opt/xauthorityfix/setxauthority.sh
echo "export XAUTHORITY=$XAUTHORITY" >> /opt/xauthorityfix/setxauthority.sh
sudo chmod 755 /opt/xauthorityfix

After that, wrap your python script in this shell script:

#!/bin/sh

source /opt/xauthorityfix/setxauthority.sh
/usr/bin/python3 /usr/sbin/test_graphic_app.py

And just have your systemd service start that script instead!

Just make sure that the XAUTHORITY environment variable is set when your install script is run. You can do that by not running it with sudo, or by using sudo -E.

Basically, this stores the XAUTHORITY environment variable as it is when the install script is run, allowing you to easily refer to it later.

1
  • The user that ran the install script might not be logged in when the service gets started, making the Xauthority file pointed to by the stored environment variable invalid.
    – telcoM
    Oct 28, 2023 at 18:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .