第21章 其他文件系统
附录 D. OpenPGP 密钥
10.5. 高级主题
Linux 兼容层是一项正在进行的工作。有关更多信息请参阅 FreeBSD Wiki - Linuxulator
所有与 Linux 相关的 sysctl(8) 旋钮列表都可以在 linux(4) 中找到。
一些应用程序要求挂载特定的文件系统。这一般由 /etc/rc.d/linux 文件决定,但可以通过在 /etc/rc.conf 中添加这一行来禁用:
1
linux_mounts_enable="NO"
Copied!
rc 脚本挂载的文件系统不适用于 chrootsjail 中的 Linux 进程;如果需要,可以在 /etc/fstab 中配置它们:
1
devfs /compat/linux/dev devfs rw,late 0 0
2
tmpfs /compat/linux/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0
3
fdescfs /compat/linux/dev/fd fdescfs rw,late,linrdlnk 0 0
4
linprocfs /compat/linux/proc linprocfs rw,late 0 0
5
linsysfs /compat/linux/sys linsysfs rw,late 0 0
Copied!
由于 Linux 二进制兼容层已经获得了对运行 32 位和 64 位 Linux 二进制程序的支持(在 64 位 x86 主机上),因此不再可能将仿真功能静态地链接到自定义内核中。

10.5.1.手动安装其他库

提示:
对于用 debootstrap(8) 创建的基本系统子目录,请参考上面的说明。
如果某个 Linux 应用程序在配置了 Linux 二进制程序兼容性后,仍警告缺少依赖库,请确定 Linux 二进制程序需要哪些依赖库,并手动安装它们。
在一个使用相同 CPU 架构的 Linux 系统中,ldd 可以用来确定应用程序需要哪些依赖库。例如,要检查 linuxdoom 需要哪些依赖库,可以从安装了 Doom 的 Linux 系统上运行这个命令:
1
% ldd linuxdoom
2
libXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0
3
libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0
4
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29
Copied!
然后,将 Linux 系统输出的最后一栏中的所有文件复制到 FreeBSD 系统的 /compat/linux 中。复制完后,建立符号链接 (Symbolic link) 至输出结果第一栏的名称。此示例将在 FreeBSD 系统上生成以下文件:
1
/compat/linux/usr/X11/lib/libXt.so.3.1.0
2
/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0
3
/compat/linux/usr/X11/lib/libX11.so.3.1.0
4
/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0
5
/compat/linux/lib/libc.so.4.6.29
6
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
Copied!
如果一个 Linux 依赖库已经存在,并符合 ldd 输出结果第一栏的主要修订版号,则不需要复制该行最后一栏文件,因为现有的库应该可以工作。不过,如果依赖库是一个较新的版本,建议复制它。旧的可以删除,只要符号链接指向新的就可以了。若有较新的版本建议仍要复制依赖库,只要符号链接指向新版的库,便可移除旧版。
例如,这些库已经存在于 FreeBSD 系统中:
1
/compat/linux/lib/libc.so.4.6.27
2
/compat/linux/lib/libc.so.4 -> libc.so.4.6.27
Copied!
ldd 输出显示二进制程序需要较新的版本:
1
libc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29
Copied!
虽然现有的库只迭代了一两个小版本,程序仍然可以使用稍旧的版本。但是,安全起见建议用新版本替换现有的 libc.so
1
/compat/linux/lib/libc.so.4.6.29
2
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
Copied!
一般来说,只有在 FreeBSD 上安装 Linux 程序的前几次,才需要寻找 Linux 二进制程序所依赖的依赖库。一段时间后,系统中就会有足够的 Linux 依赖库,不需要额外的工作能够运行新安装的 Linux 二进制程序。

10.5.2.标记 Linux ELF 二进制文件

FreeBSD 内核使用几种方法来确定要执行的二进制文件是否是 Linux 的:它检查 ELF 文件头中的标记,寻找已知的 ELF 解释器路径,并检查 ELF 注释;最后,默认情况下,没有标记的 ELF 可执行文件被认定为是 Linux 的。如果这些方法都失败,尝试执行二进制文件可能会产生错误信息:
1
% ./my-linux-elf-二进制程序
2
ELF binary type not known
3
Abort
Copied!
为了帮助 FreeBSD 内核区分是 FreeBSD ELF 二进制程序 还是 Linux 二进制程序,可以使用 brandelf(1)
1
% brandelf -t Linux my-linux-elf--binary
Copied!

10.5.3.安装基于 Linux RPM 的应用程序

