@nmschulte在评论中提到,如果未安装服务文件,则 dbus 服务文件无法启动 dunst。
仅当 dbus 以--systemd-activation
标志启动时才会发生这种情况,并且在这种情况下,如果找不到服务文件,它会忽略Exec
行。 我们应该要么
SystemdService
行,本质上不允许默认情况下由 systemd 管理 dunst 或作为在这个问题范围内的附加说明, @mathstuf在同一个线程中链接了一个问题,显然 systemd dbus 单元在系统总线而不是会话总线中看起来应该是它们应该的。
我们应该
一个短期的解决方案可能是:注释掉服务文件中的SystemdService
行,可能在其上方加上相关注释,并在构建过程中添加注释( make install
目标,或install-service
目标)关于可选(非install
ed) dunst.systemd.service
文件(注意它需要重命名以匹配 D-Bus 服务中的假设文件)。
请注意,我只是将此文件安装到我的PREFIX
( ~/.local/share/systemd/user/dunst.service
)中,并且拥有两个具有相同名称的D-Bus
服务文件(文件名和内部服务名)并不复杂)。 我还在~/.config/systemd/user.conf
( DefaultEnvironment="PATH=/home/nmshculte/.local/bin:$PATH"
) 中将更改保留为DefaultEnvironment
,但我认为在这种情况下没有必要这样做。
设置PATH
不是必需的,因为 systemd 需要Exec*
行中可执行文件的完整路径。
虽然它有点笨拙(阅读:配置影响 systemd 的所有用户单元,而不仅仅是 D-Bus/Dunst 的环境),但对于那些使用 Dunst 运行脚本的人来说,这是一个重要的细节(Dunst 支持运行由通知属性匹配的脚本)并期望他们的PATH
来自例如~/.profile
(这被称为...登录(或交互式?)会话?我不确定正确的术语。)。
也可以在每个脚本中处理PATH
问题,但是没有说 Dunst 配置(因此关心PATH
的脚本)不能用于多个 Dunst 实例(尽管...也许这不可能发生;我以为我在测试中看到了一个用例,但我可能只是误解了)。
啊。 我发现最好有一个像environment.target
这样的目标,其中我有foo-env.service
文件,这些文件在启动服务时处理systemctl --user set-environment
调用,在停止服务时处理unset-environment
. 这些服务是Before=
和BindsTo=
environment.target
。 对于 X11 特定的设置,还有一个x11-environment.target
。 然后我的dunst.service
是Requires=
和After=
x11-environment.target
以确保它具有正确的环境。
这有点复杂,但它可以工作,甚至可以让事情从下到上了解我的ssh-agent
之类的东西,而不是尝试在每个.service
文件中设置SSH_AGENT_SOCK
,这可能关心它。
(我的整个设置由systemd
管理,包括启动 X、窗口管理器等,所以我没有.profile
或(有意义的) .xinitrc
。)
仅当 [dbus-daemon] 以
--systemd-activation
标志启动时才会发生这种情况,并且在这种情况下,如果找不到服务文件,它会忽略Exec
行。
(我是上游 D-Bus 维护者。)
是的,它就是这样工作的。 在dbus-daemon --session
以--systemd-activation
启动的系统上,每个 D-Bus 会话服务要么是传统的 D-Bus 服务(总是通过Exec
运行,就好像--systemd-activation
没有被使用,没有SystemdService
)或混合 D-Bus/systemd 服务(总是通过启动SystemdService
来运行,而不是Exec
)。
您必须安装将 dunst 作为 systemd 用户服务运行所需的一切(单元文件和SystemdService
行),或者什么都不安装。 提供SystemdService
行但不提供它引用的单元文件是不正确的,就像使用Exec=/usr/local/bin/dunst-wrapper-script
将 D-Bus 服务安装到/usr/local/share/dbus-1/services
是无效的一样Exec=/usr/local/bin/dunst-wrapper-script
无需安装dunst-wrapper-script
。
一个短期的解决方案可能是:注释掉服务文件中的
SystemdService
行,可能在其上方加上相关注释,并在构建过程中添加注释(make install
目标,或install-service
目标)关于可选(未安装)dunst.systemd.service
文件(注意它需要重命名以匹配 D-Bus 服务文件中的假设)。
这将比目前的情况更好。
更好的是,IMO 将安装 systemd 服务。 在非 systemd 系统上,以及 OS 集成商未选择从 systemd 启动dbus-daemon --session --systemd-activation
的 systemd 系统上,它是无用但无害的(一个额外的安装文件,不会读取任何内容)。 在启用了 dbus-daemon 的 systemd 激活功能的系统上,它会导致 dunst 被放置在自己的 cgroup 中以进行管理和资源控制,而不是被视为 dbus-daemon 的一部分。
(如果像 Debian 或 Fedora 这样的发行版设置了你的 dbus-daemon 和 systemd,它们就是你的操作系统集成商。如果你自己做,你就是操作系统集成商。无论哪种方式,都需要由知道他们做什么的人来完成。重新做。)
虽然它有点笨拙(阅读:配置影响 systemd 的所有用户单元,而不仅仅是 D-Bus/Dunst 的环境),[操纵激活环境是]对于使用 Dunst 运行脚本的人来说是一个重要的细节
是的,为 systemd 激活的事物提供正确的环境很重要,但这不是 Dunst 的工作。 安排将正确的环境变量推送到systemd --user
和dbus-daemon --session
中,包括如果认为有必要从~/.profile
上传它们,是操作系统集成商的工作:这是所有用户服务都需要做的事情。
老实说,我看不出这里还有更多可以做的事情。 提供的dunst.service文件在正确配置的系统上工作正常(尽管仅适用于 X11! )。
这里唯一需要做的是删除Environment=DISPLAY=:0
行,因为:
systemctl --user set-environment
设置。除此之外,dunst 提供的代码只有在 OS Integrator 提供的内容不一致时才会失败,并且在此处/下游对此无能为力。
老实说,我看不出这里还有更多可以做的事情
请按照第一条评论所说的去做:要么从 D-Bus 服务文件中删除SystemdService
行,要么在安装 D-Bus 服务文件的同时安装 systemd 单元。
(或者,如果您坚持它是可编译时可配置的,那么当且仅当您要安装 systemd 单元时才写出SystemdService
行 - 但我个人认为这是不必要的复杂性,特别是在一个项目中使用 Autoconf 或类似的。无条件安装 systemd 单元不会伤害非 systemd 用户,除非存在未使用的文件,就像安装手册页不会伤害不阅读手册页的人一样。)
除此之外,dunst 提供的代码只有在 OS Integrator 提供的内容不一致时才会失败
目前 dunst 内部不一致:它总是告诉 dbus-daemon 尽可能使用 systemd 进行激活,但随后不会安装该 systemd 激活工作所需的文件。
dbus-daemon 在将激活委托给 systemd 之前不会检查引用的SystemdService
是否存在 - 它不能,因为它不知道 systemd 将搜索哪些目录。
因此,简而言之,关闭它需要做的事情是:
/usr/lib/systemd/user/dunst.service
(通过make install
)。始终将 dunst.service 文件安装到 /usr/lib/systemd/user/dunst.service(通过 make install)
这也应该考虑PREFIX
吗?
是的,你是对的,它应该。
这也应该考虑 PREFIX 吗?
是的,但使用${prefix}/lib
,而不是${libdir}
。 systemd 总是在lib
中查找单元,即使在共享库等会进入并行目录(如lib64
或lib/x86_64-linux-gnu
的系统上)。
我对默认情况下将 dunst 设置为 systemd 服务的担忧之一是,根据我的测试,如果 dunst 由于任何原因崩溃,dbus 会在下一个通知通过时愉快地重新启动它,而如果 dunst 是它会导致挂起和超时配置为 systemd 服务并且它处于失败状态。
一个解决方案可能是设置Restart=on-failure
但我不确定这会有多有效,因为它取决于超时,我似乎无法找到一种方法来设置它,以便它只从 dbus 重新启动激活。
设置超时是一个有效的选项,但如果它由于一个原因在另一个原因上持续崩溃(即 X 服务器尚未启动)可能会导致相当多的日志垃圾邮件。
我对默认情况下将 dunst 设置为 systemd 服务的担忧之一是,根据我的测试,如果 dunst 由于任何原因崩溃,dbus 会在下一个通知通过时愉快地重新启动它,而如果 dunst 是它会导致挂起和超时配置为 systemd 服务并且它处于失败状态。
我刚刚测试过,但似乎并非如此:
pkill -KILL dunst
。notify-send asdf
设置超时是一个有效的选项,但如果它由于一个原因在另一个原因上持续崩溃(即 X 服务器尚未启动)可能会导致相当多的日志垃圾邮件。
这里提到的graphical.session.target
不包括吗?
我刚测试过,好像不是这样
你是对的,我认为 systemd 是原因,但显然不是。 经过更多测试后,似乎我提到的事情发生了,因为我将 dunst 设置为在启动时失败以进行测试(通过禁用显示服务器)并且 dbus 不承认激活失败并导致该地址的所有消息挂起,直到它超时。
这里提到的 graphics.session.target 不包括吗?
根据手册页
只要任何图形会话正在运行,此目标就会处于活动状态。 它用于在会话终止时停止仅适用于图形(X、Wayland 等)会话的用户服务。
所以它只是为了停止它,它不会对它设置依赖。 我不确定在显示服务器上设置硬依赖的正确方法是什么。
所以它只是为了停止它,它不会对它设置依赖。 我不确定在显示服务器上设置硬依赖的正确方法是什么。
从man systemd.unit
:
绑定到=
配置需求依赖,风格与 Requires= 非常相似。 但是,这种依赖类型更强:除了 Requires= 的效果外,它声明如果绑定到的单元停止,则该单元也将停止。 这意味着绑定到另一个单元的单元突然进入非活动状态也将被停止。 单元可能由于不同的原因突然、意外地进入非活动状态:服务单元的主进程可能会自行终止,设备单元的后备设备可能已拔出,或者挂载单元的挂载点可能会在没有参与的情况下被卸载系统和服务管理器。当在同一单元上与 After= 结合使用时,BindsTo= 的行为会更加强大。 在这种情况下,严格绑定到的单元必须处于活动状态才能使该单元也处于活动状态。 这不仅意味着一个单元绑定到另一个突然进入非活动状态的单元,还意味着一个绑定到另一个单元由于条件检查失败而被跳过(例如 ConditionPathExists=、ConditionPathIsSymbolicLink=、... — 见下文)将停止,如果它正在运行。 因此,在许多情况下,最好将 BindsTo= 与 After= 结合使用。
TBH,不过我不会太担心这个; 如果应用程序在显示服务器未运行时尝试发送通知,则预计会失败。
实际上,仔细想想, BindsTo
并不是一个好主意:如果应用程序查询通知服务器,它将启动桌面环境。 这是不可取的。
呸,擦掉所有这些,我们在讨论PartOf
,而不是BindsTo
,我把我的狗屎弄混了。
我认为PartOf
就足够了:当图形环境停止时停止垃圾。 在没有图形环境运行时尝试发送通知应该会失败,我认为这种情况不需要额外考虑。
在没有图形环境运行时尝试发送通知应该会失败,我认为这种情况不需要额外考虑。
你是对的,我之前所说的是错误的假设,即 systemd 没有重新启动失败的单元。
请将PartOf
行添加到 #324。 合并后,我将更新 Makefile 以安装 systemd 服务文件。
通过 #324 关闭
你好,
我通过以下方式遇到了上述问题:
我运行最新的 dunst,其中包括在 #324 中所做的更改
谢谢
在发送任何通知之前,它是如何处于failed
状态的?
当第一个通知到达时,它由 DBus 激活。
实际上,我刚刚意识到可以将服务配置为在登录时自动启动,但它也会在_之前_启动图形会话。
可能有两个解决方法:
WantedBy
,因此运行systemd --user enable dunst
拒绝链接它。 这可能是最有意义的,因为 dbus 会在需要时自动启动 dunst。WantedBy
更改为PartOf=graphical-session.target
,这样至少它会延迟到图形会话启动为止。 不过,很难找到这样做的理由。嗯,我去了第一个解决方法,但根本没有工作。
失败状态仍然是 journalctl 声明
Mar 19 18:18:41 hecate systemd[861]: Starting Dunst notification daemon...
Mar 19 18:18:41 hecate dunst[880]: CRITICAL: Cannot open X11 display.
Mar 19 18:18:41 hecate systemd[861]: dunst.service: Main process exited, code=exited, status=1/FAILURE
我应该发布--full
吗?
扩展上述内容:这是重新启动和登录后的失败状态。
systemctl --user status dunst
的输出是什么?
启动并登录 X 会话后如下:
● dunst.service - Dunst notification daemon
Loaded: loaded (/home/manuel/.config/systemd/user/dunst.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Thu 2020-03-19 19:55:19 EET; 1min 16s ago
Docs: man:dunst(1)
Process: 905 ExecStart=/usr/bin/dunst (code=exited, status=1/FAILURE)
Main PID: 905 (code=exited, status=1/FAILURE)
Mar 19 19:55:19 hecate systemd[886]: Starting Dunst notification daemon...
Mar 19 19:55:19 hecate dunst[905]: CRITICAL: Cannot open X11 display.
Mar 19 19:55:19 hecate systemd[886]: dunst.service: Main process exited, code=exited, status=1/FAILURE
Mar 19 19:55:19 hecate systemd[886]: dunst.service: Failed with result 'exit-code'.
Mar 19 19:55:19 hecate systemd[886]: Failed to start Dunst notification daemon.
似乎以某种方式将 dunst 设置为登录时自动启动,而不是使用 dbus-activation。
systemctl --user disable dunst
应该可以解决问题。
嗯,它不会以任何方式影响。 禁用 dunst 后,重新启动时系统仍处于故障状态。
发出通知时,(我假设)dbus 启动服务并且系统恢复。 我认为这是在挑剔,在这一点上。
但我仍然对原因很感兴趣。
这很奇怪。 还是提前自动启动? 现在systemctl --user status dunst
的输出是什么?
find .config/systemd -iname "*dunst*"
呢?
systemctl 报告 dunst 的以下状态
● dunst.service - Dunst notification daemon
Loaded: loaded (/usr/lib/systemd/user/dunst.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Fri 2020-03-20 12:16:13 EET; 9s ago
Docs: man:dunst(1)
Process: 904 ExecStart=/usr/bin/dunst (code=exited, status=1/FAILURE)
Main PID: 904 (code=exited, status=1/FAILURE)
Mar 20 12:16:13 hecate systemd[885]: Starting Dunst notification daemon...
Mar 20 12:16:13 hecate dunst[904]: CRITICAL: Cannot open X11 display.
Mar 20 12:16:13 hecate systemd[885]: dunst.service: Main process exited, code=exited, status=1/FAILURE
Mar 20 12:16:13 hecate systemd[885]: dunst.service: Failed with result 'exit-code'.
Mar 20 12:16:13 hecate systemd[885]: Failed to start Dunst notification daemon.
并且 find 在 .config/systemd 下找不到任何东西
为了完整性:
$ systemctl --user cat dunst.service
# /usr/lib/systemd/user/dunst.service
[Unit]
Description=Dunst notification daemon
Documentation=man:dunst(1)
PartOf=graphical-session.target
[Service]
Type=dbus
BusName=org.freedesktop.Notifications
ExecStart=/usr/bin/dunst
[Install]
# WantedBy=default.target
我有点困惑为什么它仍然说禁用。 systemctl --user disable dunst
确实禁用了它,对吗?
这是在什么发行版上? 是否在系统范围内强制启用? tree /etc/systemd/user/
?
是的,它被禁用了,.config/systemd/user 下没有链接
它是 Debian 测试的一个网络。
$ tree /etc/systemd/user
/etc/systemd/user
├── default.target.wants
│ ├── dunst.service -> /usr/lib/systemd/user/dunst.service
│ └── pulseaudio.service -> /usr/lib/systemd/user/pulseaudio.service
└── sockets.target.wants
├── dirmngr.socket -> /usr/lib/systemd/user/dirmngr.socket
├── gpg-agent-browser.socket -> /usr/lib/systemd/user/gpg-agent-browser.socket
├── gpg-agent-extra.socket -> /usr/lib/systemd/user/gpg-agent-extra.socket
├── gpg-agent.socket -> /usr/lib/systemd/user/gpg-agent.socket
├── gpg-agent-ssh.socket -> /usr/lib/systemd/user/gpg-agent-ssh.socket
├── pk-debconf-helper.socket -> /usr/lib/systemd/user/pk-debconf-helper.socket
└── pulseaudio.socket -> /usr/lib/systemd/user/pulseaudio.socket
2 directories, 9 files
/etc/systemd/user
├── default.target.wants
│ ├── dunst.service -> /usr/lib/systemd/user/dunst.service
该服务由 Debian 打包在系统范围内启用,因为在安装它时,它有WantedBy=default.target
(我认为这是一个错误 - 它不应该在 GUI 之前启动,无论如何不应为其他通知实现的用户启动,例如 GNOME Shell)。 按用户禁用它不会在系统范围内禁用它。
你是对的@smcv ,感谢您追踪@WhyNotHugo @magandrez。 我现在用 43c6145 删除了WantedBy
行
我有个问题。 现在dunst
是静态的。 但是dbus --session
不能运行它,因为没有DISPLAY
变量。 我如何在那里安装它? 这是分发设置问题还是您的问题( dbus
不是图形应用程序,原则上应该有DISPLAY
吗?)? 我的它只适用于特定的DM吗?
LightDM==1:1.30.0-4
i3-gaps==4.18.2-2
dusnt==1.5.0-1.0
dbus==1.12.20-1
ps 我知道我可以使用systemctl --user start {}
最有用的评论
你是对的@smcv ,感谢您追踪@WhyNotHugo @magandrez。 我现在用 43c6145 删除了
WantedBy
行