You are not logged in.

#1 2022-05-12 09:57:43

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

[SOLVED] Access to the display when loading the systemd service

I am writing a bootable service in C and D languages.

There is a database of users with thin client settings. I access this database over the network during the download and get from there the data of a specific user linked to the MAC address. The fact is that a user can have two or more monitors connected to a thin client. Data for each monitor is also loaded from the database. Using the xrandr source code, I wrote a program that, knowing the monitor ID, sets the desired monitor in one position or another. The fact is that xrandr uses the global variable DISPLAY, which is unavailable during the loading process.

● myservice-init.service - myservice
     Loaded: loaded (/etc/systemd/system/myservice-init.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2022-05-12 19:15:14 MSK; 55s ago
    Process: 1559 ExecStart=/etc/init.d/myservice-init (code=exited, status=1/FAILURE)
   Main PID: 1559 (code=exited, status=1/FAILURE)

мая 12 19:15:14 ts_d85ed3156a39 systemd[1]: Starting myservice...
мая 12 19:15:14 ts_d85ed3156a39 thinstation[1562]: Can't open display :0
мая 12 19:15:14 ts_d85ed3156a39 systemd[1]: myservice-init.service: Main process exited, code=exited, status=1/FAILURE
мая 12 19:15:14 ts_d85ed3156a39 systemd[1]: myservice-init.service: Failed with result 'exit-code'.
мая 12 19:15:14 ts_d85ed3156a39 systemd[1]: Failed to start myservice.

Although, looking at the Xorg service - this data is there:

~# cat /etc/X11/xinit/xinitrc.d/50-systemd-user.sh

#!/bin/sh

systemctl --user import-environment DISPLAY XAUTHORITY

if command -v dbus-update-activation-environment >/dev/null 2>&1; then
    dbus-update-activation-environment DISPLAY XAUTHORITY
fi

And I start my service after downloading xorg.service. But even adding this code to the launch of my service, I still get errors:

● myservice-init.service - myservice
     Loaded: loaded (/etc/systemd/system/myservice-init.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2022-05-12 19:08:52 MSK; 18s ago
    Process: 1560 ExecStart=/etc/init.d/myservice-init (code=exited, status=1/FAILURE)
   Main PID: 1560 (code=exited, status=1/FAILURE)

May 12 19:08:52 ts_d85ed3156a39 systemd[1]: Starting myservice...
May 12 19:08:52 ts_d85ed3156a39 thinstation[1564]: dbus-update-activation-environment: error: unable to connect to D-Bus: Unable to autolaun
May 12 19:08:52 ts_d85ed3156a39 thinstation[1570]: Can't open display :0
May 12 19:08:52 ts_d85ed3156a39 systemd[1]: myservice-init.service: Main process exited, code=exited, status=1/FAILURE
May 12 19:08:52 ts_d85ed3156a39 systemd[1]: myservice-init.service: Failed with result 'exit-code'.
May 12 19:08:52 ts_d85ed3156a39 systemd[1]: Failed to start myservice.

And if I just launch my application, then it works out quite correctly:

IFace("enp3s0", "e8:5b:d2:11:6a:39", "192.168.0.15")
[Monitor("VGA-1", true, 1280, 1024)]

Last edited by alexanderzhirov (2022-05-30 05:25:27)

Offline

#2 2022-05-12 10:25:34

V1del
Forum Moderator
Registered: 2012-10-16
Posts: 21,720

Re: [SOLVED] Access to the display when loading the systemd service

The display variable is exported as part of the User session which would be set up when the user logs in. And you could configure your service to be ran as an user service instead, see: https://wiki.archlinux.org/title/Systemd/User

Offline

#3 2022-05-12 11:44:02

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

V1del wrote:

And you could configure your service to be ran as an user service instead, see: https://wiki.archlinux.org/title/Systemd/User

I tried to do it.
Placed the service in /etc/systemd/user/myprogram.service:

[Unit]
Description=myprogram

[Service]
ExecStart=/etc/init.d/myprogram

[Install]
WantedBy=default.target

Autorun file /etc/init.d/myprogram:

#!/bin/sh

myprogram

The result is still the same:

● myprogram.service - myprogram
     Loaded: loaded (/etc/systemd/user/myprogram.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Thu 2022-05-12 22:31:30 MSK; 8min ago
    Process: 2550 ExecStart=/etc/init.d/myprogram (code=exited, status=1/FAILURE)
   Main PID: 2550 (code=exited, status=1/FAILURE)

мая 12 22:31:30 ts_d85ed3156a39 systemd[2546]: Started myprogram.
мая 12 22:31:30 ts_d85ed3156a39 myprogram[2551]: Can't open display :0.0
мая 12 22:31:30 ts_d85ed3156a39 systemd[2546]: myprogram.service: Main process exited, code=exited, status=1/FAILURE
мая 12 22:31:30 ts_d85ed3156a39 systemd[2546]: myprogram.service: Failed with result 'exit-code'.

Maybe I forgot something else?

Offline

#4 2022-05-12 11:53:11

V1del
Forum Moderator
Registered: 2012-10-16
Posts: 21,720

Re: [SOLVED] Access to the display when loading the systemd service

How are the clients logging in/starting xorg? The most guaranteed way of this just working is if you/they use a display manager that already has xorg running before doing the log in, if you wanted to do this with startx then your .xinitrc needs to have some code to source the systemd-users.sh (note the blue note) as well as setting up xorg itself as a user service so you have a unit you can order yourself after: https://wiki.archlinux.org/title/System … er_service

Offline

#5 2022-05-13 05:49:53

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

V1del wrote:

How are the clients logging in/starting xorg?

I made a build based on Thinstation. icewm starts there at startup. As far as I understand, the /etc/xinitrc script is executed before icewm is started:

#!/bin/bash

xinitrcd=/etc/X11/xinit/xinitrc.d
if [ -d $xinitrcd ]; then
	for file in `ls -A $xinitrcd`; do
		. $xinitrcd/$file
	done
fi
# Just run xrandr 1 time to populate some settings in case we don't use a window manager
xrandr
cd /
if [ -n "$1" ]; then
	exec $1
elif [ -e $WKDIR/windowapps ] ; then
       	exec $WKDIR/windowapps
fi

and windowapps:

export DISPLAY_NUMBER=0
exec pkg console icewm "" "" "1" "" "" "" ""
wait

And it runs exactly, because in /etc/X11/xinit/xinitrc.d there is another script of mine that works. And then (in the script above) xrandr is launched, which means there is access to DISPLAY, and my service does not have access to DISPLAY.

Last edited by alexanderzhirov (2022-05-13 06:23:43)

Offline

#6 2022-05-13 07:14:39

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

"Can't open display :0.0" means that the process is aware of the $DISPLAY but cannot access it either because the DISPLAY doesn't exist or the process has insufficient permissions.

It's kinda unclear to me what you're trying to achieve here, but if the display is on a different host thatn the process, you'll have to signal that host as well (host:server.screen) and allow it w/ xauth
If your goal is to just configure the outputs and you're running some xinitrc anyway, just xrandr configure it in that xinitrc.

Offline

#7 2022-05-13 07:19:38

geopardo
Member
From: Europe
Registered: 2021-03-23
Posts: 114

Re: [SOLVED] Access to the display when loading the systemd service

try isolating icewm

you have to create a unique direction for each command that the desktop has to receive ..
in practice xinitricrc cannot run more than one instance in some cases.

fi
fi

Some 'security people are f*cking morons' says Linus Torvalds..

Offline

#8 2022-05-13 07:26:24

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

seth wrote:

It's kinda unclear to me what you're trying to achieve here

I want to run a systemd service (even a user) that will run in the background throughout the life of the user session while the user is working at the computer. thus, the administrator through the portal will be able to manage this thin client through this service running in the background, which would have access to the user's display.

It could be done like this /etc/X11/xinit/xinitrc.d/myprogram.sh:

#!/bin/sh

myprogram &

But why can't I do it through the systemd user service?

Offline

#9 2022-05-13 07:41:45

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

It can, but you must ensure that
a) you're accessing the *proper* display
b) invoking the proper XAUTHORITY
c) not before the display is available (to that user)

