更正:startx 进行 unset DBUS_SESSION_BUS_ADDRESS 的行为是来自上游,而不是来自 debian ( https://gitlab.freedesktop.org/xorg/app/xinit/-/issues/9 ),而过去这样做的理由应该主要是让 startx 和已有的 session bus 相互隔离吧,但是在 systemd 的 user session bus 成为主流的现在,这个行为反而会导致问题。arch 只是获得这个修复更早,并不是 debian 自己的 patch 增加的这一行。
这是一件一个月之前的事情,有一个人来到 fcitx 的 telegram 群说他在 debian lxqt 不能在 chromium 下输入。在他贴了一下 chromium 在终端输出的结果之后,事情开始变得奇怪了起来。
$ [12752:12787:1013/110502.625383:ERROR:bus.cc(399)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix")
[12752:12787:1013/110502.625545:ERROR:bus.cc(399)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix")
意思是 chromium 连接到 dbus 失败,但这个时代,除了一些奇葩的反 systemd 发行版,正常只要你用 systemd ,就应该能正确设置 dbus 的环境变量。光单单为了这一点,我就得感谢 systemd。早在 11 年前我的一篇博客曾经就写道不用主流桌面不用 display manager 而导致了 dbus 设置不对而出现的奇葩问题。但这个时代我还真没有见过用了 systemd 却还没有自动设置正确 dbus 的情况。于是接下来的事情就探入了我以前从未了解过的兔子洞中。
首先,systemd 帮助你设置 DBUS_SESSION_BUS_ADDRESS 环境变量的原理是一个 pam 模块,所谓的 pam 就是 linux 在你登录系统的时候会自动调用的一系列模块,其中例如就有 pam_env 可以读取 /etc/environment 来设置环境变量,pam_kwalletd5 来把你输入的密码传递给 kwalletd 直接进行 kwallet 解锁等等。
而 pam_systemd 正是承担了设置一系列标准 XDG 和 DBUS 环境变量的任务。所以才有了前面说的,只要你用了 systemd,就不应该出现 dbus 设置问题。而好巧不巧,他用的发行版并非正常的 debian 发行版,而是一个 debian 的衍生发行版 omv。他的默认安装正好没有包含 libpam-systemd。这种事谁能想到?但是接下来我在虚拟机中安装 lxqt 之后,却发现 libpam-systemd 作为某种依赖(猜测是推荐依赖)被安装上了。
这问题又回到了原点,接下来我们发现,他是使用 startx 来启动系统的,而他在 startx 之前,环境变量中是有 DBUS_SESSON_BUS_ADDRESS 存在的。也就是说,在 startx 之后的某个过程中,DBUS_SESSION_BUS_ADDRESS 被什么东西 unset 了!你要让我猜,我恐怕想破脑袋都无法想到到底是什么东西 unset 了这个环境变量。而我直接 startx ,根据 startx 要启动 /etc/alternatives/x-session-manager 我也可以直接进入 lxqt,而这样启动的 lxqt 环境完全正常。
接下来只有亲自实践一条路了,然后我模仿和他一模一样的配置,把 exec startlxqt 写到了 ~/.xinitrc 中,结果发现确实之后就没有 DBUS_SESSON_BUS_ADDRESS 了。此时我是完全没有头绪到底是为什么,抱着随便试一试的心情,我开始对整个磁盘上的文件进行 grep DBUS_SESSON_BUS_ADDRESS 。结果发现在 startx 的第一行赫然就写着 unset DBUS_SESSION_BUS_ADDRESS?!WTF?
看看我自己系统上的 startx,并没有这样的内容,而实际上这是最近在上游才修改的 https://gitlab.freedesktop.org/xorg/app/xinit/-/issues/9 ,在读了许久 debian startx 相关的脚本在之后,这里将 debian 机制写在这里:
1、首先,startx 之后 debian 会查找 ~/.xinitrc 或者系统级别的 /etc/X11/xinit/xinitrc,而系统级的 /etc/X11/xinit/xinitrc 里面的内容是 . /etc/X11/Xsession,也就是执行 debian 自己独有的 /etc/X11/Xsession 。而这个 /etc/X11/Xsession 干的事情概括起来,就是按顺序加载 /etc/X11/Xsession.d 下面的脚本并启动 x-session-manager 指向的东西。而它在 startx 里 unset DBUS_SESSION_BUS_ADDRESS 之后,会由 /etc/X11/Xsession.d 中的某个脚本将这个变量重新设置回来,从而达成和其他系统类似的效果。而当你使用自己的 ~/.xinitrc 的时候,/etc/X11/Xsession.d 这一系列的脚本都会被跳过,从而导致 DBUS_SESSION_BUS_ADDRESS 不被设置。
所以在 debian 下如果你想要使用 startx ,最好的办法是不要用 ~/.xinitrc ,而用 debian 专有的 ~/.xsession 代替,从而让 debian 自己的 /etc/X11/xinit/xinitrc 加载 /etc/X11/Xsession.d 下许多环境设置再进入桌面。
而如果你在其他的发行版上(如 Arch),你则不能使用 ~/.xsession ,必须用 ~/.xinitrc ,因为 ~/.xsession 是 /etc/X11/Xsession 这一整套 debian 独有的脚本负责的。
startx 的上游这个奇怪的 unset 在过去大家总要手动执行 dbus-launch 或者基于 x11 auto launch 的时代有一定的意义,但是在 dbus 改由 systemd user 启动的现在,已经不再有意义了。debian 相当于是有自己的一套机制来恢复这个变量的值,但是只能在 .xsession 中起作用, ~/.xinitrc 并不能享受到。
当我最终发现原因的时候,我整个人是无语的。这是一个你不到 debian 系统里看看就根本发现不了的问题。早年 Linux 各个发行版各自为战搞了很多自己一套独有的东西,创建启动镜像我能叫出来的就至少有三套 dracut,mkinitramfs,mkinitcpio。现在 systemd 好歹在把大家强行统一这件事情上推着走了很长的路。但也有这种历史残留会留下各种各样的不一致行为。因为你问我好用不好用,那当然是挺好的,特别是debian 自己打包的许许多多的工具实际上是依赖这一整套行为的。所以你就算让它今天删掉变成 vanilla 的版本,也并不是一件简单的事情。
这也可以说回我用 arch 作为系统的一个原因,就是系统上的包都是接近 vanilla 的状态(即上游的原始代码没有改动),能够最大程度获得和开发者一致的使用体验。
但是omv不是有自己的webui的吗? 谁会在这样的headless NAS专用发行版上安装DE甚至安装chromium的?
实在要在那上面用chromium, 主流的办法不是安装browserless吗…..
一个人想怎样用一个系统都是他的自由
看完文章,才发现不同发行版之间的差异竟然这么大。以前看到 Debian Wiki 中提到 .xsessionrc,没想到背后“暗藏玄机”。
PS:”在读了许久 debian startx 相关的脚本在之后” 里多了个“在”字