我正在开发一个 systemd/udev 设置,我想在上游共享它,但是我无法让它以非 hacky 的方式工作。本质上,我将此脚本作为 systemd 服务的执行程序:
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
该服务的要点是当插入特定的 gphoto2 支持的相机时由 udev 规则启动,因此我有这些 udev 规则:
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"
到目前为止,“好吧”,因为我已经阅读了使用RUN
systemd 服务的替代方案,但无论如何......这里的问题具体是对yad
.
yad
是一个允许您从 CLI 显示对话框的程序,我利用它来制作系统图标,因为我希望在相机处于活动状态时显示一个系统图标。
问题
与 不同notify-send
,它可能在一些常见的套接字上工作,yad
需要适当的XAUTHORITY
设置才能工作,否则你会得到cannot open display: :0
。在我的例子中,hacky 解决方案是简单地将其设置为正确的 Xauthority,因为我使用的是 SDDM(显示管理器),它驻留在目录中/tmp
,因此我可以将其添加到脚本中:
XAUTHORITY=$(ls /tmp/xauth*)
然后它就起作用了……但这很糟糕,它做了很多假设,事实上整个on-display
函数似乎也是一个坏主意。如果我把它带到不同的系统,它可能不会工作,因为适当的 Xauthority 可能在无数的地方,而且我什至还没有尝试过 Wayland(我将把它留到以后)。
关于什么xauth
我以为我可以以某种方式用来xauth
检索正确的 Xauthority,但情况似乎并非如此...这个脚本是一个系统服务,所以我xauth info
返回Authority file: /root/.xauthWV7OfU
,并以正确的用户身份运行它sudo -u $user xauth info
给我Authority file: /home/myuser/.Xauthority
,但这些都不起作用当给予yad
.正确的XAUTHORITY
是由显示管理器设置的,所以我想我只能从它的子进程中获取它。
我也尝试过这个给出的所有方法回答,但第一个不起作用,因为XAUTHORITY
实际上不在系统环境中,而第二个(除了提到的陷阱之外)不起作用,它说 xauth 文件位于/run/sddm/xauth_KvyuHd
,但尝试使用它并不不起作用,所以它与 xauth 文件不同/tmp/xauth_FzoQqz
来自与上一个问题相同的问题,这方法似乎有效,但我不知道它的便携性如何。而且看起来仍然很老套。
作为用户服务运行
也许这是最有前途的一个,因为该脚本中没有任何内容阻止它作为用户运行(它也摆脱了on-display
),我确实尝试了这种方法,而如果相机已插入并且我运行systemctl --user start dslr-webcam.service
它就会工作正如预期的那样(包括yad
),现在我对规则有疑问udev
。我搜索了很多地方,包括这里,但我找不到如何从udev
规则运行 systemd 用户服务,对我来说这也没有任何意义,如何udev
知道要使用哪个用户?
答案1
您不直接从 udev 规则运行用户服务;相反,你应该让 udev 告诉 systemd 该设备需要特定的用户服务跑步。
像TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"
这样:
ACTION=="add", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218". TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"
ACTION=="remove", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"
由于您dslr-webcam.service
需要 GUI 访问,因此它应该将自己声明为BindsTo=graphical-session.target
和After=graphical-session.target
。当以这种方式声明时,服务应该自动获取正确的 DISPLAY 和 XAUTHORITY 变量。
顺便说一下,感谢您分享您的想法;它给了我灵感去建立一些非常相似的东西......