<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>望向天脉的技术记录</title><description>Linux 桌面与发行版。Arch、KDE Plasma、Wayland，以及自己写的东西。</description><link>https://miprota.cc/</link><language>zh-CN</language><item><title>Nahimic 出厂音效续篇：变体判定与空间效果</title><link>https://miprota.cc/posts/nahimic-factory-audio-tuning-2/</link><guid isPermaLink="true">https://miprota.cc/posts/nahimic-factory-audio-tuning-2/</guid><description>接着上一篇：用 SMBIOS 的 OEM 串判定扬声器变体，排查 390 个参数的去向，复核空间效果与串扰抵消为什么在笔记本上不成立。</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一篇《把 Nahimic 出厂音效搬到 Linux》结尾留了三件事：扬声器变体 A/B 没有判定、461 个参数里有 390 个不知道取值、空间效果没有落地。
所以就有了后续。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;本次环境&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;硬件&lt;/td&gt;
&lt;td&gt;MECHREVO 蛟龙，Conexant SN6140（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;VEN_14F1 DEV_1F87&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，SUBSYS &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1D053010&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;系统&lt;/td&gt;
&lt;td&gt;CachyOS，PipeWire 1.6.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;效果器&lt;/td&gt;
&lt;td&gt;EasyEffects 8.3.0（Flatpak）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原厂数据&lt;/td&gt;
&lt;td&gt;Windows 分区里的 A-Volute/Nahimic 驱动包（180 个明文 XML）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工具&lt;/td&gt;
&lt;td&gt;Python 3、NumPy、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;cabextract&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;objdump&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;上一篇的环境是 PipeWire 1.6.8 与 EasyEffects 8.2.9。8.3.0 在 2026-09-29 发布，这一轮关于插件的结论都以 8.3.0 为准。&lt;/p&gt;
&lt;p&gt;范围限制：只看笔记本内置扬声器。耳机、外置声卡、蓝牙设备都不在范围内。&lt;/p&gt;
&lt;h2 id=&quot;一变体由-smbios-的-oem-串决定&quot;&gt;一、变体由 SMBIOS 的 OEM 串决定&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Devices/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里属于本机 SUBSYS 的扬声器档案有 8 个，分成两套曲线。上一篇停在「主板型号 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;X6xR55xK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 对不上任何一个文件名，不能按文件数量猜」这一步。&lt;/p&gt;
&lt;p&gt;判据就在设备档案末尾的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;Data&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 块里：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```xml
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;HWID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;       &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUBSYS_1D053010&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;HWID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;FormFactor&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Speakers&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;FormFactor&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;         &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;{753ed818-…}&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;SMBIOS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;     &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;1D053010K5500103&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;SMBIOS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;配置器要拿本机的一个字符串去比 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。这个字符串的来源写在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicPnPAPO4ConfiguratorDaemonModule.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;SELECT OEMStringArray FROM Win32_ComputerSystem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Win32_ComputerSystem.OEMStringArray&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就是 SMBIOS 的 Type 11（OEM Strings）。&lt;/p&gt;
&lt;h3 id=&quot;把那张表读出来&quot;&gt;把那张表读出来&lt;/h3&gt;
&lt;p&gt;Linux 这边三条常规入口都不通：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;入口&lt;/th&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/sys/firmware/dmi/tables/DMI&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;entries/11-0/raw&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;权限 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-r-------- root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/sys/class/dmi/id/*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;17 个字段里没有 OEM 串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 侧 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HKLM\SYSTEM\…\mssmbios\Data&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;Windows 11 已不再缓存这张表&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;所以做一次只读的特权读取就够：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pkexec&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/bin/cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/firmware/dmi/tables/DMI&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; data/smbios/DMI.bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/read_smbios_oem.py&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; data/smbios/DMI.bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → Type 11 OEM Strings (20 条):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#     [16] &apos;1D053010K5500103&apos;   &amp;lt;-- 形如 SUBSYS+型号键（候选选择键）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   ✅ 命中: 1D053010K5500103&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#      档案: 1D053010_1D053010K5500103_Speakers.nsx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/read_smbios_oem.py&quot;&gt;read_smbios_oem.py&lt;/a&gt;&lt;/strong&gt;
149 行 / 5.2 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/read_smbios_oem.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;判据是三段拼接：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SUBSYS_1D053010&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 取自 HWID，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;K5500103&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 OEM 键，两者与档案里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 必须逐字符相同。本机命中即变体 &lt;strong&gt;B（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;X6DR57TK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/strong&gt;，不需要扫频，也不需要听感 A/B。&lt;/p&gt;
&lt;h3 id=&quot;8-个候选其实只有-2-套曲线&quot;&gt;8 个候选其实只有 2 套曲线&lt;/h3&gt;
&lt;p&gt;把每个档案的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;ID&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（GUID）与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 归一化之后算 md5：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;档案&lt;/th&gt;
&lt;th&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;归一化后 md5&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;…K5500101&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; – &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;…K5500107&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;各不相同&lt;/td&gt;
&lt;td&gt;七个文件&lt;strong&gt;完全相同&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;c2b5d235…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;…K5500100&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1D053010K5500100&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;7cf30fdc…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;同一套调音挂在 7 个 OEM 键下面，不是 7 次独立采样。&lt;/p&gt;
&lt;p&gt;顺带一提，档案头部的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;FT-NOTE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 注释不可信：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;K5500101&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;K5500107&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的注释统统写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SMBIOS-1D053010K5500103&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，连 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;0107&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;0103&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 字段算数。&lt;/p&gt;
&lt;h2 id=&quot;二390-个参数不在磁盘上&quot;&gt;二、390 个参数不在磁盘上&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicAPO4API.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里有 &lt;strong&gt;461 个&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kSet_*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 键。XML 只出现了其中 71 个（交集 67 个），剩下 394 个键在配置文件里从来没有出现过。&lt;/p&gt;
&lt;p&gt;上一篇的猜测是：实际取值保存在运行态，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Settings/settings.dat&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是最像的地方。这一轮把候选逐一拆开看：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;实际内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Settings/settings.dat&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（8192 B，注册表 hive）&lt;/td&gt;
&lt;td&gt;只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;CurrentMicProfile=&apos;Chat\0&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ToastShown=&apos;[]\0&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LocalState/AppSettings.json&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;应用启动状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LocalState/EQPresets.json&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;每个场景选用的预设名（本机全为 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Custom&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LocalState/Chat.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Conference.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;采集链的 6 个开关，属采集侧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LocalState/Settings/v1/EQPresets/**&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;UI 那 10 段图形 EQ，已转成 EasyEffects 预设&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HKCU\Software\A-Volute\Nahimic\{701C0AEE-…}&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;守护模块登记表：每个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;*DaemonModule.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的路径与 GUID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HKCU\Software\Nahimic\…\ShortcutEngine\{7943271B-…}&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;一个快捷键码 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;k000031a4 = 8&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HKLM\SOFTWARE\…\MMDevices\Audio\Render\{端点}\FxProperties&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;只有 APO 注册项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HKLM\SYSTEM\…\Enum\SWD\…AVOLUTE_NH4APO&amp;amp;6&amp;amp;…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;设备枚举项，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Device Parameters]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;values=0 subkeys=0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;第 8、9 项本来最有希望：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;FxProperties&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是第三方 APO 在 Windows 上持久化参数的常规位置，而那一项里只有一个 APO 注册和三个 mode CLSID。&lt;/p&gt;
&lt;p&gt;结论是负的：&lt;strong&gt;这 390 个键不落盘&lt;/strong&gt;，运行时参数由后台服务推送给 APO 的共享内存。想拿到它们，只剩静态提取 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicAPO4.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内置默认值表一条路，所以我们又又延期了（详见第八节待办）。&lt;/p&gt;
&lt;p&gt;这一轮顺带确认了两件事：当前生效的 APO 是 A-Volute/Nahimic（端点属性里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;{f363df17-…},11 = &apos;A-Volute.Nahimic&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Senary Audio&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只是 OEM 驱动的品牌名；另外 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Nahimic_Mirroring&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 建了一个独立的镜像端点。&lt;/p&gt;
&lt;h2 id=&quot;三空间效果只有开关没有强度&quot;&gt;三、空间效果：只有开关，没有强度&lt;/h2&gt;
&lt;p&gt;出厂四个场景里，空间类效果的开关如下（来自同一份 XML）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;音乐&lt;/th&gt;
&lt;th&gt;电影&lt;/th&gt;
&lt;th&gt;游戏&lt;/th&gt;
&lt;th&gt;通讯&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SpkVirtualSurroundState&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;StereoWideningState&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;UpmixState&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ReverbState&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ReverbGainDB&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;-10.0&lt;/td&gt;
&lt;td&gt;-10.0&lt;/td&gt;
&lt;td&gt;-10.0&lt;/td&gt;
&lt;td&gt;-10.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;音乐场景不启用任何空间效果，只做设备校正加三段增益。电影与游戏则把四个开关全打开。&lt;/p&gt;
&lt;p&gt;问题在于强度：461 个键里，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SpkVirtualSurround&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;StereoWidening&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Upmix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 都只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;State&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，没有任何强度或角度参数。原厂只给了开关，给不出「开多大」。所以这边的做法是给一组分级试听预设，由耳朵选：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;预设&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;电影&lt;/td&gt;
&lt;td&gt;加宽弱、加宽强、串扰、综合（4 个）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;游戏&lt;/td&gt;
&lt;td&gt;加宽弱、加宽强、串扰、综合（4 个）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;音乐&lt;/td&gt;
&lt;td&gt;加宽弱、加宽强&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，原厂的音乐预设是没有加宽的，这里纯粹是我想试试效果所以加上去了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;落地用的是两个插件：立体声扩展走 Calf 的 Stereo Tools（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;stereo_tools&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），串扰抵消走 EasyEffects 原生的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;crosstalk_canceller&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。这两个插件的 JSON 键名是从上游 v8.3.0 的 kcfg 与源码里核对的，凭印象写键名会被静默忽略。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_spatial_presets.py&quot;&gt;build_spatial_presets.py&lt;/a&gt;&lt;/strong&gt;
197 行 / 8.1 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_spatial_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;四串扰抵消在笔记本扬声器上不成立至少现在不成立&quot;&gt;四、串扰抵消在笔记本扬声器上不成立（至少现在不成立）&lt;/h2&gt;
&lt;p&gt;试听串扰预设时，我总感觉听起来很奇怪，塑料味道相当大。&lt;/p&gt;
&lt;p&gt;第一件事是确认卷积器有没有在工作。厂校 FIR 在 800 Hz 有一个箱体共振凹陷，串上串扰之后这个凹陷只变化 &lt;strong&gt;-0.12 dB&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  FIR 单独            : -12.88 dB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  FIR × RACE(H_direct): -13.00 dB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&amp;gt; 凹陷被填回 -0.12 dB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;凹陷完好，卷积器在正常工作，问题出在串扰本身。&lt;/p&gt;
&lt;h3 id=&quot;race-是什么&quot;&gt;RACE 是什么&lt;/h3&gt;
&lt;p&gt;EasyEffects 的串扰抵消是 &lt;strong&gt;RACE&lt;/strong&gt;（Recursive Ambiophonic Crosstalk Elimination，作者 Antti S. Lankila）。它是一个递归结构：中置声道经过一个反馈梳状滤波器（见下方公式）之后再混回左右。：&lt;/p&gt;
&lt;div class=&quot;math-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:2.2935em;vertical-align:-0.9721em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;⋅&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;⋅&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.044em;&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7673em;&quot;&gt;&lt;span style=&quot;top:-2.989em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9721em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:0.9805em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 是 6 个双二阶（biquad）级联：250 Hz 高通、3245 Hz 低通，加四个衰减峰（688 / 1066 / 2190 / 3792 Hz）。&lt;/p&gt;
&lt;p&gt;延迟是量化过的：&lt;/p&gt;
&lt;div class=&quot;math-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:2.4em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;round&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3944em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7401em;&quot;&gt;&lt;span style=&quot;top:-2.989em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.7em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;delay_us&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;rate&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;313 µs 在 48 kHz 下等于 15 个采样，梳状间隔 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1/D&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 3.2 kHz，第一个四分之一周期正好落在 &lt;strong&gt;800 Hz&lt;/strong&gt;——厂校 FIR 挖凹陷的位置。&lt;/p&gt;
&lt;h3 id=&quot;数值复核&quot;&gt;数值复核&lt;/h3&gt;
&lt;p&gt;先把解析模型（z 域）与逐样本时域仿真对着跑：两者的最大偏差 &lt;strong&gt;0.003 dB&lt;/strong&gt;。这个自检有用，把模型里的符号写反时偏差立刻变成 2.1 dB。&lt;/p&gt;
&lt;p&gt;然后看它对频响做了什么：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;通路&lt;/th&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;直达通路&lt;/td&gt;
&lt;td&gt;全程 ±2 dB，峰 +3.11 dB @1449 Hz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交叉项（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;phantom-center-only=true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;td&gt;250–3245 Hz 带内，1597 Hz 处 -8.98 dB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交叉项相位&lt;/td&gt;
&lt;td&gt;与直达同相（800 Hz 处 87°）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;同相的交叉项起不到抵消作用，它更像一份延迟 312 µs 的副本，加在原信号上形成梳状滤波——听感上的染色就来自这里。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/analyze_crosstalk.py&quot;&gt;analyze_crosstalk.py&lt;/a&gt;&lt;/strong&gt;
347 行 / 14.3 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/analyze_crosstalk.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;串扰抵消的四联频响图：RACE 反馈滤波器、直达通路（全程 ±2 dB）、注入对侧的交叉项，以及厂校 FIR 与串上 RACE 后的对比。800 Hz 的箱体共振凹陷只变化 0.12 dB&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1430px) 1430px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1430&quot; height=&quot;1820&quot; src=&quot;/_astro/crosstalk-analysis.CJ_DsBwQ_Z2rsm7R.webp&quot; srcset=&quot;/_astro/crosstalk-analysis.CJ_DsBwQ_Z1HhgAh.webp 640w, /_astro/crosstalk-analysis.CJ_DsBwQ_17eG6p.webp 750w, /_astro/crosstalk-analysis.CJ_DsBwQ_ZTSC4R.webp 828w, /_astro/crosstalk-analysis.CJ_DsBwQ_17GAmJ.webp 1080w, /_astro/crosstalk-analysis.CJ_DsBwQ_Z11DC9F.webp 1280w, /_astro/crosstalk-analysis.CJ_DsBwQ_Z2rsm7R.webp 1430w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;为什么在笔记本上不成立&quot;&gt;为什么在笔记本上不成立&lt;/h3&gt;
&lt;p&gt;RACE 的几何前提接近 KEMAR 那种头型：两只扬声器与听者构成固定夹角，双耳时间差是已知量。笔记本内置扬声器的张角只有约 ±10°，插件里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;delay-us&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下限 200 µs 对应约 9.6 个采样，很可能已经高于这种间距下的真实双耳时间差。再加上预设用的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;phantom-center-only=true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只处理中置声道，染色正好落在人声与主奏上。&lt;/p&gt;
&lt;p&gt;结论：这 4 个串扰与综合预设在本机判定为不可用。这里没有做声学测量，机制解释属于「最合理的解释」，频响数值是实算的。&lt;/p&gt;
&lt;h2 id=&quot;五校验器漏掉的-37-个插件块&quot;&gt;五、校验器漏掉的 37 个插件块&lt;/h2&gt;
&lt;p&gt;生成预设之后要跑校验。上一轮的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;validate_presets.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里，插件分派写成一串 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;if/elif&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，最后没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;else&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。结果是：&lt;strong&gt;不认识的插件直接跳过，一个检查都不做，还照样报 OK&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;统计下来有 37 个插件块从来没被校验过：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;limiter&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 19 个、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;bass_enhancer&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 17 个、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;deepfilternet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 1 个。这个数量已经超过当时预设里被检查的部分。&lt;/p&gt;
&lt;p&gt;补法是给这三个插件写真实检查，并加两条硬规则：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```python
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 未知插件**必须报错**，不能静默放行 ——&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 否则新增插件时&quot;全部通过&quot;是假的（这正是本档案陷阱 1 的形态）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    chk&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;base &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; HANDLED_PLUGINS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        &quot;%s: 插件 %r 没有校验规则 —— 请先补 HANDLED_PLUGINS 与对应检查&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; base&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;另一条是「键集完全一致」：每个插件块的键集合必须与 kcfg 枚举的集合逐键相同，多一个少一个都算错。以前只检查键值合法，键名写错、键漏掉都发现不了。&lt;/p&gt;
&lt;p&gt;升级后立刻抓到两个真实缺陷：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-原厂-&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-完整-&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 两个预设的限幅器 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;release = 100.0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，而这个键的合法上限是 20。两处限幅器都是旁路状态，所以对听感没有影响，但这类越界以前一个都报不出来。&lt;/p&gt;
&lt;p&gt;新的校验器自己也做了五类注入测试（改枚举、删键、加键、改数值、换成不认识的插件），确认每类都能报错。整份脚本在源码仓库里：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;tools/validate_presets.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;h2 id=&quot;六脉冲响应改名以及-easyeffects-的两个坑&quot;&gt;六、脉冲响应改名，以及 EasyEffects 的两个坑&lt;/h2&gt;
&lt;p&gt;卷积器只在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kernel-name&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 变化时才重新读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.irs&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 文件。如果原地覆盖同名文件，修正过的 FIR 不会生效，而且没有任何提示。所以脉冲响应改成带内容哈希的名字：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Nahimic-Factory-X6DR57TK.irs  →  Nahimic-Factory-X6DR57TK-c03355d3.irs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;改名过程中踩到两个坑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;flatpak 停不掉&lt;/strong&gt;
现象：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl --user stop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那个 autostart 服务之后，服务显示 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;inactive (dead)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，进程仍在（flatpak 另起了 transient scope）。
处理：再停 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;app-flatpak-com.github.wwmm.easyeffects-…scope&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行态不跟预设走&lt;/strong&gt;
现象：重启后运行的还是旧 IR，EasyEffects 从 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;db/convolverrc&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 恢复，不重新读预设里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kernel-name&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
处理：预设与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;convolverrc&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 两边都改。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改完之后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;irs/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 目录里只有一个文件，运行态、预设、磁盘三者一致。预设数量在这一轮的轨迹：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;数量&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;双变体时期（输出）&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删掉 11 个 A 变体预设&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;加上 8 个空间预设（电影/游戏）&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;加上 2 个音乐加宽&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;35 = 输出 34 个 + 输入 1 个（采集链的降噪预设），统计时间是 2026-10-06。&lt;/p&gt;
&lt;h2 id=&quot;七如何获取本文的工具&quot;&gt;七、如何获取本文的工具？&lt;/h2&gt;
&lt;p&gt;代码见仓库：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning&quot;&gt;nahimic-factory-audio-tuning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;脚本认这几个环境变量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;EASYEFFECTS_DATA&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;EasyEffects 数据目录&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.var/app/com.github.wwmm.easyeffects/data/easyeffects&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_ARCHIVE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;档案根目录&lt;/td&gt;
&lt;td&gt;脚本上两级目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_DEVICES&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;设备 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 目录&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;$NAHIMIC_ARCHIVE/data/Devices&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_DLL&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicAPO4.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 路径&lt;/td&gt;
&lt;td&gt;当前目录下的同名文件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;八还没做的&quot;&gt;八、还没做的&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;事项&lt;/th&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;静态提取 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicAPO4.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内置默认值表&lt;/td&gt;
&lt;td&gt;未开始&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;VirtualBassBoost&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 tanh 驱动量、前置滤波、混合比&lt;/td&gt;
&lt;td&gt;未开始&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ape::SBP::Clarity&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的真身&lt;/td&gt;
&lt;td&gt;未开始&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 个串扰/综合预设是否删除&lt;/td&gt;
&lt;td&gt;待定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;中频电平&lt;/td&gt;
&lt;td&gt;受限：压缩后限制峰值的是 -4.06 dB 的高频段（高音增强 +4 dB 所致）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;另外两条已知差异：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;bass_enhancer&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是静态的，复现不了出厂那种随音量变化的低音补偿，所以小音量下低音比原厂少、大音量下比原厂多；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-响度&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 变体的音量小得离谱（等响度插件多半把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-12 dB&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 当成了播放电平基准），在修好之前不建议使用。&lt;/p&gt;
&lt;h2 id=&quot;九省流&quot;&gt;九、省流&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;判定自己的变体&lt;/strong&gt;（只读，需要一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkexec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pkexec&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/bin/cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/firmware/dmi/tables/DMI&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; data/smbios/DMI.bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;NAHIMIC_DEVICES&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PWD&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/data/Devices&quot;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/read_smbios_oem.py&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; data/smbios/DMI.bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;命中哪一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;SMBIOS&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，就用哪一个设备档案，不用扫频。&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;校验预设&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/validate_presets.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选空间效果&lt;/strong&gt;：先试加宽，串扰那一档在笔记本上大概率不合适。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果要让 AI Agent 重做一遍，把上一篇那段提示词的第 9 步换掉——变体现在可以判定，不必「由我确认」：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;9. 判定扬声器变体：用 UEFI 的 SMBIOS Type 11 OEM 串，与 data/Devices/*.nsx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   里的 &amp;lt;SMBIOS&amp;gt; 精确匹配（tools/read_smbios_oem.py），不要按文件数量猜，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   也不要靠听感或扫频。读 /sys/firmware/dmi/tables/DMI 需要一次只读的 pkexec。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
</content:encoded><category>Nahimic</category><category>EasyEffects</category><category>PipeWire</category><category>DSP</category><category>Linux</category></item><item><title>被人脸钱包密钥掉包的登录密码</title><link>https://miprota.cc/posts/pam-walletkey-password-hijack/</link><guid isPermaLink="true">https://miprota.cc/posts/pam-walletkey-password-hijack/</guid><description>自建 PAM 模块把人脸登录后的钱包密钥写进 PAM_AUTHTOK，位置排错，于是登录界面里输入的密码被密钥顶掉。</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在上次调试好人脸识别后用着还是挺舒服的，突然有一天反欺诈把真人频繁判成了假体。
即便我在登录界面里输入正确密码，仍然提示认证失败，只有刷脸能进桌面。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS（Arch 系）｜KDE Plasma 6.7.5｜Plasma Login Manager 6.7.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wayland｜biopass-bin 1.4.1｜kwallet 6.30.0｜kwallet-pam 6.7.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gcc 16.2.1｜pam 1.7.2｜Linux-PAM 1.7.2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;前期配置（人脸登录、自建 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 模块、钱包密钥文件）见
&lt;a href=&quot;/posts/biopass-sudo-kwallet/&quot;&gt;人脸登录后的 KWallet 自动解锁&lt;/a&gt;。
本文只描述那次配置里错误的部分，以及它引发的后果。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--warning&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;注意&lt;/p&gt;
&lt;p&gt;下面每一步都在改认证栈。动手前先开一个 root 的 TTY 放着别关
（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ctrl+Alt+F2&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 登录），改坏之后就靠它进去了。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sshd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这两条栈里没有本文涉及的任何模块。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;四条登录途径&quot;&gt;四条登录途径&lt;/h2&gt;
&lt;p&gt;同一台机器上有四个登录入口，我们可以先分清坏的是哪个。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;路径&lt;/th&gt;
&lt;th&gt;使用的 PAM 服务&lt;/th&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;登录界面 · 输密码&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;❌ 认证失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;登录界面 · 人脸&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ 正常&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;锁屏 · 输密码&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/kde&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ 正常&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTY / SSH · 输密码&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sshd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ 正常&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;最后两行是反证：同一个密码在 TTY 与 SSH 下能通过，说明密码本身没变，
问题出在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这一条栈里。&lt;/p&gt;
&lt;p&gt;人脸的可用性会掩盖这个故障。只要人脸一直认得出来，日常使用看不出异常；
直到人脸也失败的那天，用户才会去试密码，撞上另一条已经坏掉的入口。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本机人脸失效的原因写在「通用性」一节的旁支里，属另一个故障，不是根因。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;排查时间线&quot;&gt;排查时间线&lt;/h2&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;以下是第一人称视角的修复记录，您在阅读过程中可能会感觉自己被耍了，所以这里笔者先道歉。&lt;/p&gt;
&lt;p&gt;如果你需要省流环节，可以直接跳转到最终方案章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;确定错误路径&quot;&gt;确定错误路径&lt;/h3&gt;
&lt;p&gt;先看日志，看看密码到底是在哪一步被拒绝。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;10月 05 12:41:55 plasmalogin-helper[2314]: [PAM] Authenticating...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;10月 05 12:41:57 plasmalogin-helper[2314]: pam_unix(plasmalogin:auth): authentication failure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 报了认证失败。这时候手上有两条线索：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 栈里第一行是人脸模块，
第二行才是管密码的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；而 TTY 与 SSH 用同一个密码能进。&lt;/p&gt;
&lt;p&gt;再看认证栈：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-auth       optional    pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-auth       optional    pam_kwallet5.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;auth        sufficient  libbiopass_pam.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;auth        include     system-login&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;第一个假设是“登录界面把密码预先塞进了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，被 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆盖掉了”。
按这个假设，加个“非空就不覆盖”的判断就能解决。&lt;/p&gt;
&lt;p&gt;动手之前先把钱包模块的源码翻出来看它究竟做了什么：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```c
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_set_item&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_AUTHTOK&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   /* key = 钱包密钥 R，48 位 hex */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;无条件覆盖，没有“已存在就跳过”的判断。到此为止看起来都对上了。&lt;/p&gt;
&lt;h3 id=&quot;第一轮给模块加一个非空就跳过的判断&quot;&gt;第一轮：给模块加一个“非空就跳过”的判断&lt;/h3&gt;
&lt;p&gt;补丁按假设写出来：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```c
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* 若 PAM_AUTHTOK 非空，说明已有密码，绝不覆盖 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;existing &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_get_item&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_AUTHTOK&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; **)&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;existing&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; existing &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; existing&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;编译、双路径安装，再配一个对照脚本：Step 1 用当前模块复现故障，Step 2 换上新模块看是否转好。
脚本跑完贴回来的是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;【Step 1】旧模块  =&amp;gt; Authentication failure (7)      ✓ 故障复现&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;【Step 2】新模块  =&amp;gt; Authentication failure (7)      ✗ 仍然失败&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_walletkey: wallet key injected for user neo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Step 2 失败了。第一反应是“补丁没装上”，于是核对 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;md5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strings&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里搜补丁字符串，
两样都对得上，模块确实是新的。但日志里那行注入照旧出现。&lt;/p&gt;
&lt;p&gt;补丁模块既然装上了，就只可能是一件事：&lt;strong&gt;它执行的那一刻 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是空的。&lt;/strong&gt;
也就是说，密码并不是登录界面预先塞进去的。&lt;/p&gt;
&lt;p&gt;回到 Linux-PAM 的源码去找密码是谁问出来的：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```c
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* 节选自 linux-pam/modules/pam_unix/pam_unix_auth.c */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;retval &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_get_authtok&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_AUTHTOK&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;retval &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; _unix_verify_password&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; ctrl&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;密码是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 自己通过 PAM 对话向界面要的。而 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
排在它前面，此刻 authtok 必然为空，条件永远不触发。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_authtok()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 已非空时会直接复用、不再弹框。
把两件事连起来，故障的链条是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;用户输入密码  → 密码交给 PAM 对话&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_walletkey → PAM_AUTHTOK = R       ← 抢在 pam_unix 之前&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_unix      → 不弹框，直接拿 R 校验 → 认证失败&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;登录界面收到的只是“认证失败”，看不出密码被换过。&lt;/p&gt;
&lt;h3 id=&quot;第二轮补丁整套回退&quot;&gt;第二轮：补丁整套回退&lt;/h3&gt;
&lt;p&gt;判断转到“位置错了”之后，那个补丁在新位置上反而有害。推演一遍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把模块挪到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后，它执行时 authtok 里已经是用户登录密码；&lt;/li&gt;
&lt;li&gt;补丁版会跳过注入，钱包于是拿到登录密码，而钱包是用密钥 R 重新加密的，解不开；&lt;/li&gt;
&lt;li&gt;原版模块无条件注入 R，钱包拿到 R，解锁正常。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 已经校验完密码，此刻覆盖 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不影响认证结果，
正好是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 需要的那份数据。结论是把补丁整套回退，模块保持原样，只动 PAM 栈。&lt;/p&gt;
&lt;h3 id=&quot;第三轮只改顺序密码恢复&quot;&gt;第三轮：只改顺序，密码恢复&lt;/h3&gt;
&lt;p&gt;改动只有一行：把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 挪到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。验证结果如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;实验 A1（walletkey 在 unix 前） =&amp;gt; Authentication failure (7)   ← 复现故障&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;V1（复刻栈，真实密码）          =&amp;gt; Success (0)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;V2（真实 plasmalogin，真实密码）=&amp;gt; Success (0)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;复现与修复各有一个真值，密码登录恢复。&lt;/p&gt;
&lt;p&gt;顺手补一个追踪模块（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_authenticate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里读一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_USER&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与口令长度写进 syslog，返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），把 authtok 的变化打出来：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_trace_authtok[1-before-unix]:     authtok=NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_trace_authtok[2-after-unix]:      authtok=SET(len=25)       ← 25 位 = 用户密码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_walletkey: wallet key injected for user neo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_trace_authtok[3-after-walletkey]: authtok=SET(len=48)       ← 校验完才被钱包密钥覆盖&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;修复前在同一位置打出来的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;authtok=SET(len=48)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 紧跟 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix: authentication failure&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
两处长度不相等，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 手里拿的确实是钱包密钥。具体长度取决于当时的密码，
不要拿数字本身当结论。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对真实 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 服务跑过认证探针（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_authenticate()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，只做认证判定、
不建立会话），用错误密码与正确密码各跑一轮，上面这些时序取自它。
探针不改变任何会话状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;第四轮钱包又打不开了&quot;&gt;第四轮：钱包又打不开了&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这一轮的价值不大，笔者利用 AI 进行排查时走了弯路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;密码通了，注销再登录，KWallet 恼人的认证弹窗还是弹出。&lt;/p&gt;
&lt;p&gt;翻这一轮的日志，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 auth 阶段执行了，却没有存下口令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:auth): pam_kwallet5: pam_sm_authenticate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;原因在上一轮留下的位置：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 被落在了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 前面，
它执行时 authtok 还是空的，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_authenticate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 记下“没拿到密码”就返回，
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个数据槽没人填。把它也挪到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --no-pager&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_kwallet5&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → pam_kwallet5: final socket path: /run/user/1000/kwallet5.socket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;密码路径的钱包恢复正常。到这里得到两条硬约束：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 必须在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。&lt;/strong&gt; 排在前面，密码被 R 掉包，密码登录失败。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 必须在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。&lt;/strong&gt; 排在前面，auth 阶段拿不到 R，钱包打不开。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两条拼起来，顺序只能是
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;h3 id=&quot;第五轮四条路径一测窟窿露出来了&quot;&gt;第五轮：四条路径一测，窟窿露出来了&lt;/h3&gt;
&lt;p&gt;注销、登录、锁屏各试一遍，得到的是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注销用人脸还是会弹 kwallet，注销用密码、锁屏用密码不会。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同一次会话里的两行日志：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_walletkey: wallet key injected                                           ← 密码登录，钱包正常&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:session): open_session called without kwallet5_key  ← 人脸登录，钱包打不开&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 标着 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。它的语义是“成功即放行、并且终止整条栈”，
人脸认得出来时，排在它后面的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 一行都不会执行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;两个方向，各坏一条路径&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;钱包行放 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前：人脸路径正常，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 拿不到用户密码，密码登录失败。&lt;/li&gt;
&lt;li&gt;钱包行放 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后：密码路径正常，人脸成功即终止栈，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没人填。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 短路与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆盖，两件事在同一个线性 auth 栈里无法同时满足。
配置本身没有写错，是 auth 栈这个结构装不下这两条需求。&lt;/p&gt;
&lt;h3 id=&quot;第六轮绕过-authtok自己拉起-ksecretd&quot;&gt;第六轮：绕过 authtok，自己拉起 ksecretd&lt;/h3&gt;
&lt;p&gt;auth 栈里摆不开，就把这件事挪到 session 阶段去做。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 session 阶段
无非是“拿口令 → 派生密钥 → 拉起 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;”，那就自己写个程序全做完：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 拿钱包口令 R&lt;/li&gt;
&lt;li&gt;读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/kwalletd/kdewallet.salt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
用 PBKDF2-HMAC-SHA512（50000 轮，56 字节）派生主密钥，与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 同一套算法&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fork&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; + 降权到目标用户，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;exec /usr/bin/ksecretd --pam-login &amp;lt;pipe_fd&amp;gt; &amp;lt;socket_fd&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
把 56 字节密钥写进管道&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PAM 侧用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 调它：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;session     optional    pam_exec.so  quiet /usr/local/libexec/kwallet-pam-unlock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;为了一致，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet.c&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;execute_kwallet()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里那些细节都照抄了：
pipe fd 作为参数传递而不是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dup&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 到标准输入、给无关 fd 设 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;FD_CLOEXEC&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 但保留 pipe fd、
socket 绑到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;$XDG_RUNTIME_DIR/kwallet5.socket&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。还加了“已有活着的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就跳过”的护栏，
避免两个实例同时操作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet.kwl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;装上执行，拿到的是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Configuration file &quot;/root/.config/ksecretdrc&quot; not writable.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please contact your system administrator.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;setuid&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 到目标用户了，但没改环境变量，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 继承的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HOME&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 还是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
补上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;setenv(&quot;HOME&quot;, pw-&amp;gt;pw_dir, 1)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 以及 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;USER&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LOGNAME&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SHELL&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，再跑：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;kwallet-pam-unlock: ksecretd exited immediately (status=134) — wallet likely NOT unlocked&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_exec(plasmalogin:session): /usr/local/libexec/kwallet-pam-unlock failed: exit code 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;134 = 128 + 6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，SIGABRT。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 Qt 程序，PAM 的 session 阶段此时图形会话还没起来，
没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;WAYLAND_DISPLAY&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、没有可用的 DBus 会话总线，它拿不到平台插件就 abort。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 stderr 原文没有采集到（诊断脚本写好了没用上），
“缺图形环境”是从崩溃时机与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;status=134&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 推出来的判断。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;到这里停一下，回去翻这一整段时间的日志，里面有一行早就存在的记录：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;10月 05 22:58:22 neo ksecretd[48357]: Using kwallet without parent window!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 本来就能被 D-Bus 自动拉起。这一轮在重新实现一件不需要重新实现的事，
实现的细节还比原装实现更多。&lt;/p&gt;
&lt;h3 id=&quot;第七轮把缺的那一格数据补上&quot;&gt;第七轮：把缺的那一格数据补上&lt;/h3&gt;
&lt;p&gt;换思路：不碰 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，只补 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 缺的那份数据。
它的两段式设计是这样的：&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_authenticate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_item(PAM_AUTHTOK)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 取口令；为空则 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；取到后
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_set_data(&quot;kwallet5_key&quot;, 口令)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/dd&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_open_session&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_data(&quot;kwallet5_key&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，派生密钥，拉起 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;人脸路径上 auth 阶段被 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 短路，session 阶段就扑空：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:session): open_session called without kwallet5_key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;缺的是数据槽里那一格。&lt;/strong&gt; 那就写一个只在 session 阶段干活的模块，
位置排在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;session     optional    pam_session_walletkey.so        ← 新增：补 kwallet5_key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-session    optional    pam_kwallet5.so         auto_start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;模块只做三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;幂等检查&lt;/strong&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_data(pamh, &quot;kwallet5_key&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 命中就直接跳过
（密码路径已由 auth 阶段存过，于是零影响）&lt;/li&gt;
&lt;li&gt;未命中则读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 拿到 R&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_set_data(pamh, &quot;kwallet5_key&quot;, strdup(R), cleanup_wipe)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
并用清理回调在句柄释放时擦除内存里的口令&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;取值语义核对过 KDE 上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet.c&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：数据槽里放的是&lt;strong&gt;口令字符串&lt;/strong&gt;，
不是派生密钥，所以这里直接放 R，不做 PBKDF2。
（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个键名必须与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletPamDataKey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 一致。）&lt;/p&gt;
&lt;p&gt;装上之后，两条分支都在日志里出现了，输出见下面「验证」一节。&lt;/p&gt;
&lt;h2 id=&quot;最终方案&quot;&gt;最终方案&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 最后长这样：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#%PAM-1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---- Biopass 人脸认证（Plasma Login Manager 专用；失败自动回退密码）----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 钱包两行放在 sufficient 之后：人脸路径被它短路、根本走不到；&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 密码路径走到时 pam_unix 已经问完密码，此刻注入钱包密钥不影响认证结果。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        sufficient  libbiopass_pam.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_kwallet5.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_gnome_keyring.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account     include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;password    include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-password   optional    pam_gnome_keyring.so    use_authtok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     optional    pam_keyinit.so          force revoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_gnome_keyring.so    auto_start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 人脸路径的 auth 阶段被 sufficient 短路，kwallet5_key 没人放；&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 这一行在 session 阶段把它补上，解锁仍由下面的 pam_kwallet5 完成。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     optional    pam_session_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_kwallet5.so         auto_start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;与 09-25 那版的差别只有两处：钱包两行移到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后；
session 段加一行。&lt;/p&gt;
&lt;h2 id=&quot;安装&quot;&gt;安装&lt;/h2&gt;
&lt;p&gt;模块源码与安装脚本：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```c
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * pam_session_walletkey.c — 在 session 阶段把钱包口令喂给 pam_kwallet5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * ── 它解决什么问题 ─────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * plasmalogin 的 auth 栈：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     auth  sufficient  libbiopass_pam.so   &amp;lt;- 人脸成功即【终止整个 auth 栈】&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     auth  include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     -auth optional    pam_walletkey.so    &amp;lt;- 人脸路径到不了&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     -auth optional    pam_kwallet5.so     &amp;lt;- 人脸路径到不了&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * pam_kwallet5 是两段式设计：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     auth 阶段：pam_get_item(PAM_AUTHTOK) -&amp;gt; pam_set_data(&quot;kwallet5_key&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     session 阶段：pam_get_data(&quot;kwallet5_key&quot;) -&amp;gt; 派生密钥 -&amp;gt; 拉起 ksecretd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 人脸路径被 sufficient 短路后，auth 阶段没跑，session 阶段就只说&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     &quot;open_session called without kwallet5_key&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 然后钱包锁死、弹窗。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * ── 本模块的做法 ───────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 不重造 pam_kwallet5 的轮子（那要处理 ksecretd 的私有 pipe/socket 协议，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 实测 ksecretd 会因缺图形环境直接 SIGABRT）。改为在最合适的位置补上&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 缺失的那一环：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     在 session 阶段读 /etc/pam_walletkey.key，把口令用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     pam_set_data(pamh, &quot;kwallet5_key&quot;, …) 放进 PAM 句柄&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 只要本模块排在 pam_kwallet5 的 session 行【之前】，后面的 pam_kwallet5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 就会正常派生密钥并拉起 ksecretd —— 用 KDE 自己的、经过考验的实现。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * ── 幂等性 ─────────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 若 auth 阶段已经存过 kwallet5_key（密码登录路径），本模块直接跳过，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 不覆盖已存在的值。因此对密码路径是零影响，只补人脸路径的缺口。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * ── PAM 用法 ───────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *     session  optional  pam_session_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 安装位置：/usr/lib/security/pam_session_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 编译：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *   gcc -O2 -fPIC -shared -o pam_session_walletkey.so \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *       pam_session_walletkey.c $(pkg-config --cflags pam 2&amp;gt;/dev/null)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * SPDX-License-Identifier: MIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;syslog.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;sys/stat.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;pwd.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;security/pam_modules.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;security/_pam_types.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; KEYFILE_DEFAULT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;/etc/pam_walletkey.key&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; MAXKEY&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;          1024&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; DATA_KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        &quot;kwallet5_key&quot;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   /* 必须与 pam_kwallet.c 的 kwalletPamDataKey 一致 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    volatile&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        *(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* pam_set_data 的清理回调：PAM 释放句柄时擦除我们放进去的口令 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cleanup_wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_handle_t&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; error_status&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;error_status&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        free&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; read_key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; size_t&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; bufsz&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; stat st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;S_ISREG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: cannot stat %s&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    /* 不检查 st_uid==0：PAM 在 user namespace 里读到的属主可能被映射，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;     * 检查会误判。真正要紧的是没有 group/other 权限。 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_mode &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;S_IRWXG &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; S_IRWXO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: %s has group/other perms (mode=%o) — refusing&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;               path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;7777&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    FILE &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; fopen&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;r&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: cannot open %s&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;fgets&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;bufsz&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        fclose&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: cannot read %s&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    fclose&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    size_t&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; strcspn&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\r\n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_EXTERN &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_sm_open_session&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_handle_t&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;                                   int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;keyfile &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; KEYFILE_DEFAULT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;strncmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;keyfile=&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;            keyfile &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_get_user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: cannot get user; skipping&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; passwd &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; getpwnam&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; pw&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw_uid &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        /* root 不需要解锁钱包 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    /* 幂等：auth 阶段已经存过就不动它（密码登录路径走这里） */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;existing &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_get_data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; DATA_KEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;existing&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; existing&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_INFO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;               &quot;pam_session_walletkey: %s already set by auth phase; leaving as-is&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; DATA_KEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    char&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;MAXKEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;read_key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;keyfile&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; sizeof(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   /* 绝不阻断登录 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;stored &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; strdup&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;stored&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_ERR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: out of memory&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_set_data&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; DATA_KEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; stored&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cleanup_wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;r &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_ERR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_session_walletkey: pam_set_data failed (rc=%d)&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; r&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        cleanup_wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; stored&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_INFO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;           &quot;pam_session_walletkey: injected wallet key into %s for user=%s (len=%zu)&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;           DATA_KEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; strlen&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;stored&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_EXTERN &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_sm_close_session&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_handle_t&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;                                    int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# install-session-walletkey.sh — 安装 pam_session_walletkey（session 阶段补 kwallet5_key）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ── 它解决什么问题 ──────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# plasmalogin 的 auth 栈里，libbiopass_pam.so 标着 sufficient：人脸成功即终止&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 整个 auth 栈。排在它后面的 pam_walletkey / pam_kwallet5 永远不执行，于是&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# pam_kwallet5 的 session 阶段拿不到 kwallet5_key，钱包照样弹窗。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 而把钱包两行挪到 sufficient 之前，pam_walletkey 会抢在 pam_unix 之前把&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# PAM_AUTHTOK 换成钱包密钥，密码登录被打死。两条路都通不了。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 解法是绕开 auth 阶段的顺序之争：认证方式定完以后，在 session 阶段把口令&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 直接补进 PAM 句柄，解锁仍由 KDE 自己的 pam_kwallet5 完成。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#     session  optional  pam_session_walletkey.so        &amp;lt;- 新增：补 kwallet5_key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#     -session optional  pam_kwallet5.so  auto_start     &amp;lt;- 原有：正常解锁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 幂等：auth 阶段已经存过（密码登录路径）则跳过，对密码路径零影响。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 用法：sudo bash install-session-walletkey.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# SPDX-License-Identifier: MIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;DEST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/usr/lib/security/pam_session_walletkey.so&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SRC&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/pam_session_walletkey.c&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OLD_HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/usr/local/libexec/kwallet-pam-unlock&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +%F&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $EUID &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-ne&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;需要 root，请用：sudo bash &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SRC&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;找不到 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SRC&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;===================================================================&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot; 安装 pam_session_walletkey（session 阶段补 kwallet5_key）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;===================================================================&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[1/6] 现场重编译并安装模块&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;gcc&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -O2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -fPIC&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -shared&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Wall&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Wextra&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/pam_session_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SRC&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;编译失败，中止&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0755&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/pam_session_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;DEST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/pam_session_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -la&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;DEST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[2/6] 移除早前那版 pam_exec 钩子（若装过）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;kwallet-pam-unlock&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;kwallet-pam-unlock&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.tmp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        mv&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.tmp&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        chown&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root:root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;: 已移除旧钩子&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;: 无旧钩子&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 顺手清掉那个跑不起来的 helper（源码留在归档里备查）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OLD_HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OLD_HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  已删除 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OLD_HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[3/6] 备份当前 PAM 文件&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[4/6] 在 pam_kwallet5 之前插入模块&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;PYEOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;MODULE_LINE = &quot;session     optional    pam_session_walletkey.so&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;for path in (&quot;/etc/pam.d/plasmalogin&quot;, &quot;/etc/pam.d/plasmalogin-autologin&quot;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    lines = open(path, encoding=&quot;utf-8&quot;).read().splitlines()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    if any(&quot;pam_session_walletkey.so&quot; in l for l in lines):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        print(f&quot;  {path}: 已存在，跳过&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    out, inserted = [], False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    for ln in lines:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        # 在 pam_kwallet5 的 session 行之前插入&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        s = ln.strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        if (not inserted) and s.startswith(&quot;-session&quot;) and &quot;pam_kwallet5.so&quot; in s:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;            out.append(MODULE_LINE)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;            inserted = True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        out.append(ln)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    if not inserted:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        # 没有 pam_kwallet5 的 session 行：追加到末尾&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        out.append(MODULE_LINE)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    open(path, &quot;w&quot;, encoding=&quot;utf-8&quot;).write(&quot;\n&quot;.join(out) + &quot;\n&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    print(f&quot;  {path}: 已插入&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;PYEOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    chown&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root:root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[5/6] 结果&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  --- &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ---&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;^\s*-?session&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;s/^/    /&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[6/6] 清掉可能残留的死 socket&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;-------------------------------------------------------------------&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; -un&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pgrep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ksecretd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 名下已跑着 ksecretd（钱包已解锁），无需处理&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    runtime_dir&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/run/user/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;runtime_dir&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/kwallet5.socket&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;runtime_dir&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/kwallet5.socket&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  已清理 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;runtime_dir&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/kwallet5.socket&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;runtime_dir&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 下没有残留 socket&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;===================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 下一步验证（三条路径都要走一遍，缺一条就可能漏掉一个入口）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   1. 注销 → 用【人脸】登录 → 观察是否还弹「KDE 密码库服务」&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   2. 注销 → 用【密码】登录 → 必须仍然正常（不能退化）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   3. 锁屏 → 用密码解锁   → 必须仍然正常&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 验证时留意日志中新模块的痕迹：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   journalctl -b 0 --no-pager | grep -E &apos;pam_session_walletkey|pam_kwallet5|ksecretd&apos; | tail -30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 回滚（一条命令）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   sudo cp -a /etc/pam.d/plasmalogin.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   sudo cp -a /etc/pam.d/plasmalogin-autologin.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;   sudo rm -f &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;DEST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;===================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;先确认模块能编译、且只依赖 libpam 与 libc：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;gcc&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -O2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -fPIC&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -shared&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Wall&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Wextra&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_session_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_session_walletkey.c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;nm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --defined-only&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_session_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_sm&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # → pam_sm_open_session / pam_sm_close_session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;nm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --undefined-only&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_session_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;               # 只应有 libc 与 libpam 的符号&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;脚本要做 root 权限的事（装模块、改两个 PAM 文件、备份），所以用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跑：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; install-session-walletkey.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;它会现场重编译、备份 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin{,-autologin}&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、
把新模块插到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 session 行之前。&lt;/p&gt;
&lt;h2 id=&quot;验证&quot;&gt;验证&lt;/h2&gt;
&lt;p&gt;新模块的两条分支都要在日志里看到，它们分别证密码路径与人脸路径：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --no-pager&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;pam_session_walletkey|pam_walletkey|pam_kwallet5|ksecretd&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -30&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# 人脸登录：auth 阶段被短路，本模块补上数据槽&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_session_walletkey: injected wallet key into kwallet5_key for user=neo (len=48)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:session): pam_kwallet5: pam_sm_open_session&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# 密码登录：auth 阶段已经存过，本模块跳过&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_walletkey: wallet key injected for user neo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_session_walletkey: kwallet5_key already set by auth phase; leaving as-is&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:session): pam_kwallet5: pam_sm_open_session&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;判据是两件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不再出现 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;open_session called without kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;三条路径都要走一遍：人脸登录、密码登录、锁屏密码解锁。
&lt;strong&gt;只验钱包那一条会漏掉密码路径&lt;/strong&gt; —— 前面那次配置就是这么漏掉 10 天的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;钱包解锁成功的标志：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5: final socket path: /run/user/1000/kwallet5.socket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;final socket path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;start_kwallet()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 被调用的痕迹。
随后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Failed to register with host portal ... Connection already associated with an application ID&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 xdg-desktop-portal 的注册冲突，
同一 app ID 已被旧实例占用，不影响钱包解锁。&lt;/p&gt;
&lt;p&gt;另外，读者要在自己机器上判断“钱包这次到底开没开”，可以看这两个东西：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ksecretd&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                              # 有人脸/密码登录后应该能看到它&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /run/user/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/kwallet5.socket&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;       # 存在且有监听者 = 已解锁&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;通用性&quot;&gt;通用性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本文的故障机制&lt;/strong&gt; —— ✅ 通用。任何“在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前往 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写值”的模块都会打死密码登录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 短路&lt;/strong&gt; —— ✅ 通用。它是 PAM 的调度语义，与发行版无关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个键名&lt;/strong&gt; —— ⚠️ 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet-pam&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的版本绑定，升级后要重新核对上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletPamDataKey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 作为 Secret Service&lt;/strong&gt; —— ⚠️ 本机是 Plasma 6 的默认守护进程。用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletd5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletd6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的环境，路径与 socket 名都不同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自建模块的必要性&lt;/strong&gt; —— ⚠️ 只在“钱包密钥与登录密码不同值、且要保留钱包静态加密”时才需要。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本文的 PAM 文件&lt;/strong&gt; —— ❌ 别整份照抄。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 闸门那些行是本机特有的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改动只涉及两个 PAM 文件与该模块，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/kde&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（锁屏）与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sshd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没动。&lt;/p&gt;
&lt;h3 id=&quot;旁支人脸为什么会突然不认&quot;&gt;旁支：人脸为什么会突然不认&lt;/h3&gt;
&lt;p&gt;同一时间段里人脸也失败过，那是另一个故障。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/com.ticklab.biopass/logs/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
里当天的记录：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[2026-10-05 12:40:12.792] [warning] FaceAuth: AI anti-spoofing detected spoof, score: 0.95140916&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[2026-10-05 12:40:31.196] [warning] FaceAuth: AI anti-spoofing detected spoof, score: 0.8837554&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[2026-10-05 11:46:19.760] [warning] FaceAuth: AI anti-spoofing detected spoof, score: 0.95708305&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;阈值是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;anti_spoofing.threshold: 0.8&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，真人被判成假体，而且这类失败不重试
（配置里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;retries: 5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 对反欺诈失败不生效）。
两天前的记录是正常的：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[2026-10-03 14:49:09.256] [debug] FaceAuth: AI anti-spoofing check passed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[2026-10-03 14:49:09.299] [debug] FaceAuth: Recognition PASSED | score=0.5531&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同样的相机和阈值，10-03 通过、10-05 判假。变化的原因没有查到，
推测是有其他人出现在镜头中。&lt;/p&gt;
&lt;h2 id=&quot;排错表&quot;&gt;排错表&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;密码登录失败，日志里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix(plasmalogin:auth): authentication failure&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 后面没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wallet key injected&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：登录界面根本没把密码交给 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，或是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_faillock&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 已经把这个用户锁了。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;faillock --user &amp;lt;用户名&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看计数；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -b | grep -E &apos;faillock|pam_unix\(plasmalogin&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 对齐时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密码登录失败，且失败前有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wallet key injected&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 又排到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 前面去了，密码被钱包密钥顶掉。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep -nE &apos;pam_walletkey|pam_unix&apos; /etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，钱包行必须在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;include system-login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人脸登录后仍弹「KDE 密码库服务」&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_session_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没执行，或没排在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -b | grep pam_session_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。没有任何输出说明这一行没生效；
有输出但仍是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;open_session called without kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，说明插入位置在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_session_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 报 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;has group/other perms ... refusing&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 权限被改宽了。模块按设计要求拒绝读它。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;chmod 600 /etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，属主 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;root:root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。模块不检查属主 UID，
因为在用户命名空间里读到的属主可能被映射。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;登录后钱包还是锁的，但日志一切正常&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/kwalletd/kdewallet.kwl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的密码与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的值不一致。&lt;/li&gt;
&lt;li&gt;怎么办：按 KWallet 的提示手动解锁一次，然后把钱包密码重设成密钥文件里的值；
两边一致之后再试一次登录。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;回滚&quot;&gt;回滚&lt;/h2&gt;
&lt;p&gt;只摘掉新增的那一行：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;/pam_session_walletkey/d&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/lib/security/pam_session_walletkey.so&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;回到安装前的完整状态（安装脚本留下的备份）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;日&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;期&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin.pre-sessionwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;日&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;期&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--caution&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;警告&lt;/p&gt;
&lt;p&gt;不要回滚到 09-25 那份配置（钱包两行在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前的那版）。
那份会让密码登录再次失效。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;尚未验证的地方&quot;&gt;尚未验证的地方&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 SIGABRT 原文&lt;/strong&gt;：没有采集到 stderr，“缺图形环境”是推断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反欺诈为什么在 10-05 突然误判&lt;/strong&gt;：没查明。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;故障期的失败次数&lt;/strong&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只保留到 10-05 中午，
09-25 到 10-05 之间的登录日志已经不在了，这段时间的失败次数无法从日志复核。
能复核的是机制：只要配置是那样，密码路径就不可能通过。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/linux-pam/linux-pam/blob/master/libpam/pam_dispatch.c&quot;&gt;https://github.com/linux-pam/linux-pam/blob/master/libpam/pam_dispatch.c&lt;/a&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与跳转的调度实现&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/linux-pam/linux-pam/blob/master/modules/pam_unix/pam_unix_auth.c&quot;&gt;https://github.com/linux-pam/linux-pam/blob/master/modules/pam_unix/pam_unix_auth.c&lt;/a&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 由 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_authtok()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写入&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://invent.kde.org/plasma/kwallet-pam/-/raw/master/pam_kwallet.c&quot;&gt;https://invent.kde.org/plasma/kwallet-pam/-/raw/master/pam_kwallet.c&lt;/a&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的写入与读取&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>PAM</category><category>KWallet</category><category>KDE Plasma</category><category>biopass</category><category>排查</category></item><item><title>人脸登录后的 KWallet 自动解锁</title><link>https://miprota.cc/posts/biopass-sudo-kwallet/</link><guid isPermaLink="true">https://miprota.cc/posts/biopass-sudo-kwallet/</guid><description>人脸认证证明了用户身份，却不会产生登录密码，因此标准 pam_kwallet5 拿不到 PAM_AUTHTOK。用一个只读密钥 PAM 模块把钱包密钥交给认证栈，保留 KWallet 加密并覆盖 sudo、polkit 和两条登录路径。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在很长一段时间里，虽然我已经利用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;biopass&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 实现了人脸识别登录，但是我的使用率却相当低。虽然人脸已经识别成功，桌面也进去了，但是 KWallet 却弹出解锁框提示输入密码。即便把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 往前挪一行，通常也不会解决问题。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS（Arch 系）｜KDE Plasma 6.7.5｜Plasma Login Manager 6.7.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wayland｜biopass-bin 1.4.1｜kwallet 6.30.0｜kwallet-pam 6.7.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gcc 16.2.1｜pam 1.7.2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机使用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 作为 Plasma 6 的 Secret Service 守护进程（它也是 kwallet-pam 6.7.5 编译时的默认守护进程），钱包名是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。磁盘没有 LUKS，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/crypttab&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为空，所以不存在“开机解锁磁盘时顺便拿到钱包密码”的条件。&lt;/p&gt;
&lt;p&gt;需要编译一个小模块，所以机器上要有 C 编译器和 PAM 开发头文件（Arch 系在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 包里）。下面的 PAM 文件路径、用户名和密钥路径都是示例，实际安装前先确认发行版的 PAM 包、登录管理器和钱包版本；不要把本机的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 配置原样覆盖到另一台机器。&lt;/p&gt;
&lt;h2 id=&quot;现象&quot;&gt;现象&lt;/h2&gt;
&lt;p&gt;人脸登录成功后，PLM 的日志里能看到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走到了 session 阶段，但紧接着是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pam_kwallet5(plasmalogin:session): open_session called without kwallet5_key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同一会话里还有两条旁证：环境变量 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_KWALLET5_LOGIN&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不存在，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/run/user/&amp;lt;uid&amp;gt;/kwallet5.socket&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也不存在。这两样是钱包解锁成功才会有的东西。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 钱包到底开没开（true = 已解锁）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;busctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; call&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; org.kde.kwalletd6&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /modules/kwalletd6&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  org.kde.KWallet&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; isOpen&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kdewallet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -i&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_kwallet5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;先把认证栈和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的取值路径对上，再决定要不要改钱包密码。&lt;/p&gt;
&lt;h2 id=&quot;pam-的两段auth-与-session&quot;&gt;PAM 的两段：auth 与 session&lt;/h2&gt;
&lt;p&gt;要理解钱包为什么不开，得先分清 PAM 里两个阶段各自发生什么。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的工作是分开的（下面按官方 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet.c&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的行为描述）：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;auth 阶段&lt;/strong&gt;——拿密码，存起来：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_item(PAM_AUTHTOK)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 取当前认证口令；&lt;/li&gt;
&lt;li&gt;为空的话它会尝试自己弹窗问一次；&lt;/li&gt;
&lt;li&gt;还是空，就直接返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，源码里的日志原文是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Empty or missing password, doing nothing&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;拿到了，就用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_set_data(&quot;kwallet5_key&quot;, 密码)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 把它挂在 PAM handle 上。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;session 阶段&lt;/strong&gt;（配置行里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auto_start&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）——用密码开钱包：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把上一步的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 取出来；&lt;/li&gt;
&lt;li&gt;拿 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/kwalletd/kdewallet.salt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 当盐，做 PBKDF2（SHA512，50000 轮，输出 56 字节）派生钱包密钥；&lt;/li&gt;
&lt;li&gt;以用户身份拉起 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd --pam-login &amp;lt;管道&amp;gt; &amp;lt;套接字&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，把密钥写进管道，完成解锁。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关键在第一步和第二步之间的&lt;strong&gt;唯一桥梁就是那串密码&lt;/strong&gt;。也就是说，钱包的密码必须等于 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的东西，否则派生出来的密钥打不开钱包文件。这是后面所有方案的出发点。&lt;/p&gt;
&lt;h2 id=&quot;钱包为什么拿不到密码&quot;&gt;钱包为什么拿不到密码&lt;/h2&gt;
&lt;h3 id=&quot;sufficient-会把后面的模块整组跳过&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会把后面的模块整组跳过&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;man pam.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 对 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的定义是：该模块成功时，如果前面没有 required 模块失败，PAM 立即向应用返回成功，&lt;strong&gt;跳过本组剩余模块&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本机原始的授权栈顺序是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auth sufficient libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; ← 人脸成功，授权栈就地结束&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auth include system-login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_unix&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 密码）&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-auth optional pam_kwallet5.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; ← 永远走不到&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以只要刷脸成功，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 auth 钩子根本不执行，密码也就没机会被存下来给 session 阶段用。&lt;/p&gt;
&lt;h3 id=&quot;就算把顺序调过来人脸也交不出密码&quot;&gt;就算把顺序调过来，人脸也交不出密码&lt;/h3&gt;
&lt;p&gt;把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 挪到 biopass 前面，它能执行了，但 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_item(PAM_AUTHTOK)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 仍然取不到东西。原因在 biopass 的 PAM 模块（按符号表核对）：它只调用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_item&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_user&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，然后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fork&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;execl(&quot;/usr/bin/biopass-helper&quot;, &quot;--service&quot;, &amp;lt;服务名&amp;gt;, &quot;--username&quot;, &amp;lt;用户&amp;gt;, &quot;auth&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;strong&gt;从头到尾没有调用过 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_set_item&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;人脸识别不产生任何可交给钱包的字符串。所以我们可以得出结论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;人脸或指纹登录 + 标准 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; = 钱包无法自动解锁。&lt;/strong&gt; 除非密码从别处来——用户手输，或者我们自己注入。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;官方与社区结论一致。&lt;a href=&quot;https://wiki.archlinux.org/title/KDE_Wallet&quot;&gt;Arch Wiki 的 KDE Wallet 条目&lt;/a&gt;明确列出这条限制（用指纹读卡器登录时钱包无法解锁），并说明自动解锁的前提是钱包名 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、blowfish 加密、且&lt;strong&gt;钱包密码等于用户登录密码&lt;/strong&gt;。KDE bug &lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=468069&quot;&gt;468069&lt;/a&gt;（CONFIRMED）还表明，即使在“钱包密码为空 + 没有 PAM 凭据”的情况下，KDE 也不保证自动打开钱包。&lt;/p&gt;
&lt;h2 id=&quot;两条错误路径&quot;&gt;两条错误路径&lt;/h2&gt;
&lt;h3 id=&quot;只移动-pam_kwallet5&quot;&gt;只移动 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;这只能解决 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 提前结束的问题，不能创造 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。如果日志从“模块没执行”变成“没有密码”，根因仍然是同一个。&lt;/p&gt;
&lt;h3 id=&quot;借用-luks-的开机密码&quot;&gt;借用 LUKS 的开机密码&lt;/h3&gt;
&lt;p&gt;有些方案让磁盘解密密码和钱包密码相同，再由 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_systemd_loadkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 转交给钱包。本机 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/crypttab&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为空，磁盘没有 LUKS，这条路径没有可借用的密钥。&lt;/p&gt;
&lt;h2 id=&quot;方案选择&quot;&gt;方案选择&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;th&gt;代价&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;清空钱包密码&lt;/td&gt;
&lt;td&gt;不再需要输入密码&lt;/td&gt;
&lt;td&gt;钱包文件等同未加密&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;保持现状&lt;/td&gt;
&lt;td&gt;登录后手动解锁&lt;/td&gt;
&lt;td&gt;每次都要输一次密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自建 PAM 模块&lt;/td&gt;
&lt;td&gt;注入独立密钥，保留加密&lt;/td&gt;
&lt;td&gt;多维护一个模块，密钥须由 root 保护&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;本机采用第三种，理由是希望保留钱包文件的静态加密：非 root 的攻击者即使拿到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet.kwl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也解不开。而“清空密码”那条路等于把钱包变成明文文件，任何人读到你的家目录或备份都能拿到里面的 WiFi 密码、浏览器登录态和令牌。&lt;/p&gt;
&lt;p&gt;第三种方案的三条设计边界：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;密钥和登录密码不是同一个值。&lt;/strong&gt; 钱包改用一个随机长串，登录密码照旧。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密钥只存在于 root 可读的文件里。&lt;/strong&gt; 普通用户读不到，模块本身也不打印它。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块读不到密钥时返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，钱包回到手动解锁。&lt;/strong&gt; 不能因为钱包配置错误把用户锁在登录界面外。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;自建模块做什么&quot;&gt;自建模块做什么&lt;/h2&gt;
&lt;p&gt;模块只做一件事：把一个受保护文件的第一行写进 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。它要满足的校验条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;路径存在，而且是&lt;strong&gt;普通文件&lt;/strong&gt;（不是符号链接、不是目录）；&lt;/li&gt;
&lt;li&gt;属主必须是 &lt;strong&gt;root&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;group 和 other &lt;strong&gt;不能有任何权限位&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;内容不能为空；&lt;/li&gt;
&lt;li&gt;写进 PAM 之后立刻清掉本地临时缓冲区。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任何一条不满足，就记一条警告日志并返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，绝不阻断登录。PAM 行上的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;optional&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 控制位是第二层保险。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```c
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * pam_walletkey.so — 把 root 只读密钥文件中的 KWallet 密码注入 PAM_AUTHTOK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 用途：biopass（人脸/指纹）登录不会产生密码，导致 pam_kwallet5 拿不到&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *      PAM_AUTHTOK，KWallet 无法自动解锁。本模块在 auth 阶段把预先约定的&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *      钱包密码写入 PAM_AUTHTOK，紧随其后的 pam_kwallet5 即可正常存下并&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *      在 session 阶段解锁 kdewallet。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 安装位置：/usr/lib/security/pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 密钥文件：/etc/pam_walletkey.key （root:root 0600，单行，仅含钱包密码）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * PAM 用法：-auth optional pam_walletkey.so [keyfile=/path]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * 失败时一律返回 PAM_IGNORE，绝不阻断登录（配合 optional 控制位双保险）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; * SPDX-License-Identifier: MIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;syslog.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;sys/stat.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;pwd.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;security/pam_modules.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;security/_pam_types.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; PAM_WALLETKEY_DEFAULT_FILE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;/etc/pam_walletkey.key&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; PAM_WALLETKEY_MAX&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;          1024&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    volatile&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        *(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* 读取并校验密钥文件，成功返回 0 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; read_key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; size_t&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; bufsz&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; stat st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;S_ISREG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    /* 必须是 root 所有，且不允许 group/other 有任何权限 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_uid &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;st_mode &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;S_IRWXG &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; S_IRWXO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    FILE &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; fopen&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;r&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;fgets&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;bufsz&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        fclose&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    fclose&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    size_t&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; strcspn&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\r\n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    buf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_EXTERN &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_sm_authenticate&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_handle_t&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;keyfile &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_WALLETKEY_DEFAULT_FILE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;strncmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;keyfile=&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;            keyfile &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_get_user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    /* root 不需要钱包解锁，直接跳过 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; passwd &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; getpwnam&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; pw&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pw_uid &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    char&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_WALLETKEY_MAX&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; rc &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; read_key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;keyfile&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; sizeof(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;rc &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;               &quot;pam_walletkey: cannot use key file %s (rc=%d); wallet unlock left to user&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;               keyfile&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; rc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_set_item&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; PAM_AUTHTOK&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    wipe&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;r &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_walletkey: pam_set_item(PAM_AUTHTOK) failed (rc=%d)&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; r&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_IGNORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    syslog&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;LOG_DEBUG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;pam_walletkey: wallet key injected for user %s&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_EXTERN &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pam_sm_setcred&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pam_handle_t&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pamh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;flags&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; PAM_SUCCESS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;几处实现细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;S_ISREG&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 检查挡住了符号链接和特殊文件。&lt;/strong&gt; 少了它，攻击者可以用一个指向 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/dev/zero&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 或别人可写文件的路径把密钥内容变成别的字符串。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;st_uid != 0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加权限位检查缺一不可。&lt;/strong&gt; 只查属主不查权限，一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;0644&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 root 文件仍然人人可读。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getpwnam&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跳过 root 用户。&lt;/strong&gt; root 不需要解锁钱包，让它也走一遍只会多一次无谓的文件读取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_user&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 失败就返回。&lt;/strong&gt; 拿不到用户名说明 PAM 上下文不对，此时继续没有意义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wipe()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;volatile char *&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写零。&lt;/strong&gt; 不加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;volatile&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，编译器有权把这段“写了没人读”的循环优化掉，密钥就会留在栈上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;syslog&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只打返回码，不打密钥。&lt;/strong&gt; 日志会进 journal，任何会记录密钥内容的东西都不该出现在这里。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_setcred&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是个空实现，直接返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_SUCCESS&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。PAM 加载模块时会找这个符号，不提供会报错，但本方案在 setcred 阶段确实无事可做。&lt;/p&gt;
&lt;h2 id=&quot;安装&quot;&gt;安装&lt;/h2&gt;
&lt;p&gt;分三步：编译模块、生成密钥、跑安装脚本。&lt;/p&gt;
&lt;h3 id=&quot;1-编译模块&quot;&gt;1. 编译模块&lt;/h3&gt;
&lt;p&gt;把上面的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey.c&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 存到某个目录，然后：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;gcc&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -shared&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -fPIC&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -O2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_walletkey.c&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;不需要 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-lpam&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。本机实测编译出的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里未定义的符号只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_get_user&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_set_item&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 两个 PAM 符号（其余都是 libc），它们由宿主 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libpam&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在加载时提供：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;nm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --undefined-only&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_walletkey.so&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 期望只看到 pam_get_user / pam_set_item&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-生成钱包密钥&quot;&gt;2. 生成钱包密钥&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;openssl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -base64&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 24&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wallet-key.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wallet-key.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;这个文件在安装时会被装到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;root:root 0600&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。它&lt;strong&gt;不要进 Git、不要贴进文章、不要出现在任何脚本参数或日志里&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;3-把-kwallet-的钱包密码改成这个密钥&quot;&gt;3. 把 KWallet 的钱包密码改成这个密钥&lt;/h3&gt;
&lt;p&gt;这一步要在图形界面里做，而且必须在安装脚本之前完成——否则 PAM 注入的密钥和钱包密码对不上，派生出的密钥打不开钱包，症状仍然是“弹框问密码”。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletmanager&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → 更改密码 → 新密码两栏填入 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wallet-key.txt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内容。&lt;/p&gt;
&lt;h3 id=&quot;4-跑安装脚本&quot;&gt;4. 跑安装脚本&lt;/h3&gt;
&lt;p&gt;脚本把下面这些改动一次做完，并且是幂等的，重复运行不会重复插入：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# biopass + sudo/polkit 人脸认证 + pam_walletkey 安装脚本&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： sudo bash install.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 安装内容：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   1. /usr/lib/security/pam_walletkey.so        （自建 PAM 模块，把钱包密钥注入 PAM_AUTHTOK）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   2. /etc/pam_walletkey.key                    （root:root 0600，钱包密码；需与 KWallet 密码一致）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   3. /etc/pam.d/sudo                           （顶部插入 biopass sufficient 行）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   4. /etc/pam.d/plasmalogin                    （pam_walletkey + pam_kwallet5 上移到 biopass 之前）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   5. /etc/pam.d/polkit-1                       （polkit/pkexec 走 biopass）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   6. /etc/systemd/system/polkit-agent-helper@.service.d/override.conf （放开摄像头设备）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 幂等：可重复运行；每次运行都会把原文件备份到 /var/backups/biopass-kwallet-&amp;lt;时间戳&amp;gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +%Y%m%d-%H%M%S&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/var/backups/biopass-kwallet-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/pam.d/sudo&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLASMALOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/pam.d/plasmalogin&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;POLKIT_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/pam.d/polkit-1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/systemd/system/polkit-agent-helper@.service.d&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;EUID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -ne&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：请用 root 运行 → sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：缺少交付文件 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wallet-key.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin.pam.new&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit-1.pam.new&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;need&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit-agent-helper-override.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 备份到 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLASMALOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;POLKIT_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;basename&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    完成后如出问题：sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/rollback.sh&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [1/6] 安装 pam_walletkey.so 与钱包密钥&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0755&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/pam_walletkey.so&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/lib/security/pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0600&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/wallet-key.txt&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam_walletkey.key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    /etc/pam_walletkey.key 已就位（请确保它与 KWallet 钱包密码完全一致）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [2/6] 为 sudo 添加 biopass 认证（幂等）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -qE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^[[:space:]]*auth[[:space:]]+sufficient[[:space:]]+libbiopass_pam\.so&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已存在，跳过&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;BEGIN{done=0}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;         /^[[:space:]]*auth[[:space:]]/ &amp;amp;&amp;amp; !done {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;             print &quot;auth\t\tsufficient\tlibbiopass_pam.so&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;             print &quot;# biopass: 人脸认证成功即免密；失败自动回退下方 system-auth 的密码认证&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;             done=1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;         }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;         { print }&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已插入&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [3/6] 更新 plasmalogin 的 PAM 栈（pam_walletkey + pam_kwallet5 前置）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin.pam.new&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLASMALOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [4/6] 让 polkit / pkexec 走 biopass&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/polkit-1.pam.new&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;POLKIT_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [5/6] 安装 polkit-agent-helper systemd override（放开摄像头设备）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/polkit-agent-helper-override.conf&quot;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/override.conf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [6/6] 重载 systemd 并重启 polkit&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; restart&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 完成。请在【新终端】中验证（本终端不要关）：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    sudo -k; sudo true          # 预期：人脸识别通过 → 直接执行&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    pkexec id                   # 预期：弹窗中出现 biopass 人脸识别&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  验证钱包：注销后用 biopass 登录，然后执行&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    journalctl -b -u plasmalogin | grep -i pam_kwallet5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  预期不再出现 &apos;open_session called without kwallet5_key&apos;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  回滚： sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/rollback.sh&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; biopass-install.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;它会在动手前把原文件备份到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/var/backups/biopass-kwallet-&amp;lt;时间戳&amp;gt;/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。执行前先另开一个 root 终端放着别关。&lt;/p&gt;
&lt;h2 id=&quot;登录路径plasmalogin&quot;&gt;登录路径：plasmalogin&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 greeter 登录用的 PAM 服务。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 必须位于 biopass 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 行&lt;strong&gt;之前&lt;/strong&gt;，这是整件事的根因所在：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#%PAM-1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---- Biopass 人脸认证（Plasma Login Manager 专用；失败自动回退密码）----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# pam_walletkey（自建模块）先把 KWallet 密码从 /etc/pam_walletkey.key 注入 PAM_AUTHTOK，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 再由 pam_kwallet5 存入 pam_set_data，session 阶段才能真正解锁 kdewallet。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 因此这两行必须放在 biopass 的 sufficient 行之前（sufficient 成功会终止整个 auth 栈）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_kwallet5.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        sufficient  libbiopass_pam.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_gnome_keyring.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account     include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;password    include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-password   optional    pam_gnome_keyring.so    use_authtok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     optional    pam_keyinit.so          force revoke&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     include     system-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_gnome_keyring.so    auto_start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_kwallet5.so         auto_start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;auth 阶段注入的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTHTOK&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会被 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 保存下来，session 阶段才能拿到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，然后解锁 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;如果同时使用 PLM Autologin，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也要放入同样的两行；那条路径上的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 人脸闸门和 fail-closed 顺序见&lt;a href=&quot;/posts/plasmalogin-autologin-face/&quot;&gt;PLM 免按键人脸登录&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&quot;sudo&quot;&gt;sudo&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的改动只有一行，插在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# /etc/pam.d/sudo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#%PAM-1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        sufficient  libbiopass_pam.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# biopass：人脸认证成功即免密；失败自动回退下方 system-auth 的密码认证&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account     include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     optional    pam_systemd.so &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;放在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之前而不是改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 本身，影响面最小：只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走人脸，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;su&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sshd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 全都不变。人脸成功即免密；人脸失败、取消或没有摄像头，都会正常回落到下面的密码提示。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的时间戳保持默认（15 分钟，按 tty 和父进程记）。第一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo -k; sudo true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会做人脸认证，缓存有效期内的后续命令不会重复调用摄像头。&lt;/p&gt;
&lt;h2 id=&quot;polkit-与-pkexec&quot;&gt;polkit 与 pkexec&lt;/h2&gt;
&lt;p&gt;polkit 在默认配置里是&lt;strong&gt;用不了&lt;/strong&gt;人脸的两处都要改，只改 PAM 文件不够。&lt;/p&gt;
&lt;h3 id=&quot;1-pam-服务&quot;&gt;1. PAM 服务&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/polkit-1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆盖包内的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/polkit-1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（前者优先）。注意上游那份里本来就有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;password include system-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，改写时不要漏掉：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#%PAM-1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# polkit / pkexec 的 PAM 服务：先试 biopass 人脸，失败自动回退密码。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 本文件覆盖 /usr/lib/pam.d/polkit-1（/etc/pam.d 优先级更高）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 注意：还需要 systemd override（polkit-agent-helper-override.conf）放开摄像头设备，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#       并在 biopass 配置里把 polkit-1 / pkexec 从 ignore_services 移除。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth       sufficient  libbiopass_pam.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth       include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account    include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;password   include     system-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session    include     system-auth&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-systemd-drop-in放开摄像头设备&quot;&gt;2. systemd drop-in：放开摄像头设备&lt;/h3&gt;
&lt;p&gt;这一条容易漏，但它决定成败。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;polkit-agent-helper@.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 默认带 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PrivateDevices=yes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，进程在自己的设备命名空间里看不到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/dev/video*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。biopass 拿不到摄像头，人脸自然失败：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# biopass 需要访问摄像头（polkit-agent-helper 默认 PrivateDevices=yes 会屏蔽 /dev/video*）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;PrivateDevices&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;DevicePolicy&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;DeviceAllow&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;char-video4linux rw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;DeviceAllow&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;char-media rw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;DeviceAllow&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;char-drm rw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;DeviceAllow&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;/dev/uinput rw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 允许 biopass 把日志写到 ~/.local/share/com.ticklab.biopass/logs/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ProtectHome&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ProtectHome=no&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是为了让 biopass 能往 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/com.ticklab.biopass/logs/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写日志；不加也能认证，只是丢日志。&lt;/p&gt;
&lt;h3 id=&quot;3-让-biopass-别再忽略-polkit&quot;&gt;3. 让 biopass 别再忽略 polkit&lt;/h3&gt;
&lt;p&gt;biopass 默认把 polkit 相关服务排除在外，要把它从忽略列表里去掉。改的是用户自己的配置：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ~/.config/com.ticklab.biopass/config.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;strategy:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ignore_services:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; []&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机改动前这一项是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[polkit-1, pkexec]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。改完重启 polkit：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; restart&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;验证结果&quot;&gt;验证结果&lt;/h2&gt;
&lt;p&gt;每改一层就验证一层，出了问题容易回到上一步：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# sudo：人脸通过应成功，失败应回到密码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -k&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# polkit：确认 pkexec 走的是同一套人脸配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pkexec&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 登录后的钱包状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;busctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; call&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; org.kde.kwalletd6&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /modules/kwalletd6&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  org.kde.KWallet&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; isOpen&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kdewallet&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机验证结果如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 人脸通过时无需密码，未识别时回退密码；TTY（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ctrl+Alt+F3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）下也能用；&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkexec id&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 返回 root 身份（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;uid=0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），未输入密码；&lt;/li&gt;
&lt;li&gt;autologin 和 greeter 两条登录路径都执行了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 auth 和 session 阶段；&lt;/li&gt;
&lt;li&gt;日志中不再出现 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;open_session called without kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（0 条），取而代之的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_authenticate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_sm_open_session&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，且 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_KWALLET5_LOGIN=/run/user/&amp;lt;uid&amp;gt;/kwallet5.socket&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与套接字都存在；&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;isOpen(&quot;kdewallet&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，整个登录过程没有再次输入钱包密码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;钱包还是不自动解锁，日志里仍有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;without kwallet5_key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 排在了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 成功就跳过了它们。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep -nE &apos;pam_walletkey|pam_kwallet5|libbiopass&apos; /etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，确认顺序是 walletkey → kwallet5 → biopass。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密钥对了，但钱包还是打不开&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：KWallet 里的钱包密码和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内容不一致（哪怕差一个换行）。&lt;/li&gt;
&lt;li&gt;怎么办：模块会剥掉行尾的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;\r&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;/&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;\n&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，但不会 trim 空格。重设一次钱包密码，确保是同一串字符。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志里出现 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey: key file rejected (rc=-2)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的属主或权限不对（必须是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;root:root 0600&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ls -l /etc/pam_walletkey.key&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，然后用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;install -m 0600 -o root -g root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 重装一次。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按网上说法加了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletd=/usr/bin/ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 参数，没变化&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：本机 kwallet-pam 6.7.5 编译时的默认守护进程已经是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/bin/ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，这个参数是多余的。&lt;/li&gt;
&lt;li&gt;怎么办：去掉它。要紧的是钱包名 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdewallet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和钱包密码。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkexec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 还是弹密码框&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：三处改动少了一处——PAM 文件、systemd drop-in、biopass 的忽略列表。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl show polkit-agent-helper@.service -p PrivateDevices&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 应返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;no&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；再确认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ignore_services&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;polkit-1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkexec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 变慢了&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：人脸单次判定约 2 秒；第一次没在 2 秒内正对镜头就会回落到密码。&lt;/li&gt;
&lt;li&gt;怎么办：在 biopass 图形界面里调大 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;methods.face.retries&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 或 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;retry_delay&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。终端里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走 biopass 时没有摄像头预览窗口，看不到“正在识别”的反馈，这是第一次容易失败的主要原因。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;通用性&quot;&gt;通用性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“人脸不产生密码”这条限制&lt;/strong&gt; —— ✅ 所有走 PAM 的生物识别模块都一样。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sufficient&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会跳过后续模块&lt;/strong&gt; —— ✅ Linux-PAM 的固定语义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块的校验逻辑与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 兜底&lt;/strong&gt; —— ✅ 与发行版无关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;钱包密码必须等于注入的密钥&lt;/strong&gt; —— ✅ 硬性要求，任何方案都绕不过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;polkit 需要 systemd drop-in&lt;/strong&gt; —— ✅ &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PrivateDevices=yes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是上游默认值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;钱包名、盐文件路径、PBKDF2 参数&lt;/strong&gt; —— ⚠️ 由具体的 pam_kwallet 版本决定，换版本要复核。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认守护进程是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; —— ⚠️ kwallet-pam 6.7.5 的编译默认值，更早的版本可能是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletd5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的具体路径与内容&lt;/strong&gt; —— ⚠️ 发行版差异；本机是 Arch 系的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;system-login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 体系。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;回滚&quot;&gt;回滚&lt;/h2&gt;
&lt;p&gt;回滚脚本会还原三份 PAM 文件、移除自建模块与密钥文件、删掉 polkit 的 override，并重启 polkit：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 回滚脚本：撤销 install.sh 的所有系统改动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： sudo bash rollback.sh [备份目录]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#          不给参数时自动使用 /var/backups/biopass-kwallet-* 中最新的一份&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/systemd/system/polkit-agent-helper@.service.d&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;EUID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -ne&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：请用 root 运行 → sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $# &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-ge&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -1dt /var/backups/biopass-kwallet-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：找不到备份目录，请手动指定：sudo bash rollback.sh /var/backups/biopass-kwallet-YYYYmmdd-HHMMSS&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 使用备份：&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 还原 PAM 配置&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit-1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;/etc/pam.d/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    /etc/pam.d/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 已还原&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;polkit-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d/polkit-1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    /etc/pam.d/polkit-1（本次新建）已删除，回落 /usr/lib/pam.d/polkit-1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 移除自建模块与钱包密钥&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/lib/security/pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam_walletkey.key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 还原 polkit-agent-helper override&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/polkit-agent-helper@.service.d&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/polkit-agent-helper@.service.d/.&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已还原原有 override&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -rf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OVERRIDE_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已删除本次新增的 override 目录&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 重载 systemd 并重启 polkit&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; restart&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;EOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;==&amp;gt; 回滚完成。请注意两件事：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    1) KWallet 密码仍是安装时设置的随机密钥：请在 kwalletmanager 里把钱包密码改回你自己记得的值。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    2) biopass 的「忽略服务」列表请手动把 polkit-1 / pkexec 加回去&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;       （~/.config/com.ticklab.biopass/config.yaml 的 strategy.ignore_services）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; biopass-rollback.sh&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 不给参数 = 用最新那份备份&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;跑完之后还有两件事脚本没法替你做，它在结尾也会提醒：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;KWallet 的密码仍是那串随机密钥&lt;/strong&gt;，要在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kwalletmanager&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里改回你自己记得的值；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;biopass 的忽略列表要把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;polkit-1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkexec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加回去&lt;/strong&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/com.ticklab.biopass/config.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strategy.ignore_services&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;方案的安全边界很明确：root 能读到密钥，就能解锁这个钱包；普通用户不能读密钥文件。它保留了钱包文件的静态加密，但没有把 PAM 变成密钥管理系统。&lt;/p&gt;
&lt;h2 id=&quot;长期维护&quot;&gt;长期维护&lt;/h2&gt;
&lt;p&gt;这次改动会在系统升级时被绕过，而且两类文件的表现不一样，处理方式也不同。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;包自己拥有的文件会生成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.pacnew&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 属于 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 包，升级时 pacman 会把它另存为 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/sudo.pacnew&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：新版本里没有我们插入的那一行，需要手动合回去。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我们自己新建的文件不会有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.pacnew&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，但上游默认值会变。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/polkit-1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 都不属于任何包（它们的上游版本在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下），所以 pacman 不会碰它们。代价是包更新后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那份变了，我们的文件不会跟着变，也不会有人提醒。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 1) 有没有 pacnew&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; find&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/pam.d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;*.pacnew&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2) 我们改过的文件和上游默认值差在哪&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; polkit-1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;--- &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    diff&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;/usr/lib/pam.d/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;/etc/pam.d/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--warning&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;注意&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;install.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只对 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是“插入一行”的幂等操作；对另外三个文件是&lt;strong&gt;整份覆盖&lt;/strong&gt;，不是合并。上游默认值如果新增了模块或参数，重跑脚本会把它们丢掉。所以升级后先 diff，再决定是重跑脚本还是手工把那几行合进去。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上面这些路径是 Arch 系的布局（上游默认放 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。别的发行版可能把上游默认直接放在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里，那时它们&lt;strong&gt;会&lt;/strong&gt;产生 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.pacnew&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，第 2 步的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;diff&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也就没有意义了。&lt;/p&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/KDE_Wallet&quot;&gt;KDE Wallet：Arch Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://invent.kde.org/plasma/kwallet-pam/-/blob/master/pam_kwallet.c&quot;&gt;kwallet-pam 源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TickLabVN/biopass/blob/main/docs/PAM.md&quot;&gt;biopass PAM 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TickLabVN/biopass/blob/main/docs/Polkit.md&quot;&gt;biopass Polkit 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/linux-pam/linux-pam/blob/master/libpam/pam_dispatch.c&quot;&gt;Linux-PAM 调度实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=468069&quot;&gt;KDE bug 468069（空钱包密码 + 无 PAM 凭据时不自动打开）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>KWallet</category><category>pam_kwallet5</category><category>PAM</category><category>biopass</category><category>sudo</category><category>polkit</category><category>KDE Plasma</category></item><item><title>PLM 免按键人脸登录</title><link>https://miprota.cc/posts/plasmalogin-autologin-face/</link><guid isPermaLink="true">https://miprota.cc/posts/plasmalogin-autologin-face/</guid><description>Plasma Login Manager 没有让 greeter 自动开始认证的配置。用 Autologin 加一道人脸闸门，开机后通过人脸即可零按键进入桌面，失败则回到正常登录界面。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Plasma Login Manager（PLM）的登录界面里，人脸认证要先按 Enter，或者点击登录按钮。Windows Hello 式的“看向摄像头就开始识别”没有对应的配置开关。所以我多少有点标题党了，为了实现这个效果，我没有在 PLM 上死磕，而是转而使用了其他方法。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS（Arch 系）｜KDE Plasma 6.7.5｜Plasma Login Manager 6.7.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wayland｜biopass-bin 1.4.1｜pam 1.7.2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机 biopass 只开人脸（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;methods.face.enable: true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，指纹关闭），单次判定约 2 秒。下面所有配置里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;用户名&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是占位符，安装前换成你自己的登录名。&lt;/p&gt;
&lt;p&gt;整套改动落在三个地方，没有新增守护进程，也不需要编译任何东西：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/local/libexec/biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;人脸闸门包装脚本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;覆盖上游的放行式 PAM 栈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/plasmalogin.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Autologin]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 段指定登录用户&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;现象&quot;&gt;现象&lt;/h2&gt;
&lt;p&gt;在 greeter 前坐定、把脸对着摄像头，界面不会有任何反应，必须先按一次 Enter 或点一次登录按钮，识别才开始。识别本身没问题：一次通过、约 2 秒进桌面。缺的是&lt;strong&gt;谁来发起这次认证&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;greeter-为什么不自动认证&quot;&gt;greeter 为什么不自动认证&lt;/h2&gt;
&lt;p&gt;上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/frontend/greeter/qml/Login.qml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（6.7）里，能发起认证的入口只有三个：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;qml&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```qml
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;passwordBox.onAccepted:            startLogin()   &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// 密码框回车&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;loginButton.onClicked:             startLogin()   &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// 点登录按钮&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;loginButton.Keys.onReturnPressed:  clicked()      &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// 按钮聚焦时回车&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;而负责初始化界面的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Component.onCompleted&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只做三件事：填充上次登录的用户名、把焦点放到密码框、同步界面状态。它&lt;strong&gt;没有&lt;/strong&gt;调用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;startLogin()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;想加一个触发点也走不通：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有可替换的主题。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/frontend/greeter/CMakeLists.txt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ecm_add_qml_module(plasma-login-greeter URI &quot;org.kde.plasma.login&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ecm_target_qml_sources(...)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Main.qml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Login.qml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这些文件编进了二进制资源；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/frontend/settings/models/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sessionmodel&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;usermodel&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。SDDM 那种“放一个主题目录就换掉整个界面”的做法在这里不存在。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有对应配置键。&lt;/strong&gt; 上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/common/mainconfig.kcfg&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（6.7）里的键是全部：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;X11.*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Wayland.SessionLogFile&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Autologin.User/Session/Relogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;General.Namespaces&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Users.DefaultPath&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;AutoAuth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Biometric&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;AutoStartAuth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这一类键一个都没有。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以这是当前设计，不是配置写错了。改 greeter 配置或主题都不会凭空多出一个认证触发点。&lt;/p&gt;
&lt;h2 id=&quot;为什么不能直接把-biopass-标成-required&quot;&gt;为什么不能直接把 biopass 标成 required&lt;/h2&gt;
&lt;p&gt;在动手前得先绕开一个坑，它决定后面为什么用一个包装脚本而不是直接引用 biopass 的 PAM 模块。&lt;/p&gt;
&lt;p&gt;biopass 的 PAM 模块（上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auth/pam/pam.cc&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）把助手的退出码映射成三种 PAM 返回值：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;helper 退出码&lt;/th&gt;
&lt;th&gt;PAM 返回值&lt;/th&gt;
&lt;th&gt;什么时候出现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_SUCCESS&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;人脸匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;跑不起来：摄像头打不开、模型缺失、该用户无人脸&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;其他非 0&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_AUTH_ERR&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;人脸不匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;问题出在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上。Linux-PAM 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_dispatch.c&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;required&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 展开成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[success=ok new_authtok_reqd=ok ignore=ignore default=bad]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，也就是说&lt;strong&gt;模块返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 时对应的动作是 ignore，直接跳过，完全不影响整个栈的成败&lt;/strong&gt;。于是下面这种写法看起来是把人脸设成了必须项，实际不是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth required libbiopass_pam.so    &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 摄像头坏了 → PAM_IGNORE → 不算失败&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth required pam_permit.so        &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 放行 → 无认证进入桌面&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;对 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那种“先试人脸、失败回退密码”的场景，这个特性无害；对 autologin 这种&lt;strong&gt;无人值守的闸门&lt;/strong&gt;就是漏洞，摄像头一坏，闸门自己开了。&lt;/p&gt;
&lt;p&gt;规避办法是用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 调 biopass 的助手。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;man pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）只看&lt;strong&gt;进程退出码&lt;/strong&gt;，0 是通过、非 0 是失败，它没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这种中间态：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;helper 退出码 0  → pam_exec 返回 PAM_SUCCESS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;helper 退出码非 0 → pam_exec 返回 PAM_SERVICE_ERR / PAM_AUTH_ERR&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;于是映射关系变成干净的二分：能跑通并识别成功才算通过，其余一切情况——没识别到、摄像头不可用、助手缺失、脚本自身出错——都是失败。autologin 失败会回落到登录界面，用户还能输密码，不会把自己锁在外面。&lt;/p&gt;
&lt;p&gt;代价是多一个包装脚本。后面会看到，它同时还要负责给钱包传递密钥。&lt;/p&gt;
&lt;h2 id=&quot;选择-autologin&quot;&gt;选择 Autologin&lt;/h2&gt;
&lt;p&gt;PLM 的 Autologin 恰好把认证放在了 greeter 之前。上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/daemon/Display.cpp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Display::start()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cpp&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```cpp
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;m_autologinSession&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;isValid&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    m_auth&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;setAutologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;startAuth&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;m_autologinUser&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; QString&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(),&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; m_autologinSession&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                          // ← 前两个参数：用户、空密码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; handleAutologinFailure&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;();&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      // ← &quot;Autologin failed!&quot; → 拉起 greeter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;三个性质正好都用得上：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不需要按键&lt;/strong&gt;——认证发生在 greeter 和合成器启动之前，屏幕上还没有任何可点的东西。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失败不锁死&lt;/strong&gt;——&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;handleAutologinFailure()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会正常拉起登录界面，密码框和人脸重试都在。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失败是可见的&lt;/strong&gt;——日志里留下 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Autologin failed!&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 一行，排查时不用猜。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PamBackend::start()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里写明 autologin 用的 PAM 服务名就是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，所以闸门脚本要挂在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上，而不是 greeter 用的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;运行时序：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;开机 → plasmalogin 启动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ Autologin：跑 plasmalogin-autologin 的 PAM 栈&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ├─ 通过 → 创建 Plasma 会话，直接进桌面&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       └─ 失败 → Autologin failed! → 拉起 greeter&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;这里会出现两个代价，或许你需要自行抉择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;认证期间没有界面。&lt;/strong&gt; 人脸那约 2 秒是黑屏，即便启用了开机动画也看不到。这是“在 greeter 之前认证”的必然结果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开机时不能选会话。&lt;/strong&gt; 会话由配置里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Session=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 固定。本机本来就固定用 Plasma，实际影响很小（但是诸位使用 Linux 的用户大概率是多会话用户，所以可能你需要做出妥协）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;人脸闸门脚本&quot;&gt;人脸闸门脚本&lt;/h2&gt;
&lt;p&gt;脚本要做的事：从 PAM 拿当前用户名和服务名，调 biopass 助手，只把退出码原样交给 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。任何一步不成立都退出非 0。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会往子进程环境里放 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_USER&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_SERVICE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_TYPE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。脚本用前两个，并且在任何一个为空时直接拒绝放行。另外 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 默认以调用者的身份执行命令，而 autologin 时代的调用者是 root，所以这个脚本必须是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;root:root 0755&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不能让它可被普通用户改写。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# biopass-pam-auth — 由 pam_exec.so 调用的&quot;人脸闸门&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 安装位置：/usr/local/libexec/biopass-pam-auth   (root:root 0755)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 调用方式：PAM 文件中写&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#     auth required pam_exec.so quiet /usr/local/libexec/biopass-pam-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 设计原因（勿改成 auth required libbiopass_pam.so）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   biopass 的 PAM 模块在&quot;无法运行&quot;（摄像头打不开/模型缺失/该用户无人脸）时&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   helper 退出码为 2，模块会把它映射成 PAM_IGNORE；而 PAM 的 required 会忽略&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   PAM_IGNORE，配合 autologin 栈里原有的 pam_permit.so 就会变成&quot;无认证放行&quot;。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   pam_exec 只看退出码：0 = 通过，非 0 = 失败（helper 缺失/脚本异常同样失败，fail-closed）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 环境变量由 pam_exec 注入：PAM_USER / PAM_SERVICE / PAM_TYPE 等。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# SPDX-License-Identifier: MIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/usr/bin/biopass-helper&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;LOG_TAG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;biopass-pam-auth&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PAM_SERVICE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    logger&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;LOG_TAG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; auth.warning&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;PAM_USER 为空，拒绝放行（fail-closed）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    logger&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;LOG_TAG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; auth.err&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;找不到可执行的 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;，拒绝放行（fail-closed）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 让 biopass 助手能定位该用户的数据目录（人脸库/配置）；失败也不影响，仅尽力而为&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;home&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; passwd &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -d: -f6&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;home&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;home&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    export&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; HOME&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;home&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; LOGNAME&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SECONDS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HELPER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; auth&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --username&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --service&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;rc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;elapsed&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$((&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; SECONDS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;rc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -eq&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    logger&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;LOG_TAG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; auth.info&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;人脸认证通过 user=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; service=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 用时 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;elapsed&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;s&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# rc=2 表示&quot;没有可用认证方式&quot;（例如摄像头不可用）——必须按失败处理，绝不能放行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;logger&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;LOG_TAG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; auth.warning&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;人脸认证未通过 user=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; service=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rc=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;rc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 用时 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;elapsed&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;s&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;rc&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;几个处理值得单独说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_USER&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为空就 exit 1。&lt;/strong&gt; 拿不到用户名等于无法认证，此时放行是最坏的选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;找不到助手就 exit 1。&lt;/strong&gt; 助手路径写错、包被卸载，都应该表现为“认证失败并回落登录界面”，而不是静默通过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;export HOME&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是尽力而为。&lt;/strong&gt; biopass 要靠家目录定位人脸库和配置；失败也不影响，所以没有把它当作硬条件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;退出码原样透传（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;exit &quot;$rc&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只关心 0 与非 0，但日志里留下 1 和 2 的区别，排查时能立刻分清“没认出来”和“摄像头不可用”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;耗时写进日志。&lt;/strong&gt; 那 2 秒黑屏的实际长度从这里能看到，后面调优不用靠感觉。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pam-顺序&quot;&gt;PAM 顺序&lt;/h2&gt;
&lt;p&gt;目标文件是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。它在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下，优先级高于包内默认的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，所以不会和包管理器抢文件，但升级后要留意上游默认值有没有变。&lt;/p&gt;
&lt;p&gt;上游那份是这样的（包内默认，关键在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_permit.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那一行）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_env.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_faillock.so preauth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_shells.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_nologin.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_permit.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_gnome_keyring.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_kwallet5.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account     include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;password    include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_gnome_keyring.so auto_start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_kwallet5.so auto_start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;改完后：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#%PAM-1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---- autologin 人脸闸门 + KWallet 自动解锁（本项目新增 2026-09-25）----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 1) 人脸闸门用 pam_exec，只按退出码判定：0=通过，非 0=失败。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    切勿改回 &quot;auth required libbiopass_pam.so&quot;：biopass 模块在摄像头不可用/无人脸/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    模型缺失时返回 PAM_IGNORE（helper exit 2），而 required 会忽略 PAM_IGNORE，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    与 pam_permit.so 组合就会变成&quot;无认证直接进入桌面&quot;。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2) 上游默认的 &quot;auth required pam_permit.so&quot; 已被有意删除：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    没有它以后，认证结果只能来自真实模块；即使将来有人把 pam_exec 改成 optional&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    或误删该行，autologin 也只会失败并回落到登录界面（fail-closed），不会静默放行。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    如需临时关闭人脸闸门：删掉 pam_exec 行并恢复 &quot;auth required pam_permit.so&quot;。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 3) pam_walletkey 在认证阶段把 KWallet 密码（/etc/pam_walletkey.key）注入 PAM_AUTHTOK，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    供 pam_kwallet5 在 session 阶段解锁 kdewallet（人脸登录没有密码可抓）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_env.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_faillock.so preauth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_shells.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_nologin.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;auth        required    pam_exec.so quiet /usr/local/libexec/biopass-pam-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_walletkey.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_gnome_keyring.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-auth       optional    pam_kwallet5.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;account     include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;password    include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;session     include     system-local-login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_gnome_keyring.so auto_start&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;-session    optional    pam_kwallet5.so auto_start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;两处改动：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auth required pam_exec.so quiet …&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; 它排在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_nologin.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_permit.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 原来的位置。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;quiet&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 让 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不要把命令输出写进系统日志（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;man pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;stdout&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 默认本来就丢进 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/dev/null&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，这个标记省掉的是另一路噪音）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;删掉 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auth required pam_permit.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; 这一行是上游给“谁都不用认证”的 autologin 用的。留着它，认证栈里就有一个永远成功的模块；一旦有人把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那行改成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;optional&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、或者干脆删掉闸门行，结果不会是“进不去”，而是&lt;strong&gt;静默放行&lt;/strong&gt;。删掉之后，认证结果只能来自真实模块，配置被改坏也只会 autologin 失败并回落登录界面。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;顺带说明为什么 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_kwallet5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这两行也在这一段的开头：它们是钱包自动解锁用的，属于&lt;a href=&quot;/posts/biopass-sudo-kwallet/&quot;&gt;人脸登录后的 KWallet 自动解锁&lt;/a&gt;那一篇的内容。只想先要免按键登录，可以先只加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那一行，把这两行留到之后再加。&lt;/p&gt;
&lt;h2 id=&quot;autologin-配置&quot;&gt;Autologin 配置&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/plasmalogin.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只需要 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Autologin]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 段里的三项：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Autologin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;&amp;lt;用户名&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;Session&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;plasma&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;Relogin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;User&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; 指定自动登录哪个账号。不写这一行，autologin 分支根本不会触发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Session=plasma&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; 会被 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Session::create()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 自动补成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 并在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wayland-sessions&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下定位，所以写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasma&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasma.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 等价。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Relogin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; 决定注销之后的行为：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（默认值）停在登录界面，需要时再按 Enter；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 则注销后立刻再跑一次人脸。想保留“注销出来换个用户”的能力就保持 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;安装&quot;&gt;安装&lt;/h2&gt;
&lt;p&gt;装之前先另开一个 root 终端放着别关。（我们接下来修改的是登录链路上的 PAM 文件，如果写坏了，还有一个已经通过认证的 root shell 可以用来改回来）&lt;/p&gt;
&lt;p&gt;脚本会自动备份到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/var/backups/plasmalogin-face-&amp;lt;时间戳&amp;gt;/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，并且是幂等的，重复执行不会重复插入：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# Plasma Login Manager 免按键人脸登录 —— Autologin + pam_exec 人脸闸门 安装脚本&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： sudo bash install.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 安装内容：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   1. /usr/local/libexec/biopass-pam-auth        人脸闸门包装脚本（调 biopass-helper）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   2. /etc/pam.d/plasmalogin-autologin          覆盖 /usr/lib/pam.d 的上游默认（放行式）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   3. /etc/plasmalogin.conf                     [Autologin] 段加 User=&amp;lt;你&amp;gt;（Relogin 保持默认 false）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 不重启任何服务（重启 plasmalogin 会杀掉当前会话）。改动在下次开机/重启后生效。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 幂等：可重复运行；每次都会把原文件备份到 /var/backups/plasmalogin-face-&amp;lt;时间戳&amp;gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +%Y%m%d-%H%M%S&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/var/backups/plasmalogin-face-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/plasmalogin.conf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/pam.d/plasmalogin-autologin&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/usr/local/libexec/biopass-pam-auth&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SUDO_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-}}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;EUID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -ne&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：请用 root 运行 → sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 不写死用户名：优先用 TARGET_USER，其次用 sudo 记录的调用者。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：无法确定目标用户（SUDO_USER 为空）&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;      请显式指定 → TARGET_USER=你的用户名 sudo -E bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：用户 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 不存在（可用 TARGET_USER=xxx sudo -E bash install.sh 覆盖）&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; biopass-pam-auth&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin-autologin.pam.new&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：缺少交付文件 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 备份到 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;basename&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/lib/pam.d/plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin-autologin.usr-lib.pam.d&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    回滚： sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/rollback.sh&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [1/3] 安装人脸闸门脚本&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0755&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/biopass-pam-auth&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [2/3] 安装 plasmalogin-autologin 的 PAM 配置&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin-autologin.pam.new&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;（覆盖 /usr/lib/pam.d/plasmalogin-autologin，后者保持原样）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; [3/3] 在 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 的 [Autologin] 段写入 User=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;（Relogin 不动，保持 false）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;before_hash&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sha256sum&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;{print $1}&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^\[Autologin\]&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 情况 0：[Autologin] 段不存在 → 追加一段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;\n[Autologin]\nUser=%s\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已追加 [Autologin] 段&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;elif&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        /^\[Autologin\]/ { insec = 1; next }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        /^\[/            { insec = 0 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        insec &amp;amp;&amp;amp; /^[[:space:]]*User[[:space:]]*=/ { found = 1 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        END { exit(found ? 0 : 1) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 情况 1：段内已有 User= → 原位替换（保持行位置，自动纠正旧值）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; user=&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        /^\[Autologin\]/ { insec = 1; print; next }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        /^\[/            { insec = 0 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        insec &amp;amp;&amp;amp; /^[[:space:]]*User[[:space:]]*=/ {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;            if (!done) { printf &quot;User=%s\n&quot;, user; done = 1 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;            next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        { print }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已原位更新 User=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 情况 2：段存在但没有 User= → 紧跟段头插入&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; user=&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        { print }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        /^\[Autologin\]/ &amp;amp;&amp;amp; !done { printf &quot;User=%s\n&quot;, user; done = 1 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    已在 [Autologin] 段头后插入 User=&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;tmp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;after_hash&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sha256sum&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;{print $1}&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;before_hash&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;after_hash&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    （内容已是 User=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;，无变化）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; PAM 栈自检（应看到 pam_exec 行且顺序正确）：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -nE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;pam_exec|pam_walletkey|pam_permit&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;s/^/    /&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; Autologin 配置：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;/^\[Autologin\]/,/^\[/p&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;s/^/    /&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;==&amp;gt; 安装完成。验证方式（不需要注销，先验闸门脚本本身）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  # 1) 直接以 root 触发一次人脸闸门（应打开摄像头并识别人脸）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  sudo env PAM_USER=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;TARGET_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; PAM_SERVICE=plasmalogin-autologin &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;; echo &quot;退出码=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\$&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  #    预期：人脸匹配时退出码 0；遮住脸时非 0；摄像头不可用时为 2（同样会被判为失败）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  #    注：fish 里没有 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$?&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;，请改用 &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  journalctl -t biopass-pam-auth -b --no-pager | tail -n 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  # 2) 确认当前会话/登录界面未被影响（本脚本不重启任何服务）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  #    真正的 autologin 效果需要重启系统：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  #    重启后人脸正常 → 无需任何按键直接进入桌面&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  #    遮住脸/移开摄像头 → 出现登录界面（按 Enter 可重试人脸，或直接输密码）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  # 3) 重启后检查日志&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  journalctl -b -u plasmalogin | grep -iE &apos;autologin|pam_exec&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  journalctl -b -u plasmalogin | grep -i pam_kwallet5      # 钱包应自动解锁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;==&amp;gt; 回滚： sudo bash &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/rollback.sh&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin-install.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;脚本&lt;strong&gt;不会重启 plasmalogin&lt;/strong&gt;，因为那会杀掉当前会话。改动在下次开机或重启后生效。&lt;/p&gt;
&lt;h2 id=&quot;验证&quot;&gt;验证&lt;/h2&gt;
&lt;p&gt;分两层验。先验闸门脚本本身，无需注销或重启：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; env&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; PAM_USER=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;用户&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;名&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  PAM_SERVICE=plasmalogin-autologin&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  /usr/local/libexec/biopass-pam-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;exit=%s\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$?&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; biopass-pam-auth&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --no-pager&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env PAM_USER=… PAM_SERVICE=…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就是在手工模拟 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 提供的环境。预期是正脸返回 0、遮住脸返回非 0。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;$?&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在 fish 里不存在，要用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;$status&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。用 bash 跑这段最省事。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本机实测：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;12:56:36，遮脸 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;人脸认证未通过 … rc=1 用时 2s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，退出码 1；&lt;/li&gt;
&lt;li&gt;12:57:08，正脸 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;人脸认证通过 … 用时 2s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，退出码 0。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;再验真实开机路径。重启后分两次：一次正常对着镜头，一次把摄像头挡上或移开。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;autologin|Greeter&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; biopass-pam-auth&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --no-pager&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机两次开机的结果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;人脸通过&lt;/strong&gt; —— ✅ 全程零按键进桌面，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Autologin failed&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 0 条。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;13:00:10 人脸认证通过 … 用时 2s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Session started true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人脸失败&lt;/strong&gt; —— ✅ 回落登录界面，没有放行。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;13:03:35 rc=1 用时 4s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;13:03:37 Autologin failed!&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Greeter starting...&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;greeter 重试&lt;/strong&gt; —— ✅ 登录界面里按 Enter 仍能刷脸。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;13:03:46 Message received from greeter: Login&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;13:03:48 Authentication … successful&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有两条顺手确认过：TTY（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ctrl+Alt+F3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）下的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 仍能走人脸；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 直连，不经过这个闸门，所以 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -t biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里不会出现 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;service=sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;——这是预期行为，不是故障。&lt;/p&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开机后直接出现登录界面，日志里有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Autologin failed!&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：闸门退出码非 0（没认出脸、摄像头被占用、助手缺失），或 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/plasmalogin.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里没写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;User=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -t biopass-pam-auth -b&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看退出码和耗时；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo env PAM_USER=… PAM_SERVICE=plasmalogin-autologin /usr/local/libexec/biopass-pam-auth; echo $?&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 手工复现一次，能立刻区分是脚本问题还是 PAM 顺序问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开机直接进桌面，完全没刷脸&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那行被改成了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;optional&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，或者被删掉了——此时剩下的模块里如果还有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_permit.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，就是无认证放行。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep -nE &apos;pam_exec|pam_permit&apos; /etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。正确状态是&lt;strong&gt;有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_permit&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;，两项都要满足。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -t biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 一条都不出&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：闸门脚本没被执行（PAM 文件没生效），或脚本内的日志标签被改过。&lt;/li&gt;
&lt;li&gt;怎么办：确认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 存在且是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;0644 root:root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;logger -t biopass-pam-auth test&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 确认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl -t&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 过滤本身没问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;认证一直失败，但手工跑脚本是好的&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/local/libexec/biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 权限不对（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 以 root 身份执行，脚本必须 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;root:root 0755&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），或脚本首行 shebang 指向的解释器不存在。&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ls -l /usr/local/libexec/biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，然后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo bash -x /usr/local/libexec/biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跟一遍。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重启后确实免按键了，但钱包还是要手动解锁&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_walletkey&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那两行没加，或顺序排在了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libbiopass_pam.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后。&lt;/li&gt;
&lt;li&gt;怎么办：见&lt;a href=&quot;/posts/biopass-sudo-kwallet/&quot;&gt;人脸登录后的 KWallet 自动解锁&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;通用性&quot;&gt;通用性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只看退出码、不产生 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PAM_IGNORE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; —— ✅ 所有用 Linux-PAM 的系统。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在 greeter 之前认证&lt;/strong&gt; —— ✅ PLM 当前架构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 以 root 身份执行命令&lt;/strong&gt; —— ✅ Linux-PAM 的行为。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上游 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Login.qml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没有自动认证入口&lt;/strong&gt; —— ✅ PLM 6.7 系列；新版本可能变化，动手前重新核对。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;具体路径 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/local/libexec/…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; —— ⚠️ 发行版差异；先确认你的 PAM 与 PLM 装在哪。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;黑屏时长约 2 秒&lt;/strong&gt; —— ⚠️ 取决于摄像头与识别模型，本机实测 2–4 秒。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;biopass-helper&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的退出码语义&lt;/strong&gt; —— ⚠️ 换用别的生物识别模块要重新核对其退出码约定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ksecretd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 作为钱包守护进程&lt;/strong&gt; —— ⚠️ 由 kwallet-pam 版本决定（6.7.5 的编译默认值）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;回滚&quot;&gt;回滚&lt;/h2&gt;
&lt;p&gt;回滚不需要手改文件，脚本会从备份还原，并且在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 原本不存在时把它删掉、回落到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的上游默认：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 回滚脚本：撤销 install.sh 的 autologin 人脸闸门改动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： sudo bash rollback.sh [备份目录]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#          不给参数时自动使用 /var/backups/plasmalogin-face-* 中最新的一份&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -- &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/plasmalogin.conf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/etc/pam.d/plasmalogin-autologin&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/usr/local/libexec/biopass-pam-auth&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;EUID&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -ne&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：请用 root 运行 → sudo bash &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $# &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-ge&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -1dt /var/backups/plasmalogin-face-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:-}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;错误：找不到备份目录，请手动指定：sudo bash rollback.sh /var/backups/plasmalogin-face-YYYYmmdd-HHMMSS&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 使用备份：&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin.conf&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin.conf&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PLM_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 已还原（autologin User= 被移除）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin-autologin&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    install&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0644&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; root&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BACKUP_DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/plasmalogin-autologin&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 已还原&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 安装前 /etc/pam.d 下没有这个文件（包内默认在 /usr/lib/pam.d）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;AUTOLOGIN_PAM&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;（本次新建）已删除，回落到 /usr/lib/pam.d/plasmalogin-autologin&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;rmdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/local/libexec&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;WRAPPER_DST&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 已删除&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;EOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;==&amp;gt; 回滚完成。说明：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    * 本脚本不重启 plasmalogin（那会杀掉当前会话）；下次开机即恢复&quot;显示登录界面&quot;的行为。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    * KWallet 相关改动属于另一个档案（biopass-sudo-kwallet），未在此回滚。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; plasmalogin-rollback.sh&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;          # 不给参数 = 用最新那份备份&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同样不会重启 plasmalogin，下次开机即恢复“显示登录界面”的行为。回滚只覆盖这一篇的改动；钱包那部分属于另一篇，要单独回滚。&lt;/p&gt;
&lt;h2 id=&quot;什么时候可以退休&quot;&gt;什么时候可以退休&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;犹分省署直，何日是归休。
——姚合《和膳部李郎中秋夕》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PLM 的这个缺口已经有上游跟踪项：&lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=506025&quot;&gt;KDE bug 506025&lt;/a&gt;（product &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;plasma-login-manager&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，状态 CONFIRMED，wishlist）。那条报告针对的是&lt;strong&gt;指纹&lt;/strong&gt;登录，诉求和这里一样：让登录服务能在 greeter 之外、由界面主动在后台启动一次生物识别，并允许它与密码认证并行。上游目前没有这个能力。&lt;/p&gt;
&lt;p&gt;如果后续版本把它做了进去，判断标准是：&lt;strong&gt;登录服务能在 greeter 之外安全地启动生物识别，并在失败时回到正常登录流程&lt;/strong&gt;。满足之后就没有理由继续用 Autologin 绕，届时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;删掉 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/plasmalogin.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Autologin] User=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;删掉 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/pam.d/plasmalogin-autologin&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，回落到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/pam.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的上游默认；&lt;/li&gt;
&lt;li&gt;删掉 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/local/libexec/biopass-pam-auth&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这三步正好就是回滚脚本做的事，直接跑它也可以。&lt;/p&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://invent.kde.org/plasma/plasma-login-manager&quot;&gt;Plasma Login Manager 源码&lt;/a&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/frontend/greeter/qml/Login.qml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/frontend/greeter/CMakeLists.txt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/common/mainconfig.kcfg&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/daemon/Display.cpp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/helper/backend/PamBackend.cpp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/common/Session.cpp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=506025&quot;&gt;KDE bug 506025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TickLabVN/biopass/blob/main/docs/PAM.md&quot;&gt;biopass PAM 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TickLabVN/biopass/blob/main/auth/pam/pam.cc&quot;&gt;biopass PAM 模块源码（退出码到 PAM 返回值的映射）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/linux-pam/linux-pam/blob/master/libpam/pam_dispatch.c&quot;&gt;Linux-PAM 调度实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;man pam.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;man pam_exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Plasma Login Manager</category><category>PLM</category><category>biopass</category><category>PAM</category><category>Autologin</category><category>Wayland</category></item><item><title>把 Nahimic 出厂音效搬到 Linux</title><link>https://miprota.cc/posts/nahimic-factory-audio-tuning/</link><guid isPermaLink="true">https://miprota.cc/posts/nahimic-factory-audio-tuning/</guid><description>从本机 Windows 驱动中提取 Nahimic 的设备校正与场景参数，把可复现部分落成 EasyEffects 预设。</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;每次从 Windows 回到 Linux 我都会有一种遗憾，因为 Linux 下没有厂商调教的音效配置，导致我的笔记本扬声器发出的声音宛若一头年轻的水牛（没有歧视水牛的意思），所以我决定研究研究 Nahimic 是怎样增强笔记本音效的。&lt;/p&gt;
&lt;p&gt;首先，Nahimic 的音效参数不一定只能在 Windows 里使用。驱动包里有一部分明文配置，里面包含设备校正 FIR、场景参数和音圈保护数据。把它们找出来之后，就可以把其中一部分搬到 Linux 的 EasyEffects 里。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;如果这篇文章触犯了你的权益，请通过 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;me@miprota.cc&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 联系笔者删除&lt;/p&gt;
&lt;p&gt;本文章没有解包相关的教程&lt;/p&gt;
&lt;p&gt;本文章出现的脚本均可在 &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning&quot;&gt;nahimic-factory-audio-tuning&lt;/a&gt; 中下载&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;本次环境&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;硬件&lt;/td&gt;
&lt;td&gt;MECHREVO 蛟龙，Conexant SN6140&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;系统&lt;/td&gt;
&lt;td&gt;CachyOS，PipeWire 1.6.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;效果器&lt;/td&gt;
&lt;td&gt;EasyEffects 8.2.9（Flatpak）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原厂数据&lt;/td&gt;
&lt;td&gt;Windows 分区里的 A-Volute/Nahimic 驱动包&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工具&lt;/td&gt;
&lt;td&gt;Python 3、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;cabextract&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;objdump&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、NumPy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;下面的硬件匹配和听感只在这一组环境上验证过。换机型时，不能直接套用 FIR 或设备文件名。&lt;/p&gt;
&lt;h2 id=&quot;一先排除-easyeffects-没生效&quot;&gt;一、先排除 EasyEffects 没生效&lt;/h2&gt;
&lt;p&gt;优先测试一下 EasyEffects 是否生效（虽然大概率不用测试）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pw-play&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --target=&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;硬件输出端的名称&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; test.wav&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;播放仍然落在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;easyeffects_sink&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，说明音频确实经过了 EasyEffects。&lt;/p&gt;
&lt;h2 id=&quot;二瞎猜的调教&quot;&gt;二、瞎猜的调教&lt;/h2&gt;
&lt;p&gt;在没有原厂数据前，我先按听感和常见的小扬声器问题手工搓了一条曲线：100 Hz 高通，220/420 Hz 附近衰减，再压一点 3.2 kHz。听起来比完全没有处理好一些，但那种塑料感还在。&lt;/p&gt;
&lt;p&gt;问题在于，我不知道这块机器的箱体共振到底在哪。没有测量，也没有原厂曲线，继续改钟形（Bell）滤波器的 Q 值只是让一条猜出来的曲线变得更像“有依据”。这时才转向一个更直接的问题：Windows 上的 Nahimic 既然能按机型工作，调音数据应该存在哪里？&lt;/p&gt;
&lt;h2 id=&quot;三找到本机数据&quot;&gt;三、找到本机数据&lt;/h2&gt;
&lt;p&gt;先在 Linux 侧读取 codec、modalias 和子系统 ID：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /proc/asound/card2/codec#0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;Vendor Id|Subsystem Id&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/bus/hdaudio/devices/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/uevent&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; MODALIAS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机得到的关键值是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;VEN_14F1 DEV_1F87&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SUBSYS 1D053010&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。Windows 驱动的 INF 里必须出现同一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HDAUDIO\\FUNC_01&amp;amp;VEN_14F1&amp;amp;DEV_1F87&amp;amp;SUBSYS_1D053010&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，否则后面的 XML 不是这块声卡的调音数据。&lt;/p&gt;
&lt;p&gt;调音档案按机型分文件，解析得越认真，假如硬件 ID 没对上，最后越可能是在认真研究别人的机器。&lt;/p&gt;
&lt;h2 id=&quot;四从-driverstore-找到-xml&quot;&gt;四、从 DriverStore 找到 XML&lt;/h2&gt;
&lt;p&gt;Nahimic 的配置在驱动包里，不在 Program Files。先在 Windows 分区定位 A-Volute 的扩展驱动：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /mnt/windows/Windows/System32/DriverStore/FileRepository&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  -maxdepth&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -type&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;*.inf&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -print&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;avolute|nahimic|cnxt&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;命令命中了 A-Volute 的 APO4 引擎和 CNXT（Conexant）扩展。INF 给出安装目录、设备匹配和 CAB 文件名。解包后得到 180 个明文 XML，结构大致分成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Global.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：全局配置，采集链和全局开关&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;AudioProfiles/*.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：场景配置，音乐（Music）、电影（Movie）、游戏（Gaming）、通信（Communication）四个场景&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Devices/*_Speakers.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：设备配置，按 SUBSYS/SMBIOS 区分的扬声器校正&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;注意，不能只打开一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Music.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：全局配置管采集链和全局开关，场景配置给出四个场景的差异，设备配置才是这台机器的扬声器校正。设备文件里最重要的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kSet_DeviceOptimizationFilterFL/FR&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，它们是 2048 抽头的 float32 FIR，可以直接重放，不需要再猜一组 EQ 参数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;把 base64 解码后，每个通道正好是 8192 字节，也就是 2048 个 float32。能量集中在最前面的几个样本，符合最小相位校正滤波器的形状。到这里，小作坊手搓 EQ 已经有了一个明确的替代物：卷积器（Convolver）可以直接重放这条 FIR。&lt;/p&gt;
&lt;p&gt;频响还有一个很直观的线索：两个设备变体都在 800 Hz 附近留下约 -2.7 dB 的凹陷。我的猜测曲线里没有这个位置，却在 3.2 kHz 做了衰减。出厂数据第一次把“听起来合理”与“确实是原厂曲线”分开了。&lt;/p&gt;
&lt;h2 id=&quot;五xml-导致的望文生义&quot;&gt;五、XML 导致的望文生义&lt;/h2&gt;
&lt;p&gt;XML 里有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kSet_BassBoostGainDB&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kSet_VoiceBoostGainDB&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这样的名字和值，但参数名不等于算法名。要知道一个旋钮接的是 EQ、动态压缩还是谐波生成，必须再看 DLL。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NahimicAPO4.dll&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没有可用的 A-Volute 符号表，RTTI 里也只有标准库和 ATL 的类型。可行的路线是找阶段名字符串，再扫描 x64 的 RIP-relative &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;48 8D&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 引用，定位它们被注册和读取的位置。过程中还踩过一次地址坑：objdump 输出的节区 VMA 已经包含映像基址，不能再额外加一遍 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;0x180000000&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;这条路线能确认算法形态，但不能凭构造函数默认值宣称“所有运行时参数都找到了”。真实值仍然由 XML 经 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ApplyUserSettings&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写入。&lt;/p&gt;
&lt;h3 id=&quot;低音增强bassboost从低架到钟形滤波再到谐波增强&quot;&gt;低音增强（BassBoost）：从低架到钟形滤波，再到谐波增强&lt;/h3&gt;
&lt;p&gt;我在这里连续犯了两次错误。先把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;BassBoostFrequencyHz=250&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 当成 EQ 的中心频率，做成了 +6 dB 的低架；又看到别的机型里有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;BassBoostBandWidthOctave=0.707&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，推断它一定是 Q 约 2 的钟形滤波器。第二版的数学曲线能对上部分数字，却仍然解释不了“低音增强”为什么要凭空补出小扬声器放不出的基频。&lt;/p&gt;
&lt;p&gt;第三次证据来自 DLL：类名是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ape::SBP::VirtualBassBoost&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，内部还能看到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ippsTanh_32f_A24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。它对低频做软饱和、生成奇次谐波，再把谐波混回去；静态 EQ 不会凭空产生新的频率成分。于是 EasyEffects 侧的对应物改成低音增强器（Bass Enhancer），且必须放在卷积器之前，让它先看到未经 FIR 切削的原始低频。&lt;/p&gt;
&lt;h3 id=&quot;清晰度clarity不等于人声增强voiceboost&quot;&gt;清晰度（Clarity）不等于人声增强（VoiceBoost）&lt;/h3&gt;
&lt;p&gt;早期还把清晰度当成了人声增强。反汇编读到的清晰度默认值是 200 / 8000 / 6 / 6，而 XML 里的人声增强频带是 500–4000 Hz，参数对不上。DLL 里也没有一个可以直接叫作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;voiceboost_stage&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的静态引用，所以这个等同关系撤回：人声增强的真实实现还没确认，预设不拿静态 EQ 硬凑。&lt;/p&gt;
&lt;h2 id=&quot;六从证据得到可复现的链路&quot;&gt;六、从证据得到可复现的链路&lt;/h2&gt;
&lt;p&gt;现在才有足够依据列出哪些环节可以搬：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;原厂环节&lt;/th&gt;
&lt;th&gt;原厂实现&lt;/th&gt;
&lt;th&gt;EasyEffects 处理&lt;/th&gt;
&lt;th&gt;状态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;设备优化滤波器&lt;/td&gt;
&lt;td&gt;DeviceOptimizationFilter，2048 抽头 FIR&lt;/td&gt;
&lt;td&gt;卷积器&lt;/td&gt;
&lt;td&gt;已实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;低音增强&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;VirtualBassBoost&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，tanh 谐波生成&lt;/td&gt;
&lt;td&gt;低音增强器&lt;/td&gt;
&lt;td&gt;已实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;高音增强&lt;/td&gt;
&lt;td&gt;TrebleBoost，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;trebleboost_stage&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;8 kHz 高架 EQ&lt;/td&gt;
&lt;td&gt;已实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;人声增强&lt;/td&gt;
&lt;td&gt;VoiceBoost，动态处理，算法未确认&lt;/td&gt;
&lt;td&gt;不建模&lt;/td&gt;
&lt;td&gt;跳过&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DRC&lt;/td&gt;
&lt;td&gt;动态增益/压缩&lt;/td&gt;
&lt;td&gt;不使用自动增益&lt;/td&gt;
&lt;td&gt;跳过&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;衰减器&lt;/td&gt;
&lt;td&gt;Attenuator，频段音圈保护&lt;/td&gt;
&lt;td&gt;无直接对应&lt;/td&gt;
&lt;td&gt;跳过&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;限幅器&lt;/td&gt;
&lt;td&gt;Limiter，原厂限幅阶段&lt;/td&gt;
&lt;td&gt;保留插件但旁路&lt;/td&gt;
&lt;td&gt;旁路&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;七生成预设&quot;&gt;七、生成预设&lt;/h2&gt;
&lt;p&gt;完整工具在源码仓库中：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_factory_preset.py&quot;&gt;build_factory_preset.py&lt;/a&gt;&lt;/strong&gt;
156 行 / 5.7 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_factory_preset.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/decode_nahimic.py&quot;&gt;decode_nahimic.py&lt;/a&gt;&lt;/strong&gt;
126 行 / 4.6 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/decode_nahimic.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;生成脚本默认从仓库根目录的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;data/Devices&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 读原厂 XML，而仓库里不带 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;data/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，解包出来的数据要自己放进去。路径可以用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_DEVICES&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;EASYEFFECTS_DATA&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆盖，但只有部分脚本读这两个变量：其余脚本把 EasyEffects 数据目录写死在 Flatpak 路径下，换环境得改脚本。校正 FIR 必须关闭 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;autogain&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，否则 EasyEffects 会重新归一化掉原厂刻意保留的增益结构。&lt;/p&gt;
&lt;p&gt;EasyEffects 的另一个易错点是扩展名：卷积器找的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.irs&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，而脉冲响应的内容是 32 位 PCM WAV，照容器格式写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.wav&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就找不到了。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kernel-name&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 同样不能带扩展名；两件事混在一起，结果就是对话框报错或卷积器悄悄进入直通。&lt;/p&gt;
&lt;h2 id=&quot;八四个场景和低频余量&quot;&gt;八、四个场景和低频余量&lt;/h2&gt;
&lt;p&gt;音乐、电影、游戏、通信四个场景的差别主要在低音、高音、人声、空间效果和压缩器开关。当前场景脚本保留原厂场景参数，但不伪造人声增强；低频恢复使用 20–400 Hz 的多频段压缩，回收 FIR 带来的中频余量。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_nahimic_music.py&quot;&gt;build_nahimic_music.py&lt;/a&gt;&lt;/strong&gt;
184 行 / 6.9 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_nahimic_music.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/add_bass_compressor.py&quot;&gt;add_bass_compressor.py&lt;/a&gt;&lt;/strong&gt;
172 行 / 5.8 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/add_bass_compressor.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_scenario_presets.py&quot;&gt;build_scenario_presets.py&lt;/a&gt;&lt;/strong&gt;
289 行 / 11.5 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_scenario_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_official_eq_presets.py&quot;&gt;build_official_eq_presets.py&lt;/a&gt;&lt;/strong&gt;
153 行 / 5.0 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_official_eq_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_capture_presets.py&quot;&gt;build_capture_presets.py&lt;/a&gt;&lt;/strong&gt;
143 行 / 6.2 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_capture_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;生成的 EasyEffects 预设里，链路顺序不能调换：低音增强器要在卷积器和 EQ 之前，否则谐波发生器拿到的低频已经被 FIR 切掉。出厂 FIR 在 80–400 Hz 有明显增益，整条链如果不处理余量，主观音量会被迫压低；因此加入只作用于 20–400 Hz 的多频段压缩器（Multiband Compressor），把低频峰值压下来，给中频和高频留出空间。限幅器保留在链里但旁路，防削顶由固定增益预算承担。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最终的音乐链路因此变成：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;低音增强器（虚拟低音增强的近似）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  → 卷积器（出厂 2048 抽头 FIR）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  → 高架 EQ（高音增强）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  → 多频段压缩器（仅 20–400 Hz）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  → 限幅器（旁路）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;九校验失败和未决问题&quot;&gt;九、校验、失败和未决问题&lt;/h2&gt;
&lt;p&gt;预设生成后先跑校验：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/validate_presets.py&quot;&gt;validate_presets.py&lt;/a&gt;&lt;/strong&gt;
183 行 / 8.1 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/validate_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/validate_complete.py&quot;&gt;validate_complete.py&lt;/a&gt;&lt;/strong&gt;
93 行 / 3.4 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/validate_complete.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其余工具分别用于 FIR 更新、HRTF 解码、SOFA/IRS 转换、反汇编和测量。它们按调查阶段分组：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/update_irs.py&quot;&gt;update_irs.py&lt;/a&gt;&lt;/strong&gt;
175 行 / 6.4 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/update_irs.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/decode_hrtf.py&quot;&gt;decode_hrtf.py&lt;/a&gt;&lt;/strong&gt;
178 行 / 6.1 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/decode_hrtf.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/hrir_to_irs.py&quot;&gt;hrir_to_irs.py&lt;/a&gt;&lt;/strong&gt;
164 行 / 6.0 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/hrir_to_irs.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/hrir_to_sofa.py&quot;&gt;hrir_to_sofa.py&lt;/a&gt;&lt;/strong&gt;
277 行 / 11.6 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/hrir_to_sofa.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_headphone_presets.py&quot;&gt;build_headphone_presets.py&lt;/a&gt;&lt;/strong&gt;
93 行 / 3.1 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_headphone_presets.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/build_complete_preset.py&quot;&gt;build_complete_preset.py&lt;/a&gt;&lt;/strong&gt;
278 行 / 11.1 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/build_complete_preset.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/remove_limiter.py&quot;&gt;remove_limiter.py&lt;/a&gt;&lt;/strong&gt;
162 行 / 5.3 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/remove_limiter.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/measure.py&quot;&gt;measure.py&lt;/a&gt;&lt;/strong&gt;
161 行 / 5.3 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/measure.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/find_xrefs.py&quot;&gt;find_xrefs.py&lt;/a&gt;&lt;/strong&gt;
110 行 / 3.4 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/find_xrefs.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/blob/main/tools/disasm_window.py&quot;&gt;disasm_window.py&lt;/a&gt;&lt;/strong&gt;
96 行 / 2.7 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/nahimic-factory-audio-tuning/raw/main/tools/disasm_window.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HRTF 的 EasyEffects 路线已经撤销：单个立体声卷积核不能完成真正的多声道到双耳渲染，实测结果也不合格。扬声器 FIR 的 A/B 变体同样尚未根据本机主板精确判定，不能只凭文件数量猜测。&lt;/p&gt;
&lt;p&gt;预设校验解决的是 JSON、插件键和值、FIR 文件名等机器可检查的问题；它不能替你判断 A/B 变体是否属于当前主板，也不能把 HRTF 的单方向卷积变成真正的多声道环绕。&lt;/p&gt;
&lt;p&gt;文章里的脚本只保证代码与源码仓库同步；EasyEffects 插件版本、设备变体和实际听感仍需在使用者自己的环境中重新确认。&lt;/p&gt;
&lt;h2 id=&quot;十省流&quot;&gt;十、省流&lt;/h2&gt;
&lt;p&gt;我知道你不想看前面的长篇大论，只想看怎么执行步骤和结果，所以这里给出省流步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;克隆仓库&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; https://github.com/LaT-SKY/nahimic-factory-audio-tuning&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --depth&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;仓库里只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;tools/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，原厂数据要自己解包后放进去。&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;在 Windows 分区定位驱动包&lt;/strong&gt;，解包后取出 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Global.nsx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;AudioProfiles/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Devices/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;MicProfile/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /mnt/windows/Windows/System32/DriverStore/FileRepository&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  -maxdepth&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -type&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;*.inf&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -print&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;avolute|nahimic|cnxt&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;确认硬件身份&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/proc/asound/card*/codec#*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的 Vendor/Subsystem&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/sys/bus/hdaudio/devices/*/uevent&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的 MODALIAS、INF 里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SUBSYS&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三处必须一致。&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;设置数据路径&lt;/strong&gt;，再按需要覆盖路径（当然，你的路径可能与我不一致）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; EASYEFFECTS_DATA&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.var/app/com.github.wwmm.easyeffects/data/easyeffects&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; NAHIMIC_DEVICES&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PWD&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/data/Devices&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;build_factory_preset.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;build_complete_preset.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 认这两个变量；其余脚本把路径写死在 Flatpak 数据目录下，换环境要改脚本。反汇编那两个认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_DLL&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;decode_nahimic.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;NAHIMIC_ARCHIVE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;strong&gt;生成出厂卷积核与基础预设&lt;/strong&gt;，当然，你大概率可以跳过这个步骤：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/build_factory_preset.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;它从现有的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;output/Music.json&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里取限幅器键模板，所以先确认那个文件在。脚本里的设备文件名是本机的，换机型要改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;VARIANTS&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;&lt;strong&gt;按顺序搭音乐链路&lt;/strong&gt;，后一个脚本会在前一个的产物上加多频段压缩器：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/build_nahimic_music.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/add_bass_compressor.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;strong&gt;四个场景与采集链&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/build_scenario_presets.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/build_capture_presets.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;另外 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;build_official_eq_presets.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 处理的是 Nahimic UWP 应用里的 10 段图形 EQ。它不在驱动包里，而在 Windows 用户目录的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;A-Volute.Nahimic_*/LocalState/Settings/v1/EQPresets/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，要自己复制到仓库的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;data/ui-eq-presets/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下；这套参数与出厂 XML 不是一回事。&lt;/p&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;&lt;strong&gt;校验，然后在 EasyEffects 里核对三件事&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/validate_presets.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tools/validate_complete.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;卷积器的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;autogain&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 已关、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kernel-name&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不带扩展名、顺序是 低音增强器 → 卷积器 → 高架 EQ → 多频段压缩器 → 限幅器（旁路）。&lt;/p&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不要照抄的部分&lt;/strong&gt;：人声增强、DRC、衰减器没有建模；HRTF 路线已撤销；扬声器 FIR 的 A/B 变体要按自己的主板判定。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你可以用 &lt;strong&gt;AI Agent&lt;/strong&gt; 帮你完成上述步骤，你可以如下注入提示词：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;请帮我把 Windows 分区里的 Nahimic 出厂音效数据搬成 EasyEffects 预设。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;按顺序做，每步先把命令和输出贴给我看，再进下一步；对不上就停下问我，不要猜。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;0. 报告环境：发行版、PipeWire 版本、EasyEffects 版本与安装方式；&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   当前目录没有仓库的话，先 git clone --depth 1 下面的仓库。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   https://github.com/LaT-SKY/nahimic-factory-audio-tuning&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1. 读 /proc/asound/card*/codec#* 与 /sys/bus/hdaudio/devices/*/uevent，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   报出 Vendor Id、Subsystem Id 和 MODALIAS。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2. 在挂载好的 Windows 分区里找 A-Volute/Nahimic 的 INF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   （System32/DriverStore/FileRepository），读出里面的设备匹配串，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   确认 SUBSYS 与第 1 步一致；不一致就停，不要继续解包。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3. 解包 INF 指向的 CAB，把 Global.nsx、AudioProfiles/、Devices/、MicProfile/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   放进仓库的 data/ 目录，并告诉我实际路径。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4. 列出仓库里哪些脚本读环境变量、哪些把路径写死；写死的按我的实际路径改，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   改动逐条给我看。EasyEffects 若是 Flatpak，数据目录是&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   ~/.var/app/com.github.wwmm.easyeffects/data/easyeffects&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;5. 依次跑 tools/build_factory_preset.py、build_nahimic_music.py、&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   add_bass_compressor.py、build_scenario_presets.py、build_capture_presets.py。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   其中 build_factory_preset.py 要从已有的 output/Music.json 取限幅器键模板，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   缺这个文件就先告诉我。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;6. 跑 tools/validate_presets.py 与 tools/validate_complete.py，把结果报给我。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;7. 核对预设：卷积器的 autogain 已关、kernel-name 不带扩展名、顺序是&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   低音增强器 → 卷积器 → 高架 EQ → 多频段压缩器 → 限幅器（旁路）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;底线：不要伪造参数，不要把没验证的算法写成结论。人声增强、DRC、衰减器没有建模，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;不要自己补；HRTF 那条路已经撤销；扬声器 FIR 的 A/B 变体必须由我确认，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;不能按文件数量猜。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
</content:encoded><category>Nahimic</category><category>EasyEffects</category><category>PipeWire</category><category>DSP</category><category>Linux</category></item><item><title>TUN 的 fake-ip 让抓取工具拒绝了所有域名</title><link>https://miprota.cc/posts/fake-ip-blocks-fetch/</link><guid isPermaLink="true">https://miprota.cc/posts/fake-ip-blocks-fetch/</guid><description>一个抓取网页的工具在 Clash Verge 的 TUN 模式下全量报错：域名被解析成 198.18.x.x（RFC 2544 保留段），它的公网地址校验判定成内网地址。改 DNS 的 enhanced-mode 修好了主体，第二个坑在 AAAA 上。</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;网页抓取工具 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在任意 URL 上都立即失败：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Error: URL hostname &quot;example.com&quot; resolves to a non-public IP address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;失败是瞬时的，没有网络等待。同一时间 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 正常，浏览器和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;curl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 访问同一个 URL 也正常。&lt;/p&gt;
&lt;h2 id=&quot;环境&quot;&gt;环境&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;系统&lt;/td&gt;
&lt;td&gt;CachyOS（Arch）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;代理&lt;/td&gt;
&lt;td&gt;Clash Verge Rev，mihomo 内核，TUN 模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS&lt;/td&gt;
&lt;td&gt;systemd-resolved → NetworkManager 的 dnsmasq&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工具&lt;/td&gt;
&lt;td&gt;DSH &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;@deepseek-ai/dsh-web-fetch-http&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;复现这个问题需要两个条件：内核开着 fake-ip（TUN 模式最容易碰到），以及被调用的工具会校验目标地址是不是公网地址。&lt;/p&gt;
&lt;h3 id=&quot;这套做法在什么环境上验证过&quot;&gt;这套做法在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS (Arch) ｜ Clash Verge Rev（mihomo 内核）｜ TUN 模式 ｜ 混合端口 7897&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;只在这一个组合上实测过。下面这些地方会因环境而异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.0/15&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个假地址段&lt;/strong&gt;：⚠️ 取决于内核的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fake-ip-range&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。判断方法不变：解析结果落在保留段里就是它。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;IPV6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 两个键&lt;/strong&gt;：✅ mihomo 系内核通用，键名一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用 Merge 覆写订阅配置&lt;/strong&gt;：⚠️ 这是 Clash Verge Rev 的做法，别的客户端一般直接改配置本体。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拦截发生在工具侧&lt;/strong&gt;：⚠️ 本次被测的是 DSH 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。换一个工具，只要它做公网地址校验就会复现；不做校验的工具不会。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.ipv6: false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 从哪来&lt;/strong&gt;：❌ 因 Verge 版本而异。本次是它的 IPv6 开关注入的，关掉那个开关这条就没了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;一先看域名解析出来的是什么&quot;&gt;一、先看域名解析出来的是什么&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hosts&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 198.18.0.64     example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ahostsv4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; www.baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 198.18.0.65     STREAM www.baidu.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.0/15&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 RFC 2544 给网络设备基准测试留的保留段，不可能是真实网站地址。&lt;/p&gt;
&lt;p&gt;这正是 Clash / mihomo 的 &lt;strong&gt;fake-ip 模式&lt;/strong&gt;：给每个域名发一个假地址，应用连到假地址，由 TUN 网卡按域名转发。这台机器上那张网卡叫 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Meta&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，地址是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.1/30&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;h2 id=&quot;二glibc-与-c-ares-走的是两条路&quot;&gt;二、glibc 与 c-ares 走的是两条路&lt;/h2&gt;
&lt;p&gt;同一个域名，两次查询结果不同：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;require(&apos;node:dns&apos;).lookup(&apos;example.com&apos;,{all:true},(e,a)=&amp;gt;console.log(e||a))&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# [ { address: &apos;198.18.0.64&apos;, family: 4 } ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;require(&apos;node:dns&apos;).resolve4(&apos;example.com&apos;,(e,a)=&amp;gt;console.log(e?e.code:a))&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# [ &apos;104.20.23.154&apos;, &apos;172.66.147.243&apos; ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.lookup()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走 glibc 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getaddrinfo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.resolve4()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 c-ares 直接问 DNS 服务器。差别在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nsswitch.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的顺序：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^hosts&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/nsswitch.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;resolve&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（nss-resolve，问 systemd-resolved）排在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（127.0.0.1 上的 dnsmasq）前面。而 resolved 把 TUN 那条链路当成了默认 DNS 源：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;resolvectl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; Meta&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#     Current DNS Server: 198.18.0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#            DNS Servers: 198.18.0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#             DNS Domain: ~.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#            Default Route: yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DNS Domain: ~.&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Default Route: yes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，意思是所有域名都交给 mihomo 的 DNS，于是全部返回 fake-ip。&lt;/p&gt;
&lt;p&gt;绕开 resolved 直接问本机 dnsmasq，拿到的是真实地址：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +short&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; @127.0.0.1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; example.com&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 104.20.23.154&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 172.66.147.243&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;三工具为什么拒绝&quot;&gt;三、工具为什么拒绝&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在发请求前会先解析主机名，再逐个校验地址范围：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```js
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; (parsed &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;instanceof&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ipaddr&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;IPv4&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; parsed&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;unicast&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ipaddr.js&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.0/15&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 归类为 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;reserved&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;const i=require(&apos;ipaddr.js&apos;);console.log(i.parse(&apos;198.18.0.64&apos;).range())&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# reserved&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;校验不通过就抛错。这是有意的 SSRF 防护，目的是不让抓取工具去访问回环、内网和链路本地这些地址。fake-ip 让所有公网域名都“看起来”是保留地址，于是全被拦下。&lt;/p&gt;
&lt;p&gt;同一个文件里还有一条给代理留的分支：请求若被判为走代理，就不再本地解析、也不做地址钉扎，域名交给代理去解析。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```js
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; route &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; proxyRouteFor&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(url)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; (route&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;proxied&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;isNonPublicIpLiteral&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(url&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hostname&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; publicHttpNetwork&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;requestVia&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(route&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;dispatcher&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; url&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; headers&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; signal)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; addresses &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;resolveAddresses&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(url&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hostname&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; signal)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;四三条修法&quot;&gt;四、三条修法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;给工具配出站代理&lt;/strong&gt;。在工具的用户级环境文件里写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HTTP_PROXY&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HTTPS_PROXY&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，走上面那条代理分支。
改动最小、随时可回滚。代价是它依赖代理进程一直在跑：代理完全退出时这条工具会连不上，而且没有直连回退。
另外 TUN 关掉、系统代理关掉时这条照样成立 —— 混合端口是内核自己的监听，与那两个开关无关。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nsswitch.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 顺序&lt;/strong&gt;，把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 提到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;resolve&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 前面，让 glibc 走 dnsmasq 拿真实地址。
从根上恢复真实解析。代价是它改变全系统的解析行为，而且需要 root；mihomo 每次重启都会重设 TUN 链路的 DNS。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;关掉 fake-ip&lt;/strong&gt;（本次采用）。在 Clash Verge 的全局扩展配置里把 DNS 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
改完不依赖任何代理进程存活，TUN 开着也正常。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;五关掉-fake-ip&quot;&gt;五、关掉 fake-ip&lt;/h2&gt;
&lt;p&gt;mihomo 的 DNS &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 有两个取值：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fake-ip&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;strong&gt;默认是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;，所以这一步是回到默认行为，不是 hack。&lt;/p&gt;
&lt;p&gt;Clash Verge Rev 的全局扩展配置（Merge）可以覆写订阅里的设置，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不在禁止覆写的名单里（名单是 mixed-port、log-level、external-controller 这一批）。&lt;/p&gt;
&lt;p&gt;在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Merge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 末尾追加：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```yaml
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dns&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  enhanced-mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; redir-host&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;改完&lt;strong&gt;不会自动生效&lt;/strong&gt;。实测：改完当时 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;clash-verge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 mtime 没变，里面的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 还是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fake-ip&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getent&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也还是返回 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.64&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;让它生效的办法是&lt;strong&gt;重启 Clash Verge&lt;/strong&gt;（实测有效：重启后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;clash-verge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;config.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 先后更新，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode: redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 落盘）。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--warning&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;注意&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;只「重开内核」不生效&lt;/strong&gt; —— 实测重启内核不会重新读 profile，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 还是旧值。
得让 Verge 本体重启一次。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;六第二个坑aaaa-污染&quot;&gt;六、第二个坑：AAAA 污染&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 生效后普通站点恢复了，但 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.google.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 仍然报同一个错。原因跟 fake-ip 无关：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +short&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; @198.18.0.2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; www.google.com&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      # 31.13.92.37   ← Facebook 的地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +short&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; @198.18.0.2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; www.google.com&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; AAAA&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # 2001::1       ← Teredo 段&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;这台机器用的是订阅自带的 DNS（全是国内 DNS），也没有配 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fallback&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：这类配置对部分境外域名的应答本身就可能被污染。&lt;/p&gt;
&lt;p&gt;而校验的策略是&lt;strong&gt;整个应答集里只要有一个地址不是公网地址就整体拒绝&lt;/strong&gt;：A 记录没问题，AAAA 记录把它拖垮了。同一批里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;youtube.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.facebook.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.wikipedia.org&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;twitter.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 AAAA 也是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2001::1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;让 DNS 干脆不返回 AAAA 就行：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.ipv6: false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。这台机器上它是 Clash Verge 的 IPv6 开关注入的（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;config.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与合并后的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;clash-verge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里各有一处，而 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;profiles/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下所有文件都不含 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ipv6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/p&gt;
&lt;p&gt;丢掉 AAAA 不损失可达性：本机没有全局 IPv6 地址，也没有 IPv6 默认路由。mihomo 文档里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;IPV6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为 false 的行为是“回应 AAAA 的空解析”，是正规做法。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;两个条件缺一不可：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.enhanced-mode: redir-host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 消除 fake-ip，
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.ipv6: false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 消除污染 IPv6。只做前者时，应答被污染的那些域名仍然会失败。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;七验证结果&quot;&gt;七、验证结果&lt;/h2&gt;
&lt;p&gt;在 TUN 开启（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Meta&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 网卡在）的状态下实测：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getent ahostsv4 example.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;104.20.23.154&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不再是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.x.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;resolvectl query example.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：真实 IPv4（仍标注 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-- link: Meta&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，内容是真实地址）&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_fetch&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 访问 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;example.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.google.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.youtube.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.wikipedia.org&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;www.facebook.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;github.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / mihomo 官方文档 / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;raw.githubusercontent.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：全部 200&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：正常&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env | grep -i proxy&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为空，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.dsh/.env&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不存在：修复不依赖代理进程&lt;/li&gt;
&lt;li&gt;浏览器与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;curl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 侧回归：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;google.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;youtube.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;baidu.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;github.com&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 全部 200，标题正确&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;八自检命令&quot;&gt;八、自检命令&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 是否还在 fake-ip：出现 198.18.x.x 就是中招&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ahostsv4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# resolved 是否把 TUN 链路当成了全域名 DNS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;resolvectl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; Meta&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;DNS Server|DNS Domain|Default Route&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;resolvectl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; query&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 绕开 resolved 的真实解析&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +short&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; @127.0.0.1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; example.com&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# AAAA 有没有被污染&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +short&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; @198.18.0.2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; www.google.com&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; AAAA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 混合代理端口可用性（默认 7897）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /dev/null&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -w&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;%{http_code}\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; http://127.0.0.1:7897&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; https://example.com/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;九排错&quot;&gt;九、排错&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;改了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Merge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没变化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能原因：Verge 不监听 profile 文件，改完不会自动重新应用。&lt;/p&gt;
&lt;p&gt;怎么办：&lt;strong&gt;重启 Clash Verge&lt;/strong&gt;（只重开内核不生效，见第五节）；然后用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;clash-verge.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里落盘的值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;普通站点好了，个别站点仍然报同一个错&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能原因：那个域名的 AAAA 应答被污染，整个应答集因此被判为非公网。&lt;/p&gt;
&lt;p&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dig +short @&amp;lt;你的 DNS&amp;gt; &amp;lt;域名&amp;gt; AAAA&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看一眼；是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2001::1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之类就确认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.ipv6: false&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 生效了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TUN 关掉后一切正常，开着就坏&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能原因：TUN 链路带来了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DNS Domain: ~.&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 DNS 源，也就是 fake-ip 的来源。&lt;/p&gt;
&lt;p&gt;怎么办：按第五节改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；只想临时绕开就先关 TUN。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.lookup()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dns.resolve4()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 结果不一致&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能原因：前者走 glibc 的 nsswitch 链，后者走 c-ares 直接查 DNS。&lt;/p&gt;
&lt;p&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep &apos;^hosts&apos; /etc/nsswitch.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看顺序。判断“解析是否被代理接管”要用前者的结果。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.metacubex.one/config/dns/&quot;&gt;mihomo DNS 文档&lt;/a&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enhanced-mode&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;IPV6&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nameserver-policy&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的定义&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clashvergerev.com/en/guide/merge&quot;&gt;Clash Verge Rev — Merge Configuration&lt;/a&gt; —— 全局扩展配置能覆写什么、不能覆写什么&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc2544&quot;&gt;RFC 2544&lt;/a&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;198.18.0.0/15&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个保留段的出处&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>DNS</category><category>Clash Verge</category><category>mihomo</category><category>fake-ip</category><category>代理</category></item><item><title>树莓派插上网线就能连：给 eth0 加 link-local 回退</title><link>https://miprota.cc/posts/pi-eth0-link-local/</link><guid isPermaLink="true">https://miprota.cc/posts/pi-eth0-link-local/</guid><description>eth0 只配了 dhcp4 时，遇到不发地址的对端就彻底连不上。加一份 netplan 覆盖文件：DHCP 优先，失败约 10 秒后自动补 169.254，另留一个永久锚点。文末是两个幂等脚本。</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;起因&quot;&gt;起因&lt;/h2&gt;
&lt;p&gt;朋友给了一台树莓派。我先把电脑开成一个同名热点，想让 Pi 自己连上来，没成。改用网线直连，还是有问题。于是有了这套调研。&lt;/p&gt;
&lt;p&gt;这台树莓派 5（Ubuntu 24.04）原来只有一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dhcp4: true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;strong&gt;谁来发地址，谁就是单点故障。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;中间接个交换机、或者换成一台默认不发地址的电脑直连，就拿不到 IPv4，只剩 mDNS 和 IPv6 那两条路可走。&lt;/p&gt;
&lt;p&gt;现在的目标是插上网线就能连：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;          # 等价于 ssh pi@pi.local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;下面把主机名与用户名都写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，命令里换成你自己的即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;一台跑 Debian / Ubuntu 的单板机（本次是树莓派 5），网络栈是 &lt;strong&gt;netplan → systemd-networkd&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：要往 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/netplan/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写文件，再跑一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;netplan apply&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;客户端这边不用装什么：Linux 上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 要有 mDNS（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libnss-mdns&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;avahi-daemon&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），装不了就走固定锚点&lt;/li&gt;
&lt;li&gt;想用锚点地址的话，客户端要能给自己加一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.2/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;这套做法在什么环境上验证过&quot;&gt;这套做法在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;树莓派 5 ｜ Ubuntu 24.04 ｜ systemd 255（netplan → systemd-networkd）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;客户端：CachyOS（Arch）—— 下面所有通路都是在这一台机器上测的&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;只在这一个组合上实测过。&lt;/strong&gt; 下面这些地方会因环境而异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;「DHCP 失败才补 IPv4LL」的语义&lt;/strong&gt;：✅ systemd-networkd 通用，出处见第三节的 man 引文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;覆盖文件的加载顺序&lt;/strong&gt;：✅ netplan 按文件名字典序合并，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;70-&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 排在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;50-&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后，所以它是补充而不是被顶掉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;link-local: [ipv4, ipv6]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个键&lt;/strong&gt;：✅ netplan 通用。不用 netplan 的话，对应的 systemd-networkd 设置是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LinkLocalAddressing=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;avahi 发布的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;名字.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：✅ 通用，跟着主机名走，与地址无关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv6 link-local 与 MAC 绑定&lt;/strong&gt;：✅ 通用，换网卡或换机器就会变。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows / macOS 直连&lt;/strong&gt;：⚠️ &lt;strong&gt;没有实测&lt;/strong&gt;。按它们的默认行为写（Win/mac 会自己配 IPv4LL、macOS 自带 Bonjour），照抄前自己确认一遍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手机 + USB-C 网卡走锚点&lt;/strong&gt;：⚠️ &lt;strong&gt;没有实测&lt;/strong&gt;，同上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;锚点地址 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.1/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：⚠️ 网段是自选的，只要不和家里网段撞就行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;一以前与现在的差别&quot;&gt;一、以前与现在的差别&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;电脑开着网络共享&lt;/strong&gt;：以前能连（NetworkManager 的共享模式会发 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;10.42.0.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;），现在一样能连。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换一根网线&lt;/strong&gt;：以前能连，现在能连（千兆口自动 MDIX，什么线都行）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接交换机，没有人发地址&lt;/strong&gt;：以前拿不到 IPv4，只能靠 mDNS/IPv6；现在约 10 秒后自动上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;169.254.x.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 直接可用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;插到家里的路由器上&lt;/strong&gt;：以前能连，现在一样能连。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换一台 Windows / macOS 电脑直连&lt;/strong&gt;：以前那台电脑默认不发地址；现在它自己会配 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;169.254.x.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（Win/mac 的默认行为），mDNS 也能解析 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手机加 USB-C 网卡直连&lt;/strong&gt;：以前不行；现在 mDNS 支持差的设备可以用锚点 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（手机静态设 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.2/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改动只有一件：给 eth0 加了 IPv4 link-local 回退，外加一个永久的固定锚点。&lt;/p&gt;
&lt;h2 id=&quot;二现在同时具备的四条通路&quot;&gt;二、现在同时具备的四条通路&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DHCP&lt;/strong&gt;：对端有 DHCP 服务器时自动获得。不需要对端额外配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;固定锚点 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：永远都在。需要客户端手工配 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.2/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不用配网关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv4 link-local &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;169.254.x.y&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：DHCP 失败约 10 秒后自动加上，地址每次自动选、会变。需要客户端也支持 IPv4LL（Win / macOS / Linux 默认都支持）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv6 link-local &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fe80::…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：与网卡 MAC 绑定，永远都在、零配置。需要客户端有 IPv6，默认都有。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;名字那条路是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（avahi / mDNS），它会同时发布上面所有地址，地址变了自动跟着变。所以平时只需要记住 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;第四条通路的地址由 MAC 派生，&lt;strong&gt;换网卡或换硬件就变&lt;/strong&gt;；&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不受影响。
网络里如果出现第二台同名机器，avahi 会把它改名成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi-2.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;三pi-上改了什么&quot;&gt;三、Pi 上改了什么&lt;/h2&gt;
&lt;p&gt;新增的文件只有一个，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/netplan/70-eth0-fallback.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```yaml
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 让 eth0 在有/没有 DHCP 服务器时都能连&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 优先级：DHCP（对端有服务器时，比如电脑共享或家里路由器）&amp;gt; 固定锚点 192.168.77.1 &amp;gt; IPv4 link-local 169.254.x.x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;network&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  version&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ethernets&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    eth0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      dhcp4&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      optional&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      # 同时开启 IPv4/IPv6 链路本地地址，完全不依赖任何服务器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      link-local&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;ipv4&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ipv6&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      # 固定锚点地址：给不支持 mDNS 的客户端手工直连用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      addresses&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 192.168.77.1/24&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;原有的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/netplan/50-cloud-init.yaml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没动，改之前备份了一份到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/root/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;应用方式：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; apply&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;注意这套网络栈是 &lt;strong&gt;netplan → systemd-networkd&lt;/strong&gt;，eth0 在 NetworkManager 里是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;unmanaged&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，所以用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nmcli&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 改是没有用的。&lt;/p&gt;
&lt;h3 id=&quot;为什么-dhcp-正常时看不到-169254&quot;&gt;为什么 DHCP 正常时看不到 169.254&lt;/h3&gt;
&lt;p&gt;systemd 255 的 man 页写得很直接：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An IPv4 link-local address is configured when &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;yes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; or &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ipv4&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; &lt;strong&gt;and when DHCPv4 autoconfiguration has been unsuccessful for some time.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;有 DHCP 就优先用 DHCP，失败才补 IPv4LL。这正是想要的语义：多一条兜底，不改动正常情况下的行为。&lt;/p&gt;
&lt;p&gt;实测（用一对 veth 造了一条没有 DHCP 服务器的链路，不碰 eth0）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DHCP=ipv4&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LinkLocalAddressing=ipv4&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：10 秒内拿到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;169.254.112.168/16&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;在此基础上再加静态地址（模拟锚点）：两者&lt;strong&gt;共存&lt;/strong&gt;，锚点不会顶掉回退。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;四两个脚本&quot;&gt;四、两个脚本&lt;/h2&gt;
&lt;p&gt;上面那份配置手写也就十行，但「备份 → 写入 → 校验 → 应用 → 验证」这套动作值得脚本化，另外脚本里加了一道&lt;strong&gt;自动回滚保险&lt;/strong&gt;。两个脚本都是幂等的，重复跑安全。&lt;/p&gt;
&lt;h3 id=&quot;setup-pish在-pi-上跑&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;setup-pi.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：在 Pi 上跑&lt;/h3&gt;
&lt;p&gt;它会先把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/netplan/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里现有的配置备份到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/root/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（带时间戳，不覆盖旧备份），再写新文件、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;netplan generate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 校验语法，然后挂一个 &lt;strong&gt;180 秒的自动回滚定时器&lt;/strong&gt;才应用 —— 如果新配置把网络弄断了，180 秒后它会自己删掉新文件并恢复。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 在 Pi 上（或 ssh 进去）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi@pi.local&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;sudo bash -s&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; setup-pi.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 在树莓派上运行（或 ssh 进去运行）：让 eth0 在没有 DHCP 服务器时也能连上。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： ssh pi@pi.local &apos;sudo bash -s&apos; &amp;lt; setup-pi.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   幂等：重复运行安全；自带 180 秒自动回滚保险。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 目的：不再依赖&quot;某一台电脑负责发地址&quot;。插上网线后，无论对端是&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   - 家里路由器（有 DHCP）        -&amp;gt; 拿路由器分配的地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   - 一台开着网络共享的电脑        -&amp;gt; 拿电脑分配的地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   - 交换机 / 另一台什么都没配的电脑 -&amp;gt; 自动上 169.254.x.x（IPv4 link-local）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   - 永远都在                    -&amp;gt; 固定锚点 192.168.77.1 + IPv6 链路本地 fe80::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 四种情况都能连。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/etc/netplan/70-eth0-fallback.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;192.168.77.1/24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;STAMP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +%F-%H%M%S&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $EUID &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-eq&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;请用 sudo 运行：sudo bash &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 1/5 备份现有 netplan 到 /root/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/netplan/*.yaml&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  [[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $f &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;  dest&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;/root/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;basename&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.bak-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$STAMP&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $dest &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$dest&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # 不覆盖已有备份&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -1t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /root/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.bak-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 2/5 写入 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;YAML&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;# 由 setup-pi.sh 生成：让 eth0 在有/没有 DHCP 服务器时都能连&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;# 优先级：DHCP &amp;gt; 固定锚点 192.168.77.1 &amp;gt; IPv4 link-local 169.254.x.x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;network:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  version: 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  ethernets:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    eth0:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      dhcp4: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      optional: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      link-local: [ipv4, ipv6]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      addresses:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;        - 192.168.77.1/24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;YAML&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 3/5 校验语法（失败则不动任何东西）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;netplan&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    语法 OK&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 4/5 挂 180 秒自动回滚保险，然后应用&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemd-run&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --on-active=180&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --unit=netplan-rollback&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  /bin/bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;rm -f &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;; netplan apply&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;netplan&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; apply&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;==&amp;gt; 5/5 验证&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -brief&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; eth0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; show&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; eth0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;%/*}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; stop&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan-rollback.timer&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; reset-failed&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan-rollback.timer&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan-rollback.service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;✅ 成功：锚点 &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;%/*}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 已生效，回滚保险已取消。&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;   现在这些通路都可用（mDNS 名称 pi.local 会同时发布它们）：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     - DHCP 地址        ：有 DHCP 服务器时自动获得&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     - 固定锚点         ：&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;%/*}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  （客户端配 192.168.77.2/24 即可直连）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     - IPv4 link-local  ：169.254.x.x  （无 DHCP 服务器时约 10 秒后自动获得）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     - IPv6 link-local  ：fe80::...    （一直都在，无需任何服务器）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;⚠️  没看到锚点地址，180 秒后会按原配置自动回滚。&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;setup-clientsh在要连-pi-的那台电脑上跑&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;setup-client.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：在要连 Pi 的那台电脑上跑&lt;/h3&gt;
&lt;p&gt;不需要 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不改系统配置，只往 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 写两个别名（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走 mDNS、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi-anchor&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 走固定锚点），然后按优先级探测一遍，告诉你哪条通路通了。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; setup-client.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ 跑之前先把脚本开头那两行改成你自己的主机名与用户名（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PI_NAME&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PI_USER&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，示例值是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 在一台新电脑上运行（Linux / macOS），配好连接树莓派所需的一切。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   用法： bash setup-client.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   不需要 sudo，不改系统配置，只写 ~/.ssh/config。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ⚠️ 先改下面两行：主机名与用户名换成你自己的（下面是示例值）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 做的事：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   1. 检查本机 mDNS（.local 域名）解析能力&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   2. 没有 SSH 密钥就生成一个&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   3. 往 ~/.ssh/config 写 pi / pi-anchor 两个别名&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   4. 按优先级探测树莓派，并说清哪条通路通了、哪条没通&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -uo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;pi.local&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PI_USER&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;pi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PI_ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;192.168.77.1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;192.168.77&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ANCHOR_CLIENT_IP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;192.168.77.2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;KEY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.ssh/id_ed25519&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;CFG&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.ssh/config&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;   {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;  \033[32m✅ %s\033[0m\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;bad&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;  \033[31m❌ %s\033[0m\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;warn&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;  \033[33m⚠️  %s\033[0m\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;\n==&amp;gt; %s\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;OS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;uname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;环境&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;  系统: &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;uname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -r&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---------- 1. mDNS ----------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;1/4 检查 mDNS（.local 域名解析）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;case&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  Darwin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;macOS 自带 Bonjour，&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 可直接用&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  Linux&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hosts&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;已能解析 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hosts &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;{print $1}&apos; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; tr&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;\n&apos; &apos; &apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; is-active&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --quiet&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; avahi-daemon&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      warn&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;avahi 在跑，但暂时解析不到 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;（Pi 可能没插线/没开机）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      bad&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;本机缺少 mDNS 支持，&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 解析不了&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     装一下（Debian/Ubuntu）： sudo apt install libnss-mdns avahi-daemon&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     或者退回固定锚点： 见下面 pi-anchor 别名&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  *)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    warn&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;未知系统，跳过 mDNS 检查&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;esac&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---------- 2. 密钥 ----------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;2/4 检查 SSH 密钥&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.ssh&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 700&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.ssh&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;已有 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ssh-keygen&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ed25519&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -N&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&amp;amp;1;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;已生成新密钥 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    warn&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;这是新电脑的新密钥：Pi 上默认没有它。两种办法登录——&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;       (a) 用密码登录一次，然后 ssh-copy-id &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;       (b) 直接把老电脑的 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KEY&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 拷过来&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    bad&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;密钥生成失败，请手动 ssh-keygen -t ed25519&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---------- 3. ssh config ----------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;3/4 写入 ~/.ssh/config&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -qE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;^Host\s+.*\bpi\b&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CFG&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;已存在 pi 相关配置，跳过（没动你的文件）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;# 连树莓派用的 SSH 别名 —— 由 setup-client.sh 添加&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;# 用法: ssh pi        (走 mDNS 名称，换网线/换地址都自动跟随)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;#      ssh pi-anchor (走固定锚点，需要本机有 192.168.77.x 地址)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;Host pi &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    HostName &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    User &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    IdentityFile ~/.ssh/id_ed25519&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    IdentitiesOnly yes&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    ServerAliveInterval 30&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    StrictHostKeyChecking accept-new&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;Host pi-anchor&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    HostName &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    User &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    IdentityFile ~/.ssh/id_ed25519&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    IdentitiesOnly yes&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;    StrictHostKeyChecking accept-new&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CFG&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  chmod&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 600&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CFG&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;已写入 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CFG&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;（pi / pi-anchor）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ---------- 4. 探测 ----------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;4/4 探测树莓派&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;try_ssh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; BatchMode=yes&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ConnectTimeout=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; StrictHostKeyChecking=accept-new&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;echo $(hostname)&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;CONNECTED&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; H&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;try_ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$H&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;mDNS 通路可用：ssh &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  (主机名 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$H&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;  CONNECTED&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  bad&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;mDNS 通路不通：&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_NAME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONNECTED&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;\.&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;     ifconfig&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;inet &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;\.&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; H&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;try_ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$H&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;锚点通路可用：ssh &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  (主机名 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$H&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;      CONNECTED&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      bad&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;锚点通路不通：&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    warn&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;本机没有 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.x 地址，锚点通路用不了&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     想用它就手工加一个地址（需要管理员权限）：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    case&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      Darwin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;       sudo ifconfig &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\$&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;(route -n get default | awk &apos;/interface/{print &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\$&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;2}&apos;) alias &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$ANCHOR_CLIENT_IP&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netmask 255.255.255.0&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;      *)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;       sudo ip addr add &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$ANCHOR_CLIENT_IP&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/24 dev &amp;lt;你的网卡名&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    esac&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -z&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$CONNECTED&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]];&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  warn&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;两条路都不通。快速排查：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     · 网线插好了吗？Pi 的网口灯亮吗？（Pi 5 千兆口支持任意网线，不需要交叉线）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     · 看本机邻居表里有没有可疑的 Pi：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    Darwin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;         arp -a | grep -E &apos;169&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.254|&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;|10&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.42&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.&apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    *)&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;      echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;         ip neigh | grep -E &apos;169&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.254|&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$PI_ANCHOR_NET&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;|10&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.42&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.&apos;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  esac&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     · 找不到就用 IPv6 广播 ping 整条链路：&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;         ping6 -c3 ff02::1%&amp;lt;你的网卡名&amp;gt;   # macOS/Linux&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;     · 还是没有：Pi 没开机，或者它卡在启动 / 别的问题&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;搞定。以后一条命令： ssh pi&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;五重启验证&quot;&gt;五、重启验证&lt;/h2&gt;
&lt;p&gt;断电重启是这个方案里没法在运行中验证的一环，所以单独测了一次：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;确实重启了&lt;/strong&gt;：开机时间从 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;04:23:06&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 变成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;05:21:51&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;eth0 地址&lt;/strong&gt;：重启前是静态锚点、DHCP 地址、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fe80::…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 三个，重启后完全一致，全部自动恢复。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认路由&lt;/strong&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;via 10.42.0.1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（走电脑共享上网），一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;avahi 与 ssh&lt;/strong&gt;：都是 active，且自启。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：可用，Pi 出网也正常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多余的 169.254&lt;/strong&gt;：无。有 DHCP 时本来就不该有。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;重启耗时：kernel &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;5.357s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; + userspace &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;44.844s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，掉线到 SSH 恢复大约 30 秒。&lt;/p&gt;
&lt;p&gt;结论：配置是持久的，拔电、换线、换电脑都不需要再动 Pi。&lt;/p&gt;
&lt;h2 id=&quot;六换一台新电脑怎么连&quot;&gt;六、换一台新电脑怎么连&lt;/h2&gt;
&lt;p&gt;跑一遍 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;setup-client.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（见上一节）。手动做的话是这三步：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 1) 先看通路在不在&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ping&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;arp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;169\.254|192\.168\.77|10\.42\.&apos;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # .local 不通时用这个找地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2) 新电脑的公钥还没装到 Pi 上时，先用密码登录一次&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ssh-copy-id&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi@pi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 3) 写 ssh 别名，以后直接用 ssh pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.ssh/config&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;EOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;Host pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    HostName pi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    User pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;第三步里 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HostName&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；如果这台电脑解析不了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，把它改成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（网卡先设静态 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.2/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）即可。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 解析需要 mDNS：Debian / Ubuntu 上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo apt install libnss-mdns avahi-daemon&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。Ubuntu 22.04 之后的 systemd-resolved 通常也能直接解析。装不了就用锚点地址。&lt;/p&gt;
&lt;p&gt;Windows 10 / 11 自带 mDNS 解析和 OpenSSH，基本开箱可用：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;powershell&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```powershell
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 1) 探测&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ping pi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;ssh pi&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pi.local                &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 首次问指纹，输 yes；没有密钥就用密码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2) 万一 .local 不通，从邻居表里找地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;arp &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;a &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; findstr &lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;169.254 192.168.77 10.42.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 3) 写别名：%USERPROFILE%\.ssh\config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;实在解析不了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 时，给网卡设静态地址 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.77.2 / 255.255.255.0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，然后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi@192.168.77.1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;h2 id=&quot;七连不上时的排查顺序&quot;&gt;七、连不上时的排查顺序&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ① 名字能不能解析（能解析说明 avahi 在，只是路可能不通）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;avahi-resolve&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ② 邻居表里找 Pi：三条通路各自的网段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; neigh&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;169\.254|192\.168\.77|10\.42\.&apos;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;     # Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;arp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                                                  # macOS / Windows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ③ 整条链路 IPv6 广播 ping，最底层的&quot;有人吗&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ping6&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ff02::1%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;你的网卡&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;名&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 会列出链路上所有 IPv6 主机&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ④ mDNS 彻底不通时，用锚点（客户端先配 192.168.77.2/24）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pi@192.168.77.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;网口灯不亮就是物理层问题，先换线换口。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实测遇到过一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh: Could not resolve hostname pi.local: Temporary failure in name resolution&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
那是&lt;strong&gt;客户端&lt;/strong&gt; mDNS 解析的瞬时抖动，当时 Pi 完全正常（直连 IP 与 IPv6 广播 ping 都通），重试一次或者直接用 IP 连就好。
mDNS 只是方便，不是非它不可 —— 这也是锚点地址一直留着的理由。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;八几条运维备注&quot;&gt;八、几条运维备注&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;登录 shell 是 fish 的话&lt;/strong&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi@pi.local &apos;带*通配符的命令&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会被 fish 解析而报错，脚本化时写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh pi@pi.local &apos;bash -s&apos; &amp;lt;&amp;lt;&apos;EOF&apos;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这种显式 bash 的形式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;两条默认路由的 metric&lt;/strong&gt;：同时接了有线与 WiFi 时，metric 小的优先（netplan 里可以给 WiFi 设 50、有线设 100），于是插着网线也可能走 WiFi。自己按需要调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换硬件或重刷系统之后 SSH 指纹会变&lt;/strong&gt;：客户端执行 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ssh-keygen -R pi.local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 清掉旧记录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;optional: true&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 别省&lt;/strong&gt;：没有它时，DHCP 等不到地址会拖慢开机（systemd-networkd 要等超时）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;九怎么撤销&quot;&gt;九、怎么撤销&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/netplan/70-eth0-fallback.yaml&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; netplan&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; apply&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 需要的话再还原云初始化的那份&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /root/50-cloud-init.yaml.bak&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/netplan/50-cloud-init.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemd.network&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; — &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;LinkLocalAddressing=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/a&gt;：DHCP 失败才补 IPv4LL 那条语义的出处&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://netplan.readthedocs.io/en/stable/&quot;&gt;netplan 文档&lt;/a&gt;：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;link-local&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;optional&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 等键的说明&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc3927&quot;&gt;RFC 3927&lt;/a&gt;：IPv4 link-local 地址（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;169.254.0.0/16&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）的规范&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>树莓派</category><category>netplan</category><category>systemd-networkd</category><category>mDNS</category><category>IPv4 link-local</category></item><item><title>链接悬停填充：细线长满、文字翻色，以及一些奇怪的 BUG</title><link>https://miprota.cc/posts/link-hover-fill/</link><guid isPermaLink="true">https://miprota.cc/posts/link-hover-fill/</guid><description>文章正文里的链接，悬停时底部细线向上长满、文字翻成背景色。两条实现路线的实测差别、两处会坏掉的环境，以及&quot;快速划过也要播完&quot;为什么只能用一段脚本。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;文章正文里的链接，悬停时底部那条细线向上长满整个链接，文字同时从链接色翻成背景色。
下面是这套效果的实现、实测数据，以及它在什么环境下不成立。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;数字都在本机 Chromium 151（Chrome for Testing）上用 CDP 量的，
量法写在「怎么复算」一节。
最后，这是一篇记录向，可能对你没有帮助。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;目标与参数&quot;&gt;目标与参数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;取值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;静止态&lt;/td&gt;
&lt;td&gt;一条 2px 细线，撑满链接宽度，位置与原来的下划线重合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;悬停态&lt;/td&gt;
&lt;td&gt;细线向上长满（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-size: 100% 2px&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;100% 100%&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文字&lt;/td&gt;
&lt;td&gt;从 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--rose-ink&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 翻成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;时长 / 缓动&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--dur-base&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（260ms）/ &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--ease-out&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;触屏&lt;/td&gt;
&lt;td&gt;阉割&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;键盘&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:focus-visible&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 hover 走同一套&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;填充色与翻转色是既有链接色的反用：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--rose-ink&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 压在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上是 5.12:1，
反过来的对比度相同，所以没有引入新的配色对，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;check:contrast&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的阈值不用改。&lt;/p&gt;
&lt;h2 id=&quot;作用范围&quot;&gt;作用范围&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;main&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的链接都有这个效果，几处例外：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;效果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;首页的「最近写的」、文章列表页的标题、项目页、关于页、标签页、404&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文章正文&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文章页的目录、上一篇 / 下一篇、返回列表&lt;/td&gt;
&lt;td&gt;❌（显式标记 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.no-fill&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;标签胶囊&lt;/td&gt;
&lt;td&gt;❌（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.tag&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，胶囊本身有底色）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;页头导航、页脚与备案&lt;/td&gt;
&lt;td&gt;❌（它们在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;main&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之外）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;排除导航与页脚除了观感，还有一个具体原因：&lt;strong&gt;那些链接的静止色不是链接色&lt;/strong&gt;，
它们是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--ink-muted&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--ink-dim&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。而 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Base.astro&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 scoped 样式里写着
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.site-nav a:hover { color: var(--rose-ink) }&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.site-footer__filing a:hover { color: var(--rose-ink) }&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
这几条比新加的样式表优先级高（Astro 的 scoped 样式会带上属性选择器）。
结果是悬停时文字颜色被设成&lt;strong&gt;填充色本身&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;导航链接悬停 400ms 后：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  color = rgb(186, 56, 86)     ← --rose-ink，与填充同色&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  background-size = 100% 100%  ← 填充已铺满&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  → 玫瑰色字压在玫瑰色块上，那块看起来是空的&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;正文链接没有这条冲突（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;a:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那条优先级更低），悬停终态是
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;rgb(247, 246, 241)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，也就是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;这类冲突不会报错、也不影响其它属性：&lt;strong&gt;只有颜色被顶掉&lt;/strong&gt;，
表现是“填充块里没有字”。改 hover 颜色时先查一遍有没有更高优先级的同名规则。&lt;/p&gt;
&lt;h2 id=&quot;实现路线&quot;&gt;实现路线&lt;/h2&gt;
&lt;h3 id=&quot;路线一整字翻色&quot;&gt;路线一：整字翻色&lt;/h3&gt;
&lt;p&gt;文字颜色用一次普通的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;color&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 过渡，与填充块的上升同时进行。块是链接自己的背景：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```css
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-image&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; linear-gradient&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--fill&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--fill&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-repeat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; no-repeat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-size&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; background-size &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; color&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-size&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--flip&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;中间那 130ms 里，被盖住的下半个字是“玫瑰色字压在玫瑰色块上”。
把填充阈值设为 65%、文字色取过渡中点后截屏，逐像素统计覆盖区域：
&lt;strong&gt;纸色像素 0.0%&lt;/strong&gt;，字与底色同色。&lt;/p&gt;
&lt;h3 id=&quot;路线二精确裁切&quot;&gt;路线二：精确裁切&lt;/h3&gt;
&lt;p&gt;字色不是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;color&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，而是一张裁到字形上的渐变（下半是背景色、上半是链接色，
硬断点在中间），用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-position&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 让断点跟着填充块的上沿走：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```css
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  color&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; transparent&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-image&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; linear-gradient&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(to&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; top&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--paper&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--rose-ink&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-size&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-clip&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; text&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; background-position &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  content&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; z-index&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--rose-ink&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; scaleY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; transform-origin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; bottom&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; transform &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; scaleY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;两个量都是“进度 p 的线性函数”：块的上沿在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;(1−p)·H&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，渐变里那条硬断点在窗口里的
位置也在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;(1−p)·H&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。同一条缓动、同一个时长，于是每一帧都重合。
实测把填充阈值设为 50%：填充上沿落在图 y82，理论值 y84，&lt;strong&gt;差 0.5 CSS px&lt;/strong&gt;；
同一段覆盖区域里纸色像素 &lt;strong&gt;17.8%&lt;/strong&gt;，字完整可见。&lt;/p&gt;
&lt;h3 id=&quot;取舍&quot;&gt;取舍&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;路线一 · 整字翻色&lt;/th&gt;
&lt;th&gt;路线二 · 精确裁切&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;中间态&lt;/td&gt;
&lt;td&gt;有，覆盖区域里字与底色同色&lt;/td&gt;
&lt;td&gt;无，逐帧重合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;折行的链接&lt;/td&gt;
&lt;td&gt;正常，逐行分别填充&lt;/td&gt;
&lt;td&gt;坏：字形消失&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;带底色的容器&lt;/td&gt;
&lt;td&gt;正常&lt;/td&gt;
&lt;td&gt;坏：链接整个看不见&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖&lt;/td&gt;
&lt;td&gt;只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-size&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 过渡&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-clip: text&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; + &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;z-index: -1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;本站用路线一。中间态只存在 260ms，而路线二要付出两种环境下失效的代价，
而且失效是静默的：页面不会报错，只是看起来“这里没样式”。&lt;/p&gt;
&lt;h2 id=&quot;精确裁切不成立的-bug&quot;&gt;精确裁切不成立的 BUG&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，局限于笔者水平，您可能在实际编码过程中可以完美解决这些问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;折行的链接&quot;&gt;折行的链接&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-clip: text&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的渐变按每一行各自计算（每行都当成“上半链接色、下半背景色”），
悬停终态下整个链接的字都会变成背景色，在纸面上就是&lt;strong&gt;字消失&lt;/strong&gt;；
同时 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;inset: 0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的伪元素在折行的行内元素上退化了，填充块也看不见。
用 22ch 的窄容器把一条长链接逼成五行，实测：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;路线&lt;/th&gt;
&lt;th&gt;悬停终态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;整字翻色&lt;/td&gt;
&lt;td&gt;逐行分别长满，能读&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;精确裁切&lt;/td&gt;
&lt;td&gt;字形消失，填充块退化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;带底色的容器&quot;&gt;带底色的容器&lt;/h3&gt;
&lt;p&gt;路线二的填充块靠 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;z-index: -1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 躲在字形下面，而“负 z-index 的子孙”画在
&lt;strong&gt;最近的层叠上下文&lt;/strong&gt;里。链接与那个上下文之间只要有一块带背景的元素
（表格单元格、提示块、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper-sunken&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 面板），填充就会被那块背景盖住：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层&lt;/th&gt;
&lt;th&gt;悬停时&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;容器背景&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper-sunken&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;填充块&lt;/td&gt;
&lt;td&gt;被盖住，不可见&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文字&lt;/td&gt;
&lt;td&gt;翻成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--paper-sunken&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;结果&lt;/td&gt;
&lt;td&gt;整条链接消失&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;绕法只有一条：给链接套一层自己开层叠上下文（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;isolation: isolate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）的容器，
把填充挂在那一层上。折行那条仍然绕不开。&lt;/p&gt;
&lt;h2 id=&quot;快速划过-a-时不中断-hover-动画&quot;&gt;快速划过 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;a&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 时不中断 hover 动画&lt;/h2&gt;
&lt;h3 id=&quot;现象&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;鼠标快速划过一个链接（悬停 50ms 就走）时，动画只播了个开头。
实测（正常速度 260ms，每 80ms 采一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-size&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;悬停 60ms 后移开：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  + 40ms   填充 31.4%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +120ms   填充  1.5%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  +200ms   填充  0.0%   → 回到细线&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;指针离开 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 之后过渡改向，CSS 还有一条“反向”规则会按比例缩短时长，
于是只剩一闪。&lt;/p&gt;
&lt;h3 id=&quot;为什么不用-css-解决&quot;&gt;为什么不用 CSS 解决&lt;/h3&gt;
&lt;p&gt;动画与过渡都挂在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上，选择器一失效就被撤掉，而 CSS 里没有任何东西
能记住“刚才 hover 过”。三条看着可行的绕法都不成立：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;绕法&lt;/th&gt;
&lt;th&gt;实际结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;换成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;@keyframes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 动画&lt;/td&gt;
&lt;td&gt;同样挂在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上，指针一走照样被撤掉&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;退场加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;transition-delay&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;延迟期间属性停在旧值，填充卡在半路不动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;animation-play-state: paused&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;离开时是“暂停”不是“继续”，填充冻在半路&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;使用只监听类名的脚本&quot;&gt;使用只监听类名的脚本&lt;/h3&gt;
&lt;p&gt;指针离开时，如果进场还没跑完，就把“悬停态”这个类名留到那一刻再摘；
摘掉类名才开始退场，于是一进一出都完整。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.fx-hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 共用同一份声明，
脚本不碰任何样式属性：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```js
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; until &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; WeakMap&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; timer &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; WeakMap&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// ⚠️ CSS 时长读出来可能是 &quot;260ms&quot;，也可能是 &quot;2.08s&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;v&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; parseFloat&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(v) &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(v)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;indexOf&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;ms&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; dur&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;matchMedia&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;(prefers-reduced-motion: reduce)&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;  // 没有过渡就不必等&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;--dur-base&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(SEL)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;  el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;pointerenter&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    clearTimeout&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(timer&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;classList&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;fx-hover&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    until&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; performance&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; dur&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;  el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;pointerleave&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; off&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;classList&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;fx-hover&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    var&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; rest &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; (until&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el) &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; performance&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; (rest &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;) timer&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(el&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; setTimeout&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(off&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; rest))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   // 进场没跑完 → 等它跑完&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; off&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                                           // 已经跑完 → 立刻退场&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;strong&gt;读 CSS 时长进 JS 时的单位&lt;/strong&gt;：同一个变量读出来可能是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&quot;260ms&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
也可能是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&quot;2.08s&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，浏览器会把 1 秒以上的时长换成秒表示。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;parseFloat(&quot;2.08s&quot;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 等于 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2.08&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，于是“等 2.08 毫秒”，类名当场被摘掉、
补完功能静默失效；而普通速度下读到的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&quot;260ms&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，看不出问题。
把时长放大 8 倍观察才会暴露。所有把 CSS 时长读进 JS 的地方都要先判单位。&lt;/p&gt;
&lt;p&gt;实测同一划法（悬停 50–60ms 后移开）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;有这段脚本：  90.7% → 99.5% → 100% → 停住 → 9.3% → 0.1% → 2px&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;没有：        31.4% →  1.5% →  0.0%（回到细线）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;退场方向继续向上&quot;&gt;退场方向：继续向上&lt;/h2&gt;
&lt;p&gt;进场自下而上灌满，退场不原路退回、而是继续向上排空走掉 —— 这需要两个方向
用不同的插值起点，而一个属性的过渡只有一个起点。做法是把填充拆成两层，两层同色：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```css
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* ① 进场层：链接自己的背景，细线 → 长满 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-image&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; linear-gradient&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--fill&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--fill&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-repeat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; no-repeat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-size&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;  /* 静止态的 transition 写成 0s：离开 hover 时它瞬间回细线，把退场让给下面那层 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; background-size &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; color&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background-size&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; background-size &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; color&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;/* ② 退场层：同色的伪元素，缩向顶端 = 向上排空 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  content&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; absolute&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; inset&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; z-index&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  background&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--fill&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; scaleY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transform-origin&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; top&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; transform &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;--ease-out&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transform&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; scaleY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;  /* ③ 延迟一个进场时长才补满，否则它一上来就盖满，进场的长上去就看不见了 */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  transition&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; transform &lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 260&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ms&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;偏差在于 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;transition&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的第四个位置（延迟）：进场期间退场层保持零高度，
进场结束的那一刻它补满，离开时它缩向顶端。&lt;/p&gt;
&lt;p&gt;实测（慢放 8 倍逐帧）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;时刻&lt;/th&gt;
&lt;th&gt;进场层&lt;/th&gt;
&lt;th&gt;退场层 scaleY&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;首屏 160ms&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;100% 2px&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;进场中&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;悬停终态&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;退场 +220ms&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;100% 2px&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0.559&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;退场 +300ms&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;100% 2px&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0.192&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;退场 +420ms&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;100% 2px&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0.037&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;退场时填充块始终贴在元素顶端往下缩，底部细线同时已经回来。
退化情况两条：快速划进划出时退场层可能还没补满，那时就是普通的“退回去”；
链接落在带底色的容器里时，退场层被容器背景盖住，表现是填充直接消失。
&lt;strong&gt;本站没有采用这一版&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;怎么复算&quot;&gt;怎么复算&lt;/h2&gt;
&lt;p&gt;静止态可以直接在控制台里看：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```js
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(document&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;main a:not(.tag, .no-fill)&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;backgroundSize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// → &quot;100% 2px&quot;     细线&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;getComputedStyle&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(document&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;main a:not(.tag, .no-fill)&apos;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;textDecorationLine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// → &quot;none&quot;         细线取代了原来的下划线&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;中间态要把它钉住再看（否则 260ms 一晃就过去了）。用 CDP 注入一段只改动目标值的样式，
&lt;strong&gt;等过渡跑完&lt;/strong&gt;再截屏：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```css
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;has-hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;lk--c&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; background-position&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; !important&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;has-hover&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;lk--c&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;after&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; scaleY&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; !important&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;「快速划过」要发真实鼠标事件，不是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;dispatchEvent&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```js
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dispatchMouseEvent&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;mouseMoved&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// 移到链接上&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;// 等 50ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dispatchMouseEvent&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;mouseMoved&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;通用性&quot;&gt;通用性&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;结论&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;量测环境&lt;/td&gt;
&lt;td&gt;Chromium 151.0.7922.34（Chrome for Testing），Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用到的特性&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background-size&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 过渡、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:is()&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;@media (hover: hover) and (pointer: fine)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;WeakMap&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;浏览器验证范围&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;只在 Chromium 里量过&lt;/strong&gt;；Firefox 与 Safari 没验&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;触屏&lt;/td&gt;
&lt;td&gt;按设计整段不生效（媒体查询），未在真机验收&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;过渡时长归零（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;base.css&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 有全局兜底），未单独验收&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;排错表&quot;&gt;排错表&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;th&gt;下一步&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;填充块里没有字，整块看起来是空的&lt;/td&gt;
&lt;td&gt;有更高优先级的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 规则把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;color&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 设成了填充色&lt;/td&gt;
&lt;td&gt;查该链接所在的容器有没有自己的 hover 颜色规则（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--rose-ink&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这类），用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getComputedStyle(el).color&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在悬停时对比&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;快速划过只闪一下&lt;/td&gt;
&lt;td&gt;补完脚本没跑（JS 关了）、或它的选择器没覆盖到这条链接&lt;/td&gt;
&lt;td&gt;看元素上有没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.fx-hover&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；确认选择器与样式表范围一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;悬停时长变了但类名立刻就摘&lt;/td&gt;
&lt;td&gt;CSS 时长读进 JS 没判单位（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2.08s&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2.08&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）&lt;/td&gt;
&lt;td&gt;打印 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;getComputedStyle(el).getPropertyValue(&apos;--dur-base&apos;)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看实际字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;折行的链接悬停后字消失&lt;/td&gt;
&lt;td&gt;用了精确裁切那一路&lt;/td&gt;
&lt;td&gt;换整字翻色；这条路对折行不成立&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;带底色的块里链接悬停后看不见&lt;/td&gt;
&lt;td&gt;同上，填充被容器背景盖住&lt;/td&gt;
&lt;td&gt;换整字翻色，或给链接套一层 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;isolation: isolate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;静止态多出一条下划线&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;text-decoration&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没去掉&lt;/td&gt;
&lt;td&gt;细线本身就是下划线，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;text-decoration: none&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><category>CSS</category><category>动画</category><category>无障碍</category></item><item><title>Markdown 支持清单</title><link>https://miprota.cc/posts/markdown-support/</link><guid isPermaLink="true">https://miprota.cc/posts/markdown-support/</guid><description>每条语法：写法、渲染结果，以及它在终端浏览器（w3m / lynx）里读成什么。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;标题&quot;&gt;标题&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 二级标题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;二级标题&quot;&gt;二级标题&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 三级标题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;三级标题&quot;&gt;三级标题&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;####&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 四级标题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h4 id=&quot;四级标题&quot;&gt;四级标题&lt;/h4&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;#####&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 五级标题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h5 id=&quot;五级标题&quot;&gt;五级标题&lt;/h5&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;######&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 六级标题&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h6 id=&quot;六级标题&quot;&gt;六级标题&lt;/h6&gt;
&lt;p&gt;终端：w3m 给每个标题前后各留一个空行，不按层级缩进，三级以下彼此分不出来；lynx 每级缩进两格，层级看得见。&lt;/p&gt;
&lt;h2 id=&quot;自定义锚点&quot;&gt;自定义锚点&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt; 一个不跟着文字改的锚点 {#stable-anchor}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;stable-anchor&quot;&gt;一个不跟着文字改的锚点&lt;/h3&gt;
&lt;p&gt;终端：HTML 里是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;id=&quot;stable-anchor&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，改标题文字不影响这个锚点。&lt;/p&gt;
&lt;h2 id=&quot;行内标记&quot;&gt;行内标记&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;粗体&lt;/strong&gt; &lt;em&gt;斜体&lt;/em&gt; &lt;del&gt;删除线&lt;/del&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;行内代码&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上标&lt;sup&gt;2&lt;/sup&gt; 下标&lt;sub&gt;n&lt;/sub&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8;font-weight:bold&quot;&gt;粗体&lt;/span&gt;&lt;span style=&quot;color:#8892B4;font-weight:bold&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color:#8892B4;font-style:italic&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7;font-style:italic&quot;&gt;斜体&lt;/span&gt;&lt;span style=&quot;color:#8892B4;font-style:italic&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ~~&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;删除线&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;~~&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;行内代码&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 上标^2^ 下标~n~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;转义：*这一对星号不是斜体*。实体：© —  （不间断空格）。&lt;/p&gt;
&lt;p&gt;终端：粗体、斜体、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;kbd&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的样式全部消失；删除线读作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[DEL:删除线:DEL]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，上标读作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;^2&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，下标读作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[n]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（lynx 的方括号里多两个空格）；行内代码多出一对反引号。&lt;/p&gt;
&lt;h2 id=&quot;链接&quot;&gt;链接&lt;/h2&gt;
&lt;p&gt;站内链接：&lt;a href=&quot;/posts/&quot;&gt;全部文章&lt;/a&gt;。站外链接：&lt;a href=&quot;https://github.com/withastro/astro&quot;&gt;Sätteri 的仓库&lt;/a&gt;。自动链接：&lt;a href=&quot;https://astro.build&quot;&gt;https://astro.build&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;终端：只有链接文字，看不到地址；但链接本身能跳转 —— w3m 里 &lt;kbd&gt;Tab&lt;/kbd&gt; 选中、回车跟随（实测从本页的自动链接跳到了 astro.build）。&lt;/p&gt;
&lt;h2 id=&quot;列表&quot;&gt;列表&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 第一项&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 第二项&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;第一项&lt;/li&gt;
&lt;li&gt;第二项，里面可以放 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;代码&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与&lt;strong&gt;粗体&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 第一步&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 第二步&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;第一步&lt;/li&gt;
&lt;li&gt;第二步&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 上层&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 下层用四个空格缩进&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;上层
&lt;ul&gt;
&lt;li&gt;下层用四个空格缩进&lt;/li&gt;
&lt;li&gt;第二项&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 已经做完的事&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; [ ] 还没做的事&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; 已经做完的事&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 还没做的事&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;终端：无序是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;•&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，有序保留 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1. 2.&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，嵌套第二层是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;□&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;h2 id=&quot;引用与提示框&quot;&gt;引用与提示框&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 引用里的第一段。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 引用里的第二段。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;引用里的第一段。&lt;/p&gt;
&lt;p&gt;引用里的第二段。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;!NOTE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 这类框用来放补充说明。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--note&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;提示&lt;/p&gt;
&lt;p&gt;这类框用来放补充说明。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;!TIP&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 这类框用来放技巧。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--tip&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;技巧&lt;/p&gt;
&lt;p&gt;这类框用来放技巧。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;!IMPORTANT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 这类框用来放重要的事。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--important&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;重要&lt;/p&gt;
&lt;p&gt;这类框用来放重要的事。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;!WARNING&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 这类框用来放容易踩的坑。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--warning&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;注意&lt;/p&gt;
&lt;p&gt;这类框用来放容易踩的坑。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;!CAUTION&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; 这类框用来放警告。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote class=&quot;callout callout--caution&quot;&gt;&lt;p class=&quot;callout__title&quot;&gt;警告&lt;/p&gt;
&lt;p&gt;这类框用来放警告。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;终端：块引用缩进四格，标题是一行真文字。&lt;/p&gt;
&lt;h2 id=&quot;代码&quot;&gt;代码&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;```&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.path&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;没有语言标签的代码块。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;没有语言标签的代码块，Shiki 按 plaintext 处理。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wireplumber&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --since&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;14 days ago&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;lua|not supported|error&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -40&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;这一行是四个空格缩进的代码块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;渲染结果与不带语言的围栏一致&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;终端：上下各注入一行围栏，语言标签补在开围栏上；超长行要按 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 横向移动才能看全。&lt;/p&gt;
&lt;h2 id=&quot;表格&quot;&gt;表格&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;通用性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ss -tlnp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;任何 Linux 都能用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;端口号&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;随版本变，要自己确认&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;终端：不画表格线，靠列对齐；自然宽（汉字算两列、列间一个空格）超过 79 列就会折行，而折行之后读不出哪一格属于哪一列。宽表格改写成列表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt; —— 完全不生效
&lt;ul&gt;
&lt;li&gt;可能原因：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kde-theme-sync.path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没启用&lt;/li&gt;
&lt;li&gt;怎么办：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl --user status kde-theme-sync.path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;脚注&quot;&gt;脚注&lt;/h2&gt;
&lt;p&gt;这句话带一个脚注&lt;sup&gt;&lt;a href=&quot;#user-content-fn-why&quot; id=&quot;user-content-fnref-why&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;p&gt;终端：脚注编号与文末列表都保留。&lt;/p&gt;
&lt;h2 id=&quot;图片&quot;&gt;图片&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/divider.svg&quot; alt=&quot;站点的分隔线图形&quot;&gt;&lt;/p&gt;
&lt;p&gt;终端：只读得到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;alt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 文字，上面这张图读作「站点的分隔线图形」。&lt;/p&gt;
&lt;h2 id=&quot;数学&quot;&gt;数学&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;行内：$a^2 + b^2 = c^2$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;行内：&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:0.8974em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```markdown
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$$&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;\int_0^1 x^2 \, dx = \frac{1}{3}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;div class=&quot;math-block&quot;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:2.476em;vertical-align:-0.9119em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop op-symbol large-op&quot; style=&quot;margin-right:0.4445em;position:relative;top:-0.0011em;&quot;&gt;∫&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.564em;&quot;&gt;&lt;span style=&quot;top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.8129em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9119em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;katex-sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;katex-base&quot;&gt;&lt;span class=&quot;katex-strut&quot; style=&quot;height:2.0074em;vertical-align:-0.686em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;终端：公式只剩一串字符。行内读作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;a2+b2=c2&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；块级读作 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;∫01x2dx=31&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 上下标、分式、根号在终端里全被拍平成字符顺序，KaTeX 的 MathML 那一层会让 lynx 直接吐出 XML 源码，所以构建期只输出 HTML。&lt;/p&gt;
&lt;h2 id=&quot;定义列表&quot;&gt;定义列表&lt;/h2&gt;
&lt;dl&gt;
&lt;dt&gt;术语&lt;/dt&gt;
&lt;dd&gt;解释。缩进加不加都行，处理器认的是行首的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;: &lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/dd&gt;
&lt;dt&gt;终端浏览器&lt;/dt&gt;
&lt;dd&gt;块引用缩进、列表缩进、定义列表缩进。&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;终端：术语一行，解释缩进四格。&lt;/p&gt;
&lt;h2 id=&quot;分隔线与原始-html&quot;&gt;分隔线与原始 HTML&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;原始 HTML 原样保留：按 &lt;kbd&gt;Ctrl&lt;/kbd&gt; 切换键盘，&lt;mark&gt;高亮的一段&lt;/mark&gt;。&lt;/p&gt;
&lt;dl&gt;
  &lt;dt&gt;术语&lt;/dt&gt;
  &lt;dd&gt;解释。&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;终端：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;kbd&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的样式消失，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;dl&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是术语一行、解释缩进四格。&lt;/p&gt;
&lt;h2 id=&quot;不支持的写法&quot;&gt;不支持的写法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;冒号围栏&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;:::note&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：整块内容被静默丢掉，什么都不剩。替代品是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;gt; [!NOTE]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[[双链]]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;：开关关闭，开了只会生成死链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图表&lt;/strong&gt;：Mermaid 之类需要客户端 JS，不支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;脚注&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-why&quot;&gt;
&lt;p&gt;脚注由 GFM 提供，文末自动生成回链列表。 &lt;a href=&quot;#user-content-fnref-why&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded><category>Markdown</category><category>写作</category><category>终端</category></item><item><title>微信说「不在同一网络」，其实是被防火墙丢了包</title><link>https://miprota.cc/posts/wechat-chat-import-timeout/</link><guid isPermaLink="true">https://miprota.cc/posts/wechat-chat-import-timeout/</guid><description>导入聊天记录时提示两台设备不在同一网络。ping 是通的，微信也确实监听了 8015。直到从手机浏览器去访问那个端口拿到 ErrorTimeOut，方向才定下来。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;手机和电脑连同一个热点，用微信导入聊天记录，电脑上弹出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;暂无法导入，请保持手机和电脑在同一网络&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;两台设备确实在同一个网段里。USB 网络共享试过，Wi-Fi 热点也试过，都能正常上网，
但导入就是失败。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;微信 Linux 原生版&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.x 与 Wine 版的导入机制不同，本文针对 4.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;一台 Linux 电脑 + 一台手机&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用手机热点或 USB 网络共享组成局域网&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -br&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                    # 看手机那侧的接口名和网段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; verbose&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 防火墙是不是 UFW 在管&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ss&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -tlnp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8015&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;           # 导入窗口打开时，这个端口在不在监听&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;这套排查在什么环境上验证过&quot;&gt;这套排查在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS (Arch) ｜ KDE Plasma 6 ｜ Wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;微信 Linux 原生版 4.1.8 ｜ UFW&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;是否通用&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8015 这个端口&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;是当时观测到的&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;微信版本变了可能变，用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ss -tlnp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 自己确认&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UFW 的默认 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DROP&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 策略&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;取决于你的配置&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ufw status verbose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看自己的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strace&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的跟踪方式&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;任何 Linux 都能用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;手机热点的网段&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;每次都不同&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;由手机 DHCP 分配，必须现场查&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;接口名&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;会变&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Wi-Fi 是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wlan0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，USB 共享是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enp6s0f4u2u2&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这类名字&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;先说那个错误提示&quot;&gt;先说那个错误提示&lt;/h2&gt;
&lt;p&gt;「请保持手机和电脑在同一网络」是一句&lt;strong&gt;泛化提示&lt;/strong&gt;。微信在这条路径上失败时都会这么说，
不管真实原因是不同网段、防火墙丢包、还是别的。&lt;/p&gt;
&lt;p&gt;所以它只能证明「这条链路没通」，&lt;strong&gt;不能证明两台设备不在同一子网&lt;/strong&gt;。
顺着字面意思去查网络拓扑，会走偏。&lt;/p&gt;
&lt;h2 id=&quot;第一步把看着可疑但其实正常的先排掉&quot;&gt;第一步：把「看着可疑但其实正常」的先排掉&lt;/h2&gt;
&lt;p&gt;一开始怀疑的是地址段：手机热点分给电脑的地址是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;10.112.4.254&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，看着不像家里的
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.x.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，当时以为是 KDE 建了什么虚拟网卡，或者被 VPN 接管了。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -br&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                    # 看接口和地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;nmcli&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; device&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                   # 看 NetworkManager 怎么认这个接口&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;实际拿到的：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wi-Fi 热点：  wlan0     10.112.4.254/24   手机网关 10.112.4.49&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;USB 共享：    enp6s0f4u2u2  10.146.37.73/24   手机网关 10.146.37.96&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;10.0.0.0/8&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是标准 IPv4 私有地址段，和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;192.168.0.0/16&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是一回事。
&lt;strong&gt;地址由手机 DHCP 分配，不是异常拓扑。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;第二步两个直接验证都不用停任何服务&quot;&gt;第二步：两个直接验证，都不用停任何服务&lt;/h2&gt;
&lt;h3 id=&quot;验证一微信到底有没有在监听&quot;&gt;验证一：微信到底有没有在监听&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 先找到微信主进程的 pid，再跟踪它的网络调用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; strace&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -ff&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -tt&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; trace=network&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;微信pi&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;打开导入窗口，抓到的是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 305&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bind(305, {sa_family=AF_INET, sin_port=htons(8015),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;           sin_addr=inet_addr(&quot;0.0.0.0&quot;)}, 16) = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;listen(305, 8) = 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;bind&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;listen&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 都返回 0，说明三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;导入模块已经进入网络阶段&lt;/li&gt;
&lt;li&gt;它在&lt;strong&gt;所有 IPv4 接口&lt;/strong&gt;上监听 8015&lt;/li&gt;
&lt;li&gt;不存在「没权限绑端口」的问题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这一步把排查范围从「应用没起来」缩到了「入站路径不通」。用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ss&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 也能看到同样的结论，
但 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strace&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 能证明它是&lt;strong&gt;微信自己&lt;/strong&gt;建的监听，而不是别的进程占了端口。&lt;/p&gt;
&lt;h3 id=&quot;验证二从对端访问这个端口决定性的一步&quot;&gt;验证二：从对端访问这个端口（决定性的一步）&lt;/h3&gt;
&lt;p&gt;保持导入窗口开着，用&lt;strong&gt;手机浏览器&lt;/strong&gt;访问电脑的那个端口：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;http://&amp;lt;电脑的局域网IP&amp;gt;:8015&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;结果是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ErrorTimeOut&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;超时，不是拒绝。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这两种失败指向的方向不一样：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;连接被拒绝&lt;/td&gt;
&lt;td&gt;端口没在监听，或者应用拒绝了&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;超时&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;报文被丢掉了，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DROP&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的典型表现&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;顺带一个反面对照：这时候电脑是能 ping 通手机的。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PING 10.112.4.49&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3 packets transmitted, 3 received, 0% packet loss&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ping 通只证明 ICMP 和基础路由可用，不代表特定 TCP 端口的入站被放行。&lt;/strong&gt;
这两件事经常被当成一件。&lt;/p&gt;
&lt;h2 id=&quot;第三步查防火墙&quot;&gt;第三步：查防火墙&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; verbose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: active&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Default: deny (incoming), allow (outgoing), disabled (routed)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;再看配置：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/etc/default/ufw: DEFAULT_INPUT_POLICY=&quot;DROP&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;默认入站是 DROP。&lt;/strong&gt; 手机发往 8015 的包到了电脑就被丢了，应用层根本看不到，
所以微信只能报一句「不在同一网络」。&lt;/p&gt;
&lt;h3 id=&quot;️-一个容易漏的地方&quot;&gt;⚠️ 一个容易漏的地方&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```text
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ufw.service: active (exited)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;firewalld.service: inactive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;nftables.service: inactive&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;UFW 的服务状态是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;active (exited)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 它是&lt;strong&gt;一次性服务&lt;/strong&gt;，开机时把 Netfilter 规则
写进内核就退出了，之后一直显示 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;exited&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;只看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;firewalld&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 或 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nftables.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的状态，会以为这台机器没有防火墙在管事。
&lt;strong&gt;它们不活动不等于没有规则&lt;/strong&gt;，规则已经在内核里了。&lt;/p&gt;
&lt;h2 id=&quot;修复&quot;&gt;修复&lt;/h2&gt;
&lt;p&gt;加一条最小放行规则：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; allow&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wlan0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 10.112.4.0/24&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8015&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; proto&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;这条规则限定得很死，只放行：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;限定项&lt;/th&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;入站接口&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wlan0&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;来源网段&lt;/td&gt;
&lt;td&gt;手机热点的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;协议&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;目标端口&lt;/td&gt;
&lt;td&gt;8015&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;放行后重启微信，重新进导入页面，&lt;strong&gt;导入成功&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;usb-共享时要换接口名和网段&quot;&gt;USB 共享时要换接口名和网段&lt;/h3&gt;
&lt;p&gt;USB 共享走的是另一个接口，名字和网段都不一样，所以规则也得重写一条。
&lt;strong&gt;先查，再写&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;nmcli&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; device&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -br&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; addr&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;比如这次 USB 共享是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;enp6s0f4u2u2&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、网段 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;10.146.37.0/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; allow&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; enp6s0f4u2u2&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 10.146.37.0/24&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8015&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; proto&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;不要图省事写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;sudo ufw allow 8015/tcp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 那等于对&lt;strong&gt;所有&lt;/strong&gt;来源开放这个端口。&lt;/p&gt;
&lt;h3 id=&quot;用完想删掉&quot;&gt;用完想删掉&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; delete&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; allow&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wlan0&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 10.112.4.0/24&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 8015&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; proto&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;被排除掉的七个假设&quot;&gt;被排除掉的七个假设&lt;/h2&gt;
&lt;p&gt;这一段值得留着看。当时怀疑过下面这些，&lt;strong&gt;每一个都是停掉服务实测过的&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;假设&lt;/th&gt;
&lt;th&gt;怎么排除的&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FRP 隧道干扰&lt;/td&gt;
&lt;td&gt;停掉 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;frpc.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，问题依旧&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;strongSwan / IPsec&lt;/td&gt;
&lt;td&gt;服务本来就是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;inactive&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不是活动连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KDE Connect 的 SSH TUN&lt;/td&gt;
&lt;td&gt;停掉后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;tun66&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 消失，导入仍失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clash Verge 代理&lt;/td&gt;
&lt;td&gt;停服务 + 完全重启微信，仍失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KDE Connect 用户守护进程&lt;/td&gt;
&lt;td&gt;停掉后重启微信，仍失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker 虚拟网卡让微信选错地址&lt;/td&gt;
&lt;td&gt;停 Docker、containerd 和容器、清掉 veth，仍失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;微信数据目录权限&lt;/td&gt;
&lt;td&gt;目录属主权限正常、可读写、无 immutable 属性、磁盘有 700 GB 空闲&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;七个全排除，才把注意力从「谁在干扰网络」转到「包到底有没有到」。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;顺序值得注意&lt;/strong&gt;：验证一和验证二都不需要停任何服务。先做那两个，
范围就已经缩到防火墙了。上面这七个是在这之前做的，每一个都在短时间内
把机器上的一个服务关掉，属于扩大了影响面。&lt;/p&gt;
&lt;h2 id=&quot;这套排查里能带走的&quot;&gt;这套排查里能带走的&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;泛化的错误提示不可信。&lt;/strong&gt; 「不在同一网络」不代表真的不在同一网络。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;10.x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不异常。&lt;/strong&gt; 它是标准私有段，没证据就不要当成 VPN。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ping 通不等于端口通。&lt;/strong&gt; ICMP 和 TCP 入站是两条独立的路径，防火墙可以只放前者。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超时和拒绝是两种不同的失败。&lt;/strong&gt; 超时指向丢包，拒绝指向没有监听。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strace&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 能把「应用没起来」和「网络不通」切开&lt;/strong&gt;，比看日志直接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查防火墙别只看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;firewalld&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nftables.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; UFW 可以在自身
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;active (exited)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的状态下，规则早就进了内核。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;先做直接的、无副作用的验证，再去停服务。&lt;/strong&gt; 顺序反了，排查成本会成倍上升。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;th&gt;下一步&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;手机浏览器访问端口超时&lt;/td&gt;
&lt;td&gt;防火墙 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DROP&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;查 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ufw status verbose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的默认入站策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;手机浏览器连接被拒绝&lt;/td&gt;
&lt;td&gt;端口没在监听&lt;/td&gt;
&lt;td&gt;确认导入窗口开着，用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ss -tlnp&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 查&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;放行了还是不行&lt;/td&gt;
&lt;td&gt;接口名或网段写错&lt;/td&gt;
&lt;td&gt;重新 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ip -br addr&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 确认，规则要跟实际一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wi-Fi 能导入、USB 不能&lt;/td&gt;
&lt;td&gt;两条路的接口和网段都不同&lt;/td&gt;
&lt;td&gt;给 USB 接口单独加一条规则&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;换了手机热点就连不上&lt;/td&gt;
&lt;td&gt;网段变了&lt;/td&gt;
&lt;td&gt;规则里写死的是上一次的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/24&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，重新查再改&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;strace&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ss&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nmcli&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ip&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，都是系统自带&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ufw status verbose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，看默认策略和已有规则&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Uncomplicated_Firewall&quot;&gt;Arch Wiki: Uncomplicated Firewall&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>UFW</category><category>防火墙</category><category>微信</category><category>排查方法</category></item><item><title>让 RustDesk 走我自己的服务器</title><link>https://miprota.cc/posts/self-host-rustdesk/</link><guid isPermaLink="true">https://miprota.cc/posts/self-host-rustdesk/</guid><description>商业远控的连接都要过一次别人的服务器。自建 hbbs + hbbr 能把这个环节拿回来，代价只是一条 docker compose。国内拉镜像和 latest 标签，是最容易卡住的两处。</description><pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TeamViewer、ToDesk、向日葵这类远控，连接都要过一次厂商的服务器。自建 RustDesk
服务端的意义在于把这个环节拿回来，代价是一条 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;docker compose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;它由两个组件组成，加起来不到 200 MB 内存。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以上是 AI 帮我写的，实际上，我用 RustDesk 的原因是：
ChatGPT 力荐，我有一个ECS。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;一台有公网 IP 的服务器&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;客户端要能直接连上它，所以不能是纯内网机&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docker + Docker Compose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;部署方式，两个容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;能改云服务商的安全组&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;端口要在&lt;strong&gt;安全组&lt;/strong&gt;和&lt;strong&gt;服务器本机防火墙&lt;/strong&gt;两处都开&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RustDesk 客户端&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Windows / macOS / Linux / Android / iOS 都有&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --version&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 有 Docker 就行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; compose&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 注意是 compose 子命令，不是 docker-compose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;这套做法在什么环境上验证过&quot;&gt;这套做法在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;部署时间：2026-07-20 ｜ 镜像 rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;服务端：国内云服务器 ｜ Docker Compose ｜ network_mode: host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;客户端：Linux (CachyOS) ｜ 自定义 ID 服务器 + 中继 + 密钥&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;是否通用&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;hbbs / hbbr 的职责与端口&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RustDesk 自身设计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;compose 文件结构&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;与云厂商无关&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;国内拉镜像&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;只对国内服务器&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;有外网或已配加速器的可以跳过那一节&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;防火墙命令&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;因发行版而异&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ufw&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 还是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;firewalld&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，先看自己那台&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;镜像版本号&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;会过时&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;写这篇时是 1.1.15，装之前去看一眼 Releases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;它由两个组件组成&quot;&gt;它由两个组件组成&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;组件&lt;/th&gt;
&lt;th&gt;容器&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;hbbs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;rustdesk-hbbs&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;设备注册、NAT 类型测试、P2P 连接协调&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;hbbr&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;rustdesk-hbbr&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;P2P 直连失败时，负责中继转发&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;A 想连 B&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └─ 先问 hbbs：B 在哪？能直连吗？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     ├─ 能 ──→ 数据走 P2P，不经服务器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     └─ 不能 ──→ 走 hbbr 中继&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  （对称 NAT 之类）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;大多数时候流量是不经过服务器的&lt;/strong&gt;，服务器只负责牵线。这也是它便宜的原因：
一台最低配的机器就够了，只有在中继时才吃带宽。&lt;/p&gt;
&lt;h2 id=&quot;端口&quot;&gt;端口&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;端口&lt;/th&gt;
&lt;th&gt;协议&lt;/th&gt;
&lt;th&gt;归属&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;21115&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;hbbs&lt;/td&gt;
&lt;td&gt;NAT 类型测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21116&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;hbbs&lt;/td&gt;
&lt;td&gt;ID 注册与心跳&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21116&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;UDP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;hbbs&lt;/td&gt;
&lt;td&gt;打洞 / NAT 穿透&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21117&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;hbbr&lt;/td&gt;
&lt;td&gt;中继服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;21118&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;hbbs&lt;/td&gt;
&lt;td&gt;WebSocket，可选&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;21115 TCP、21116 TCP + UDP、21117 TCP 四个必须开。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;21116 那个 UDP 最容易漏。只开 TCP 的话，客户端能注册上线，但打洞会失败，
于是所有流量都被挤到中继上，速度明显不对。&lt;/p&gt;
&lt;h2 id=&quot;第一步写-compose-文件&quot;&gt;第一步：写 compose 文件&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/rustdesk-server&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/rustdesk-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;写入 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;compose.yml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```yaml
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  hbbs&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    container_name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rustdesk-hbbs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      # 必须写具体版本号&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    command&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hbbs -r &amp;lt;你的服务器IP&amp;gt;:21117 -k _&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ./data:/root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    network_mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    restart&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    depends_on&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hbbr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  hbbr&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    container_name&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rustdesk-hbbr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;      # 同上&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    command&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hbbr -k _&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ./data:/root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    network_mode&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    restart&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; unless-stopped&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;参数逐个说：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-r &amp;lt;IP&amp;gt;:21117&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;告诉客户端中继服务器在哪。&lt;strong&gt;填公网 IP&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-k _&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;强制密钥认证。首次启动自动生成密钥对&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;network_mode: host&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;直接用宿主机网络栈，端口不用再做映射&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;./data:/root&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;持久化密钥和数据库。&lt;strong&gt;这个目录丢了，所有客户端都要重配&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;️-坑一绝不能用-latest&quot;&gt;⚠️ 坑一：绝不能用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;latest&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，这篇文章的更新时间虽然是&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2026-9-20&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，但实际上笔者在这一天并没有真正意义上去测试，所以这一条的时间线为&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;2026-07-20&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是这篇里最值得记的一条。用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;latest&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 拉到旧版本镜像后，容器起不来，日志里是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ERROR: Registered email required (-m option).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please pay and register on https://rustdesk.com/server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;看着像「要付费注册」，其实是&lt;strong&gt;国内某些镜像源缓存了几年前的旧版本&lt;/strong&gt;，
而旧版本要求商业授权。&lt;strong&gt;写死版本号就能绕开。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;装之前先去 &lt;a href=&quot;https://github.com/rustdesk/rustdesk-server/releases&quot;&gt;Releases&lt;/a&gt;
看一眼当前版本，把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1.1.15&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 换成它。&lt;/p&gt;
&lt;h3 id=&quot;️-坑二国内服务器拉不动镜像&quot;&gt;⚠️ 坑二：国内服务器拉不动镜像&lt;/h3&gt;
&lt;p&gt;如果服务器在国内且没有代理，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;docker compose pull&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 会卡在 Docker Hub 上。两个办法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;办法一：直接用代理前缀拉，再打回原标签&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pull&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; docker.1ms.run/rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tag&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; docker.1ms.run/rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;           rustdesk/rustdesk-server:1.1.15&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;改完标签，compose 文件里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;image&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不用动。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;办法二：给 Docker 配加速器，一劳永逸&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tee&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/docker/daemon.json&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;EOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  &quot;registry-mirrors&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &quot;https://docker.1ms.run&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &quot;https://docker.xuanyuan.me&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    &quot;https://docker.m.daocloud.io&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; restart&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; docker&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;配多个源是为了容灾，某一个挂了还有别的。之后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;docker compose pull&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就能直接拉。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这些镜像代理的可用性会变，用之前先自己试一下。写这篇时三个都还能用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;第二步启动并拿到密钥&quot;&gt;第二步：启动并拿到密钥&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/rustdesk-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; compose&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; up&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 拿公钥&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ./data/id_ed25519.pub&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;密钥文件在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;./data/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下，是首次启动时自动生成的。客户端要填的就是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;id_ed25519.pub&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
里的那一串。&lt;/p&gt;
&lt;h2 id=&quot;第三步开端口&quot;&gt;第三步：开端口&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;两处都要开&lt;/strong&gt;，只开一处等于没开：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;服务器本机防火墙&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ufw（Debian / Ubuntu）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; allow&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 21115:21117/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; allow&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 21116/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ufw&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; reload&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# firewalld（RHEL / CentOS / Fedora）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; firewall-cmd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --permanent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --add-port=21115-21117/tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; firewall-cmd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --permanent&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --add-port=21116/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; firewall-cmd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --reload&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;云服务商的安全组&lt;/strong&gt;，在控制台里放行同样这几个端口。&lt;/p&gt;
&lt;h2 id=&quot;第四步配客户端&quot;&gt;第四步：配客户端&lt;/h2&gt;
&lt;p&gt;在 RustDesk 客户端里进 &lt;strong&gt;设置 → 网络&lt;/strong&gt;，填三样：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&lt;/th&gt;
&lt;th&gt;填什么&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ID 服务器&lt;/td&gt;
&lt;td&gt;你的服务器 IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;中继服务器&lt;/td&gt;
&lt;td&gt;同一个 IP（端口不用写，默认 21117）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;密钥&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;id_ed25519.pub&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;点应用，状态变绿显示「就绪」就是通了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;手机上也要各填一遍。&lt;/strong&gt; 这几项不会跟着账号走，换设备就得重填。&lt;/p&gt;
&lt;h2 id=&quot;怎么验证&quot;&gt;怎么验证&lt;/h2&gt;
&lt;h3 id=&quot;-服务端在不在&quot;&gt;① 服务端在不在&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; compose&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ps&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;            # 两个容器都应该是 Up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; logs&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; rustdesk-hbbs&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 没有报错&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;-端口对外通不通&quot;&gt;② 端口对外通不通&lt;/h3&gt;
&lt;p&gt;在&lt;strong&gt;另一台机器&lt;/strong&gt;上跑，不要在服务器本机跑（本机跑测不出安全组）：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 21115&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 21116&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 21117&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  timeout&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; bash&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;echo &amp;gt; /dev/tcp/&amp;lt;你的服务器IP&amp;gt;/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 开着&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 不通&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;三个都应该是「开着」。&lt;/p&gt;
&lt;h3 id=&quot;-客户端连上后看状态&quot;&gt;③ 客户端连上后看状态&lt;/h3&gt;
&lt;p&gt;RustDesk 主界面左下角，状态是「就绪」就说明 ID 服务器通了。&lt;/p&gt;
&lt;h3 id=&quot;-真正连一次&quot;&gt;④ 真正连一次&lt;/h3&gt;
&lt;p&gt;从手机连一次电脑，看画面能不能出来。&lt;strong&gt;这一步才作数&lt;/strong&gt; —— 前面三项目前全绿、
最后连不上，通常是中继或者 UDP 打洞的问题。&lt;/p&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;th&gt;下一步&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;容器起不来，日志提「paid and register」&lt;/td&gt;
&lt;td&gt;用了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;latest&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，拉到旧版本&lt;/td&gt;
&lt;td&gt;改成具体版本号重新拉&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;docker compose pull&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 卡住&lt;/td&gt;
&lt;td&gt;国内直连 Docker Hub&lt;/td&gt;
&lt;td&gt;用代理前缀，或配加速器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;客户端显示「未就绪」&lt;/td&gt;
&lt;td&gt;21116 没通&lt;/td&gt;
&lt;td&gt;安全组和本机防火墙都查一遍&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;能连上但很卡&lt;/td&gt;
&lt;td&gt;P2P 没打通，全走中继&lt;/td&gt;
&lt;td&gt;检查 21116 &lt;strong&gt;UDP&lt;/strong&gt; 开了没有&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;换服务器后客户端连不上&lt;/td&gt;
&lt;td&gt;密钥变了&lt;/td&gt;
&lt;td&gt;重新 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;cat ./data/id_ed25519.pub&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 填进去&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重装服务器后全部客户端失效&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;./data/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没了，密钥重新生成&lt;/td&gt;
&lt;td&gt;把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;./data/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 备份出来&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://rustdesk.com/docs/en/self-host/&quot;&gt;RustDesk 自建文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rustdesk/rustdesk-server/releases&quot;&gt;rustdesk-server Releases&lt;/a&gt;，装之前来看版本号&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/r/rustdesk/rustdesk-server&quot;&gt;Docker Hub: rustdesk/rustdesk-server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>RustDesk</category><category>自建服务</category><category>Docker</category><category>远程桌面</category></item><item><title>怎么确认自己有没有中 AUR 投毒</title><link>https://miprota.cc/posts/aur-poisoned-packages-2026/</link><guid isPermaLink="true">https://miprota.cc/posts/aur-poisoned-packages-2026/</guid><description>2026 年 6 月的「Atomic Arch」事件里，1936 个 AUR 包被投毒，而 PKGBUILD 本身看着是干净的。这份自查分两轮：先比包名，再扫 IOC。末尾是 2026-09 在本机复跑的结果。</description><pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2026 年 6 月，AUR 上有一批包被投毒，官方名单里是 1936 个包名。&lt;/p&gt;
&lt;p&gt;这件事值得单独立一份自查清单，原因&lt;strong&gt;载荷&lt;/strong&gt;：窃取浏览器 Cookie、SSH 密钥、
各类 Token 之外，它在 root 权限下会加载一个 eBPF rootkit 来隐藏自己的进程、文件和网络连接。
按公开分析的说法，那东西&lt;strong&gt;卸载软件包去不掉，只能重装系统&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;所以自查这件事，做得越早越省事（当然，由于 AUR 投毒事件发生时我没有使用 Arch，而用回 Arch 的时候已经是 7 月了，所以在时间上看起来有些奇怪）。&lt;/p&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Arch 系发行版&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CachyOS / EndeavourOS / Manjaro 同样适用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;能读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/var/lib/pacman/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;查已装包与安装脚本，普通用户通常可读&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;几分钟&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;第一轮几秒，第二轮主要花在搜文件上&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pacman&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Qm&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                    # 列出所有非官方仓库的包（也就是 AUR 来的）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/fs/bpf/&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;               # eBPF 映射，rootkit 藏身的地方之一&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;事件经过&quot;&gt;事件经过&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;日期&lt;/th&gt;
&lt;th&gt;发生了什么&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6 月 11 日&lt;/td&gt;
&lt;td&gt;第一波。载荷通过 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;npm install atomic-lockfile&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 拉取，1500+ 包&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 月 13 日&lt;/td&gt;
&lt;td&gt;第二波。改用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;bun install js-digest&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，代码混淆规避检测&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 月 14 日&lt;/td&gt;
&lt;td&gt;第三波。载荷高度混淆，靠 AI 模型辅助分析才发现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 月 15 日&lt;/td&gt;
&lt;td&gt;Arch 暂停 AUR 新用户注册，清理全部恶意包&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;官方仓库没有受影响&lt;/strong&gt;，被渗透的是 AUR 这个社区仓库。&lt;/p&gt;
&lt;h3 id=&quot;攻击是怎么做的&quot;&gt;攻击是怎么做的&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;① 找孤儿包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   AUR 允许认领无人维护的包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;② 认领后改 PKGBUILD 与 .install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;③ 伪造提交元数据，看起来像原维护者&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;④ 载荷不写在 PKGBUILD 里&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   而是让 PKGBUILD 去 npm / bun 下载&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;第 ④ 步是这件事最难查的地方。&lt;strong&gt;你去读 PKGBUILD，上面没有一行恶意代码&lt;/strong&gt; ——
它只是调用了一次包管理器，而恶意内容在远端那个 npm 包里。&lt;/p&gt;
&lt;p&gt;所以「我每次都读过 PKGBUILD」在这里不构成防线。要防的是另一件事：
&lt;strong&gt;AUR 包为什么要从 npm / pip / bun 下载东西。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;第一轮比包名&quot;&gt;第一轮：比包名&lt;/h2&gt;
&lt;p&gt;拿到官方名单，和自己的 AUR 包列表做一次全等比对。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 官方名单：https://md.archlinux.org/s/SxbqukK6IA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 存成 package-list.txt，一行一个包名&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pacman&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Qm&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;{print $1}&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/aur-mine.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;comm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -12&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/aur-mine.txt)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &amp;lt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; package-list.txt)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;comm -12&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 输出的是&lt;strong&gt;两个文件的交集&lt;/strong&gt;。有输出就是命中，没有输出就是干净。&lt;/p&gt;
&lt;p&gt;用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;comm&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 而不是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep -f&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，是因为它按整行精确比对，不会把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 匹配到名单里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;本机（2026-09-20）的结果：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pacman&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -Qm&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; wc&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # → 27&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;27 个 AUR 包逐个比对，&lt;strong&gt;0 命中&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;第二轮扫-ioc&quot;&gt;第二轮：扫 IOC&lt;/h2&gt;
&lt;p&gt;包名干净不等于没中 —— 包可能已经删掉，载荷还在。下面每一项都是可以独立跑的。&lt;/p&gt;
&lt;h3 id=&quot;-ebpf-rootkit-的映射&quot;&gt;① eBPF rootkit 的映射&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/fs/bpf/&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; hidden&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 无输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;公开分析里提到的映射名是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;hidden_pids&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;hidden_names&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;hidden_inodes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
这几个名字本身就是「我要藏东西」的意思，正常系统上不会有。&lt;/p&gt;
&lt;h3 id=&quot;-恶意二进制&quot;&gt;② 恶意二进制&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /var/lib&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -maxdepth&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; deps&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -type&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 无输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;载荷是一个 Rust 写的、名叫 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;deps&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 ELF 文件。&lt;/p&gt;
&lt;h3 id=&quot;-npm-缓存里的恶意包&quot;&gt;③ npm 缓存里的恶意包&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -rl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;atomic-lockfile\|js-digest\|lockfile-js\|nextfile-js&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.npm/_cacache/index-v5/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 无输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;四个恶意 npm 包名：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;包名&lt;/th&gt;
&lt;th&gt;版本&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;atomic-lockfile&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;1.4.2&lt;/td&gt;
&lt;td&gt;第一波，载荷文件 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;src/hooks/deps&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;js-digest&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;4.2.2&lt;/td&gt;
&lt;td&gt;第二波，载荷伪装成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;lib/install-deps.mjs&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;lockfile-js&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;1.4.2&lt;/td&gt;
&lt;td&gt;变体&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;nextfile-js&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;1.4.2&lt;/td&gt;
&lt;td&gt;变体&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;-持久化&quot;&gt;④ 持久化&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/systemd/user/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 逐个看：是不是你自己建的&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;载荷会往 systemd 里塞服务，特征是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Restart=always&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 配 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;RestartSec=30&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -rl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;RestartSec=30&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/systemd/system/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 无输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;-出站连接&quot;&gt;⑤ 出站连接&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; tor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# → 无输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;C2 走的是 Tor v3 onion：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;olrh4mibs62l6kkuvvjyc5lrercqg5tz543r4lsw3o6mh5qb7g7sneid.onion&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同时也往 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;temp.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 上传。系统上没有 Tor 进程，这条基本可以排除。&lt;/p&gt;
&lt;h3 id=&quot;-安装脚本&quot;&gt;⑥ 安装脚本&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /var/lib/pacman/local/&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -name&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;*.install&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机 1763 个包目录里，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.install&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 文件数是 &lt;strong&gt;0&lt;/strong&gt; —— 这条检查项在本机没有可检查的对象。
写出来是因为它对你的机器可能不是 0。&lt;/p&gt;
&lt;h2 id=&quot;复跑结果2026-09-20&quot;&gt;复跑结果（2026-09-20）&lt;/h2&gt;
&lt;p&gt;上面两轮在本机重跑了一遍，不是复述七月的结论：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;检查项&lt;/th&gt;
&lt;th&gt;结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AUR 包名比对（27 个 vs 1936 行名单）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 命中&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eBPF &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;hidden_*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 映射&lt;/td&gt;
&lt;td&gt;0 处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;恶意二进制 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;deps&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;0 个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm 缓存中的恶意包&lt;/td&gt;
&lt;td&gt;0 处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户级 systemd 服务&lt;/td&gt;
&lt;td&gt;3 个，都是自己建的（主题同步、mip-paper、kdeconnect 监听）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tor 进程&lt;/td&gt;
&lt;td&gt;0 个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/var/lib&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;atomic*&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 植入物&lt;/td&gt;
&lt;td&gt;0 个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;RestartSec=30&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的系统服务&lt;/td&gt;
&lt;td&gt;0 个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pacman &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.install&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 脚本&lt;/td&gt;
&lt;td&gt;全机 0 个&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;三个看起来像其实无关的&quot;&gt;三个「看起来像、其实无关」的&lt;/h2&gt;
&lt;p&gt;自查时容易误报的几处：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;看着可疑&lt;/th&gt;
&lt;th&gt;实际情况&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;linux-cachyos 内核&lt;/td&gt;
&lt;td&gt;CachyOS 内核来自&lt;strong&gt;官方仓库&lt;/strong&gt;。投毒名单里的是 AUR 上的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;linux-cachyos-native&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，另一个东西&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在名单里&lt;/td&gt;
&lt;td&gt;那是旧版 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。官方仓库的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不受影响&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;proper-lockfile&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;合法 npm 包，和恶意的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;lockfile-js&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不是一回事&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;装之前怎么防&quot;&gt;装之前怎么防&lt;/h2&gt;
&lt;p&gt;第一轮和第二轮都是&lt;strong&gt;事后&lt;/strong&gt;检查，而 eBPF rootkit 那一步是不可逆的。所以在装之前：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;能用官方仓库就用官方仓库。&lt;/strong&gt; AUR 只留给确实没有替代的包，本机 1763 个包里只有 27 个来自 AUR，这个比例是刻意维持的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AUR 包主动去 npm / pip / bun 下载依赖的，直接当可疑处理。&lt;/strong&gt; 这是这次事件的核心手法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;警惕「最近换过维护者」的废弃包。&lt;/strong&gt; 攻击入口就是孤儿包收养。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;source&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 字段的上游 URL&lt;/strong&gt;，是不是指向项目的官方地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;别跳过 PKGBUILD 的 diff。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;yay&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 默认会展示，认真读完再回车。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;正常打包不会在安装阶段去网上抓代码。这么做既违反打包惯例，也绕开了读 PKGBUILD
这个动作 —— 而那是你手上仅有的审查点。&lt;/p&gt;
&lt;h2 id=&quot;如果中了&quot;&gt;如果中了&lt;/h2&gt;
&lt;p&gt;按公开分析的描述，eBPF rootkit 会隐藏自己的进程、文件和套接字，卸载软件包去不掉。&lt;/p&gt;
&lt;p&gt;处理顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;断网&lt;/strong&gt;，别让它继续外传&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;备份数据，不要备份二进制和配置&lt;/strong&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.ssh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、浏览器配置、各类 Token 都算泄露，要轮换而不是备份）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重装系统&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;重装后&lt;strong&gt;轮换所有凭据&lt;/strong&gt;：SSH 密钥、GitHub Token、各类 API Key、浏览器登录态&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://md.archlinux.org/s/SxbqukK6IA&quot;&gt;Arch Linux 官方受影响包列表&lt;/a&gt;，1936 行&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.truesec.com/hub/blog/supply-chain-attack-compromising-arch-linux-aur-packages-infostealer-rootkit&quot;&gt;Truesec 技术分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sonatype.com/blog/atomic-arch-npm-campaign-adds-malicious-dependency&quot;&gt;Sonatype 的分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threats.wiz.io/all-incidents/atomic-arch-aur-package-supply-chain-compromise-using-malicious-npm-package&quot;&gt;Wiz 威胁情报&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://labs.cloudsecurityalliance.org/research/csa-research-note-aur-supply-chain-ebpf-rootkit-20260617-csa/&quot;&gt;CSA Research Note&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Arch Linux</category><category>AUR</category><category>供应链攻击</category><category>恶意软件</category></item><item><title>让 PipeWire 不再爆音</title><link>https://miprota.cc/posts/pipewire-crackling/</link><guid isPermaLink="true">https://miprota.cc/posts/pipewire-crackling/</guid><description>偶发的电音难在复现，也难在确认修好没有。把听感换成 pw-top 上的 ERR 计数之后，两次定位都有了依据：第一次是 memlock 权限，第二次是一份 WirePlumber 压根没读的配置文件。</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;音乐播着播着会突然「啪」一下，或者有那么一两秒像电流声，然后又正常了。&lt;/p&gt;
&lt;p&gt;间歇出现，几分钟到几小时一次。重启没用，换线没用，换播放器也没用。&lt;/p&gt;
&lt;p&gt;这类问题的麻烦有两层：复现不了，也没法确认修好了没有。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个教程只是提供我自己的解决方案
实际效果因系统而异，不能确保可以 100% 解决你遇到的问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PipeWire&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;本文的命令都是它自带的：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-metadata&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wpctl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;能改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/security/limits.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;第一次修复动的是这里，要 root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;能重新登录&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;组权限只在登录时读一次&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;这套做法在什么环境上验证过&quot;&gt;这套做法在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS (Arch) ｜ KDE Plasma 6 ｜ Wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PipeWire 1.6.7 ｜ WirePlumber 0.5.17&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;声卡：3 个 HDA-Intel 设备（NVIDIA HDMI + 2 个 AMD）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;是否通用&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-metadata&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wpctl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PipeWire 自带，与发行版无关&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;realtime&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 组与 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;memlock&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;因发行版而异&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Arch 系是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/security/limits.d/99-realtime-privileges.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；Debian 系组名和文件位置都不同，先查自己那份&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;snd_hda_intel&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 省电参数&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;只对 HDA 声卡&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;USB 声卡、蓝牙耳机不适用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WirePlumber 配置格式&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;0.5 起换过了&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;见「一份没有生效的配置」&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU governor&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;因内核而异&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CachyOS 只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;powersave&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;performance&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 两档&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pw-top&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                                                  # 看 ERR 列&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/module/snd_hda_intel/parameters/power_save&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;             # 省电秒数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^@realtime&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/security/limits.d/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.conf&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 组权限&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;第一步把听感换成数字&quot;&gt;第一步：把听感换成数字&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 PipeWire 版的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。要看的只有一列：&lt;strong&gt;ERR&lt;/strong&gt;，也就是 xrun 的次数。&lt;/p&gt;
&lt;p&gt;缓冲区没喂上，硬件只能拿旧数据顶上，听到的就是那声「啪」。所以 ERR 涨一次，
耳朵那边就响一次，两者是对得上的。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-b -n 3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是批处理模式，跑三次就退出，把输出留在终端里：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pw-top&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;S   ID  QUANT   RATE    WAIT    BUSY   W/Q   B/Q  ERR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;R   52   2048  48000   8.4us  26.2us  0.00  0.00    0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;R  134   2400  48000  10.3us  14.3us  0.00  0.00    0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;（原输出末尾还有 FORMAT 和 NAME 两列，这里截掉了。）&lt;/p&gt;
&lt;p&gt;ERR 是 0，说明这段时间没出问题。数字一旦涨，后面就有可以对照的东西了：
改配置、再看 ERR、看它涨没涨。&lt;strong&gt;听感靠不住，计数靠得住。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;顺带记住 QUANT 那一列，它是当前的缓冲区大小（单位是帧）。后面两次定位都和它有关。&lt;/p&gt;
&lt;h2 id=&quot;第一次定位err-有-25-个&quot;&gt;第一次定位：ERR 有 25 个&lt;/h2&gt;
&lt;h3 id=&quot;现象&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;Proton 跑 Windows 游戏时出现电流声。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里 alsa_output 那一行的 ERR 是 &lt;strong&gt;25&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;排查&quot;&gt;排查&lt;/h3&gt;
&lt;p&gt;同一个界面里还有一列能看：进程的实时优先级。当时 PipeWire 显示的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
意思是&lt;strong&gt;没有实时优先级&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;顺着权限往下查：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;groups&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                                    # 用户组里有没有 realtime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^@realtime&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/security/limits.d/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;^@audio&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;    /etc/security/limits.d/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;拿到的结果：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@realtime - rtprio 98&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@realtime - memlock unlimited&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;@realtime - nice -11&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;@audio&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那份只给了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;rtprio&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;strong&gt;没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;memlock&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;。而用户当时在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;audio&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 组里。&lt;/p&gt;
&lt;h3 id=&quot;根因&quot;&gt;根因&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;memlock unlimited&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 决定进程能不能把音频缓冲区锁在物理内存里。&lt;/p&gt;
&lt;p&gt;拿不到这个权限，缓冲区就可能被换出去，等要用的时候再换回来。换回来那一下的延迟，
就是一次 xrun。&lt;/p&gt;
&lt;p&gt;所以在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;audio&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 组不等于够用，音频线程要的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;realtime&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 组。&lt;/p&gt;
&lt;h3 id=&quot;修复&quot;&gt;修复&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; usermod&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -aG&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; realtime&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$USER&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 注销重新登录，组权限只在登录时读一次&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;结果&quot;&gt;结果&lt;/h3&gt;
&lt;p&gt;ERR 从 25 降到 1，电流声消失。&lt;/p&gt;
&lt;h2 id=&quot;第二次定位还剩偶发&quot;&gt;第二次定位：还剩偶发&lt;/h2&gt;
&lt;p&gt;过了几天，音乐播放时又出现偶发的电音，游戏那边的电流声倒是没有了。
重新看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，ERR 不再是 0。&lt;/p&gt;
&lt;p&gt;这一次没有单一根因，候选有四条：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;候选&lt;/th&gt;
&lt;th&gt;判断依据&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;snd_hda_intel&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 省电&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;power_save = 10&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，10 秒没声音就让编解码器休眠，唤醒时爆音&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;CPU governor&lt;/td&gt;
&lt;td&gt;所有核心跑在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;powersave&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，音频线程拿不到实时性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;min-quantum&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 过低&lt;/td&gt;
&lt;td&gt;值是 32，也就是 0.67 ms，任何抖动都会 xrun&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;WirePlumber 链路失败&lt;/td&gt;
&lt;td&gt;日志里有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;1 of 1 PipeWire links failed to activate&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;四条里改了哪几条2026-09-实测&quot;&gt;四条里改了哪几条（2026-09 实测）&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;候选&lt;/th&gt;
&lt;th&gt;档案里的方案&lt;/th&gt;
&lt;th&gt;现在的状态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/modprobe.d/audio-nosuspend.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;❌ 文件不存在，内核参数仍是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;power_save=10&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/default/cpupower&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; + 启用服务&lt;/td&gt;
&lt;td&gt;❌ 文件不存在，governor 仍是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;powersave&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/pipewire/pipewire.conf.d/99-min-quantum.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;已生效&lt;/strong&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-metadata&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 读出 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;min-quantum = 256&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;WirePlumber 规则&lt;/td&gt;
&lt;td&gt;⚠️ 文件在，但&lt;strong&gt;没有被读&lt;/strong&gt;，见下一节&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;一份没有生效的配置&quot;&gt;一份没有生效的配置&lt;/h2&gt;
&lt;p&gt;回头再看这台机器时，WirePlumber 的日志里有这么两行：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wireplumber: Old configuration file detected:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             ~/.config/wireplumber/main.lua.d/51-disable-suspension.lua&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wireplumber: Lua configuration files are NOT supported in WirePlumber 0.5.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             You need to port them to the new format if you want to use them.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;那份配置是 0.4 时代的写法，内容是禁用音频设备的自动挂起。它一直在磁盘上，
看着像已经生效了，但 WirePlumber 0.5 起不再读 Lua 配置，所以从升级那天起，
它就是个死文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;判断配置有没有生效，要看守护进程怎么说、设备上的属性是什么，不能看文件在不在。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;里面两个属性名也没了&quot;&gt;里面两个属性名也没了&lt;/h3&gt;
&lt;p&gt;那份 Lua 规则用了三个属性，在 0.5 里的情况：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性&lt;/th&gt;
&lt;th&gt;0.5 里还在吗&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;session.suspend-timeout-seconds&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;✅ 仍在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;suspend-node.lua&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里被读取，默认 5 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;api.alsa.disable-power-save&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;❌ 脚本和二进制模块里都搜不到&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;api.alsa.disable-suspend&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;❌ 同上&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;所以就算把它转成新格式，能保留的也只有第一个。&lt;/p&gt;
&lt;h3 id=&quot;新格式长什么样&quot;&gt;新格式长什么样&lt;/h3&gt;
&lt;p&gt;WirePlumber 0.5 的配置放在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/wireplumber/wireplumber.conf.d/*.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
官方自带的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;alsa-vm.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就是现成样例：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;monitor.alsa.rules = [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    matches = [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      { node.name = &quot;~alsa_output.pci.*&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    actions = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      update-props = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        api.alsa.period-size   = 1024&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        api.alsa.headroom      = 2048&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;照这个格式，那条禁用挂起的规则搬过来是：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# ~/.config/wireplumber/wireplumber.conf.d/51-disable-suspend.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;monitor.alsa.rules = [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    matches = [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      { node.name = &quot;~alsa_output.*&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      { node.name = &quot;~alsa_input.*&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    actions = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      update-props = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        session.suspend-timeout-seconds = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;上面这一段&lt;strong&gt;没有在本机跑过&lt;/strong&gt;。属性名确认过在 0.5 的脚本里还被读取，
文件格式照抄的是官方样例，但「改完到底生效没有」这一步没验。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;怎么验证&quot;&gt;怎么验证&lt;/h2&gt;
&lt;h3 id=&quot;-看数字&quot;&gt;① 看数字&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pw-top&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                            # ERR 列&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;-看配置有没有落到设备上&quot;&gt;② 看配置有没有落到设备上&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pw-metadata&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; settings&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;quantum|rate&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;本机现在的输出：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;update: id:0 key:&apos;clock.rate&apos; value:&apos;48000&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;update: id:0 key:&apos;clock.quantum&apos; value:&apos;1024&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;update: id:0 key:&apos;clock.min-quantum&apos; value:&apos;256&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;update: id:0 key:&apos;clock.max-quantum&apos; value:&apos;2048&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;-看守护进程有没有抱怨&quot;&gt;③ 看守护进程有没有抱怨&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; wireplumber&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --since&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;14 days ago&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -iE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;lua|not supported&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;出现 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Old configuration file detected&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，就说明那个文件是死的。&lt;/p&gt;
&lt;h3 id=&quot;-回头看内核参数&quot;&gt;④ 回头看内核参数&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/module/snd_hda_intel/parameters/power_save&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /sys/module/snd_hda_intel/parameters/power_save_controller&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # Y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;这两个值本机至今没有改过。省电那一层本来是靠 WirePlumber 兜的，
而那份配置又没生效，所以这一层目前是空的。&lt;/p&gt;
&lt;h2 id=&quot;现在的状态2026-09-20-实测&quot;&gt;现在的状态（2026-09-20 实测）&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 ERR（两个活动节点）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;clock.min-quantum&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;256（原为 32）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户组&lt;/td&gt;
&lt;td&gt;含 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;realtime&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;近 14 天 pipewire 日志里的 xrun&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 条&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;近 14 天 wireplumber 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;link failed&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11 条&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;snd_hda_intel power_save&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;10（未改）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU governor&lt;/td&gt;
&lt;td&gt;powersave（未改）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;link failed&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 那条线还活着，说明候选 4 没有结。不过 ERR 是 0、日志里也没有 xrun，
所以它现在没有表现为听得见的爆音。&lt;/p&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;th&gt;下一步&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ERR 一直涨&lt;/td&gt;
&lt;td&gt;缓冲区喂不上&lt;/td&gt;
&lt;td&gt;先看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 QUANT 是不是太小，再提高 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;min-quantum&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;只在游戏里出现&lt;/td&gt;
&lt;td&gt;Proton 的音频延迟&lt;/td&gt;
&lt;td&gt;Steam 启动项加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PULSE_LATENCY_MSEC=60 %command%&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;改了配置没变化&lt;/td&gt;
&lt;td&gt;服务没重启&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl --user restart wireplumber pipewire pipewire-pulse&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;配置写了却没生效&lt;/td&gt;
&lt;td&gt;格式不对，0.5 不读 Lua&lt;/td&gt;
&lt;td&gt;看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;journalctl --user -u wireplumber&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 有没有抱怨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ERR 是 0 但还有杂音&lt;/td&gt;
&lt;td&gt;不是 xrun 引起的&lt;/td&gt;
&lt;td&gt;问题不在缓冲区，往硬件、线材、DSP 链查&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-top&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pw-metadata&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wpctl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，都是 PipeWire 与 WirePlumber 自带的命令&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/security/limits.d/99-realtime-privileges.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;realtime&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 组的权限来源&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/share/wireplumber/wireplumber.conf.d/alsa-vm.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，0.5 配置格式的官方样例&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/share/wireplumber/scripts/node/suspend-node.lua&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;session.suspend-timeout-seconds&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的读取处&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/PipeWire&quot;&gt;Arch Wiki: PipeWire&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>PipeWire</category><category>音频</category><category>xrun</category><category>KDE Plasma</category></item><item><title>让 Linux 的时间方案与 Windows 一致</title><link>https://miprota.cc/posts/linux-rtc-local-time/</link><guid isPermaLink="true">https://miprota.cc/posts/linux-rtc-local-time/</guid><description>作为双系统用户，每次从 Windows 回到 Linux 后（反之亦然），我的系统时间都会出现错乱，所以干脆修改 Linux 的系统时间方案，使其和 Windows 一致，防止打架</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;虽然我现在很少使用 Windows 了，但总还是会有回到 Win 上玩游戏的需求的，然而以前总是从 Windows 切回 Linux 后，我的系统时间就会出现错乱（两套系统会互相改写 RTC）所以，为了让两个系统不打架，同时考虑到 Linux 操作相对简单一些（Maybe？）&lt;/p&gt;
&lt;p&gt;所以，来让 Linux RTC 使用本地时间吧！&lt;/p&gt;
&lt;h2 id=&quot;背景&quot;&gt;背景&lt;/h2&gt;
&lt;p&gt;Windows 和 Linux 对硬件时钟（RTC）的默认处理方式不同：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;系统&lt;/th&gt;
&lt;th&gt;硬件时钟假设&lt;/th&gt;
&lt;th&gt;行为&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;本地时间（local time）&lt;/td&gt;
&lt;td&gt;RTC 直接存 +8 时间，不做偏移&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;UTC 时间&lt;/td&gt;
&lt;td&gt;RTC 存 UTC，根据时区 +8 显示本地时间&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;双系统切换时，两套系统会互相改写 RTC，导致时间错乱 8 小时。&lt;/p&gt;
&lt;h2 id=&quot;当前状态&quot;&gt;当前状态&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;RTC time: 2026-07-06 03:39:48 (UTC)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Local time: 2026-07-06 11:39:48 (CST, +0800)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;RTC in local TZ: no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;当前 Linux 将 RTC 视为 UTC，硬件时钟比本地时间少 8 小时。&lt;/p&gt;
&lt;h2 id=&quot;解决方案&quot;&gt;解决方案&lt;/h2&gt;
&lt;p&gt;让 Linux 迁就 Windows，将 RTC 视为本地时间：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; timedatectl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; set-local-rtc&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;影响分析&quot;&gt;影响分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点&lt;/strong&gt;：双系统时间一致，不再互相打架&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;切换时区时 RTC 需要手动调整（对于我这种不会出国的用户基本没有影响）&lt;/li&gt;
&lt;li&gt;systemd 会在启动时自动处理，不会有实质性问题&lt;/li&gt;
&lt;li&gt;可能产生一条 warning 日志，不影响使用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;验证命令&quot;&gt;验证命令&lt;/h2&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;timedatectl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;RTC in local&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 应显示：RTC in local TZ: yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/System_time&quot;&gt;Arch Wiki: System time&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>Windows</category><category>RTC</category><category>local-time</category></item><item><title>让 Kitty 和 Starship 跟着 KDE 一起换色</title><link>https://miprota.cc/posts/kitty-kde-color-sync/</link><guid isPermaLink="true">https://miprota.cc/posts/kitty-kde-color-sync/</guid><description>换壁纸取色、切配色方案、昼夜自动切换 —— 让终端配色自动跟上 KDE。两个零依赖 Python 脚本、一条 systemd 链路，以及一个会静默失败的竞态陷阱。</description><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;KDE 那边把 accent 调成了玫瑰粉，终端还停在上一套主题；Starship 的 git 分支胶囊又是另一个颜色。壁纸一换，三处全不对。&lt;/p&gt;
&lt;p&gt;手动改当然可以，但每次换壁纸、每次切深浅色都要记得改一遍 —— 那就等于没改。&lt;/p&gt;
&lt;p&gt;这篇讲的是一套&lt;strong&gt;自动&lt;/strong&gt;方案：让终端配色跟着 KDE 走。读完你能得到两个零依赖的 Python 脚本、一条 systemd 自动同步链路，以及一个&lt;strong&gt;会静默失败的竞态陷阱&lt;/strong&gt;的完整避坑方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;配套代码与完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync&quot;&gt;https://github.com/LaT-SKY/kde-terminal-theme-sync&lt;/a&gt;（MIT）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KDE Plasma 6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;配色数据源。昼夜自动切换需要 &lt;strong&gt;6.5+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kitty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;终端本体，支持 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGUSR1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 热重载&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Starship&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提示符。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[palettes.*]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 需要 &lt;strong&gt;1.20+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python 3.8+&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;两个脚本只用标准库，没有 pip 依赖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;systemd –user&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;自动同步用它。Arch / Fedora / Ubuntu 默认有&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;这套东西在什么环境上验证过&quot;&gt;这套东西在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS (Arch) ｜ KDE Plasma 6 ｜ Kitty ｜ Starship 1.26.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wayland ｜ Python 3.14&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;只在上面这一个组合上实测过。&lt;/strong&gt; 下面这份清单说明哪些地方会因环境而异 ——
标 ✅ 的可以放心，标 ⚠️ 和 ❌ 的要自己确认一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;配置文件路径&lt;/strong&gt;（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/…&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）—— ✅ 通用。XDG 规范，各发行版一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KDE 配色存储位置与优先级&lt;/strong&gt; —— ✅ 通用。同上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的内容&lt;/strong&gt; —— ⚠️ 因 Plasma 版本而异。见下面「一个会静默失败的陷阱」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; —— ✅ 3.8+ 都行。只用标准库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemd --user&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; —— ⚠️ 需发行版启用。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl --user status&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 自查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PathModified=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的触发时机&lt;/strong&gt; —— ✅ 通用。systemd 行为。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kitty 热重载 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGUSR1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt; —— ✅ 通用。kitty 自身特性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;starship 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 重绘&lt;/strong&gt; —— ❌ 只对 fish 有效。bash / zsh 要换做法，见「第三步：让它自己跑起来」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;昼夜自动切换&lt;/strong&gt; —— ⚠️ 需要 Plasma 6.5+。低版本没有这个功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --version&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                    # 要 3.8 以上&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 能输出就说明有 systemd --user&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # 存在就说明有 KDE 配置&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;原理kde-把配色存在哪&quot;&gt;原理：KDE 把配色存在哪&lt;/h2&gt;
&lt;p&gt;搞清楚数据从哪来，后面所有事都好办了。KDE 的配色分散在三个地方，按优先级回退：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 用户覆盖，&lt;strong&gt;优先级最高&lt;/strong&gt;。accent 色这类个性化设置在这里&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/color-schemes/&amp;lt;名称&amp;gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 用户自己装的配色&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/share/color-schemes/&amp;lt;名称&amp;gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 系统自带，最后兜底&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当前用的是哪一套，从 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[General] ColorScheme&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 读。&lt;/p&gt;
&lt;h3 id=&quot;️-一个反直觉的点&quot;&gt;⚠️ 一个反直觉的点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;那个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ColorScheme&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 键不一定在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这不是配置写坏了。Plasma 在切换主题时是&lt;strong&gt;分阶段写文件&lt;/strong&gt;的，而且写的地方不止一处 ——
方案名可能跑到了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/kdedefaults/kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;自己确认一下：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 看 kdeglobals 里有没有 ColorScheme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;ColorScheme&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 如果没有，看这里&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;ColorScheme&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/kdedefaults/kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;记住这个细节&lt;/strong&gt; —— 「一个会静默失败的陷阱」的根因就在这儿。&lt;/p&gt;
&lt;h3 id=&quot;colors-基座文件是什么&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 基座文件是什么&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;&amp;lt;名称&amp;gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是完整的配色方案文件，里面是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:View]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:Window]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
这样的段。脚本读它的顺序是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先读 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:*]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 段（那是用户覆盖后的结果）&lt;/li&gt;
&lt;li&gt;再用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 文件&lt;strong&gt;补齐&lt;/strong&gt;缺失的段&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个「补齐」在正常情况下是好事 —— 少几个键不影响。但它也正是那个陷阱
最难发现的地方，到时候会说。&lt;/p&gt;
&lt;h2 id=&quot;第一步读-kde-配色生成-kitty-主题&quot;&gt;第一步：读 KDE 配色，生成 Kitty 主题&lt;/h2&gt;
&lt;p&gt;先建一个目录放脚本。位置随意，但&lt;strong&gt;记住它&lt;/strong&gt; —— 后面 systemd 单元要指过来。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.local/share/kde-terminal-theme-sync&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.local/share/kde-terminal-theme-sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;generate-kitty-theme.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 放进去。&lt;strong&gt;这个脚本 492 行，不铺在正文里&lt;/strong&gt; ——
下载或 clone 下来放到那个目录即可：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync/blob/main/generate-kitty-theme.py&quot;&gt;generate-kitty-theme.py&lt;/a&gt;&lt;/strong&gt;
492 行 / 19.8 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync/raw/main/generate-kitty-theme.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;下面讲它的两处设计决策。&lt;strong&gt;不用对着源码读&lt;/strong&gt;，看完再回去翻也来得及。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先跑一次看看它能不能读出你的配色：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate-kitty-theme.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;我这边（BreezeDark）的输出是这样，&lt;strong&gt;这是真实运行结果&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 当前 KDE 配色方案: BreezeDark  (来源: ~/.config/kdeglobals)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 读取基础配色文件: /usr/share/color-schemes/BreezeDark.colors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 检测到 暗色 主题 (背景亮度=22)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;foreground  #fcfcfc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;background  #151a1e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cursor      #3daee9&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h3 id=&quot;两个设计决策值得单独讲&quot;&gt;两个设计决策，值得单独讲&lt;/h3&gt;
&lt;p&gt;脚本里有两处看起来可以「更统一」、但&lt;strong&gt;故意不统一&lt;/strong&gt;的地方。&lt;/p&gt;
&lt;h4 id=&quot;-background-为什么要掺-5-accent&quot;&gt;① &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 为什么要掺 5% accent&lt;/h4&gt;
&lt;p&gt;纯搬 KDE 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;BackgroundNormal&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 得到的是一块死板的灰。它和 KDE 窗口放在一起，
一眼能看出「不是一家人」。&lt;/p&gt;
&lt;p&gt;所以脚本把 accent 按 5% 掺进背景 —— 上面那个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;#151a1e&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，
原始 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;BackgroundNormal&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;(20, 22, 24)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，掺入 accent 之后变成了 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;#151a1e&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
差别很小，但整块背景「活」了。&lt;/p&gt;
&lt;h4 id=&quot;-ansi-蓝为什么不跟随-accent&quot;&gt;② ANSI 蓝为什么不跟随 accent&lt;/h4&gt;
&lt;p&gt;这是更重要的一个。&lt;/p&gt;
&lt;p&gt;如果你的 KDE &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ForegroundLink&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 被覆盖成了非蓝色（比如玫瑰粉），
&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;color4&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（ANSI 蓝）不会跟着变&lt;/strong&gt; —— 脚本会检测色相，不是蓝就回退到标准蓝 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;#2980b9&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;理由很实际：终端里太多程序用 ANSI 蓝表示「目录」「信息」「链接」。
它变成粉色之后，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ls&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的输出会读不懂 —— 目录和普通文件分不出来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;功能语义色不能为了好看让路。&lt;/strong&gt; 这和「配色统一」是两回事，
脚本选了前者。&lt;/p&gt;
&lt;h2 id=&quot;第二步生成-starship-调色板&quot;&gt;第二步：生成 Starship 调色板&lt;/h2&gt;
&lt;p&gt;同样放进那个目录（589 行，一样不铺在正文里）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;完整脚本：&lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync/blob/main/generate-starship-palette.py&quot;&gt;generate-starship-palette.py&lt;/a&gt;&lt;/strong&gt;
589 行 / 22.4 KB ｜ &lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync/raw/main/generate-starship-palette.py&quot;&gt;直接下载&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;为什么只改-paletteskde-段&quot;&gt;为什么只改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[palettes.kde]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 段&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;starship.toml&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是你自己的配置文件，里面可能有大量手动调过的东西。
脚本&lt;strong&gt;默认整份输出&lt;/strong&gt;（第一次用），但加上 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--palette-only&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 就只更新
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[palettes.kde]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这一段，其它原样保留：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate-starship-palette.py&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --palette-only&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 首次备份到: ~/.config/starship.toml.bak&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[✓] palette 段已更新: ~/.config/starship.toml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;自动同步链路用的就是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--palette-only&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— &lt;strong&gt;自动化不该覆盖你的手动配置。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;调色板是怎么派生的&quot;&gt;调色板是怎么派生的&lt;/h3&gt;
&lt;p&gt;从 KDE 拿到的只有一个 accent 色。脚本用混色派生出三个层次：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;键&lt;/th&gt;
&lt;th&gt;怎么来的&lt;/th&gt;
&lt;th&gt;用在哪&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;accent&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;KDE &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DecorationFocus&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 原色&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Git 分支&lt;/strong&gt;胶囊（最醒目）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;accent_soft&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;accent 与背景 &lt;strong&gt;55% 混合&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主机名、用户名胶囊&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;accent_dim&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;accent 与背景 &lt;strong&gt;25% 混合&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;目录、命令耗时胶囊&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这样几个胶囊之间有层次，而不是一片同样的颜色。&lt;/p&gt;
&lt;h2 id=&quot;第三步让它自己跑起来&quot;&gt;第三步：让它自己跑起来&lt;/h2&gt;
&lt;p&gt;手动跑脚本能解决问题，但&lt;strong&gt;每次换壁纸都要记得跑一次，那就等于没有&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;用 systemd 的用户级 Path 单元监听 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;下面这三个文件很短，直接铺开&lt;/strong&gt; —— 正文要讲解的部分必须能当场对着看：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Unit&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Watch kdeglobals for KDE theme changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Path&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 监听这个文件被改写。KDE 换壁纸取色 / 切配色方案 / 昼夜自动切换&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 都会改写它，所以三种情况都能触发同步。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;PathModified&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;%h/.config/kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Install&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;WantedBy&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;default.target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```ini
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Unit&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Sync Kitty/Starship colors from KDE theme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;After&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;graphical-session.target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;oneshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ⚠️ 路径按你的安装位置改。%h 是 systemd 的家目录占位符，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    所以这一份不用改就能用（前提是你把脚本放在这个目录）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    用 /usr/bin/bash 显式调用，省得依赖脚本的可执行位。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;ExecStart&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;/usr/bin/bash &lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;%h/.local/share/kde-terminal-theme-sync/auto-sync.sh&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同步入口：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# KDE 配色变化 → 同步 Kitty/Starship（由 kde-theme-sync.path 触发，也可手动运行）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 幂等：内容无变化则不写盘、不发信号&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2026-09-19 竞态修复：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   KDE 分阶段写 kdeglobals（先 General/ColorSchemeHash，颜色段随后落盘），&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   而 systemd PathModified 在写入瞬间就触发，旧实现会读到半成品 →&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   生成浅色主题 → 与已有文件逐字节相同 → 判定“无变化” → 永不重试，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   结果切到暗色模式后 kitty 背景仍是浅色（starship 因稍后读取而正常）。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   现在：生成前等内容稳定，生成后复核，若期间又变则整体重跑；且生成器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#   遇到必需颜色缺失会退出码 3、本脚本跳过本次同步而不是写入浅色垃圾。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 9&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/tmp/kde-theme-sync.lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;flock&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 9&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;  # 已有实例在跑则直接退出，防并发&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 脚本自己所在目录 —— **不写死路径**，clone 到哪都能跑。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# （原版写死了作者的私人路径，发布前必须去掉这类东西。）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;DIR&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;BASH_SOURCE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;]}&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; pwd&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;KDEGLOBALS&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kdeglobals&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;KITTY_CONF&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kitty/colors-kde.conf&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;REDO_COUNT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 本次同步内允许的“整体重跑”次数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;MAX_REDO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SETTLE_WAIT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;0.4&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; # 稳定采样间隔&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;SETTLE_TRIES&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt; # 最多等 12×0.4s ≈ 4.8s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 内容摘要：作为“kdeglobals 是否仍在变”的判据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;file_sig&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; md5sum&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -d&apos; &apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 等 kdeglobals 写完：连续两次采样摘要一致才继续（KDE 分阶段写盘）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;settle_kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    local&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; prev&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; cur i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; SETTLE_TRIES&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++));&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;        cur&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;file_sig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KDEGLOBALS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        [[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$cur&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$cur&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$prev&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;        prev&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$cur&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        sleep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$SETTLE_WAIT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] 警告：kdeglobals 在 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$SETTLE_TRIES&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 次采样内未稳定，继续尝试&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 返回 0 表示“内容在同步期间又变了，需要重跑”，1 表示稳定&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;kdeglobals_changed_since&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;    [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;file_sig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KDEGLOBALS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ── 生成前：等 KDE 把 kdeglobals 写完 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;settle_kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    SIG_BEFORE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;file_sig&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KDEGLOBALS&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    TMP_K&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$DIR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/generate-kitty-theme.py&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$TMP_K&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 退出码 3 = kdeglobals 半成品（生成器已自行重试过）；其余为真实错误&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] kitty 配色生成失败（kdeglobals 尚未写完或数据异常），本次跳过&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$TMP_K&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        exit&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 1) Kitty：生成到临时文件比对，仅内容变化时落盘并 SIGUSR1 热重载&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cmp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$TMP_K&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KITTY_CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$TMP_K&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$KITTY_CONF&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        pkill&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -USR1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kitty&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] kitty colors-kde.conf 已更新并发送 SIGUSR1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] kitty 配色无变化&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$TMP_K&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # 2) Starship：只更新 [palettes.kde] 段（脚本内部自带幂等）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;    OUT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$DIR&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/generate-starship-palette.py&quot; --palette-only &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OUT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;palette 段已更新&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 真正写入了新 palette → 通知所有 fish 重绘 prompt（等效窗口 resize；&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # SIGWINCH 默认忽略、无杀伤。fish 重绘时 starship 重读配置即换色，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # 解决 transience 下已开终端 prompt 不刷新问题）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        pkill&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -WINCH&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; fish&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] starship palette 已更新，已通知 fish 重绘&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OUT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -q&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;palette 无变化&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] starship palette 无变化&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] starship 更新异常：&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$OUT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;    # ── 生成后复核：若 kdeglobals 在本次同步期间又被改写（说明读到的可能仍是半成品），整体重跑 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; kdeglobals_changed_since&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$SIG_BEFORE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;REDO_COUNT &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; MAX_REDO&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;));&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;            REDO_COUNT&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$((&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;REDO_COUNT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;            echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] 检测到 kdeglobals 在同步期间再次变化，重跑同步（第 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$REDO_COUNT&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 次）&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;            settle_kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;            continue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;[&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;+%F %T&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;] 警告：kdeglobals 在 &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$MAX_REDO&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; 次重跑后仍在变化，放弃本次同步&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;整条链路是这样：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;kdeglobals 变化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; └─ kde-theme-sync.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     │  (systemd --user，监听文件修改)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     └─ kde-theme-sync.service  oneshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         └─ auto-sync.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             ├─ 生成到临时文件&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             ├─ 与现有配置逐字节比对&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             ├─ 有变化才落盘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             ├─ kitty: SIGUSR1 热重载&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             └─ starship: 只更新&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                [palettes.kde] 段&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这张图刻意每行不超过 44 列 —— 手机上不用横向滚动就能一眼看全。
代码块本身是支持横向滚动的（超宽时在块内滑动，页面不动），
但对树形图来说，能一眼看全比能滚动有用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;为什么用-pathmodified-而不是定时轮询&quot;&gt;为什么用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PathModified=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 而不是定时轮询&lt;/h3&gt;
&lt;p&gt;KDE 改配置是&lt;strong&gt;事件驱动&lt;/strong&gt;的。轮询要么延迟高（间隔大），要么空转（间隔小）。
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PathModified=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 精确到「这个文件被写了」这个事件。&lt;/p&gt;
&lt;h3 id=&quot;热重载两个信号各有各的原因&quot;&gt;热重载：两个信号，各有各的原因&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Kitty —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGUSR1&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; Kitty 收到就重新读配置文件。没有它，你得重启终端。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Starship —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; 这个稍微绕一点：&lt;/p&gt;
&lt;p&gt;Starship 每次画 prompt 都会重读配置，所以&lt;strong&gt;新开的终端&lt;/strong&gt;本来就会用新色。
但&lt;strong&gt;已经开着的终端不会&lt;/strong&gt; —— 它会一直停在旧色上。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是终端窗口大小改变的信号。fish 收到会重绘 prompt，
重绘时 Starship 重新读配置，于是&lt;strong&gt;已开终端也即时换色&lt;/strong&gt;。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pkill&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -WINCH&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; fish&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; 2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 注意 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;-x&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;：它要求&lt;strong&gt;进程名精确匹配&lt;/strong&gt;。不要用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkill -f&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; ——
那个模式串会匹配到命令行里任何含该字符串的进程，&lt;strong&gt;包括执行它的那个 shell 自己&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;不用-fish-怎么办&quot;&gt;不用 fish 怎么办&lt;/h3&gt;
&lt;p&gt;上面那一行是&lt;strong&gt;唯一&lt;/strong&gt;和 shell 绑定的地方。换 shell 就换它：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fish&lt;/strong&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkill -WINCH -x fish&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（本方案默认）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bash&lt;/strong&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pkill -WINCH -x bash&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。但 bash 收到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不一定重绘 prompt，可能仍需新开终端&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;zsh&lt;/strong&gt; —— 同理；可以用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;TRAPWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; + &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;zle reset-prompt&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，但需要额外配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;其它部分与 shell 无关。&lt;/strong&gt; 你也可以直接删掉那一行 —— 代价只是已开终端要新开一个才换色。&lt;/p&gt;
&lt;h3 id=&quot;安装&quot;&gt;安装&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 1. 装 systemd 单元&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.path&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.service&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/systemd/user/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; daemon-reload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; enable&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --now&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 2. Kitty 那边接上 include（~/.config/kitty/kitty.conf）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;#    include colors-kde.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 3. 看状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.path&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;journalctl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -u&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; kde-theme-sync.service&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里默认写的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;%h/.local/share/kde-terminal-theme-sync/auto-sync.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;%h&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 systemd 的家目录占位符）。&lt;strong&gt;脚本放在别处就改那一行。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;️-一个会静默失败的陷阱&quot;&gt;⚠️ 一个会静默失败的陷阱&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;这一节是全文最值钱的部分。&lt;/strong&gt; 任何监听 KDE 配置文件的工具都可能踩进去，
而且它失败的时候&lt;strong&gt;日志里一切正常&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;现象&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;自动同步上线两周后，某天切到暗色模式：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;kitty 背景&lt;strong&gt;仍是浅色&lt;/strong&gt;，而 starship &lt;strong&gt;已经正确变暗&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同一个桌面、同一次切换、同一份输入，一个跟上了，一个没跟上。&lt;/p&gt;
&lt;p&gt;journal 里更奇怪：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;9月 19 18:30:16  Starting Sync colors...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;9月 19 18:30:16  kitty 配色无变化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 ↑ 该更新却判定&quot;无变化&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;9月 19 18:30:16  starship palette 已更新&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 ↑ 同一份输入却变了&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;同一秒、同一份 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，两个脚本得出相反结论。&lt;/p&gt;
&lt;h3 id=&quot;根因链&quot;&gt;根因链&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;六步，一步都不能少。&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;KDE 写 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是分阶段的。&lt;/strong&gt; 不是一次写完 ——
可能先落 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[General]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，颜色段随后才写&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PathModified=&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 在第一次写入事件就触发。&lt;/strong&gt; 它不知道「文件还没写完」这回事&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同步抢在颜色段落盘之前读文件。&lt;/strong&gt; 读到的是「有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[General]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、无 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:View]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;」的中间态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;取色函数拿不到值，回退到默认。&lt;/strong&gt; 于是生成一份&lt;strong&gt;看起来正确&lt;/strong&gt;的浅色主题&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;它与磁盘上已有的浅色文件逐字节相同&lt;/strong&gt; → 幂等比对判定「无变化」→ &lt;strong&gt;不写盘、不发信号&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;颜色段真正落盘时，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;PathModified&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 不再触发&lt;/strong&gt;（文件已经“改过”了）→
&lt;strong&gt;永远不重试&lt;/strong&gt; → kitty 永久僵在浅色&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而 starship 那个脚本晚了一点点拿到完整文件，所以它变暗了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论：这是同步链路的竞态 ——「读到半成品 + 只比较一次」，不在 kitty，也不在 starship。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;为什么它特别隐蔽&quot;&gt;为什么它特别隐蔽&lt;/h3&gt;
&lt;p&gt;三个「看起来正常」叠在一起：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;脚本&lt;strong&gt;没报错&lt;/strong&gt;（它确实成功生成了一个主题）&lt;/li&gt;
&lt;li&gt;日志说**「配色无变化」**（从它的角度看，确实没变化）&lt;/li&gt;
&lt;li&gt;终端里&lt;strong&gt;确实有一个配色&lt;/strong&gt;（只是错的）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;没有任何一个环节会亮红灯。&lt;/strong&gt; 你只会觉得「这次怎么没跟上」，
手动跑一次又好了 —— 于是永远查不到根因。&lt;/p&gt;
&lt;h3 id=&quot;三条防线&quot;&gt;三条防线&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;一、生成前等它写完。&lt;/strong&gt; 不抢跑，连续两次采样内容一致才继续：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;settle_kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    local&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kdeglobals&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; prev&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; cur i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;++));&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;        cur&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;md5sum&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cut&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -d&apos; &apos; -f1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;        [[&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$cur&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$prev&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; ]]&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;        prev&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$cur&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sleep&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F5A9C8&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # 超时也继续，避免卡死整条链路&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;二、只接受完整输入。&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:View] BackgroundNormal&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 缺失就视为
「还没写完」，&lt;strong&gt;报错退出（退出码 3）&lt;/strong&gt;，让调用方跳过本次 ——
而不是拿默认值生成一份浅色垃圾。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三、生成后复核。&lt;/strong&gt; 再校验一次摘要；如果期间又变了（说明 KDE 还在写），
整体重跑，上限 2 次。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三层叠起来的效果一句话&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;宁可这次不更新，也绝不写入错误的颜色。&lt;/strong&gt;
不更新只是晚一点，写错了会一直错到下次切换。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;退出码约定&quot;&gt;退出码约定&lt;/h3&gt;
&lt;p&gt;调用方要据此决策，所以写进文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0&lt;/strong&gt; —— 成功（含「无变化」），正常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;/strong&gt; —— 参数错误，修正调用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3&lt;/strong&gt; —— KDE 配色数据不完整（半成品，重试后仍缺关键段）。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auto-sync.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跳过本次，等下次变化再触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;调试重试节奏用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--wait &amp;lt;秒&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--attempts &amp;lt;次数&amp;gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；
需要退回旧行为（缺失时用回退默认值）时加 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--allow-missing-colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; ——
&lt;strong&gt;但那个开关只该用来排错，不该进自动化链路。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;-浅色垃圾到底是什么颜色&quot;&gt;⭐ 「浅色垃圾」到底是什么颜色&lt;/h3&gt;
&lt;p&gt;这里有个&lt;strong&gt;连我自己第一版都复现错&lt;/strong&gt;的地方，值得讲清楚。&lt;/p&gt;
&lt;p&gt;拿一个半成品 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（只剩 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[General]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;）配合 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--allow-missing-colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[General] ColorScheme=BreezeDark&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;（方案名还在）
&lt;ul&gt;
&lt;li&gt;新行为：退出码 3，不写盘 ✅&lt;/li&gt;
&lt;li&gt;旧行为：⚠️ 仍然正确 —— 方案名还在，从 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 兜底读到了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只剩 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ColorSchemeHash&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/strong&gt;（方案名也不在）
&lt;ul&gt;
&lt;li&gt;新行为：退出码 3，不写盘 ✅&lt;/li&gt;
&lt;li&gt;旧行为：❌ 产出 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;background #f5fafd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（近白）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;关键在第二条。&lt;/strong&gt; 只有方案名也缺失时，兜底路径才断掉，
取色函数才会拿到默认值 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;(255,255,255)&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; → 判为亮色 → 生成近白的浅色。&lt;/p&gt;
&lt;p&gt;而那个近白的浅色，&lt;strong&gt;恰好与磁盘上已有的浅色文件逐字节相同&lt;/strong&gt; ——
于是触发第 5 步的「无变化」判定，&lt;strong&gt;永远不再重试&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这也解释了为什么这个问题那么难查：它需要&lt;strong&gt;两个条件同时成立&lt;/strong&gt;
（颜色段缺失 + 方案名缺失）才会发生。偶发、难复现、日志正常。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;第二个坑判断完整性必须看原始文件&quot;&gt;第二个坑：判断「完整性」必须看原始文件&lt;/h3&gt;
&lt;p&gt;第一版我把「必需颜色是否齐全」的判断放在&lt;strong&gt;合并后&lt;/strong&gt;的字典上。测试直接打脸：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.colors&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 基座文件会把缺失的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;[Colors:View]&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 补齐&lt;/strong&gt; —— 防护形同虚设，
真实缺色的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 照样生成了浅色主题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;必须判断原始的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt; 因为「半成品」的定义就是
&lt;strong&gt;原始文件里颜色段还没落盘&lt;/strong&gt;，跟合并后的结果没关系。&lt;/p&gt;
&lt;h2 id=&quot;怎么验证它真的在工作&quot;&gt;怎么验证它真的在工作&lt;/h2&gt;
&lt;h3 id=&quot;隔离测试用假-home不碰真实配置&quot;&gt;隔离测试：用假 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HOME&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，不碰真实配置&lt;/h3&gt;
&lt;p&gt;不要去动你自己的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。造一个假的：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;FAKE&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/tmp/fakehome&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $FAKE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 用系统自带的 BreezeDark 造一份&quot;完整&quot;的 kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;[General]&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;ColorScheme=BreezeDark&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;ColorSchemeHash=deadbeef&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  echo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;  # 把系统配色文件里的 [Colors:*] 段搬进来&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;  awk&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;/^\[Colors:/{p=1} /^\[(?!Colors:)/{p=0} p&apos;&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;      /usr/share/color-schemes/BreezeDark.colors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $FAKE/.config/kdeglobals&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;然后 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;HOME=$FAKE python3 generate-kitty-theme.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 输出与真实环境一致。&lt;/p&gt;
&lt;h3 id=&quot;手动复现那个陷阱&quot;&gt;手动复现那个陷阱&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;这是最值得跑一遍的测试。&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ① 只写 [General]，模拟&quot;KDE 还在写&quot;的中间态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;[General]\nColorSchemeHash=deadbeef\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $FAKE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ② 跑一次 —— 应当退出码 3、一个字节都不写&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HOME&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$FAKE &lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate-kitty-theme.py&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --wait&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0.3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --attempts&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;退出码: &lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$?&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;真实的输出：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[!] kdeglobals 尚未写完（缺 kdeglobals[Colors:View]/BackgroundNormal），0.3s 后重试 (2/2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[✗] KDE 配色数据不完整，缺少: kdeglobals[Colors:View]/BackgroundNormal。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    通常是 kdeglobals 正在被写入的半成品状态。 本次跳过，不更新 Kitty 配色。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;退出码: 3      ← stdout 零行，什么都没写&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;再试「写到一半又补上」&lt;/strong&gt; —— 也就是当初 bug 的原始场景：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 先写半成品，1.2 秒后在后台补全&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;[General]\nColorSchemeHash=deadbeef\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $FAKE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kdeglobals&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; sleep&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 1.2&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /tmp/full-kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt; $FAKE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/.config/kdeglobals&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; )&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;HOME&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$FAKE &lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; generate-kitty-theme.py&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --wait&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 0.4&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; --attempts&lt;/span&gt;&lt;span style=&quot;color:#F0DCB4&quot;&gt; 6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[!] kdeglobals 尚未写完（缺 kdeglobals[Colors:View]/BackgroundNormal），0.4s 后重试 (2/6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[!] kdeglobals 尚未写完（缺 kdeglobals[Colors:View]/BackgroundNormal），0.4s 后重试 (3/6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[!] kdeglobals 尚未写完（缺 kdeglobals[Colors:View]/BackgroundNormal），0.4s 后重试 (4/6)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 当前 KDE 配色方案: BreezeDark  (来源: ~/.config/kdeglobals)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] 检测到 暗色 主题 (背景亮度=22)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;退出码: 0      ← 重试机制接住了，拿到正确的暗色&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;旧代码在这个场景下必然留下浅色。&lt;/strong&gt; 现在它会重试到数据完整为止。&lt;/p&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;完全不生效&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kde-theme-sync.path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 没启用 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;systemctl --user status kde-theme-sync.path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;systemd 单元里的路径不对 → 看 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ExecStart&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，路径要与脚本实际位置一致&lt;/li&gt;
&lt;li&gt;Kitty 没接上 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/kitty/kitty.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里要有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;include colors-kde.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换了颜色但已开终端不变&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Starship 需要重绘 → 那一行 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;SIGWINCH&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是否生效？新开一个终端验证是否正常&lt;/li&gt;
&lt;li&gt;不是 fish → 见上面「不用 fish 怎么办」&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;亮暗切换时 kitty 不跟随&lt;/strong&gt; —— 就是那个竞态。确认脚本版本包含三条防线；手动跑一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;bash auto-sync.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚本报退出码 3&lt;/strong&gt; —— &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是半成品。正常防护，等下次变化；反复出现就加大 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--wait&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--attempts&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;颜色明显不对&lt;/strong&gt; —— 方案名读错了。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;grep ColorScheme ~/.config/kdeglobals ~/.config/kdedefaults/kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ANSI 蓝没跟着 accent 变&lt;/strong&gt; —— 这是故意的。功能语义色不跟随，见「第一步」里「ANSI 蓝为什么不跟随 accent」&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;备选方案kitty-自带的-auto-color-scheme&quot;&gt;备选方案：kitty 自带的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auto-color-scheme&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Kitty 0.38 起自带这个功能：跑一次 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kitten themes&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，把主题分别存成
light / dark / no-preference 三份 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;*.auto.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，之后 kitty 自己查询系统配色并切换。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不需要任何外部脚本。&lt;/strong&gt; 听起来应该直接换过去，但它有个要命的性质：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When these files exist, the colors in these files override all other colors,
&lt;strong&gt;and also all background image settings, even those specified using the
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kitty --override&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; command line flag.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它会&lt;strong&gt;完全压制&lt;/strong&gt; &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;include colors-kde.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。也就是说，用了它就等于放弃跟随
KDE 的 accent 和壁纸取色 —— 而那正是这套东西存在的理由。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么时候它更合适&lt;/strong&gt;：你只需要亮/暗跟随，不需要终端配色「从壁纸长出来」。&lt;/p&gt;
&lt;h2 id=&quot;文件清单&quot;&gt;文件清单&lt;/h2&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;generate-kitty-theme.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;读 KDE 配色 → 生成 Kitty 主题。放在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.local/share/kde-terminal-theme-sync/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/dd&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;generate-starship-palette.py&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;读 KDE 配色 → 生成 Starship 调色板。同上。&lt;/dd&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auto-sync.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;同步入口：幂等比对 + 热重载信号。同上。&lt;/dd&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kde-theme-sync.path&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;监听 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kdeglobals&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。放在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/systemd/user/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/dd&gt;
&lt;dt&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;kde-theme-sync.service&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/dt&gt;
&lt;dd&gt;oneshot 执行 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;auto-sync.sh&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。同上。&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;&lt;strong&gt;完整代码&lt;/strong&gt;：&lt;a href=&quot;https://github.com/LaT-SKY/kde-terminal-theme-sync&quot;&gt;https://github.com/LaT-SKY/kde-terminal-theme-sync&lt;/a&gt;（MIT，可直接 clone）&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; https://github.com/LaT-SKY/kde-terminal-theme-sync&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;kitty 配置文档：&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/share/doc/kitty/html/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://man.archlinux.org/man/kitten-themes.1.en&quot;&gt;kitten-themes(1) man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://raw.githubusercontent.com/kovidgoyal/kitty/f13c8cd44dbe1caeaf6a78fbc33ad304b9369fe2/docs/kittens/themes.rst&quot;&gt;kitty 官方文档 themes.rst&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>KDE Plasma</category><category>Kitty</category><category>Starship</category><category>systemd</category><category>配色</category></item><item><title>让微信在 Wayland 下原生跑起来</title><link>https://miprota.cc/posts/wechat-wayland-chinese-input/</link><guid isPermaLink="true">https://miprota.cc/posts/wechat-wayland-chinese-input/</guid><description>微信打不出中文，问题不在输入法。把 Qt 应用推回原生 Wayland 的 text-input 协议，一行 Exec 就够。</description><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;同一个桌面、同一个 fcitx5、同一个用户。终端能使用中文输入法，微信不能。&lt;/p&gt;
&lt;p&gt;这真的是一个很恼火的问题，而且对于小白来说也确实是使用 Linux 的第一关（Maybe？）。所以我准备了如下教程。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，如果你是一个 Hyprland / niri 用户，以下教程可能不适合你。
笔者曾经使用 Hyprland 时找遍了网络的教程也没法调教好微信&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;先决条件&quot;&gt;先决条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;需要&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;微信 Linux 版 4.x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3.x 及 Wine 版是另一回事，见附录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fcitx5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;输入法本体。&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5-diagnose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 跟着它一起装&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wayland 会话&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;echo $XDG_SESSION_TYPE&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 要输出 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;wayland&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KDE / GNOME 等&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;靠 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 文件启动应用的环境都适用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;这套做法在什么环境上验证过&quot;&gt;这套做法在什么环境上验证过&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CachyOS (Arch) ｜ KDE Plasma 6 ｜ Wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wechat-bin 4.1.13.23 ｜ fcitx5 5.1.22&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;只在上面这一个组合上实测过。&lt;/strong&gt; 下面这张表说明哪些地方会因环境而异：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项&lt;/th&gt;
&lt;th&gt;是否通用&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;用户级 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 覆盖系统级&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;XDG 规范，各桌面环境一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env VAR=值 命令&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的写法&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;通用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 coreutils，一定有&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个模块名&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;需要 Qt 自带&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;见「这两个参数各干什么」&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--ozone-platform=wayland&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;⚠️ &lt;strong&gt;只对有内嵌 Chromium 的应用有意义&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;同上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;微信的具体版本&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;会变&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;写这篇时是 4.1.13.23&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三个自查命令：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$XDG_SESSION_TYPE&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                    # 要输出 wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;which&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; fcitx5-diagnose&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;                       # 诊断工具，随 fcitx5 一起装&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.local/share/applications/&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;             # 用户级 launcher 放这&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;h2 id=&quot;第一步先搞清楚微信到底是什么&quot;&gt;第一步：先搞清楚微信到底是什么&lt;/h2&gt;
&lt;p&gt;网上流传一个说法：「Linux 微信是 Wine / 兼容层跑的」。&lt;strong&gt;实际上，微信的官网上或者 AUR 上均可以下载到原生的 Linux版本&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ① 它链接了 Qt 吗？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;ldd&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/wechat/wechat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; Qt&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;              # → 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ② 那 Qt 在哪？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -m1&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;Qt 6\.[0-9.]*&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/wechat/wechat&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;   # → Qt 6.6.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# ③ 是 Chromium 套壳吗？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;Electron/&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/wechat/wechat&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # → 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;三条读下来：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;结论&lt;/th&gt;
&lt;th&gt;依据&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;它是 Qt 6.6 应用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主程序里能搜到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Qt 6.6.&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qt 是静态链接进去的&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ldd&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 看不到任何 Qt 库，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/opt/wechat/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 下也没有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libQt*.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— 整个 Qt 被编进了那个 181 MB 的主程序&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;不是 Electron / Chromium 套壳&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Electron/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Chrome/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 各 0 处&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;不是 Wine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;同上。这是腾讯官方的 Linux 原生客户端&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;虽然现在的微信已经是原生的 Linux 程序了，但是我们还是会按照古法教程提供可能已经没有作用的环境变量设置&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;原理qt-应用在-wayland-下有两条路&quot;&gt;原理：Qt 应用在 Wayland 下有两条路&lt;/h2&gt;
&lt;p&gt;同一个 Qt 应用，在一个同时有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;DISPLAY&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;WAYLAND_DISPLAY&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的会话里，
可能落在两个完全不同的地方：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;① 兼容路径（XWayland）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   Qt → xcb 插件 → XWayland → X 服务器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   输入走 XIM：按【字符串】名字查服务&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;② 原生路径（Wayland）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   Qt → wayland 插件 → 合成器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   输入走 text-input：协议握手，不查名字&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;XIM 是&lt;strong&gt;按名字查&lt;/strong&gt;的：应用拿着 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;XMODIFIERS&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里那个字符串去找服务，
差一个字符就连不上，而且失败时它不吭声（附录里有完整案例）。&lt;/p&gt;
&lt;p&gt;原生 Wayland 没有这一层 —— 输入法由合成器统一调度，
应用和输入法之间是协议握手，不存在「名字对不上」这种失败模式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;所以正解不是「把 XIM 修好」，是「别走 XIM」。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;第二步修改应用程序快捷方式&quot;&gt;第二步：修改应用程序快捷方式&lt;/h2&gt;
&lt;p&gt;⚠️ &lt;strong&gt;不要改 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/share/applications/wechat.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。&lt;/strong&gt;，下次升级就会被覆盖回去了。&lt;/p&gt;
&lt;p&gt;拷一份到用户级目录，改那份：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.local/share/applications&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/share/applications/wechat.desktop&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.local/share/applications/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;然后把里面的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 改成这一行：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Exec=env QT_IM_MODULE=text-input-unstable-v3 /opt/wechat/wechat %U --ozone-platform=wayland&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;用户级目录里的同名文件会覆盖系统级那个&lt;/strong&gt;，不用删系统文件，也不用 root。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;嫌手改麻烦就在桌面的菜单编辑器里改（KDE 是右键 → 编辑应用程序）。
它会把改完的整份文件写到用户级目录 —— 效果一样，而且是同一个机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;改完重新从菜单启动微信。&lt;strong&gt;已经在跑的进程不会变&lt;/strong&gt;，得退干净再开。&lt;/p&gt;
&lt;h2 id=&quot;这两个参数各干什么&quot;&gt;这两个参数各干什么&lt;/h2&gt;
&lt;p&gt;分开说，因为它们的&lt;strong&gt;作用域完全不同&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;qt_im_moduletext-input-unstable-v3&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;QT_IM_MODULE=text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;让 Qt 用 Wayland 原生的 text-input 协议找输入法&lt;/strong&gt;，而不是回退到 X11 那套。&lt;/p&gt;
&lt;p&gt;这个值是谁认的？实测可以查：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -rl&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;text-input-unstable-v3&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /usr/lib/qt6/sbom/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;输出里有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;qtbase-WaylandClient_Attribution_wayland-text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; ——
&lt;strong&gt;它是 QtBase 自带的 Wayland 客户端实现&lt;/strong&gt;，编译在 Qt 里，不是外挂插件。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;顺带排掉一个误解：它&lt;strong&gt;不是&lt;/strong&gt; fcitx5 提供的。系统里的
&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/usr/lib/qt6/plugins/platforminputcontexts/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 只有 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;compose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;、&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ibus&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
三个插件，没有这个名字 —— 它走的是 Qt 自己那条路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;--ozone-platformwayland&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;--ozone-platform=wayland&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;把应用里内嵌的 Chromium 组件推上原生 Wayland。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里要诚实说一句实测结果：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ozone&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/wechat/wechat&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;        # → 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -a&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ozone&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /opt/wechat/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;.so&lt;/span&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;          # → libmmcronet.so、libmmmojo.so&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;ozone&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 这个字符串在主程序里一个都没有&lt;/strong&gt;，它只出现在 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libmmcronet.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;
（Chromium 的网络栈）和 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;libmmmojo.so&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（Chromium 的 IPC）里。&lt;/p&gt;
&lt;p&gt;也就是说：这个开关管的是&lt;strong&gt;微信内嵌网页渲染那一半&lt;/strong&gt;，不是 Qt 主界面。
打包者把它和上面那条一起给，两条配着用 —— &lt;strong&gt;别只加一条&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;️-为什么写成-env-前缀而不是塞进-etcenvironment&quot;&gt;⚠️ 为什么写成 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 前缀，而不是塞进 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/environment&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;把 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;QT_IM_MODULE=text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 全局设上，会&lt;strong&gt;连 X11 应用一起改&lt;/strong&gt; ——
而那些应用恰恰相反，需要的是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;QT_IM_MODULE=fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（Qt 的 X11 输入法模块）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一个变量，两种应用，需求是相反的。&lt;/strong&gt; 所以正确的粒度是&lt;strong&gt;按应用&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;作用范围&lt;/th&gt;
&lt;th&gt;怎么设&lt;/th&gt;
&lt;th&gt;给谁&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;全局&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/environment&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 或 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/environment.d/&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;走 XWayland 的 Qt 应用 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;QT_IM_MODULE=fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;单个应用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;.desktop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 前缀&lt;/td&gt;
&lt;td&gt;走原生 Wayland 的 Qt 应用 → &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;实测这台机器上就是这么配的，同一个手法用在两个应用上：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wechat.desktop   Exec=env QT_IM_MODULE=text-input-unstable-v3 /opt/wechat/wechat %U --ozone-platform=wayland&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;chatgpt.desktop  Exec=env QT_IM_MODULE=text-input-unstable-v3 chatgpt %U&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;这个模式可以推广&lt;/strong&gt;：任何「Qt + 跑在 Wayland + 打不出中文」的应用，
先别动全局变量，先给它单独加一个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;env QT_IM_MODULE=text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。
改错了只影响这一个应用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;怎么验证&quot;&gt;怎么验证&lt;/h2&gt;
&lt;h3 id=&quot;-能打字这似乎是废话&quot;&gt;① 能打字（这似乎是废话）&lt;/h3&gt;
&lt;p&gt;打开微信，&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Ctrl&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（实际切换键盘的按键因人而异），输入法面板弹出来、能输入中文。&lt;/p&gt;
&lt;h3 id=&quot;-想确认它真落在-wayland-而不是-xwayland&quot;&gt;② 想确认它真落在 Wayland 而不是 XWayland&lt;/h3&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7B87A6;font-style:italic&quot;&gt;# 看这个进程实际拿到的环境变量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;=$(&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;/opt/wechat/wechat&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;\0&apos;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;\n&apos;&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /proc/&lt;/span&gt;&lt;span style=&quot;color:#EDEFF7&quot;&gt;$pid&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;/environ&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; &apos;QT_IM_MODULE|QT_QPA_PLATFORM&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;期望看到 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;QT_IM_MODULE=text-input-unstable-v3&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;。看不到就说明 launcher 没生效 ——
多半是&lt;strong&gt;还在用旧的桌面缓存&lt;/strong&gt;，注销重登一次。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;更彻底的办法是看它有没有出现在 X11 的客户端列表里
（&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;xlsclients&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，Arch 上是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;xorg-xlsclients&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 包）。
出现在那里 = 还在走 XWayland。这个工具本文没有实测，只作为线索。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;附录如果应用还在走-xwayland&quot;&gt;附录：如果应用还在走 XWayland&lt;/h2&gt;
&lt;p&gt;老版本微信、不支持 Wayland 的 Qt 应用、纯 X11 程序 —— 它们还是得走 XIM。
这时才轮到下面这套。&lt;/p&gt;
&lt;h3 id=&quot;先跑-fcitx5-diagnose&quot;&gt;先跑 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5-diagnose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;它是 fcitx5 自带的体检表，会逐环检查环境变量、X 服务器上的注册名、
Qt / GTK 的 IM module。&lt;strong&gt;报错会指名道姓地说哪个变量不对。&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;小节&lt;/th&gt;
&lt;th&gt;管谁&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;## Xim:&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;X11 应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;## Qt:&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; / &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;## Gtk:&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;对应框架的程序&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 它会打印发行版、内核版本、进程名。脚本自己在结尾也提醒了 ——
贴到论坛之前先自己扫一遍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;️-莫大的陷阱尾随空格&quot;&gt;⚠️ 莫大的陷阱：尾随空格&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/environment&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 里那一行长这样：&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;XMODIFIERS=@im=fcitx &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;看着完全正常。但那&lt;strong&gt;最后一个空格会被原样当成服务名的一部分&lt;/strong&gt;，
而 X 服务器上注册的名字是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;（不带空格）。名字对不上就查不到，
查不到它也不报错 —— 表现就是「按了没反应」。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;让它现形&lt;/strong&gt;：用 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;cat -A&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，它把行尾这类不可见字符显示出来。&lt;/p&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -A&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; /etc/environment&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; XMODIFIERS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```plaintext
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;XMODIFIERS=@im=fcitx $      ← 出错：$ 前面多一个空格&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;XMODIFIERS=@im=fcitx$       ← 正确：$ 紧贴着 x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;末尾那个 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;$&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 是 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;cat -A&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 给行尾打的标记。&lt;strong&gt;它前面挨着的是不是空格，就是全部区别。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;怎么修&lt;/strong&gt;：环境变量有两个独立注入点，别只改一处。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;机制&lt;/th&gt;
&lt;th&gt;文件&lt;/th&gt;
&lt;th&gt;谁读它&lt;/th&gt;
&lt;th&gt;要 root 吗&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;/etc/environment&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pam_env&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;，登录时&lt;/td&gt;
&lt;td&gt;要&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;systemd –user&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;~/.config/environment.d/*.conf&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;systemd 用户管理器&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;不要&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;astro-code night-sky&quot; style=&quot;background-color:#0c1226;color:#edeff7; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;span class=&quot;t-only&quot;&gt;```bash
&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/environment.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A9B6EC&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt; ~/.config/environment.d/fcitx5.conf&lt;/span&gt;&lt;span style=&quot;color:#8892B4&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;&apos;EOF&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;XMODIFIERS=@im=fcitx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;GTK_IM_MODULE=fcitx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;QT_IM_MODULE=fcitx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;SDL_IM_MODULE=fcitx&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EFC77E&quot;&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;&lt;br&gt;```
&lt;/span&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，如果你选择直接复制我的代码，那么建议自行输入最后的 EOF 并回车&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;改完&lt;strong&gt;必须重新登录&lt;/strong&gt; —— 环境变量只在会话建立时读一次，新开终端不算。&lt;/p&gt;
&lt;h2 id=&quot;排错&quot;&gt;排错&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;可能原因&lt;/th&gt;
&lt;th&gt;下一步&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;改完没变化&lt;/td&gt;
&lt;td&gt;应用还在跑旧进程&lt;/td&gt;
&lt;td&gt;退干净再启动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;还是没有&lt;/td&gt;
&lt;td&gt;桌面缓存没刷新&lt;/td&gt;
&lt;td&gt;注销重登，或 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;update-desktop-database ~/.local/share/applications&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wayland 应用也打不出中文&lt;/td&gt;
&lt;td&gt;输入法没起来&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;pgrep -a fcitx5&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;；没进程就 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5 -d&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;只有 X11 应用不行&lt;/td&gt;
&lt;td&gt;走的是 XIM&lt;/td&gt;
&lt;td&gt;看上面的附录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;xprop&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 说没有 XIM_SERVERS&lt;/td&gt;
&lt;td&gt;不在 X 会话里&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;echo &quot;$DISPLAY&quot;&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 要有值&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;fcitx5-diagnose&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; —— fcitx5 自带的诊断工具，附录部分的第一手来源&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aur.archlinux.org/packages/wechat-bin&quot;&gt;AUR: wechat-bin&lt;/a&gt; —— 上面那行 &lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt;&lt;code&gt;Exec&lt;/code&gt;&lt;span class=&quot;t-only&quot;&gt;`&lt;/span&gt; 的建议出处&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fcitx-im.org/wiki/Input_method_related_environment_variables/zh-cn&quot;&gt;Fcitx5 Wiki — 输入法相关环境变量&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Linux</category><category>Fcitx5</category><category>微信</category><category>Wayland</category><category>Qt</category></item></channel></rss>