第十二章 Linux二进制兼容性12.1. 简介12.2. 配置Linux二进制兼容性12.3. Linux用户区12.3.1. FreeBSD包中的Rocky Linux基础系统12.3.2. FreeBSD包中的CentOS基础系统12.3.3. 带有debootstrap的Debian/Ubuntu基础系统12.4. 高级主题12.4.1. 手动安装其他库12.4.2. Linux ELF二进制文件品牌化12.4.3. 安装基于Linux RPM的应用程序12.4.4. 配置主机名解析程序12.4.5. 杂项
FreeBSD提供与Linux®(通常称为Linuxulator)的可选二进制兼容性,允许用户安装和运行未经修改的Linux二进制文件。它适用于x86(32位和64位)和AArch64架构。一些Linux特定的操作系统功能尚未得到支持;这主要发生在特定于硬件或与系统管理相关的功能上,如cgroups或命名空间。
在阅读本章之前,您应该:
阅读本章后,你会知道:
默认情况下,未启用 linux(4) 二进制兼容性。
要在启动时启用Linux ABI,请执行以下命令:
xxxxxxxxxx# sysrc linux_enable="YES"启用后,可以通过执行以下命令在不重新启动的情况下启动它:
xxxxxxxxxx# service linux start这足以使静态链接的Linux二进制文件工作。
Linux服务将加载必要的内核模块,并在 /compat/Linux 下挂载Linux应用程序所需的文件系统。它们可以以与原生FreeBSD二进制文件相同的方式启动;它们的行为几乎与本机进程完全相同,可以用通常的方式进行跟踪和调试。
可以通过执行以下命令检查 /compat/linux 的当前内容:
xxxxxxxxxx# ls -l /compat/linux/total 1dr-xr-xr-x 13 root wheel 512 Apr 11 19:12 devdr-xr-xr-x 1 root wheel 0 Apr 11 21:03 procdr-xr-xr-x 1 root wheel 0 Apr 11 21:03 sysLinux软件需要的不仅仅是ABI。为了运行Linux软件,必须首先安装Linux用户区。
xxxxxxxxxx如果只想运行Ports树中已经包含的一些软件,可以通过包管理器安装,pkg(8)将自动设置所需的Linux用户区。例如,要安装Sublime Text 4及其所依赖的所有Linux库,请运行以下命令: # pkg install linux-sublime-text4要安装Rocky Linux 9用户区,请执行以下命令:
xxxxxxxxxx# pkg install linux_base-rl9emulators/linux_base-rl9 将把从Rocky linux 9派生的基础系统放置到 /compat/linux 中。
安装软件包后,可以通过运行以下命令来验证 /compat/linux 的内容,以检查Rocky Linux用户区是否已安装:
xxxxxxxxxx# ls -l /compat/linux/total 36drwxr-xr-x 2 root wheel 512 Oct 9 17:28 afslrwxr-xr-x 1 root wheel 7 May 16 2022 bin -> usr/bindrwxr-xr-x 3 root wheel 512 Oct 9 17:28 devdrwxr-xr-x 24 root wheel 1536 Oct 9 17:28 etclrwxr-xr-x 1 root wheel 7 May 16 2022 lib -> usr/liblrwxr-xr-x 1 root wheel 9 May 16 2022 lib64 -> usr/lib64drwxr-xr-x 2 root wheel 512 Oct 9 17:28 optdrwxr-xr-x 2 root wheel 512 Oct 9 17:28 proclrwxr-xr-x 1 root wheel 8 Oct 1 03:11 run -> /var/runlrwxr-xr-x 1 root wheel 8 May 16 2022 sbin -> usr/sbindrwxr-xr-x 2 root wheel 512 Oct 9 17:28 srvdrwxr-xr-x 2 root wheel 512 Oct 9 17:28 sysdrwxr-xr-x 8 root wheel 512 Oct 9 17:28 usrdrwxr-xr-x 16 root wheel 512 Oct 9 17:28 varxxxxxxxxxx随着上游项目的弃用,emulators/linux_base-c7 已被弃用。这意味着 emulators/linux_base-c7将不会收到安全更新。除非需要32位兼容性,否则建议使用Rocky Linux基础系统。要安装CentOS用户区,请执行以下命令:
xxxxxxxxxx# pkg install linux_base-c7emulators/linux_base-c7 将把CentOS 7的基础系统放入 /compat/linux 。
安装软件包后,可以通过运行以下命令来验证 /compat/linux 的内容,以检查是否已安装CentOS用户区:
xxxxxxxxxx# ls -l /compat/linux/total 30lrwxr-xr-x 1 root wheel 7 Apr 11 2018 bin -> usr/bindrwxr-xr-x 13 root wheel 512 Apr 11 21:10 devdrwxr-xr-x 25 root wheel 64 Apr 11 21:10 etclrwxr-xr-x 1 root wheel 7 Apr 11 2018 lib -> usr/liblrwxr-xr-x 1 root wheel 9 Apr 11 2018 lib64 -> usr/lib64drwxr-xr-x 2 root wheel 2 Apr 11 21:10 optdr-xr-xr-x 1 root wheel 0 Apr 11 21:25 proclrwxr-xr-x 1 root wheel 8 Feb 18 02:10 run -> /var/runlrwxr-xr-x 1 root wheel 8 Apr 11 2018 sbin -> usr/sbindrwxr-xr-x 2 root wheel 2 Apr 11 21:10 srvdr-xr-xr-x 1 root wheel 0 Apr 11 21:25 sysdrwxr-xr-x 8 root wheel 9 Apr 11 21:10 usrdrwxr-xr-x 16 root wheel 17 Apr 11 21:10 var提供Linux共享库的另一种方法是使用 sysutils/debootstrap。这具有提供完整Debian或Ubuntu发行版的优点。
要安装debootstrap,请执行以下命令:
xxxxxxxxxx# pkg install debootstrapdebootstrap(8) 需要启用 linux(4) ABI。启用后,执行以下命令在 /compat/ubuntu 中安装Ubuntu或Debian:
xxxxxxxxxx# debootstrap jammy /compat/ubuntuxxxxxxxxxx虽然技术上可以安装到/compat/linux中,但由于可能与基于CentOS的软件包冲突,因此不建议安装。相反,从发行版或版本名派生目录名,例如/compat/ubuntu。输出应类似于以下内容:
xxxxxxxxxxI: Retrieving InReleaseI: Checking Release signatureI: Valid Release signature (key id F6ECB3762474EDA9D21B7022871920D1991BC93C)I: Retrieving PackagesI: Validating PackagesI: Resolving dependencies of required packages...I: Resolving dependencies of base packages...I: Checking component main on http://archive.ubuntu.com/ubuntu...[...]I: Configuring console-setup...I: Configuring kbd...I: Configuring ubuntu-minimal...I: Configuring libc-bin...I: Configuring ca-certificates...I: Base system installed successfully.然后在 /etc/fstab 中设置挂载。
x如果应共享主目录的内容并能够运行X11应用程序,则应使用nullfs(5)将/home和/tmp挂载到linux compat区域进行环回。以下示例可以添加到/etc/fstab中:# Device Mountpoint FStype Options Dump Pass#devfs /compat/ubuntu/dev devfs rw,late 0 0tmpfs /compat/ubuntu/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0fdescfs /compat/ubuntu/dev/fd fdescfs rw,late,linrdlnk 0 0linprocfs /compat/ubuntu/proc linprocfs rw,late 0 0linsysfs /compat/ubuntu/sys linsysfs rw,late 0 0/tmp /compat/ubuntu/tmp nullfs rw,late 0 0/home /compat/ubuntu/home nullfs rw,late 0 0然后执行mount(8): # mount -al要使用 chroot(8) 访问系统,请执行以下命令:
xxxxxxxxxx# chroot /compat/ubuntu /bin/bash然后可以执行 uname(1) 来检查Linux环境:
xxxxxxxxxx# uname -s -r -mLinux 5.15.0 x86_64一旦进入chroot,系统的行为就像正常的Ubuntu安装一样。虽然systemd不起作用,但 service(8) 命令照常工作。
xxxxxxxxxx要添加默认值中缺少的包存储库,请编辑文件 /compat/ubuntu/etc/apt/sources.list。对于amd64,可以使用以下示例:deb http://archive.ubuntu.com/ubuntu jammy main universe restricted multiversedeb http://security.ubuntu.com/ubuntu/ jammy-security universe multiverse restricted maindeb http://archive.ubuntu.com/ubuntu jammy-backports universemultiverse restricted maindeb http://archive.ubuntu.com/ubuntu jammy-updates universe multiverse restricted main对于arm64,可以使用其他示例:deb http://ports.ubuntu.com/ubuntu-ports bionic main universe restricted multiverse在 linux(4) 中可以找到所有与Linux相关的 sysctl(8) 旋钮的列表。
某些应用程序需要挂载特定的文件系统。
这通常由 /etc/rc.d/linux 脚本处理,但可以在启动时执行以下命令禁用:
xxxxxxxxxxsysrc linux_mounts_enable="NO"rc脚本挂载的文件系统不适用于chroot或jail中的Linux进程;如果需要,请在 /etc/fstab 中配置它们:
xxxxxxxxxxdevfs /compat/linux/dev devfs rw,late 0 0tmpfs /compat/linux/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0fdescfs /compat/linux/dev/fd fdescfs rw,late,linrdlnk 0 0linprocfs /compat/linux/proc linprocfs rw,late 0 0linsysfs /compat/linux/sys linsysfs rw,late 0 0由于Linux二进制兼容层已经获得了运行32位和64位Linux二进制文件的支持,因此不再可能将仿真功能静态链接到自定义内核中。
xxxxxxxxxx对于使用debootstrap(8)创建的基本系统子目录,请使用上面的说明。如果Linux应用程序在配置Linux二进制兼容性后抱怨缺少共享库,请确定Linux二进制需要哪些共享库并手动安装。
在使用相同CPU架构的Linux系统中, ldd 可用于确定应用程序需要哪些共享库。
例如,要检查 linuxdoom 需要哪些共享库,请在安装了Doom的Linux系统上运行以下命令:
xxxxxxxxxx% ldd linuxdoomlibXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29然后,将Linux系统输出的最后一列中的所有文件复制到FreeBSD系统上的 /compat/linux 中。复制后,创建指向第一列中名称的符号链接。
此示例将在FreeBSD系统上生成以下文件:
xxxxxxxxxx/compat/linux/usr/X11/lib/libXt.so.3.1.0/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0/compat/linux/usr/X11/lib/libX11.so.3.1.0/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0/compat/linux/lib/libc.so.4.6.29/compat/linux/lib/libc.so.4 -> libc.so.4.6.29如果Linux共享库已经存在,并且其主要修订号与 ldd 输出的第一列匹配,则不需要将其复制到最后一列中指定的文件中,因为现有库应该可以工作。不过,如果共享库是较新版本,建议复制它。只要符号链接指向新链接,就可以删除旧链接。
例如,这些库已经存在于FreeBSD系统中:
xxxxxxxxxx/compat/linux/lib/libc.so.4.6.27/compat/linux/lib/libc.so.4 -> libc.so.4.6.27ldd 表示二进制文件需要更高版本:
xxxxxxxxxxlibc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29由于现有库的最后一位数字只有一两个版本过期,因此程序仍应使用稍旧的版本。但是,用新版本替换现有的 libc.so 是安全的:
xxxxxxxxxx/compat/linux/lib/libc.so.4.6.29/compat/linux/lib/libc.so.4 -> libc.so.4.6.29通常,在FreeBSD上安装Linux程序的前几次,人们需要寻找Linux二进制文件所依赖的共享库。一段时间后,系统上将有一组足够的Linux共享库,能够运行新安装的Linux二进制文件,而无需任何额外的工作。
FreeBSD内核使用多种方法来确定要执行的二进制文件是否是Linux的:它检查ELF文件头中的品牌,查找已知的ELF解释器路径并检查ELF注释;最后,默认情况下,无品牌的ELF可执行文件无论如何都被假定为Linux。
如果所有这些方法都失败,尝试执行二进制文件可能会导致错误消息:
xxxxxxxxxx% ./my-linux-elf-binaryELF binary type not knownAbort为了帮助FreeBSD内核区分FreeBSD ELF二进制文件和Linux二进制文件,请使用 brandelf(1) :
xxxxxxxxxx% brandelf -t Linux my-linux-elf-binary要安装基于Linux RPM的应用程序,请先安装 archivers/rpm4 软件包或端口。安装后,root可以使用此命令安装 a.rpm:
xxxxxxxxxx# cd /compat/linux# rpm2cpio < /path/to/linux.archive.rpm | cpio -id如有必要,标记(brandelf)已安装的ELF二进制文件。请注意,这将阻止彻底卸载。
如果DNS不起作用或出现此错误:
xxxxxxxxxxresolv+: "bind" is an invalid keyword resolv+:"hosts" is an invalid keyword按如下方式配置 /compat/linux/etc/host.conf :
xxxxxxxxxxorder hosts, bindmulti on这指定首先搜索 /etc/hosts ,然后搜索DNS。当 /compat/linux/etc/host.conf 不存在时,linux应用程序会在主机系统中使用 /etc/host.conf ,但由于FreeBSD中不存在该文件,它们会发出抱怨。如果未使用 /etc/resolv.conf 配置名称服务器,请删除绑定。
有关二进制兼容性如何与Linux®兼容的更多信息,请参阅 FreeBSD中的Linux仿真 文章。