Now that we know how to work with the ports collection let’s have a look another option you have in FreeBSD: Sometimes it might be required to run unmodified Linux binaries on FreeBSD and to achieve this, FreeBSD comes with a Linux compatibility layer. This is optional and not enabled by default, but pretty easy to setup and use. Before you do that, please check if the functionality you’re looking for is not already there as either a package or the ports collection. If it is there, use it from there.
To enable the layer at boot time, use “sysrc” as we’ve done it in the previous post and start the corresponding service:
root@freebsd14:~ $ sysrc linux_enable="YES"
linux_enable: NO -> YES
root@freebsd14:~ $ service linux start
root@freebsd14:~ $ service linux describe
Enable Linux ABI
Once the service is running, you’ll see additional mountpoints which Linux applications usually are expecting under “/compat/linux”:
root@freebsd14:~ $ df -h | grep compat
linprocfs 8.0K 0B 8.0K 0% /compat/linux/proc
linsysfs 8.0K 0B 8.0K 0% /compat/linux/sys
devfs 1.0K 0B 1.0K 0% /compat/linux/dev
fdescfs 1.0K 0B 1.0K 0% /compat/linux/dev/fd
tmpfs 2.2G 4.0K 2.2G 0% /compat/linux/dev/shm
This also loaded the required kernel modules:
root@freebsd14:~ $ kldstat | grep -i linux
10 1 0xffffffff82e2f000 30a80 linux.ko
11 4 0xffffffff82e60000 c2a8 linux_common.ko
12 1 0xffffffff82e6d000 2de10 linux64.ko
The next step is to install the Linux userland. Currently, two of those are available (Debian is available with the debootstrap package):
root@freebsd14:~ $ pkg search linux_base
linux_base-c7-7.9.2009_3 Base set of packages needed in Linux mode (Linux CentOS 7.9.2009)
linux_base-rl9-9.4 Base set of packages needed in Linux mode (Rocky Linux 9.4)
As CentOS 7 is end of life, we’ll obviously go for the Rocky Linux 9.4 userland (this is not the most recent minor release as of today, but it is close). You’ll also see those userlands in the ports tree in the “emulators” category:
root@freebsd14:~ $ ls -la /usr/ports/emulators/linux_base-*
/usr/ports/emulators/linux_base-c7:
total 124
drwxr-xr-x 2 root wheel 8 Dec 11 09:49 .
drwxr-xr-x 193 root wheel 194 Dec 11 09:49 ..
-rw-r--r-- 1 root wheel 6478 Dec 11 09:49 Makefile
-rw-r--r-- 1 root wheel 36074 Dec 11 09:49 distinfo
-rw-r--r-- 1 root wheel 468 Dec 11 09:49 pkg-descr
-rw-r--r-- 1 root wheel 95620 Dec 11 09:49 pkg-plist.aarch64
-rw-r--r-- 1 root wheel 108836 Dec 11 09:49 pkg-plist.amd64
-rw-r--r-- 1 root wheel 95512 Dec 11 09:49 pkg-plist.i386
/usr/ports/emulators/linux_base-rl9:
total 132
drwxr-xr-x 2 root wheel 8 Dec 11 09:49 .
drwxr-xr-x 193 root wheel 194 Dec 11 09:49 ..
-rw-r--r-- 1 root wheel 6943 Dec 11 09:49 Makefile
-rw-r--r-- 1 root wheel 1380 Dec 11 09:49 Makefile.version
-rw-r--r-- 1 root wheel 40711 Dec 11 09:49 distinfo
-rw-r--r-- 1 root wheel 466 Dec 11 09:49 pkg-descr
-rw-r--r-- 1 root wheel 91404 Dec 11 09:49 pkg-plist.aarch64
-rw-r--r-- 1 root wheel 104964 Dec 11 09:49 pkg-plist.amd64
As usual, when it comes to binary packages, pkg is used to bring this onto the system:
root@freebsd14:~ $ pkg install linux_base-rl9
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Updating database digests format: 100%
The following 1 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
linux_base-rl9: 9.4
Number of packages to be installed: 1
The process will require 297 MiB more space.
39 MiB to be downloaded.
Proceed with this action? [y/N]: y
[1/1] Fetching linux_base-rl9-9.4.pkg: 100% 39 MiB 20.5MB/s 00:02
Checking integrity... done (0 conflicting)
[1/1] Installing linux_base-rl9-9.4...
[1/1] Extracting linux_base-rl9-9.4: 100%
Looking again at the “/compat/linux” structure, this is now populated:
root@freebsd14:~ $ ls -la /compat/linux/
total 39
drwxr-xr-x 11 root wheel 16 Dec 11 17:04 .
drwxr-xr-x 3 root wheel 3 Dec 11 16:15 ..
drwxr-xr-x 2 root wheel 2 Dec 11 17:04 afs
lrwxr-xr-x 1 root wheel 7 May 16 2022 bin -> usr/bin
drwxr-xr-x 10 root wheel 512 Dec 11 17:04 dev
drwxr-xr-x 24 root wheel 60 Dec 11 17:04 etc
lrwxr-xr-x 1 root wheel 7 May 16 2022 lib -> usr/lib
lrwxr-xr-x 1 root wheel 9 May 16 2022 lib64 -> usr/lib64
drwxr-xr-x 2 root wheel 2 Dec 11 17:04 opt
dr-xr-xr-x 1 root wheel 0 Dec 11 17:06 proc
lrwxr-xr-x 1 root wheel 8 Oct 31 02:04 run -> /var/run
lrwxr-xr-x 1 root wheel 8 May 16 2022 sbin -> usr/sbin
drwxr-xr-x 2 root wheel 2 Dec 11 17:04 srv
dr-xr-xr-x 1 root wheel 0 Dec 11 17:06 sys
drwxr-xr-x 8 root wheel 9 Dec 11 17:04 usr
drwxr-xr-x 16 root wheel 17 Dec 11 17:04 var
If we chroot into this, we have a Rocky Linux environment to work with:
root@freebsd14:~ 1 chroot /compat/linux/
sh-5.1$ cat /etc/os-release
NAME="Rocky Linux"
VERSION="9.4 (Blue Onyx)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Rocky Linux 9.4 (Blue Onyx)"
ANSI_COLOR="0;32"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:rocky:rocky:9::baseos"
HOME_URL="https://rockylinux.org/"
BUG_REPORT_URL="https://bugs.rockylinux.org/"
SUPPORT_END="2032-05-31"
ROCKY_SUPPORT_PRODUCT="Rocky-Linux-9"
ROCKY_SUPPORT_PRODUCT_VERSION="9.4"
REDHAT_SUPPORT_PRODUCT="Rocky Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.4"
What we don’t have, is neither rpm nor dnf:
sh-5.1$ which rpm
which: no rpm in (/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin)
sh-5.1$ which dnf
which: no dnf in (/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin)
rpm can be installed by installing the rpm4 package first:
root@freebsd14:~ $ pkg search rpm4
rpm4-4.18.2_1 Red Hat Package Manager
root@freebsd14:~ $ pkg install rpm4
Once we have that, we can download a rpm e.g. from the Rocky Linux repositories:
root@freebsd14:/compat/linux $ fetch https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/Packages/u/unzip-6.0-57.el9.x86_64.rpm
unzip-6.0-57.el9.x86_64.rpm 179 kB 3851 kBps 00s
Confirm that unzip is not yet available:
root@freebsd14:/compat/linux $ find . -name "unzip"
Install it, and verify it is usable:
root@freebsd14:/compat/linux $ rpm2cpio < unzip-6.0-57.el9.x86_64.rpm | cpio -id
787 blocks
root@freebsd14:/compat/linux $ find . -name "unzip"
./usr/bin/unzip
./usr/share/licenses/unzip
./usr/share/doc/unzip
root@freebsd14:/compat/linux $ ./usr/bin/unzip --help
UnZip 6.00 of 20 April 2009, by Info-ZIP. Maintained by C. Spieler. Send
bug reports using http://www.info-zip.org/zip-bug.html; see README for details.
Usage: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
Default action is to extract files in list, except those in xlist, to exdir;
file[.zip] may be a wildcard. -Z => ZipInfo mode ("unzip -Z" for usage).
-p extract files to pipe, no messages -l list files (short format)
-f freshen existing files, create none -t test compressed archive data
-u update files, create if necessary -z display archive comment only
-v list verbosely/show version info -T timestamp archive to latest
-x exclude files that follow (in xlist) -d extract files into exdir
modifiers:
-n never overwrite existing files -q quiet mode (-qq => quieter)
-o overwrite files WITHOUT prompting -a auto-convert any text files
-j junk paths (do not make directories) -aa treat ALL files as text
-U use escapes for all non-ASCII Unicode -UU ignore any Unicode fields
-C match filenames case-insensitively -L make (some) names lowercase
-X restore UID/GID info -V retain VMS version numbers
-K keep setuid/setgid/tacky permissions -M pipe through "more" pager
-O CHARSET specify a character encoding for DOS, Windows and OS/2 archives
-I CHARSET specify a character encoding for UNIX and other archives
See "unzip -hh" or unzip.txt for more help. Examples:
unzip data1 -x joe => extract all files except joe from zipfile data1.zip
unzip -p foo | more => send contents of foo.zip via pipe into program more
unzip -fo foo ReadMe => quietly replace existing ReadMe if archive file newer
Nice. If you have the requirement to use Linux tools on FreeBSD, this can be very helpful.