https://man.archlinux.org/man/systemd.s … User_Units isn't covered by https://wiki.archlinux.org/title/System … er_service
And since we're talking about your own code here, you could check what environment actually makes it to the process (to ensure you're invoking it properly) and then keep calling the server until you can access it (if you need to launch it w/ the session and pot. unrelated to any existing X11 server)

Offline

#10 2022-05-13 08:17:16

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

seth wrote:

It can, but you must ensure that
a) you're accessing the *proper* display
b) invoking the proper XAUTHORITY
c) not before the display is available (to that user)

https://man.archlinux.org/man/systemd.s … User_Units isn't covered by https://wiki.archlinux.org/title/System … er_service
And since we're talking about your own code here, you could check what environment actually makes it to the process (to ensure you're invoking it properly) and then keep calling the server until you can access it (if you need to launch it w/ the session and pot. unrelated to any existing X11 server)

I still don't understand it yet. Is there an example of a similar service that runs the same way? To see which settings are being used.

Offline

#11 2022-05-13 10:07:04

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

alexanderzhirov wrote:

Is there an example of a similar service that runs the same way? To see which settings are being used.

I understand I need to do something like this. Only I don't understand what exactly I need to do. Where to start.

Offline

#12 2022-05-13 10:28:07

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: [SOLVED] Access to the display when loading the systemd service