要安装基于 Linux RPM 的应用程序,首先安装 archivers/rpm4 套件或 Port 。安装后,root 可以使用此命令安装 .rpm
1
# cd /compat/linux
2
# rpm2cpio < /path/to/linux.archive.rpm | cpio -id
Copied!
如有必要,brandelf 已安装的 ELF 二进制程序。注意,这将无法干净地卸载他。

10.5.4.配置域名解析

如果 DNS 解析故障或出现这个错误:
1
resolv+: "bind" is an invalid keyword resolv+:
2
"hosts" is an invalid keyword
Copied!
请配置 /compat/linux/etc/host.conf 文件,如下:
1
order hosts, bind
2
multi on
Copied!
上面的配置指定了先搜寻 /etc/hosts ,其次搜索 DNS 。当 /compat/linux/etc/host.conf 不存在时,Linux 应用程序会使用 /etc/host.conf 并会警告与 FreeBSD 不相容的语法。如果没有使用 /etc/resolv.conf 配置域名服务器,则可删除 bind

10.5.5.其他

这一节描述了 Linux 二进制兼容性的工作原理,它基于 Terry Lambert 写给 FreeBSD 聊天邮件列表 的一封邮件 [email protected] (邮件 ID: [email protected])。
FreeBSD 有一个叫做“执行类加载器”的抽象概念。这是一个楔入 execve(2) 系统调用的工具。
以前,UNIX® 加载器检查幻数(通常是文件的前 4 或 8 个字节),看它是否是系统已知的二进制文件,如果是,则调用二进制加载器。
如果它是系统未知的二进制类型,execve(2) 调用就会返回失败,并且 shell 尝试将其作为 shell 命令开始执行。该假设是“无论当前的 shell 是什么”的默认设置。
后来,对 sh(1) 进行了修改,检查前两个字符,如果它们是 :,则改为调用 csh(1) shell。
FreeBSD 有一个加载器列表,而不是单个加载器,并带有 #! 用于运行 shell 解释器或 shell 脚本的加载程序。
对于 Linux ABI 支持,FreeBSD 将幻数视为 ELF 二进制文件。ELF 加载程序会寻找一个专门的品牌,它是 ELF 映像中的一个注释部分,并且在 SVR4/Solaris™ ELF 二进制文件中不存在。
要使 Linux 二进制文件正常运行,必须使用 brandelf(1) 将它们标记为 Linux 类型:
1
# brandelf -t Linux file
Copied!
当 ELF 加载器看到 Linux 品牌时,加载器会替换 proc 结构中的一个指针。所有系统调用都通过这个指针进行索引。此外,该进程被标记为 signal trampoline 的陷阱向量进行特殊处理,以及由 Linux 内核模块处理的其他几个(次要)修复。
Linux 系统调用向量包含一个 sysent[] 条目列表,其地址位于内核模块中。
当一个系统调用被 Linux 二进制文件调用时,陷阱代码会解除对 proc 结构中系统调用函数指针的引用,并获得 Linux 而不是 FreeBSD 的系统调用入口点。
Linux模式下动态 reroots 查询。这实际上等同于文件系统挂载的 union 。首先,尝试在 /compat/linux/original-path 中查找文件。如果失败,则在 /original-path 中进行查找。这确保了需要其他二进制文件的二进制文件能够运行。例如,Linux 工具链都可以在 Linux ABI 支持下运行。这也意味着,如果没有相应的 Linux 二进制文件存在,Linux 二进制文件可以加载和执行 FreeBSD 二进制文件,并且可以在 /compat/linux 目录树下放置 uname(1) 命令,以确保 Linux 二进制文件无法知道它们不是在 Linux 上运行。
实际上,在 FreeBSD 的内核中就有一个 Linux 内核。实现内核所提供的所有服务的各种底层函数与 FreeBSD 系统调用表项和 Linux 系统调用表项都是相同的:件系统操作,虚拟内存操作,信号传递,以及 System V IPC
唯一的区别是 FreeBSD 二进制文件得到 FreeBSD 的 glue 函数,而 Linux 二进制文件得到 Linux 的 glue 函数。FreeBSD 的 glue 函数是静态链接到内核的,而 Linux 的 glue 函数可以是静态链接的,也可以通过内核模块访问。
从技术上讲,这并不是真正的仿真,而是 ABI 的实现。它有时被称为“Linux 仿真”,因为这个实现是在没有其他词来描述所发生的事情的时候完成的。说 FreeBSD 运行 Linux 二进制文件是不正确的,因为这些代码没有被编译进去。