为什么 systemd 没有运行我的 ExecStartPre 脚本?

为什么 systemd 没有运行我的 ExecStartPre 脚本?

我有两张显卡,需要根据我在 grub 中选择的启动选项配置 xorg 以使用正确的显卡。为了实现这一点,我在一个启动选项的内核参数中添加了一个任意字符串(在本例中为“FORCENVIDIA”),并且我有一个脚本来检查该字符串是否存在,然后根据它是否存在将 .conf 文件符号链接到另外两个文件之一:

#!/bin/sh

if cat /proc/cmdline | grep FORCENVIDIA > /dev/null; then
        rm -f /usr/share/X11/xorg.conf.d/old-config
        cp /usr/share/X11/xorg.conf.d/40-force-gpu.conf /usr/share/X11/xorg.conf.d/old-config
        rm -f /usr/share/X11/xorg.conf.d/40-force-gpu.conf
        ln -s /usr/share/X11/xorg.conf.d/XX-force-nvidia /usr/share/X11/xorg.conf.d/40-force-gpu.conf
else
        rm -f /usr/share/X11/xorg.conf.d/old-config
        cp /usr/share/X11/xorg.conf.d/40-force-gpu.conf /usr/share/X11/xorg.conf.d/old-config
        rm -f /usr/share/X11/xorg.conf.d/40-force-gpu.conf
        ln -s /usr/share/X11/xorg.conf.d/XX-force-amd /usr/share/X11/xorg.conf.d/40-force-gpu.conf
fi

因此,如果 FORCENVIDIA 位于 /proc/cmdline 中,它会删除旧的 .conf 内容,并重新创建指向 XX-force-nvidia 的符号链接(显然,它包含适合我的 nvidia 卡的正确设置)。如果 FORCENVIDIA 不在 /proc/cmdline 中,它会对 XX-force-amd 执行相同的操作。

为了使其在 X 启动之前运行,我已将其作为显示管理器 - sddm 的 ExecStartPre 包含进来,方法sudo systemctl edit sddm.service是创建一个如下所示的配置:

[Service]
# select the primary GPU to display X
ExecStartPre=@/bin/sh /usr/share/select_primary_card.sh

我可以用来systemctl status sddm.service验证 systemd正在运行的是:

● sddm.service - Simple Desktop Display Manager
   Loaded: loaded (/lib/systemd/system/sddm.service; indirect; vendor preset: enabled)
  Drop-In: /etc/systemd/system/sddm.service.d
           └─override.conf
   Active: active (running) since Thu 2020-05-28 06:28:36 BST; 9min ago
     Docs: man:sddm(1)
           man:sddm.conf(5)
 Main PID: 1350 (sddm)
    Tasks: 4 (limit: 4915)
   CGroup: /system.slice/sddm.service
           ├─1350 /usr/bin/sddm
           └─1352 /usr/lib/xorg/Xorg -nolisten tcp -auth /var/run/sddm/{eea7054b-d749-4569-9c3f-e44f13be8942} -background none -noreset -displayfd 18 -seat seat0 vt1

May 28 06:30:55 PC sddm-helper[1731]: Starting: "/etc/sddm/Xsession \"/usr/bin/startkde\""
May 28 06:30:56 PC sddm[1350]: Auth: sddm-helper exited successfully
May 28 06:30:56 PC sddm[1350]: Greeter stopped.
May 28 06:30:56 PC sddm[1350]: Session started                                                                                                                                                                                                                                 
May 28 06:30:57 PC sddm[1350]: Checking for pam module                                                                                                                                                                                                                         
May 28 06:30:57 PC sddm[1350]: Got pam-login                                                                                                                                                                                                                                   
May 28 06:30:57 PC sddm[1350]: kwalletd: Waiting for hash on 15-                                                                                                                                                                                                               
May 28 06:30:57 PC sddm[1350]: kwalletd: waitingForEnvironment on: 3                                                                                                                                                                                                           
May 28 06:30:57 PC sddm[1350]: kwalletd: client connected                                                                                                                                                                                                                      
May 28 06:30:57 PC sddm[1350]: kwalletd: client disconnected

问题是不是正在运行。在脚本中,我包含了一些行,用于将现有的 .conf 文件复制到名为“old-config”的文件,这样我就可以看到上次启动时 conf 文件的样子(nvidia 启动选项不起作用,当您重新启动到正常工作的启动选项并替换 .conf 时很难诊断)。当我启动和登录时,那个 old-config 文件不存在。但据我所知,脚本很好。如果我手动运行它,它似乎可以sudo /usr/share/select_primary_card.sh完成它应该做的事情。

有人能看到这里发生了什么吗?

答案1

你使用了@前缀,这意味着/bin/sh可执行文件将接收以下参数列表:

{[0] = "/usr/share/select_primary_card.sh"}

而不是预期的:

{[0] = "/bin/sh", [1] = "/usr/share/select_primary_card.sh"}

按照惯例,参数列表中的第零项始终包含程序自己的名称,并且或多或少被大多数软件忽略。

但是当脚本通过解释器运行时,argv[0] 包含口译员名称,而脚本的路径通常是项目 #1 – 即解释器命令行的常规部分。因此,当使用时@,/bin/sh 认为它是用空命令行运行的,并尝试进入交互模式,失败并退出。

不要需要任何特殊的 argv[0] 技巧才能运行脚本。只需像这样运行它(遵守标题#!):

ExecStartPre=/usr/share/select_primary_card.sh

或者像这样(绕过#!标题):

ExecStartPre=/bin/sh /usr/share/select_primary_card.sh

附注:不要将您的自定义配置放在 /usr/share 中 – 这是 /etc/X11 的用途。

相关内容