If you want to keep it really simple, just don't enable the service but put `systemctl --user start myprogram.service` in .xinitrc after DISPLAY is imported into the systemd/user instance (by the snippet in xinitrc.d).

Especially if you might use more services that depend on X, it would be cleaner to start a target instead, which gives you a synchronization point/anchor to hook up such services. This could be a custom target, but you should check seth's link for special units. Currently you're using default.target, which starts immediately on login before the xinitrc stuff runs.

Offline

#13 2022-05-19 06:03:20

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

Raynman wrote:

... it would be cleaner to start a target instead, which gives you a synchronization point/anchor to hook up such services. This could be a custom target, but you should check seth's link for special units. Currently you're using default.target, which starts immediately on login before the xinitrc stuff runs.

Could you write a similar example? I don't quite understand how to do this. I understand I need to do something like this. I can't make a file structure for my service yet. Can anyone tell me?

Offline

#14 2022-05-19 12:11:49

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

You create a user target like "xinit-session.target"

[Unit]
Description=User systemd services for xinit session
Wants=xinit.service
BindsTo=graphical-session.target

The "xinit.service" then Exec's xinit/startx, you don't run that command anywhere but "systemctl --isolate graphical-session.target and base your service on "graphical-session.target" instead of "default.target"

If that sounds clumsy and convoluted, that's because it is.
#8 is the far more straigt forward way - especially if you're operating on a homogenuous xinit environment anyway.

Offline

#15 2022-05-19 13:57:35

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: [SOLVED] Access to the display when loading the systemd service

You can make it as clumsy and convoluted as you want, of course. You and V1del seem to push for "all or nothing": if you're gonna have a user service that does something with X, let's go all the way and put xinit/startx in a user service as well. That gives an already struggling OP more to process.

OTOH, OP hasn't really given any reasons for wanting to move myprogram to a user service in the first place,

And AFAICT, Thinstation has very little to do with Arch (note also the parsing of ls output in xinitrc).

Last edited by Raynman (2022-05-19 14:03:34)

Offline

#16 2022-05-19 14:15:38

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

Well, simply starting the service from the xinitrc is pretty much pointless in comparism to just running the designated process from the xinitrc.
And if you're not doing that, you need to establish the graphical-session.target (or any target) and depend the desired service on that target and the scaling approach is the convoluted one (as it will also apply if you eg. start gnome from GDM)

So the middle ground would be to start a random system target (not graphical-session as thats not startable) from the xinitrc?
Which will get you the xinit ties and modification requirement AND the fragility of systemd…

An alternative solution would be to have the user service or the client ping the server until it responds and act only then.

OP hasn't really given any reasons for wanting to move myprogram to a user service in the first place

Possible reasons are to somehow systemd'ify the process for principle reasons or to cope w/ various session starting mechanisms (as DMs won't run xinitrc)
In the latter case, ~/.xprofile would be the straight path - and not cause xrandr calls if the graphical-session.target is invoked by wayland.

Offline

#17 2022-05-19 15:33:35

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: [SOLVED] Access to the display when loading the systemd service

Yeah, I agree with most or all of that. I hadn't checked when I first replied that

seth wrote:

(not graphical-session as thats not startable)

(as I hoped to let OP do further research). But then your example in #14 should also start (isolate seems a bit strong) xinit-session.target and isn't something like After=xinit.service missing?

seth wrote:

Well, simply starting the service from the xinitrc is pretty much pointless in comparism to just running the designated process from the xinitrc.

Well, at least for

Possible reasons are to somehow systemd'ify the process for principle reasons

it should be enough and then if it's really nothing more than the idea that "systemd is the cool/new way", I would indeed also say "why not just stick with #8?".

Edit: I guess what I don't fully understand is why the strong preference for xinit-session.target started manually/from shell init (or what did you have in mind?) with ExecStart=startx in xinit.service over a similar xinit-session.target started from .xinitrc (or xinitrc.d snippet) without xinit.service and startx run manually/from shell init.

Last edited by Raynman (2022-05-19 16:52:39)

Offline

#18 2022-05-19 18:38:12

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

I don't fully understand is why the strong preference for xinit-session.target started

