合并 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-usr
USE 标志。只要已经切换到了任意一个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-usr
USE 标志的 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-usr
USE 标志,让支持区分/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-usr
USE 标志的改动。当您运行安装在
/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/sbin
cp
的-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/sbin
livecd /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-usr
USE 标志并重新编译 systemd 之后重新安装sys-kernel/dracut
即可。 -
/usr/lib/modules/*.*.*/build
和/usr/lib/modules/*.*.*/source
也可以不修复。
而其余的符号链接,如
/usr/bin/awk
和/usr/sbin/resolvconf
,就需要手动干预修复了。 -
-
屏蔽
split-usr
USE 标志,具体的步骤和在安装时合并/usr
步骤中的第 5 步相同。 -
更新 Portage 的
@world
集合,重新构建原本启用了split-usr
USE 标志的软件包,以应用新的 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"