将 glibc 从 initrd 复制到我的根文件系统

将 glibc 从 initrd 复制到我的根文件系统

我正在尝试使用 FAQ 中引用的指南将 glibc 2.20(最近构建)安装到 Debian这一页(常见问题解答中的问题是如何安装我刚刚构建的所有 GNU C 库项目库?):

安装这些库的唯一正确方法是执行 make install INSTALLDIR=/tmp/glibc,将库安装到 /tmp/glibc,然后将该目录复制到初始根磁盘,启动初始根磁盘,并将结果复制到根文件系统,然后在启动的最后一步转到根文件系统。这就是仅有的今天安装 glibc 的安全方法。

我已设法将这个新的 glibc 目录(包含的产品make install)复制到 initrd 的解压缩副本(默认加载的副本)中,将其压缩回来,并在通过编辑命令行在 GRUB 中指定这个新的 initrd 后成功启动。

有人能告诉我如何以及在何处将这个 glibc 复制到我的根文件系统(使其成为系统中的主要 C 库而不是当前(默认)库)吗?

答案1

你的问题 (”我应该如何以及在何处将此 glibc 复制到我的根文件系统“) 给出了几种答案,其中常见问题解答中提到的答案具有最低要求(尽管在我看来,它并不是最简单的)。

他们建议,一旦你启动了内核,就可以挂载新的 initrd(因此,会以类似“(initramfs)' 是将您的真实系统挂载到文件系统下方的某个位置。假设您的真实根文件系统位于 /dev/sda1,如下所示:

   (initramfs) mkdir /new_root
   (initramfs) mount /dev/sda1 /new_root

此后,您将拥有:

  • /lib=> 包含新的您自己编译并打包在用于引导和 root 挂载的 INITRD 中的库;
  • /新根/lib=> 包含老的在您的(未运行的)实际系统内,这些库仍然存在于您的硬盘上;

(顺便说一句:你也可以有一个lib64除了上述结构之外/lib,具体取决于您的架构。在应用我写的内容之前,请先应用一些常识和健全性检查)

在此阶段,您已经拥有将内容从 /lib 复制到 /new_root/lib 所需的一切,然后只需 umount /new_root 并重新启动即可。

那么为什么他们要建议使用pivot_root之类的“魔法”呢?

恕我直言,他们在常见问题解答中假设的是,您希望将重启次数限制为最低限度。一次重启是不可避免的(从 INITRD 启动)。然后,您可以挂载根分区,复制库并...告诉系统继续正常启动,指向您刚从硬盘挂载的(新)根文件系统。这里的关键点是“根挂载点”(换句话说,即“/”文件夹)需要从与 INITRD 映像相关的挂载点替换为与您的真实系统相关的挂载点(挂载到 INITRD 文件系统下的 /new_root 的 /dev/sda1 分区)。

有几种工具能够“更改根”,其中常见问题解答中引用了pivot_root。这里您可以找到有关使用pivot_root在两个Linux安装之间切换的讨论。 它非常适合您的情况,因为这两个系统是INITRD初始系统和磁盘上的真实系统。

这里您可以找到一些将pivot_root与switch_root进行比较的信息(和链接)。

在发布这个答案之前,我已经进行了一些pivot_root测试:不幸的是,我一直无法到pivot_root,以各种错误结束(顺便说一句:似乎我不孤独这里)。

由于上述问题,我得出结论:“第二次重启”不是问题,并且使整个过程变得简单。

至于其他方法,也可以(...甚至更简单)使用 Live-CD 启动 Linux 系统(例如系统救援光盘) 和:

  • 从 INITRD 中手动提取(新)库;
  • 用上面的内容替换系统中的(旧)内容。

显然,要访问您的 INITRD 以及您的真实系统,您需要将您的分区“挂载”在 live-cd 的文件系统中的某个位置(以与上面讨论的方式相同)。

至于提取过程,我们假设您的 initrd 是 /mnt/initrd.img-3.2.0-58-generic。让我们检查它是否已压缩:

damiano@tablet:/$ file /mnt/initrd.img-3.2.0-58-generic
/mnt/initrd.img-3.2.0-58-generic: gzip compressed data, from Unix, last modified: Wed Jan  8 11:54:03 2014

我们先解压它,以便更好地检查其内容(我们将在 /tmp/libs 目录中工作):

damiano@tablet:/$ mkdir /tmp/libs
damiano@tablet:/$ cd /tmp/libs
damiano@tablet:/tmp/libs$ gzip -dc /mnt/initrd.img-3.2.0-58-generic > init_uncompressed
damiano@tablet:/tmp/libs$

现在让我们检查一下解压缩后的文件中有什么:

damiano@tablet:/tmp/libs$ file init_uncompressed 
init_uncompressed: ASCII cpio archive (SVR4 with no CRC)

好的。现在我们有了cpio 档案提取其内容非常简单:

damiano@tablet:/tmp/libs$ cpio -i < init_uncompressed
109835 blocchi

现在,我们终于提取了所有内容,包括你的库:

 damiano@tablet:/tmp/libs$ ls -l
 totale 54968
 drwxr-xr-x  2 verzulli verzulli     4096 dic 31 14:42 bin
 drwxr-xr-x  3 verzulli verzulli     4096 dic 31 14:42 conf
 drwxr-xr-x  8 verzulli verzulli     4096 dic 31 14:42 etc
 -rwxr-xr-x  1 verzulli verzulli     7230 dic 31 14:42 init
 -rw-rw-r--  1 verzulli verzulli 56235520 dic 31 14:38 init_uncompressed
 drwxr-xr-x  9 verzulli verzulli     4096 dic 31 14:42 lib
 drwxr-xr-x  2 verzulli verzulli     4096 dic 31 14:42 lib64
 drwxr-xr-x  2 verzulli verzulli     4096 dic 31 14:42 run
 drwxr-xr-x  2 verzulli verzulli     4096 dic 31 14:42 sbin
 drwxr-xr-x 10 verzulli verzulli     4096 dic 31 14:42 scripts
 drwxr-xr-x  4 verzulli verzulli     4096 dic 31 14:42 usr

此时,您可以简单地将 lib(和 lib64)文件夹从 /tmp/libs 复制到 /mnt(假设您的根分区 --/dev/sda1-- 安装在 /mnt 下),然后重新启动。


最后(非常个人化)说明:说了以上所有内容,让我补充一点……尽管常见问题解答中明确指出,依靠包管理器来更新系统库很危险我个人认为自己手动处理系统库……肯定更危险:-)