It'd certainly not be my preferred approach, but if you want to engage w/ the systemd target/service trigger approach the idea behind it is to use an abstract requirement (the graphical-session.target) that can be met by all sorts of things and serves as a barrier for other services. Intermangling this w/ xinitrc is pointless as that provides a different (simpler and imho more robust…) kind of service launching. If you're using the latter anyway, there's no reason to draw in a different system.

isn't something like After=xinit.service missing

This could get even trickier as, however you go about it, starting xinit and even the Xorg process doesn't mean that you can immediately talk to it (you need to wait for the display socket) so you'd have to depend the target on the socket being ready.
(Typically /tmp/.X11-unix/X0)

Setting up X11 from a dedicated X INITialization process is the more direct and less troublesome approach and unless you *have* to acommodate to a system where you can *only* rely on systemd as infrastructure, I don't see where this approach would be worth the effort.

Offline

#19 2022-05-19 22:51:03

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

Here is the hierarchy of my service:

.
├── bin
│   └── myprogram
└── etc
	 ├── init.d
	 │   └── myprogram
	 └── systemd
	     └── user
	         ├── default.target.wants
	         │   └── myprogram.service -> ../myprogram.service
	         └── myprogram.service

Where /bin/myprogram is the program itself.
File /etc/init.d/myprogram:

#!/bin/sh

. /etc/thinstation.global

myprogram

where the /etc/thinstation.global file contains global variables.

And the /etc/systemd/user/myprogram.service file looks like this:

[Unit]
Description=myprogram
BindsTo=graphical-session.target

[Service]
ExecStart=/etc/init.d/myprogram

As a result, it turns out that the service starts, but still does not see the screen:

