Run display dependent command in a system setting event
0
votes
1
answer
172
views
I am working on a systemd/udev setting that I would like to share upstream, however I can't get it to work in a non-hacky way. Essentially, I have this script as the exec of a systemd service:
ICON="somepath/dslr-camera-white.png"
function on-display() {
local sdisplay=$(echo $XDG_SESSION_TYPE)
if [ "$sdisplay" == "wayland" ]; then
local display=":$(echo $WAYLAND_DISPLAY)"
else
local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
fi
local user=$(who | grep '('$display')' | awk '{print $1}' | head -n 1)
local uid=$(id -u $user)
sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus "$@"
}
cleanup() {
on-display notify-send -i $ICON "Disconnected" "The DSLR Camera has been turned off." --app-name="DSLR Webcam"
trap - SIGTERM && kill -- -$$
}
trap cleanup SIGINT SIGTERM EXIT
on-display notify-send -i $ICON "Connected" "The DSLR Camera has been turned on and it is ready to use." --app-name="DSLR Webcam"
on-display yad --window-icon=$ICON --image=$ICON --no-buttons --title="DSLR Webcam" --notification --listen &
output=$(v4l2-ctl --list-devices)
line=$(echo "$output" | grep "Virtual Camera")
vdevice=$(echo "$output" | sed -n "/$line/{n;s/^\t\+//p;}")
gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 $vdevice
The point of the service is to be started by an udev rule when an specific gphoto2 supported camera is plugged in, therefor I have these udev rules:
ACTION=="add", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", RUN+="systemctl start dslr-webcam.service"
ACTION=="remove", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", RUN+="systemctl stop dslr-webcam.service"
So far so "ok", because I have read on alternatives to using RUN
for a systemd service, but regardless... The issue here is specifically the call to yad
.
yad
is a program that allows you to display dialogue boxes from the CLI, I am leveraging it for its ability to make a systrey icon, as I would like for one to show up when the camera is active.
## The problem
Unlike notify-send
, which probably works off some common socket, yad
requires the appropriate XAUTHORITY
set in order for it to work, otherwise you will get cannot open display: :0
. The hacky solution in my case is to simply set it the right Xauthority, since I am using SDDM (display manager), it resides in the /tmp
directory, so I can add this to the script:
XAUTHORITY=$(ls /tmp/xauth*)
And then it works... But this is terrible, it makes a lot of assumptions, in fact the whole on-display
function also seems like a bad idea. If I took this to a different system, it probably wouldn't work, because the proper Xauthority could be in a myriad of places, and I haven't even tried Wayland yet (I will leave that for later).
## What about xauth
I thought I could somehow use xauth
to retrieve the right Xauthority, but that doesn't seem to be the case... This script is a system service, so my xauth info
returns Authority file: /root/.xauthWV7OfU
, and running it as the right user sudo -u $user xauth info
gives me Authority file: /home/myuser/.Xauthority
, none of which work when given to yad
. The correct XAUTHORITY
is set by the display manager, so I think I could only get it from child processes of it.
I have also tried all the approaches give by this [answer](https://unix.stackexchange.com/a/429106/528934) , but the first one would not work, as XAUTHORITY
isn't actually in the system env, and the second one (aside from the mentioned pitfalls), doesn't work, it says the xauth file is at /run/sddm/xauth_KvyuHd
, but trying to use it doesn't work, so it is not the same xauth file as /tmp/xauth_FzoQqz
From the same question as the previous one, [this](https://unix.stackexchange.com/a/429162/528934) approach seems to work, but I don't know how portable it is. And still seems hacky.
----------
## Run as user service
Perhaps this is the most promising one, as nothing in that script prevents it from being run as a user (it also gets rid of on-display
), I did try this approach, and while if the camera was plugged-in and I ran systemctl --user start dslr-webcam.service
it would work as expected (including yad
), now I have a problem with the udev
rule. I searched many places, including [here](https://unix.stackexchange.com/questions/550279/udev-rule-to-trigger-systemd-service) , but I cannot find how to run a systemd user service from an udev
rule, and to me that doesn't really make any sense either, how would udev
know what user to use?
Asked by Mathias Sven
(273 rep)
Oct 28, 2023, 05:43 PM
Last activity: Oct 28, 2023, 06:48 PM
Last activity: Oct 28, 2023, 06:48 PM