合并 Gentoo 上的 /usr 目录
2022年12月15日更新:
本教程已过时。 为响应 systemd 在 2023 年停止支持 /usr 未合并的系统的计划,Gentoo 已开始官方支持 /usr 合并。
因此,现在在 Gentoo 上合并 /usr 的话就无需再参考此教程了。 根据情形的不同,目前推荐的合并 /usr 的操作也不同:
-
如果要安装一个新的 Gentoo 系统,那么在选择 stage 压缩包时,选一个文件名中包含
mergedusr字样的压缩包,然后按正常步骤安装系统即可。 -
如果已经有了一个
/usr分区尚未合并的 Gentoo 系统,那么可以直接使用 Gentoo 官方提供的sys-apps/merge-usr工具来完成合并。欲了解具体步骤,请参考相应的新闻条目和 Gentoo Wiki 页面(均为英文页面)。 -
如果之前已经根据此教程完成了
/usr合并,那么尽管理论上无须任何额外操作即可保持系统正常运行,但还是推荐执行下列操作:-
将系统配置文件(profile)切换至一个
merged-usr配置文件。首先,可以用下列命令找出可供选择的配置文件:$ eselect profile list | grep merged-usr然后,使用
eselect profile set选择合适的配置文件。 -
删除
/etc/portage/profile/use.mask文件中的split-usrUSE 标志。只要已经切换到了任意一个merged-usr配置文件,就可以从该文件中删除该 USE 标志了。 -
如果之前执行过任何附加步骤小节中列出的步骤,那么将相应的步骤复原(删除当时创建的新文件、撤销当时作出的配置改动)。
-
如果当时合并
/usr时采用的是第一种方式,那么仍然推荐运行一下sys-apps/merge-usr。Gentoo 官方选用的是第二种方式,故如果在使用第一种方式合并后遇到任何问题,可能会不受官方支持。merge-usr可以将已通过第一种方式被合并的系统转为第二种方式:$ ls -dl /sbin /usr/sbin lrwxrwxrwx 1 root root 8 Dec 13 2020 /sbin -> usr/sbin drwxr-xr-x 1 root root 6680 Nov 29 09:03 /usr/sbin $ merge-usr --dryrun WARNING: Already a symlink: '/bin' WARNING: Already a symlink: '/sbin' INFO: Migrating files from '/usr/sbin' to '/usr/bin' INFO: No problems found for '/usr/sbin' WARNING: Already a symlink: '/lib' WARNING: Already a symlink: '/lib64'相比于在
/usr尚未合并的系统上运行merge-usr,这种情况会导致一处不同:/sbin不会被改为指向usr/bin。不过这对系统正常运行应该没有任何影响,毕竟链接串起来后就成了/sbin -> /usr/sbin -> /usr/bin。如果介意的话,可以手动将/sbin改为指向usr/bin:# rm /sbin && ln -s usr/bin /sbin
-
此教程会被保留,以作历史纪录。
/usr 合并是指在诸如 GNU/Linux 等的遵循文件系统层次结构标准(FHS)的系统上,将 /bin、/lib、/lib64 和 /sbin 中的内容分别迁移至 /usr/bin、/usr/lib、/usr/lib64 和 /usr/sbin 中,然后把 /bin、/lib、/lib64 和 /sbin 改成指向 /usr 中同名目录的符号链接(symbolic link)。如果想了解有关 /usr 合并的更多信息,可以参阅 freedesktop.org 和 Fedora Wiki 中的相关页面(皆为英文页面)。
现在绝大多数主流 GNU/Linux 发行版中的 /usr 合并大趋势应该是由 Fedora 在 2012 年牵头开始的;之后,包括 Debian Ubuntu 和 Arch Linux 在内的许多常见的发行版也都相应地完成了 /usr 合并。说起来这和 systemd 在 GNU/Linux 社区中的侵蚀也有点类似,都是由 Red Hat 想按照自己的方式定型当代 GNU/Linux 发行版的野心和 Lennart Poettering 大肆为其背书开始、在 Fedora 上首秀,然后逐渐被其它发行版采纳。
2022年4月7日更新:读了前两天 LWN.net 上的一篇文章,了解到关于 Debian 目前合并 /usr 时出现的进退两难的窘境后,我发现我直接被打脸,一开始写这篇文章的时候不知怎么,竟然以为 Debian 已经完成 /usr 合并了。为了不掩盖我当时憨憨了的事实,特划掉 Debian,改为 Ubuntu。Ubuntu 作为一个 Debian 衍生发行版,居然比 Debian 先完成了 /usr 合并,也是有点意思。
而 Gentoo 却不是潮流的追随者,不仅是为数不多的默认不使用 systemd 的发行版,更没有跟随合并 。虽说如此,Gentoo /usr 的大势。目前,按照默认方式安装 Gentoo 后,/bin、/lib、/lib64 和 /sbin 仍然是独立的目录,而不是像其它发行版改成了符号链接应该还是有实现 /usr 合并的计划的,因为他们在 Portage 中定义了一个 split-usr USE 标志。现在这个 USE 标志是强制启用的,因为目前 Gentoo 官方可以完全支持 /bin、/lib、/lib64 和 /sbin 这些目录还未合并,也就是分离(split)的状态;如果日后有一天/usr 合并了,那届时就可以让 split-usr 变成一个可选的 USE 标志。
这篇文章将向您展示的是,在目前 Gentoo 官方尚未支持的情况下,如何合并 我的旨意并不是说 /usr。/usr 合并有很多好处,/usr 合并的优点也不在本文的讨论范围之内。这篇文章唯一的目的是给那些知道自己想要合并 /usr、却不知道该怎么弄的用户提供一个教程。
不同的 /usr 合并方式
在开始前,有必要介绍一下目前 GNU/Linux 发行版中常见的两种不同的合并 /usr 的方式:
-
将
/bin并入/usr/bin、/lib并入/usr/lib、/lib64并入/usr/lib64、/sbin并入/usr/sbin。这是 Fedora 和DebianUbuntu 采用的方式。$ ls -dl /bin /lib /lib64 /sbin /usr/sbin lrwxrwxrwx 1 root root 7 Dec 13 14:11 /bin -> usr/bin lrwxrwxrwx 1 root root 7 Dec 13 14:11 /lib -> usr/lib lrwxrwxrwx 1 root root 9 Dec 13 14:11 /lib64 -> usr/lib64 lrwxrwxrwx 1 root root 8 Dec 13 14:11 /sbin -> usr/sbin drwxr-xr-x 1 root root 7006 Dec 26 09:50 /usr/sbin -
在上述合并的基础上,再将
/usr/sbin并入/usr/bin。Arch Linux 目前采用这种方式;从已经支持split-usrUSE 标志的 Gentoo 软件包sys-apps/baselayout的ebuild来看,Gentoo应该也是准备采取这种方式。$ ls -dl /bin /lib /lib64 /sbin /usr/sbin lrwxrwxrwx 1 root root 7 Dec 13 14:11 /bin -> usr/bin lrwxrwxrwx 1 root root 7 Dec 13 14:11 /lib -> usr/lib lrwxrwxrwx 1 root root 9 Dec 13 14:11 /lib64 -> usr/lib64 lrwxrwxrwx 1 root root 7 Dec 13 14:11 /sbin -> usr/bin lrwxrwxrwx 1 root root 3 Dec 13 14:11 /usr/sbin -> bin
上面的命令输出只是用于演示两种不同的合并 /usr 方式下的 /usr/sbin 的区别,可能会与您实际遇到的目录布局有所偏差。
本文将主要使用第一种方式,因为我用过 Fedora 和 Debian Ubuntu,对这种方式产生的文件系统布局更熟悉,而 Arch Linux 我还没用过。不过,即使您准备采取第二种方式,也可以参阅本教程。第二种是 Gentoo 合并 /usr 所计划采用的方式,因此使用该方式会稍微简单些,反倒是第一种方式略微复杂。如果这篇教程介绍的是完成一种更复杂的方式的步骤,那借助它来做一件更简单的事应该不在话下。虽说如此,您仍然需要能触类旁通,适当修改此教程中提到的命令,以满足您自己的情况和需求。
前提条件
-
/usr合并既可以在新系统安装时完成,也可以在一个已经安装好的系统上进行。这两种情况下的操作步骤有所不同,本文将会在两个不同的小节中分别讨论。 -
在开始之前,您需要准备一个启动盘(例如用 Gentoo 安装光盘 ISO 映像制作的 USB 启动盘)。如果您是在安装新的 Gentoo 系统,那您肯定已经有了一个 Gentoo 安装盘;但是如果您准备在一个已经装好的系统上合并
/usr的话,就需要找一个启动盘或者做一个了,因为有些步骤需要在您的系统不在运行时进行,此时就需要有另一个允许您对您的 Gentoo 系统进行任意操作的环境。
在系统安装时合并
以下步骤假设您是遵循 Gentoo 手册的步骤安装的系统。
-
完成“安装 stage3”中的 stage 压缩包的解压后,进入解压出的
usr目录,然后从 stage 压缩包中重新解压./bin、./lib、./lib64和./sbin。livecd /mnt/gentoo # cd usr livecd /mnt/gentoo/usr # tar xpvf ../stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner ./{bin,lib,lib64,sbin} -
回到上层目录,然后将
bin、lib、lib64和sbin替换为指向usr下同名目录的符号链接。livecd /mnt/gentoo/usr # cd .. livecd /mnt/gentoo # rm -rf bin lib lib64 sbin livecd /mnt/gentoo # ln -s usr/bin bin livecd /mnt/gentoo # ln -s usr/lib lib livecd /mnt/gentoo # ln -s usr/lib64 lib64 livecd /mnt/gentoo # ln -s usr/sbin sbin如果您准备采用第二种
/usr合并方式,您应该在此基础上,将usr/sbin中的所有内容移到usr/bin中,然后把usr/sbin替换成指向usr/bin的符号链接:livecd /mnt/gentoo # cd usr livecd /mnt/gentoo/usr # mv sbin/* bin livecd /mnt/gentoo/usr # rmdir sbin livecd /mnt/gentoo/usr # ln -s bin sbin如下所示,这样操作的结果是
bin、lib、lib64和sbin变为符号链接:livecd /mnt/gentoo # ls -l total 16 lrwxrwxrwx 1 root root 7 Dec 28 04:07 bin -> usr/bin drwxr-xr-x 1 root root 10 Dec 23 05:20 boot drwxr-xr-x 1 root root 1686 Dec 23 05:25 dev drwxr-xr-x 1 root root 1546 Dec 23 06:32 etc drwxr-xr-x 1 root root 10 Dec 23 05:20 home lrwxrwxrwx 1 root root 7 Dec 28 04:07 lib -> usr/lib lrwxrwxrwx 1 root root 9 Dec 28 04:07 lib64 -> usr/lib64 drwxr-xr-x 1 root root 10 Dec 23 05:20 media drwxr-xr-x 1 root root 10 Dec 23 05:20 mnt drwxr-xr-x 1 root root 10 Dec 23 05:20 opt drwxr-xr-x 1 root root 0 Dec 23 03:28 proc drwx------ 1 root root 10 Dec 23 05:20 root drwxr-xr-x 1 root root 10 Dec 23 05:20 run lrwxrwxrwx 1 root root 8 Dec 28 04:08 sbin -> usr/sbin drwxr-xr-x 1 root root 10 Dec 23 05:20 sys drwxrwxrwt 1 root root 10 Dec 23 06:32 tmp drwxr-xr-x 1 root root 128 Dec 23 05:29 usr drwxr-xr-x 1 root root 66 Dec 23 05:20 var -
继续按照 Gentoo 手册中的指示操作,直到您
chroot进了/mnt/gentoo。 -
使用
find -L /usr -type l命令找出/usr下所有损坏的符号链接。(chroot) livecd / # find -L /usr -type l /usr/sbin/resolvconf /usr/bin/awk上面的例子中,
/usr/sbin/resolvconf和/usr/bin/awk是损坏的符号链接,也就是说它们所指向的路径不存在。如果其它程序和脚本需要使用这些符号链接指向的文件时,就会出现错误。例如,许多软件包的构建都需要用到awk命令,而/usr/bin/awk符号链接断了,就会导致awk命令不可用,您在安装需要awk的软件包时就会遇到问题。(chroot) livecd / # /usr/bin/awk bash: /usr/bin/awk: No such file or directory若要修复一个损坏的符号链接,首先切换到该链接所在的目录,然后用
ls -l查看它所指向的路径。(chroot) livecd / # cd /usr/bin/ (chroot) livecd /usr/bin # ls -l awk lrwxrwxrwx 1 root root 15 Dec 23 05:26 awk -> ../usr/bin/gawk因为
awk符号链接本来应该是在/bin下的,它就会被解析到/bin/../usr/bin/gawk,也就是/usr/bin/gawk,是一个合法路径。但是现在挪到/usr后,它被解析到/usr/bin/../usr/bin/gawk,也就是/usr/usr/bin/gawk,就是个不存在的路径,导致链接断开。修复起来也不难,将原来的链接删除,然后重新连到正确的目标即可:(chroot) livecd /usr/bin # rm awk (chroot) livecd /usr/bin # ln -s gawk awk对于
/usr/sbin/resolvconf来说,也是同样的操作:(chroot) livecd / # cd /usr/sbin/ (chroot) livecd /usr/sbin # ls -l resolvconf lrwxrwxrwx 1 root root 21 Dec 23 06:28 resolvconf -> ../usr/bin/resolvectl (chroot) livecd /usr/sbin # rm resolvconf (chroot) livecd /usr/sbin # ln -s ../bin/resolvectl resolvconf如果您现在再运行
find -L /usr -type l的话,该命令应该不再输出任何内容,意味着所有损坏的符号链接都已被成功修复。实际上,
find -L -type l可以用来在各种情景下搜索损坏的符号链接。find虽说是个很基础的命令,但是非常强大,在各路 GNU/Linux 发行版上基本也都是预装。因此,完全没有必要安装任何诸如symlinks的其它软件包来寻找损坏的符号链接。find(1)手册页面对此的描述如下:-type c File is of type c: l symbolic link; this is never true if the -L option or the -follow option is in effect, unless the symbolic link is broken. If you want to search for symbolic links when -L is in effect, use -xtype. -
屏蔽
split-usrUSE 标志,让支持区分/usr合并后的系统的软件包在构建时可以为合并后的文件系统进行构建。由于split-usr是强制启用的 USE 标志,仅仅声明-split-usr是不够的;您需要在/etc/portage/profile/use.mask中屏蔽 `split-usr。# /etc/portage/profile/use.mask # 屏蔽分离式 /usr 布局的 USE 标志 split-usr如果想了解更多的话,请参阅相关的 Gentoo Wiki 条目。
-
按照 Gentoo 手册中的步骤,完成剩余的安装步骤。请记得更新
@world集合以应用split-usrUSE 标志的改动。当您运行安装在
/sbin或/usr/sbin中的命令时,您可能会遇到“command not found”的错误提示。例如,如果您准备安装 GRUB,那么在运行/usr/sbin/grub-install的时候就会碰到该错误。您可以用whereis确认您要运行的命令确实在/usr/sbin下。(chroot) livecd ~ # grub-install --target=x86_64-efi --efi-directory=/boot bash: grub-install: command not found (chroot) livecd ~ # whereis grub-install grub-install: /usr/sbin/grub-install /usr/share/man/man8/grub-install.8.bz2导致这个问题的原因是
/usr/sbin从PATH环境变量中消失了:(chroot) livecd ~ # printenv PATH /usr/local/bin:/usr/bin:/opt/bin为了能完成系统安装,最简便、最快速的解决方法是使用
export PATH="/usr/sbin:$PATH",暂时将/usr/sbin加到PATH中。但是,每次打开一个新的 shell 的时候都需要运行一次这个命令。要永久解决这个问题的话,请参阅下面的“将/usr/sbin永久添加到PATH中”小节。(chroot) livecd ~ # export PATH="/usr/sbin:$PATH" (chroot) livecd ~ # printenv PATH /usr/sbin:/usr/local/bin:/usr/bin:/opt/bin (chroot) livecd ~ # grub-install --target=x86_64-efi --efi-directory=/boot Installing for x86_64-efi platform. Installation finished. No error reported.
在已安装好的系统上合并
-
从您准备的启动盘启动您的电脑,然后挂载您系统的 root 分区。以下步骤假设您将 root 分区挂载到了
/mnt/gentoo下。切换到您分区被挂载的位置。livecd ~ # cd /mnt/gentoo -
使用
\cp命令和-r、--preserve=all和--remove-destination选项,将bin、lib、lib64和sbin中的内容分别复制到usr/bin、usr/lib、usr/lib64和usr/sbin中。livecd /mnt/gentoo # \cp -rv --preserve=all --remove-destination bin/* usr/bin livecd /mnt/gentoo # \cp -rv --preserve=all --remove-destination lib/* usr/lib livecd /mnt/gentoo # \cp -rv --preserve=all --remove-destination lib64/* usr/lib64 livecd /mnt/gentoo # \cp -rv --preserve=all --remove-destination sbin/* usr/sbincp的-v选项允许您查看复制进度。如果不需要,可以省略该选项。在
cp前面加一个反斜杠\可以忽略为cp设置的别名。如果您使用的是 Gentoo 安装光盘映像,那么cp默认的别称是cp -i;这个-i选项会导致cp在每次覆写文件前都要求您手动确认。livecd ~ # alias cp alias cp='cp -i'如果使用
\cp而非cp,就可以忽略该别名。您也可以用unalias cp移除该别名,然后不加\、正常调用cp;也可以利用yes程序,使用yes | cp ...向cp的标准输入传递一大堆y,自动确认每个要覆写的文件。livecd /mnt/gentoo # unalias cp livecd /mnt/gentoo # cp -rv --preserve=all --remove-destination bin/* usr/bin livecd /mnt/gentoo # cp -rv --preserve=all --remove-destination lib/* usr/lib livecd /mnt/gentoo # cp -rv --preserve=all --remove-destination lib64/* usr/lib64 livecd /mnt/gentoo # cp -rv --preserve=all --remove-destination sbin/* usr/sbinlivecd /mnt/gentoo # yes | cp -rv --preserve=all --remove-destination bin/* usr/bin livecd /mnt/gentoo # yes | cp -rv --preserve=all --remove-destination lib/* usr/lib livecd /mnt/gentoo # yes | cp -rv --preserve=all --remove-destination lib64/* usr/lib64 livecd /mnt/gentoo # yes | cp -rv --preserve=all --remove-destination sbin/* usr/sbin -
将
bin、lib、lib64和sbin替换为指向usr下同名目录的符号链接。livecd /mnt/gentoo # rm -rf bin lib lib64 sbin livecd /mnt/gentoo # ln -s usr/bin bin livecd /mnt/gentoo # ln -s usr/lib lib livecd /mnt/gentoo # ln -s usr/lib64 lib64 livecd /mnt/gentoo # ln -s usr/sbin sbin如果您准备采用第二种
/usr合并方式,您应该在此基础上,将usr/sbin中的所有内容移到usr/bin中,然后把usr/sbin替换成指向usr/bin的符号链接。点击此处查看相关的命令。 -
重启电脑,进入到您的系统中(不是启动盘)。只要您把
/bin、/lib、/lib64和/sbin中的文件正确地复制到了/usr中、并正确地建立了符号链接,您的系统就应该能正常启动。 -
修复
/usr下损坏的符号链接,具体的步骤和在安装时合并/usr步骤中的第 4 步相同。不过,有一些符号链接是可以不用手动修复的:-
如果您同时使用 systemd 和 dracut,您可能会遇到一些名称类似
dracut-*.service的链接。此种链接不需要手动修复,只需在屏蔽split-usrUSE 标志并重新编译 systemd 之后重新安装sys-kernel/dracut即可。 -
/usr/lib/modules/*.*.*/build和/usr/lib/modules/*.*.*/source也可以不修复。
而其余的符号链接,如
/usr/bin/awk和/usr/sbin/resolvconf,就需要手动干预修复了。 -
-
屏蔽
split-usrUSE 标志,具体的步骤和在安装时合并/usr步骤中的第 5 步相同。 -
更新 Portage 的
@world集合,重新构建原本启用了split-usrUSE 标志的软件包,以应用新的 USE 标志变动。# emerge --ask --update --deep --newuse @world如果您同时使用 systemd 和 dracut,您现在就可以运行下面的命令重新安装 dracut,从而修复损坏的
dracut-*.service符号链接了。如果您不使用 dracut,请勿运行下面的命令,因为它会安装 dracut。# emerge --ask --oneshot sys-kernel/dracut
附加步骤
完成上述步骤后,您的系统的 /usr 目录就成功合并了,并且运行起来基本上应该和没合并前一样。虽说如此,但现在系统仍然有一些对正常运行没有大影响的小瑕疵,可以通过执行下面的附加步骤来解决。
将 /usr/sbin 永久添加到 PATH 中
如果您使用的是第二种 /usr 合并方式的话,那么无需执行此步骤。
之前推测 Gentoo 会如何完成 /usr 合并的时候简单提及过,/usr/sbin 会被合并到 /usr/bin 中。如果仔细看 sys-apps/baselayout 的 ebuild 的话,您也许会发现,如果 split-usr USE 标志被禁用的话,/usr/sbin 会被从 PATH 环境变量中移除,毕竟所有本该在 /usr/sbin 里的命令都被挪到 /usr/bin 里了,而 /usr/bin 是在 PATH 里面的。
但是,如果您使用的是第一种 /usr 合并方式,那么这样就会出现问题了。这种方式中,/usr/sbin 里的命令仍在原处,但在禁用了 split-usr USE 标志后 PATH 里就没有了 /usr/sbin,导致任何 /usr/sbin 中的命令都无法被直接调用,除非您在命令前面加上 /usr/sbin/。
我推荐的解决方式是在在 /etc/env.d 中创建一个文件,把 /usr/sbin 加回 PATH,就可以在系统全局层面解决这个问题。选择一个文件名(例如 50baselayout-sbin),然后在文件中写入如下的 PATH 和 ROOTPATH 定义:
# /etc/env.d/50baselayout-sbin
PATH="/usr/local/sbin:/usr/sbin"
ROOTPATH="/usr/local/sbin:/usr/sbin"这里我不仅把 /usr/sbin 加了回来,还添上了 /usr/local/sbin,因为这个路径在 sys-apps/baselayout 的 split-usr USE 标志被禁用时也会被从 PATH 中移除。
随后,重新加载环境设置以应用更改:
# /usr/sbin/env-update
$ source /etc/profile
如需关于使用 /etc/env.d 目录的更多信息,您可以参阅 Gentoo 手册中的相关部分。
移除 emerge 关于符号链接的提示信息
您在使用 emerge 更新或卸载软件时可能会遇到如下的提示信息:
* One or more symlinks to directories have been preserved in order to
* ensure that files installed via these symlinks remain accessible. This
* indicates that the mentioned symlink(s) may be obsolete remnants of an
* old install, and it may be appropriate to replace a given symlink with
* the directory that it points to.
*
* /bin
* /lib64
* /sbin
*这是正常现象,毕竟 /bin、/lib、/lib64 和 /sbin 在 /usr 被合并后的确不再是目录,而是符号链接了。
如果您想移除这些提示的话,可以在 /etc/portage/make.conf 中添加如下一行:
UNINSTALL_IGNORE="/bin /lib /lib64 /sbin"