所以,如果您在无法启动的系统中运行,请不要责怪我;-)


更新 1:

至于“启动内核后,挂载新的 initrd“,您可以按照以下步骤进行:

  1. 在 grub 菜单中,选择您通常运行的条目并按“E”(编辑)。(顺便说一句:如果您没有 grub 菜单,那么这个问题和/或其他在线搜索可以提供帮助)。您将看到类似以下的屏幕:

在此处输入图片描述

请注意与内核相关的行。在这样的行上你会发现:

  • 参考内核(我的示例中为 vmlinux-3.8.0-19-generic);
  • 引用用于挂载根文件系统的设备(在我的示例中为 root=/dev/mapper/kubuntu--vg-root);
  • 其他启动参数( ro quiet splace $vt_handoff )

    1. 因为您想要 root 挂载您准备好的 initrd 文件(...包含更新的 glibc;而不是通用设备/硬盘驱动器/分区),您需要编辑上面的行,替换对“root=”参数的引用,如下所示:

在此处输入图片描述

请注意我使用了根=/initrd.img-3.8.0-19-通用尽管你应该链接到你的特定 initrd 文件

  1. 正确定义“root=”参数后,只需按 F10 即可。几秒钟后,您应该会看到 (initramfs) 提示符,如下所示:

在此处输入图片描述

现在您的“/”有一个 /lib 文件夹,其中包含您编译的库...并打包在 INITRD 中。


相关内容