● myprogram.service - myprogram
     Loaded: loaded (/etc/systemd/user/myprogram.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Fri 2022-05-20 01:34:18 MSK; 21s ago
    Process: 3454 ExecStart=/etc/init.d/myprogram (code=exited, status=1/FAILURE)
   Main PID: 3454 (code=exited, status=1/FAILURE)

may 20 01:34:18 ts_080027b3b812 systemd[3451]: Started myprogram.
may 20 01:34:18 ts_080027b3b812 myprogram[3593]: Can't open display :0.0
may 20 01:34:18 ts_080027b3b812 systemd[3451]: myprogram.service: Main process exited, code=exited, status=1/FAILURE
may 20 01:34:18 ts_080027b3b812 systemd[3451]: myprogram.service: Failed with result 'exit-code'.

Here, at the moment when the xrandr call string is being processed in the code, the service crashes because there is no access to the display.

Other information (network interface) collects and logs into a file:

ts_080027b3b812:~# cat /var/log/myprogram.log 
IFace("enp0s8", "08:00:27:ff:42:ed", "192.168.56.107")

Information about the screen should also have been recorded in this file. But alas, the service does not see the display.

I start the service manually - everything works, since the display is available:

ts_080027b3b812:~# systemctl --user start myprogram.service
ts_080027b3b812:~# systemctl --user status myprogram.service
● myprogram.service - myprogram
     Loaded: loaded (/etc/systemd/user/myprogram.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Fri 2022-05-20 02:04:39 MSK; 28s ago
    Process: 4673 ExecStart=/etc/init.d/myprogram (code=exited, status=0/SUCCESS)
   Main PID: 4673 (code=exited, status=0/SUCCESS)

may 20 02:04:39 ts_080027b3b812 systemd[3451]: Started myprogram.
may 20 02:04:39 ts_080027b3b812 systemd[3451]: myprogram.service: Succeeded.

ts_080027b3b812:~# cat /var/log/myprogram.log
IFace("enp0s8", "08:00:27:ff:42:ed", "192.168.56.107")
[Monitor("VGA-1", true, 1280, 1024)]

I still don't understand what I'm doing wrong.

Last edited by alexanderzhirov (2022-05-19 23:09:45)

Offline

#20 2022-05-19 23:51:13

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: [SOLVED] Access to the display when loading the systemd service

The service is still being pulled in/started by default.target. First you should remove the link in default.target.wants that's left over from when you enabled the previous version of the service file. Then you need to hook the service up to something else.

The superuser.com answer you linked to earlier links a service to xsession.target. If you imitate that, it should at least give you a working setup. It uses ~/.xsession (sourced by at least LightDM), but you were using .xinitrc, so you can put the starting of xsession.target there and forget the import-environment command.

But do you have a strong reason for wanting to run it as a service or are you just trying it out now, or...?

seth wrote:

isn't something like After=xinit.service missing

This could get even trickier as, however you go about it, starting xinit and even the Xorg process doesn't mean that you can immediately talk to it (you need to wait for the display socket) so you'd have to depend the target on the socket being ready.
(Typically /tmp/.X11-unix/X0)

Ah, yes, the wiki has a warning about that with an upstream bug and socket activation being broken and all that. So it's not like "X as a user service" has come a long way since I looked at it years ago. If you mostly gave that incomplete example to scare the OP back to the simple and robust xinit, it might have helped to emphasize that it does nothing for the timing issues.

Then "intermangling this [= {xinit-session,graphical-session}.target] w/ xinitrc" (if you want to engage with that, yes) is also a way to avoid this trickiness, a lower-effort compromise that doesn't seem too crazy to me, even if I don't see a reason to try and use it now. (Another (small?) thing is that the wiki says you can't use the "rootless X" when started as a service.)

Offline

#21 2022-05-20 08:19:37

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

Raynman wrote:

But do you have a strong reason for wanting to run it as a service or are you just trying it out now, or...?

I want to manage the service in case of its failure. It is very convenient to do this via systemd. This is the answer to your question wink

In the end, what happened at the moment. I configured the service as follows:

.
|-- bin
|   `-- myprogram
`-- etc
    `-- systemd
        `-- user
            |-- myprogram.service
            `-- xsession.target

myprogram.service:

[Unit]
Description=myprogram
PartOf=graphical-session.target

[Service]
ExecStart=/usr/bin/myprogram

[Install]
WantedBy=graphical-session.target

xsession.target:

[Unit]
Description=X session managed by systemd
BindsTo=graphical-session.target

~/.xinitrc:

(. /etc/thinstation.global; use_idesk &)
systemctl --no-block --user start xsession.target

After downloading the distribution, I check the services.

systemctl --user status xsession.target:

● xsession.target - X session managed by systemd
     Loaded: loaded (/etc/systemd/user/xsession.target; static; vendor preset: enabled)
     Active: active since Fri 2022-05-20 10:32:11 MSK; 21min ago

may 20 10:32:11 ts_0800273e9027 systemd[2983]: Reached target X session managed by systemd.

systemctl --user status myprogram.service:

● myprogram.service - myprogram
     Loaded: loaded (/etc/systemd/user/myprogram.service; disabled; vendor preset: enabled)
     Active: inactive (dead)

As you can see, the service does not start automatically. I tried running it with

[Unit]
Description=myprogram
PartOf=graphical-session.target

[Service]
ExecStart=/usr/bin/myprogram

[Install]
WantedBy=xsession.target

but it still wouldn't run. The service is started manually.

Offline

#22 2022-05-20 08:39:01

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

alexanderzhirov wrote:

As you can see, the service does not start automatically.

So, I sort of figured it out. In general, I executed the command in a loaded system:

systemctl --user enable myprogram.service

after that, a link to the service was created.

Created symlink /root/.config/systemd/user/graphical-session.target.wants/myprogram.service → /etc/systemd/user/myprogram.service.

Actually, after that, the service began to start automatically!

Did I do everything right? roll

Offline

#23 2022-05-21 14:49:28

seth
Member
Registered: 2012-09-03
Posts: 51,149

Re: [SOLVED] Access to the display when loading the systemd service

Did I do everything right?

/root/.config/systemd/user/graphical-session.target.wants/myprogram.service → /etc/systemd/user/myprogram.service

implies that you're running an X11 (graphical) session as root what is about as wrong as it can get.
Don't.

I want to manage the service in case of its failure. It is very convenient to do this via systemd. This is the answer to your question

I'm not really sure what that means, but if you just want to be able to "systemctl status myprogram.service" the easist way to get there is indeed to "systemctl --user start myprogram.service" instead of "myprogram" from your xinitrc.

Offline

#24 2022-05-22 14:16:42

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

seth wrote:

implies that you're running an X11 (graphical) session as root what is about as wrong as it can get.
Don't.

Yes, you are right, in the Thinstation project, some assemblies log in as root, which is why the service being launched is like this.

seth wrote:

I'm not really sure what that means, but if you just want to be able to "systemctl status myprogram.service" the easist way to get there is indeed to "systemctl --user start myprogram.service" instead of "myprogram" from your xinitrc.

I redid it without an anchor, now the service is launched as a single service. wink

Offline

#25 2022-05-30 05:24:39

alexanderzhirov
Member
Registered: 2022-05-12
Posts: 39
Website

Re: [SOLVED] Access to the display when loading the systemd service

Thank you all so much for your help!

Offline

Board footer

Powered by FluxBB