如何远程调试损坏的 initrd?

如何远程调试损坏的 initrd?

背景

我有一个运行 Linux 的系统。它是一个 NAS,没有任何显示器、键盘或串行端口。它确实有一个网络端口。我对其上运行的软件不满意,并且正在尝试运行不同的发行版。

我拥有的

在现有系统上,我可以通过使用 Web 界面升级 ROM 来设法获得新内核并启动 initrd,但该升级是一个特制的映像,它只不过是解压内核、initrd,kexec然后运行kexec使用启动新内核所需的参数。

initrd 建立网络连接,启动 SSH 服务器 (dropbear),并等待其结束。然后它运行一个不同的脚本。使用它,我可以做一些测试:我可以启动到该内核/initrd,通过 SSH 登录,自定义 stage-2 脚本,杀死 dropbear,并希望得到最好的结果。

使用这种方法,我成功地在硬盘上安装了一个功能正常的操作系统。 (目前,它是 NixOS,如果重要的话,但我将来可能会改变它。不过,我的问题不是关于任何特定的发行版。)我故意不是使其可启动。我希望保持闪存原样,这样除了硬盘上的数据之外,NAS仍然是“官方”的。然而,我已经获得了发行版自己的内核和 initrd,我想将其放入升级映像中。

问题

使用该内核和 initrd,系统无法启动。

我的尝试

我已经整理了一个共享的 initrd,其中包含发行版的设置以及我自己的设置,它继续启动到 dropbear。然后,我在 SSH shell 中尝试运行发行版的初始化脚本。然而,这会失败,因为它依赖于作为 PID 1 运行。

然后,我尝试让 PID 1 接受任意命令:我让它从管道运行脚本,并从远程 shell 写入该管道,打算手动检查该命令是否具有所需的效果。然而,这不起作用:init-shell (PID 1) 在第一个命令后看到 EOF,并立即退出。你好,内核恐慌。

我还尝试通过传递 systemd--system选项来测试如果我让它不关心它是否作为 PID 1 运行,然后从我的 shell 运行发行版的 init 脚本,会发生什么。在这种形式下,我无法重现该问题:它只是有效。

我的问题:现在怎么办?

此时,我正在回顾管道方法以寻找另一种方法,这种方法实际上可以运行多个命令。最好还能让我看到命令的输出。

基本上:我想知道如何远程查看从 PID 1 运行的引导程序的输出,该程序无法在 SSH 会话中运行,而无需实际连接监视器或串行电缆。

采用完全不同方法的答案也是受欢迎的,但请记住我正在处理的系统限制。我不仅没有显示器或串行电缆,甚至没有 VGA 或串行端口。我有一个 USB 端口,如果需要的话,我可以将键盘插入其中,但我当然看不到我输入的任何内容。

答案1

实现此目的的总体思路是用一个脚本替换 init,该脚本在后台生成基于 initrd 的引导脚本,继续挂载系统根目录,并执行 [ -x /root/sbini/init ] && exec chroot /root / sbin/初始化。 (在下面放置一些代码来处理它不存在的情况。)

答案2

启动 SSH 会话后,其他会话也可以通过写入/dev/pts/<N>.所以为了看看发生了什么,因为我已经能够控制 PID 1 最终将运行的内容,我只需要把它写在那里。使用exec 0<>/dev/pts/0 1<>/dev/pts/0 2<>/dev/pts/0PID 1 并确保没有其他东西在那里读/写,我可以看到发生了什么。当它最终失败时,发行版的初始化脚本会提示询问要做什么,甚至正确响应我输入的R重新启动。

我遇到的实际问题似乎是由未加载所需的内核模块引起的。虽然我能够手动让一切工作,这显然意味着块、RAID 和文件系统模块可用并正在加载,但发行版的 initscript 依赖于 udev,而且事实证明这需要一些额外的模块,特别是unix(我'我从来没有选择自己不构建到内核中)。

相关内容