# 21.7 Gentoo Linux 兼容层

本节将系统地介绍在 FreeBSD 操作系统上构建 Gentoo Linux 兼容层的技术方法与实现步骤。

## 构建基本系统

构建 Gentoo Linux 兼容层的前置条件之一是启用系统所需的若干核心守护进程。

### 守护进程

```sh
# service linux enable       # 设置 Linux 内核模块开机自启
# service linux start        # 启动 Linux 内核模块
# service dbus enable        # 设置 dbus 服务开机自启（一般桌面环境已配置）
# service dbus start         # 启动 dbus 服务（一般桌面环境已配置）
```

### 获取基本系统镜像

```sh
# wget https://mirrors.ustc.edu.cn/gentoo/releases/amd64/autobuilds/20230101T164658Z/stage3-amd64-systemd-20230101T164658Z.tar.xz  # 下载 Gentoo Stage3 镜像，链接会随版本更新，请读者自行查找最新链接
# mkdir -p /compat/gentoo        # 创建 Gentoo 兼容层目录
# tar xpvf stage3-amd64-systemd-20230101T164658Z.tar.xz -C /compat/gentoo --numeric-owner  # 将 Gentoo 镜像解压到兼容层目录
```

### fstab 文件

编辑 `/etc/fstab`，加入：

```sh
# Device        Mountpoint              FStype          Options                      Dump    Pass#
devfs           /compat/gentoo/dev      devfs           rw,late                      0       0
tmpfs           /compat/gentoo/dev/shm  tmpfs           rw,late,size=1g,mode=1777    0       0
fdescfs         /compat/gentoo/dev/fd   fdescfs         rw,late,linrdlnk             0       0
linprocfs       /compat/gentoo/proc     linprocfs       rw,late                      0       0
linsysfs        /compat/gentoo/sys      linsysfs        rw,late                      0       0
/tmp            /compat/gentoo/tmp      nullfs          rw,late                      0       0
#/home           /compat/gentoo/home     nullfs          rw,late                      0       0
```

项目结构：

```sh
/compat/gentoo/
├── dev/                  # 设备文件系统
│   ├── fd/               # 文件描述符文件系统
│   └── shm/              # 内存文件系统
├── etc/
│   ├── portage/
│   │   ├── make.conf     # Portage 配置文件
│   │   └── repos.conf/
│   │       └── gentoo.conf # Gentoo 仓库配置
│   └── resolv.conf       # DNS 配置
├── home/                 # 用户主目录（可选）
├── proc/                 # Linux 进程文件系统
├── sys/                  # Linux 内核对象文件系统
├── tmp/                  # 临时目录
└── usr/
    └── share/
        └── portage/
            └── config/
                └── repos.conf # 默认仓库配置
```

挂载 `/etc/fstab` 中定义的所有文件系统：

```sh
# mount -al # 检查是否有编写错误
```

编辑 `/compat/gentoo/etc/portage/make.conf` 文件，加入：

```sh
MAKEOPTS="-j2"                                                                 # 设置 Gentoo 编译时使用的并行作业数为 2
GENTOO_MIRRORS="https://mirrors.ustc.edu.cn/gentoo"                            # 指定 Gentoo 镜像源为中国科学技术大学镜像
FEATURES="-ipc-sandbox -mount-sandbox -network-sandbox -pid-sandbox -xattr -sandbox -usersandbox"  # 禁用 Gentoo Portage 编译系统中的各种沙箱功能
```

进行常见配置：

```sh
# mkdir -p /compat/gentoo/etc/portage/repos.conf/                                        # 在 FreeBSD 系统中创建 Gentoo Portage 仓库配置目录
# cp /compat/gentoo/usr/share/portage/config/repos.conf /compat/gentoo/etc/portage/repos.conf/gentoo.conf  # 在 FreeBSD 系统中复制 Gentoo 的默认仓库配置文件
# cp /etc/resolv.conf /compat/gentoo/etc/                                                   # 在 FreeBSD 系统中将 DNS 配置复制到 Gentoo 兼容层
```

### 修改 Gentoo 的软件源

在 FreeBSD 下，编辑 `/compat/gentoo/etc/portage/repos.conf/gentoo.conf` 文件，修改 Gentoo 仓库配置文件：将 `sync-uri = rsync://rsync.gentoo.org/gentoo-portage` 修改为 `sync-uri = rsync://mirrors.tuna.tsinghua.edu.cn/gentoo-portage`。

进入 Gentoo 兼容层环境，使用 Bash 作为 shell：

```sh
# chroot /compat/gentoo /bin/bash # 此处位于 Gentoo!
```

使用 Gentoo 的 webrsync 工具同步 Portage 树：

```sh
# emerge-webrsync	# 获取 Gentoo ebuild 数据库快照。
```

## 测试使用

测试安装 screenfetch：

```sh
# emerge -v screenfetch	# 使用 Gentoo Portage 安装 screenfetch 工具，并显示详细输出

 * IMPORTANT: 13 news items need reading for repository 'gentoo'.
 * Use eselect news read to view new items.


These are the packages that would be merged, in order:

Calculating dependencies... done!
Dependency resolution took 0.57 s (backtrack: 0/20).

[ebuild  N     ] app-misc/screenfetch-3.9.9::gentoo  79 KiB

Total: 1 package (1 new), Size of downloads: 79 KiB

……省略一部分……

>>> app-misc/screenfetch-3.9.9 merged.

>>> Recording app-misc/screenfetch in "world" favorites file...

>>> Completed (1 of 1) app-misc/screenfetch-3.9.9::gentoo

 * Messages for package app-misc/screenfetch-3.9.9:

 * Install additional packages for optional runtime features:
 *   media-gfx/scrot for screenshot taking
 *   net-misc/curl for screenshot uploading
 *   x11-apps/xdpyinfo for resolution detection

 * GNU info directory index is up-to-date.

 * IMPORTANT: 13 news items need reading for repository 'gentoo'.
 * Use eselect news read to view new items.
```

可以正常安装软件。

在 Gentoo 环境中运行 `screenfetch` 命令，显示系统信息：

```bash
ykla / # screenfetch
         -/oyddmdhs+:.                root@ykla
     -odNMMMMMMMMNNmhy+-`             OS: Gentoo
   -yNMMMMMMMMMMMNNNmmdhy+-           Kernel: x86_64 Linux 6.2.10
 `omMMMMMMMMMMMMNmdmmmmddhhy/`        Uptime: 36m
 omMMMMMMMMMMMNhhyyyohmdddhhhdo`      Packages: 317
.ydMMMMMMMMMMdhs++so/smdddhhhhdm+`    Shell: bash 5.3.3
 oyhdmNMMMMMMMNdyooydmddddhhhhyhNd.   Disk: 2.4G / 187G (2%)
  :oyhhdNNMMMMMMMNNNmmdddhhhhhyymMh   CPU: 12th Gen Intel Core i7-1260P @ 16x 2.496GHz
    .:+sydNMMMMMNNNmmmdddhhhhhhmMmy   RAM: 2881MiB / 4053MiB
       /mMMMMMMNNNmmmdddhhhhhmMNhs:
    `oNMMMMMMMNNNmmmddddhhdmMNhs+`
  `sNMMMMMMMMNNNmmmdddddmNMmhs/.
 /NMMMMMMMMNNNNmmmdddmNMNdso:`
+MMMMMMMNNNNNmmmmdmNMNdso/-
yMMNNNNNNNmmmmmNNMmhs+/-`
/hMMNNNNNNNNMNdhs++/-`
`/ohdmmddhys+++/:.`
  `-//////:--.
```

## Shell 脚本

脚本内容：

```sh
#!/bin/sh

rootdir=/compat/gentoo   # 设置 Gentoo 根目录路径
fetch https://mirrors.ustc.edu.cn/gentoo/releases/amd64/autobuilds/latest-stage3-amd64-systemd.txt   # 下载最新 Stage3 构建列表
gentoodownload=$(grep 'stage3-amd64-systemd' latest-stage3-amd64-systemd.txt | awk '{print $1}')   # 提取最新 Stage3 文件名
rm latest-stage3-amd64-systemd.txt   # 删除临时文件

url="https://mirrors.ustc.edu.cn/gentoo/releases/amd64/autobuilds/"   # Gentoo 下载基础 URL

echo "Starting Gentoo Linux installation..."   # 输出开始信息
echo "check modules ..."   # 输出模块检查提示

# 检查 linux 模块是否启用
if [ "$(sysrc -n linux_enable)" = "NO" ]; then
        echo "linux module should be loaded. Continue?(Y|n)"   # 提示用户是否继续
        read answer   # 读取用户输入
        case $answer in
                [Nn][Oo]|[Nn])
                        echo "linux module not loaded"   # 提示模块未加载
                        exit 1   # 退出脚本
                        ;;
                [Yy][Ee][Ss]|[Yy]|"")
                        sysrc linux_enable=YES   # 启用 linux 模块
                        ;;
        esac
fi
echo "start linux"   # 输出启动信息
service linux start   # 启动 linux 模块

# 检查 dbus 是否安装
if ! /usr/bin/which -s dbus-daemon;then
        echo "dbus-daemon not found. install it [Y|n]"   # 提示安装 dbus
        read  answer   # 读取用户输入
        case $answer in
            [Nn][Oo]|[Nn])
                echo "dbus not installed"   # 提示未安装
                exit 2   # 退出脚本
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                pkg install -y dbus   # 安装 dbus
                ;;
        esac
    fi

# 检查 dbus 是否启用
if [ "$(sysrc -n dbus_enable)" != "YES" ]; then
        echo "dbus should be enabled. Continue? (Y|n)"   # 提示是否启用
        read answer
        case $answer in
            [Nn][Oo]|[Nn])
                        echo "dbus not running"   # 提示未运行
                        exit 2
                        ;;
            [Yy][Ee][Ss]|[Yy]|"")
                        service dbus enable   # 启用 dbus 服务
                        ;;
        esac
fi
echo "start dbus"   # 输出启动信息
service dbus start   # 启动 dbus 服务

echo "now we will bootstrap gentoo"   # 提示开始 bootstrap

fetch ${url}/$gentoodownload   # 下载最新 Stage3 文件
mkdir -p ${rootdir}   # 创建 Gentoo 根目录
tar xpvf stage3-amd64-systemd*.tar.xz -C ${rootdir} --numeric-owner   # 解压 Stage3 文件
rm stage3-amd64-systemd*.tar.xz   # 删除压缩包

# 检查 nullfs 是否启用
if [ ! "$(sysrc -f /boot/loader.conf -qn nullfs_load)" = "YES" ]; then
        echo "nullfs_load should be loaded. Continue? (Y|n)"
        read answer
        case $answer in
            [Nn][Oo]|[Nn])
                echo "nullfs is not loaded"
		exit 3
                ;;
            [Yy][Ee][Ss]|[Yy]|"")
                sysrc -f /boot/loader.conf nullfs_load=yes   # 设置 nullfs 自动加载
                ;;
        esac
fi

# 加载 nullfs 模块
if ! kldstat -n nullfs >/dev/null 2>&1;then
        echo "load nullfs module"
        kldload -v nullfs
fi

echo "mount some fs for linux"   # 输出挂载提示
echo "devfs ${rootdir}/dev devfs rw,late 0 0" >> /etc/fstab   # 配置 devfs
echo "tmpfs ${rootdir}/dev/shm tmpfs rw,late,size=1g,mode=1777 0 0" >> /etc/fstab   # 配置 tmpfs
echo "fdescfs ${rootdir}/dev/fd fdescfs rw,late,linrdlnk 0 0" >> /etc/fstab   # 配置 fdescfs
echo "linprocfs ${rootdir}/proc linprocfs rw,late 0 0" >> /etc/fstab   # 配置 linprocfs
echo "linsysfs ${rootdir}/sys linsysfs rw,late 0 0" >> /etc/fstab   # 配置 linsysfs
echo "/tmp ${rootdir}/tmp nullfs rw,late 0 0" >> /etc/fstab   # 配置 /tmp
mount -al   # 挂载所有文件系统

echo "for Gentoo Linux, we should change 'compat.linux.osrelease' to upgrade Linux kernel version, continue? (Y|n)"
read answer
case $answer in
	[Nn][Oo]|[Nn])
		echo "close to success"
		exit 4
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "compat.linux.osrelease=6.2.10" >> /etc/sysctl.conf   # 设置内核版本兼容
		sysctl compat.linux.osrelease=6.2.10   # 立即生效
                ;;
esac
echo "complete!"   # 提示完成
echo "to use: chroot ${rootdir} /bin/bash"   # 提示如何进入 Gentoo 环境
echo ""
echo " I will set resolv.conf to Ali DNS"   # 提示将设置 DNS
echo "continue?[Y|n]"
read answer
case $answer in
	[Nn][Oo]|[Nn])
		echo "Set up your Gentoo by yourself. Bye!"   # 用户选择不自动配置
		exit 0
		;;
	[Yy][Ee][Ss]|[Yy]|"")
		echo "nameserver 223.5.5.5" >> ${rootdir}/etc/resolv.conf   # 设置 DNS
esac
echo "Now write MAKEOPTS FEATURES in /compat/gentoo/etc/portage/make.conf -- using USTC mirrors for GENTOO_MIRRORS"		
echo "MAKEOPTS=\"-j2\"" >> /${rootdir}/etc/portage/make.conf   # 设置 MAKEOPTS
echo "GENTOO_MIRRORS=\"https://mirrors.ustc.edu.cn/gentoo\"" >> ${rootdir}/etc/portage/make.conf   # 设置镜像源
echo "FEATURES=\"-ipc-sandbox -mount-sandbox -network-sandbox -pid-sandbox -xattr -sandbox -usersandbox\"" >> ${rootdir}/etc/portage/make.conf   # 设置 FEATURES

echo "Now configuring software sources -- Using TUNA mirror for emerge-webrsync"	
mkdir -p ${rootdir}/etc/portage/repos.conf/   # 创建 repos.conf 目录
cp ${rootdir}/usr/share/portage/config/repos.conf ${rootdir}/etc/portage/repos.conf/gentoo.conf   # 复制仓库配置
sed -i "" 's/rsync.gentoo.org/mirrors.tuna.tsinghua.edu.cn/' ${rootdir}/etc/portage/repos.conf/gentoo.conf   # 修改为清华镜像

echo " I will run emerge-webrsync"   
chroot ${rootdir} /bin/bash -c "emerge-webrsync"   # 在 Gentoo 环境同步 Portage 树
    
echo "all done."   # 提示完成
echo "Now you can run '#chroot /compat/gentoo/ /bin/bash' to enter Gentoo"   # 提示如何进入 Gentoo 环境
```

## 课后习题

1. 在 FreeBSD 中，实现在 Gentoo 兼容层中移除的 `FEATURES` 中的 `-sandbox` 相关选项。
2. 尝试将 Gentoo 的 Portage 的部分功能移植到 FreeBSD Ports 框架。
