> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-20-zhang-linux-jian-rong-ceng/di-20.3-jie-ubuntu-debian-kali-linux-jian-rong-ceng.md).

# 20.3 Ubuntu/Debian/Kali Linux 兼容层

本节基于 debootstrap 和 WSL 在 FreeBSD 上构建 Ubuntu 22.04/26.04 LTS 兼容层，并附 Debian 13/Kali Linux 构建脚本。

视频教程：[06-FreeBSD-Ubuntu 兼容层脚本使用说明](https://www.bilibili.com/video/BV1iM4y1j7E9)

## Ubuntu 兼容层

![Ubuntu 兼容层](/files/l4RM9NQDkPEhdxtyhrnV)

此外，可采用类似方法构建 Debian 兼容层。其他系统的支持情况请参见 **/usr/local/share/debootstrap/scripts/** 目录。

### 开始构建 Ubuntu 兼容层（基于 Ubuntu 22.04 LTS）

构建前，需启用相关守护进程和服务：

```sh
# service linux enable   # 启用 Linux 兼容层服务，设置开机自启
# service linux start    # 启动 Linux 兼容层服务
# service dbus enable    # 启用 D-Bus 服务，设置开机自启（桌面环境通常已配置）
# service dbus start     # 启动 D-Bus 服务（桌面环境通常已配置）
```

构建 Ubuntu 22.04 LTS 基本系统：

```sh
# pkg install debootstrap                                   # 安装 debootstrap 工具
# debootstrap jammy /compat/ubuntu http://mirrors.ustc.edu.cn/ubuntu/   # 使用 debootstrap 安装 Ubuntu Jammy 至 /compat/ubuntu
```

### 指定兼容层路径

构建完成后，须挂载必要的文件系统。将 Linux 兼容层默认路径指向 **/compat/ubuntu** 以实现相关文件系统的自动挂载。

立即生效：

```sh
# sysctl compat.linux.emul_path=/compat/ubuntu
```

永久设置：

```sh
# echo "compat.linux.emul_path=/compat/ubuntu" >> /etc/sysctl.conf
```

### 设置 Linux 内核版本

可能需要设定合适的 Linux 内核版本，否则 chroot 时将提示 `FATAL: kernel too old`。

`7.0.11` 仅为示例，建议参考 [The Linux Kernel Archives](https://www.kernel.org/) 中公布的版本号设置。

```sh
# echo "compat.linux.osrelease=7.0.11" >> /etc/sysctl.conf   # 将内核版本写入 sysctl 配置文件，永久生效
# sysctl compat.linux.osrelease=7.0.11                      # 立即设置内核版本，当前会话即可使用
```

重启 Linux 兼容层服务：

```sh
service linux restart
```

### 进入 Ubuntu 兼容层

完成文件系统挂载和内核版本设定后，进入 Ubuntu 兼容层继续配置。

chroot 进入 Ubuntu 兼容环境，移除可能导致错误的软件：

```bash
# chroot /compat/ubuntu /bin/bash	# 进入 Linux 兼容环境
# apt remove rsyslog # 进入兼容层后，卸载 rsyslog
```

### Ubuntu 切换软件源

更换 Ubuntu 兼容层的软件源可提高下载速度。

卸载 rsyslog 后须更换软件源；由于 SSL 证书尚未更新，暂时无法使用 HTTPS 源。

使用文本编辑器编辑 Ubuntu 兼容环境中的 APT 软件源配置文件 **/compat/ubuntu/etc/apt/sources.list**，写入软件源：

```ini
deb http://mirrors.ustc.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb-src http://mirrors.ustc.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.ustc.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://mirrors.ustc.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
deb http://mirrors.ustc.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://mirrors.ustc.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.ustc.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://mirrors.ustc.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
```

进入 Ubuntu 兼容层，开始更新系统，安装常用软件：

```bash
# export LANG=C # 设置字符集以避免错误
# apt update && apt upgrade && apt install nano wget fonts-wqy-microhei fonts-wqy-zenhei language-pack-zh-hans # 以下命令在 Ubuntu 兼容层内执行
# update-locale LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 # 设置中文字符集
```

## 附录：Ubuntu 兼容层脚本（基于 Ubuntu 26.04 LTS）

Ubuntu 26.04 LTS 兼容层：

![Ubuntu 26.04 LTS 兼容层](/files/13LzeHS50HQgqtqPEV6w)

脚本内容如下：

```sh
#!/bin/sh

ROOT_DIR=/compat
DIST_Linux=ubuntu
DIST=ubuntu-releases
DIST_FULLNAME="Ubuntu 26.04"
VER=26
SUB_VER=04
FILE=ubuntu-${VER}.${SUB_VER}-wsl-amd64.wsl
SUBDIR=""
URL=https://mirrors.ustc.edu.cn/${DIST}/${VER}.${SUB_VER}/
UPDATE_CMD="apt-get update -y"
UPGRADE_CMD="apt-get upgrade -y"
INSTALL_CMD="apt-get install -y"
UPDATE=1
UPGRADE=1
INSTALL=1

# 提前创建目标目录
TARGET_PATH="${ROOT_DIR}/${DIST_Linux}"
mkdir -p "${TARGET_PATH}"

echo "Starting ${DIST_FULLNAME} installation"
sleep 0.5

# 检查 Linux 模块
echo "Checking required modules"

if [ "$(sysrc -n linux_enable 2>/dev/null)" != "YES" ]; then
    echo "Linux service is not enabled. Enable it now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "Warning: You must start the Linux service with \"service linux start\" after each FreeBSD reboot."
            echo "Are you sure you want to continue without enabling the Linux service? (y|N)"
            read ANSWER
            case $ANSWER in
                [Yy][Ee][Ss]|[Yy])
                    echo "WARNING: Linux module not enabled"
                    ;;
                [Nn][Oo]|[Nn]|"")
                    echo "Enabling Linux module"
                    service linux enable
                    ;;
                *)
                    echo "Aborting."
                    exit 4
                    ;;
            esac
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Enabling Linux module"
            service linux enable
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

echo "Starting Linux service"
service linux start

# 检查 dbus
if ! which -s dbus-daemon; then
    echo "dbus-daemon not found. Install D-Bus now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "Aborting. D-Bus not installed"
            exit 2
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Installing D-Bus"
            pkg install -y dbus
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

if [ "$(sysrc -n dbus_enable 2>/dev/null)" != "YES" ]; then
    echo "D-Bus is not enabled. Enable it now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "WARNING: You must start D-Bus with \"service dbus start\" after each FreeBSD reboot."
            echo "Are you sure you want to continue without enabling D-Bus? (y|N)"
            read ANSWER
            case $ANSWER in
                [Yy][Ee][Ss]|[Yy])
                    echo "Warning: D-Bus service not enabled"
                    ;;
                [Nn][Oo]|[Nn]|"")
                    echo "Enabling D-Bus service"
                    service dbus enable
                    ;;
                *)
                    echo "Aborting."
                    exit 4
                    ;;
            esac
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Enabling D-Bus service"
            service dbus enable
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

# =====================================================================
# 下载与解压主体逻辑
# =====================================================================
echo "${DIST_FULLNAME} will be installed in ${TARGET_PATH}"

# 动态完整性校验
check_integrity() {
    # 1. 目标文件不存在，直接失败
    [ -f "${FILE}" ] || return 1

    # 2. 校验文件不存在，直接失败
    if [ ! -f "SHA256SUMS" ]; then
        echo "Error: SHA256SUMS file is missing." >&2
        return 1
    fi

    # 3. 从 SHA256SUMS 中提取期望哈希值
    local expected_hash
    expected_hash=$(grep "${FILE}" SHA256SUMS | awk '{print $1}')

    if [ -z "${expected_hash}" ]; then
        return 1
    fi

    # 4. 获取本地实际哈希值
    local actual_hash
    if command -v sha256 >/dev/null 2>&1; then
        actual_hash=$(sha256 -q "${FILE}")
    else
        echo "Error: sha256 command not found on this system." >&2
        return 1
    fi

	# 打印 SHA256 比对清单
    echo "========================================================"
    echo " Verifying checksum for: ${FILE}"
    echo "--------------------------------------------------------"
    echo " Expected SHA256: ${expected_hash}"
    echo " Actual   SHA256: ${actual_hash}"
    echo "========================================================"

    # 5. 字符串比对
    if [ "${expected_hash}" = "${actual_hash}" ]; then
        return 0
    else
        return 1
    fi
}

# 优先下载最新的校验和文件
echo "Updating verification manifest (SHA256SUMS)..."
fetch "${URL}/SHA256SUMS"

if [ ! -f "SHA256SUMS" ]; then
    echo "Critical Error: Failed to download SHA256SUMS manifest from remote server." >&2
    exit 1
fi

# 步骤 1：检查本地是否已有有效文件
if check_integrity; then
    echo "Valid basic system archive detected locally. Skipping download."
else
    # 如果文件存在但校验失败，说明上一次下载未完成，尝试断点续传
    if [ -f "${FILE}" ]; then
        echo "Local file exists but is incomplete or invalid. Attempting to resume download..."
    else
        echo "Downloading basic system..."
    fi

    # 第一次下载：配合 -r 参数开启断点续传
    fetch -r "${URL}/${FILE}"

    # 步骤 2：下载后进行校验，失败则重试一次
    if ! check_integrity; then
        echo "Checksum mismatch after download. Cleaning up corrupted cache and retrying one last time..."

        # 清除可能损坏的断点残片，重试完整下载
        rm -f "${FILE}"
        fetch "${URL}/${FILE}"

        # 最终校验：若仍失败，终止脚本
        if ! check_integrity; then
            echo "Error: Checksum verification failed again after retry. Installation aborted." >&2
            exit 1
        fi
    fi
fi

# 步骤 3：解压基础系统
echo "Extracting basic system"
sleep 0.5
tar xvpf "${FILE}" ${SUBDIR:-} -C "${TARGET_PATH}" --numeric-owner 2>&1 | grep -v "Error exit delayed from previous errors"

# 修改兼容层默认路径
sysctl compat.linux.emul_path="${TARGET_PATH}"
if ! grep -q "compat.linux.emul_path" /etc/sysctl.conf; then
    echo "compat.linux.emul_path=${TARGET_PATH}" >> /etc/sysctl.conf
else
    # 如果已存在则更新它
    sed -i '' "s|compat.linux.emul_path=.*|compat.linux.emul_path=${TARGET_PATH}|" /etc/sysctl.conf
fi

linux_path=$(sysctl -n compat.linux.emul_path)
echo "Now compat.linux.emul_path is $linux_path"

# 设置 Linux 内核版本，否则 chroot 时将提示 FATAL: kernel too old
sysctl compat.linux.osrelease=7.0.11
if ! grep -q "compat.linux.osrelease" /etc/sysctl.conf; then
    echo "compat.linux.osrelease=7.0.11" >> /etc/sysctl.conf
else
    sed -i '' "s|compat.linux.osrelease=.*|compat.linux.osrelease=7.0.11|" /etc/sysctl.conf
fi

osrelease=$(sysctl -n compat.linux.osrelease)
echo "Now compat.linux.osrelease is $osrelease"
service linux restart

# 配置 DNS
echo "Should ${DIST_FULLNAME} use Alibaba DNS or local resolv.conf? ((A)li | (L)ocal | (C)ancel)"
read ANSWER
case $ANSWER in
    [Aa][Ll][Ii]|[Aa]|"")
        echo "Setting Alibaba DNS"
		grep -q "nameserver 223.5.5.5" "${TARGET_PATH}/etc/resolv.conf" 2>/dev/null || \
		    echo "nameserver 223.5.5.5" >> "${TARGET_PATH}/etc/resolv.conf"
		grep -q "nameserver 223.6.6.6" "${TARGET_PATH}/etc/resolv.conf" 2>/dev/null || \
		    echo "nameserver 223.6.6.6" >> "${TARGET_PATH}/etc/resolv.conf"
        ;;
    [Ll][Oo][Cc][Aa][Ll]|[Ll])
        echo "Using local resolv.conf"
        cp /etc/resolv.conf "${TARGET_PATH}/etc/resolv.conf"
        ;;
    *)
        echo "Canceled."
        echo "You must manually edit ${TARGET_PATH}/etc/resolv.conf!"
        ;;
esac

# 设置 USTC 镜像源
echo "Do you want to use the USTC mirror for ${DIST_FULLNAME}? (Y|n)"
read ANSWER
case $ANSWER in
    [Yy][Ee][Ss]|[Yy]|"")
echo "Setting USTC mirror"
        chroot "${TARGET_PATH}" /bin/bash -c "sed -i.bak \
            -e 's|http://archive.ubuntu.com/ubuntu/|https://mirrors.ustc.edu.cn/ubuntu/|g' \
            -e 's|http://security.ubuntu.com/ubuntu/|https://mirrors.ustc.edu.cn/ubuntu/|g' \
            /etc/apt/sources.list.d/ubuntu.sources"
		# APT::Cache-Start 用于设置 apt 默认缓存大小，按提示调大
		echo "APT::Cache-Start 90000000;" >> "${TARGET_PATH}/etc/apt/apt.conf"
        ;;
    [Nn][Oo]|[Nn])
        echo "Will not set USTC mirror. Skipping update, upgrade, and installation."
        UPDATE=0
        UPGRADE=0
        INSTALL=0
        ;;
    *)
        echo "Aborting."
        exit 4
        ;;
esac

# 更新、升级和安装软件
# 检查网络连通性
if ping -c 1 -W 3000 223.5.5.5 > /dev/null 2>&1; then
    echo "Network reachable, starting operations..."

    echo "Cleaning up snapd..."
    chroot "${TARGET_PATH}" /bin/bash -c "
        if dpkg -l | grep -q snapd; then
            dpkg --purge --force-all snapd 2>/dev/null
            apt-get autoremove --purge -y
        fi
    " || exit 1

    if [ "$UPDATE" = "1" ]; then
        echo "Updating package cache"
        chroot "${TARGET_PATH}" /bin/bash -c "$UPDATE_CMD" || exit 1
    fi

    if [ "$INSTALL" = "1" ]; then
        echo "Installing language-pack and tools"
        # 安装语言包并生成 locale，安装失败则退出
        chroot "${TARGET_PATH}" /bin/bash -c "$INSTALL_CMD nano language-pack-zh-hans locales && locale-gen zh_CN.UTF-8 && update-locale LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8" || exit 1
    fi

    if [ "$UPGRADE" = "1" ]; then
        echo "Upgrading system packages"
        chroot "${TARGET_PATH}" /bin/bash -c "$UPGRADE_CMD" || exit 1
    fi

else
    echo "Network unreachable, skipping update and installation."
fi

# 清理
echo "Cleaning up"
rm -f ${FILE}

echo "All done."
echo "You can switch to ${DIST_FULLNAME} with \"chroot ${TARGET_PATH} /bin/bash\""
```

## 附录：Debian 13 / Kali Linux 兼容层

Debian 13 兼容层：

![Debian 13 兼容层](/files/y4GJxspTV222aj0KCjSd)

Kali Linux 兼容层：

![Kali Linux 兼容层](/files/8myaHBlafZlPEckviZLL)

脚本内容如下：

```sh
#!/bin/sh

ROOT_DIR=/compat
UPDATE_CMD="apt-get update -y"
UPGRADE_CMD="apt-get upgrade -y"
INSTALL_CMD="apt-get install -y"
UPDATE=1
UPGRADE=1
INSTALL=1

echo "========================================"
echo "  Welcome to FreeBSD WSL Image Installer"
echo "========================================"
echo "Which distribution do you want to install?"
echo "1) Debian 13 (Default)"
echo "2) Kali Linux (Rolling)"
echo "----------------------------------------"
echo -n "Enter your choice (1 or 2): "
read DIST_CHOICE

case "$DIST_CHOICE" in
    2)
        DIST_Linux="kali"
        DIST_FULLNAME="Kali Linux"
        echo "Fetching latest Kali WSL image info..."
        RAW_DATA=$(fetch -q -o - https://kali.download/wsl-images/current/SHA256SUMS | awk '/amd64\.wsl/')
        EXPECTED_HASH=$(echo "$RAW_DATA" | awk '{print $1}')
        FILE=$(echo "$RAW_DATA" | awk '{print $2}')
        URL="https://kali.download/wsl-images/current"

        if [ -z "$FILE" ] || [ -z "$EXPECTED_HASH" ]; then
            echo "Error: Failed to fetch dynamic Kali image info. Check network."
            exit 1
        fi
        ;;
    1|"")
        DIST_Linux="debian"
        DIST_FULLNAME="Debian 13"
        DIST="9606244"
        VER="v1.26.0.0"
        FILE="Debian_WSL_AMD64_${VER}.wsl"
        URL="https://salsa.debian.org/debian/WSL/-/jobs/${DIST}/artifacts/raw/"
        EXPECTED_HASH="5ec7dc68216e75d1d4d4761474e99d8461a98d316537110314b137122a879e0f"
        ;;
    *)
        echo "Invalid choice. Aborting."
        exit 1
        ;;
esac

# 提前创建目标目录
TARGET_PATH="${ROOT_DIR}/${DIST_Linux}"
mkdir -p "${TARGET_PATH}"

echo "Starting ${DIST_FULLNAME} installation workflow"
sleep 0.5

# -----------------
# 检查 Linux 模块
# -----------------
echo "Checking required modules"
if [ "$(sysrc -n linux_enable 2>/dev/null)" != "YES" ]; then
    echo "Linux service is not enabled. Enable it now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "Warning: You must start the Linux service with \"service linux start\" after each FreeBSD reboot."
            echo "Are you sure you want to continue without enabling the Linux service? (y|N)"
            read ANSWER
            case $ANSWER in
                [Yy][Ee][Ss]|[Yy])
                    echo "WARNING: Linux module not enabled"
                    ;;
                [Nn][Oo]|[Nn]|"")
                    echo "Enabling Linux module"
                    service linux enable
                    ;;
                *)
                    echo "Aborting."
                    exit 4
                    ;;
            esac
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Enabling Linux module"
            service linux enable
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

echo "Starting Linux service"
service linux start

# -----------------
# 检查 dbus
# -----------------
if ! which -s dbus-daemon; then
    echo "dbus-daemon not found. Install D-Bus now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "Aborting. D-Bus not installed"
            exit 2
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Installing D-Bus"
            pkg install -y dbus
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

if [ "$(sysrc -n dbus_enable 2>/dev/null)" != "YES" ]; then
    echo "D-Bus is not enabled. Enable it now? (Y|n)"
    read ANSWER
    case $ANSWER in
        [Nn][Oo]|[Nn])
            echo "WARNING: You must start D-Bus with \"service dbus start\" after each FreeBSD reboot."
            echo "Are you sure you want to continue without enabling D-Bus? (y|N)"
            read ANSWER
            case $ANSWER in
                [Yy][Ee][Ss]|[Yy])
                    echo "Warning: D-Bus service not enabled"
                    ;;
                [Nn][Oo]|[Nn]|"")
                    echo "Enabling D-Bus service"
                    service dbus enable
                    ;;
                *)
                    echo "Aborting."
                    exit 4
                    ;;
            esac
            ;;
        [Yy][Ee][Ss]|[Yy]|"")
            echo "Enabling D-Bus service"
            service dbus enable
            ;;
        *)
            echo "Aborting."
            exit 4
            ;;
    esac
fi

# -----------------------------------
# 下载、安全校验与解压
# -----------------------------------
echo "${DIST_FULLNAME} will be installed in ${TARGET_PATH}"
echo "Downloading basic system image: ${FILE}"
fetch "${URL}/${FILE}"

echo "Verifying SHA256 Checksum..."
ACTUAL_HASH=$(sha256 -q "${FILE}")

if [ "$ACTUAL_HASH" != "$EXPECTED_HASH" ]; then
    echo "CRITICAL ERROR: SHA256 checksum mismatch!"
    echo "Expected : $EXPECTED_HASH"
    echo "Actual   : $ACTUAL_HASH"
    echo "The file might be corrupted or compromised. Cleaning up and aborting."
    rm -f "${FILE}"
    exit 1
fi
echo "Checksum successfully verified!"

echo "Extracting basic system"
sleep 0.5
tar xvpf "${FILE}" -C "${TARGET_PATH}" --numeric-owner 2>&1 | grep -v "Error exit delayed from previous errors"

# 修改默认兼容层路径
sysctl compat.linux.emul_path="${TARGET_PATH}"
if ! grep -q "compat.linux.emul_path" /etc/sysctl.conf; then
    echo "compat.linux.emul_path=${TARGET_PATH}" >> /etc/sysctl.conf
else
    sed -i '' "s|compat.linux.emul_path=.*|compat.linux.emul_path=${TARGET_PATH}|" /etc/sysctl.conf
fi

linux_path=$(sysctl -n compat.linux.emul_path)
echo "Now compat.linux.emul_path is $linux_path"

# 设置 Linux 内核版本，否则 chroot 时将提示 FATAL: kernel too old
sysctl compat.linux.osrelease=7.0.11
if ! grep -q "compat.linux.osrelease" /etc/sysctl.conf; then
    echo "compat.linux.osrelease=7.0.11" >> /etc/sysctl.conf
else
    sed -i '' "s|compat.linux.osrelease=.*|compat.linux.osrelease=7.0.11|" /etc/sysctl.conf
fi

osrelease=$(sysctl -n compat.linux.osrelease)
echo "Now compat.linux.osrelease is $osrelease"
service linux restart

# -----------------
# 基础网络配置
# -----------------
echo "Should ${DIST_FULLNAME} use Alibaba DNS or local resolv.conf? ((A)li | (L)ocal | (C)ancel)"
read ANSWER
case $ANSWER in
    [Aa][Ll][Ii]|[Aa]|"")
        echo "Setting Alibaba DNS"
		grep -q "nameserver 223.5.5.5" "${TARGET_PATH}/etc/resolv.conf" 2>/dev/null || \
		    echo "nameserver 223.5.5.5" >> "${TARGET_PATH}/etc/resolv.conf"
		grep -q "nameserver 223.6.6.6" "${TARGET_PATH}/etc/resolv.conf" 2>/dev/null || \
		    echo "nameserver 223.6.6.6" >> "${TARGET_PATH}/etc/resolv.conf"
        ;;
    [Ll][Oo][Cc][Aa][Ll]|[Ll])
        echo "Using local resolv.conf"
        cp /etc/resolv.conf "${TARGET_PATH}/etc/resolv.conf"
        ;;
    *)
        echo "Canceled."
        echo "You must manually edit ${TARGET_PATH}/etc/resolv.conf!"
        ;;
esac

# -----------------
# 镜像源配置
# -----------------
echo "Do you want to use the USTC mirror for ${DIST_FULLNAME}? (Y|n)"
read ANSWER
case $ANSWER in
    [Yy][Ee][Ss]|[Yy]|"")
        echo "Setting USTC mirror for ${DIST_FULLNAME}"

        if [ "$DIST_Linux" = "debian" ]; then
            chroot "${TARGET_PATH}" /bin/bash -c "sed -i.bak \
                -e 's|http://archive.debian.org/|https://mirrors.ustc.edu.cn/|g' \
                -e 's|http://security.debian.org/|https://mirrors.ustc.edu.cn/|g' \
                /etc/apt/sources.list.d/0000debian.sources"

        elif [ "$DIST_Linux" = "kali" ]; then
            # 将 Kali 镜像源插入到 sources.list 文件最前方
            echo "deb https://mirrors.ustc.edu.cn/kali kali-rolling main non-free non-free-firmware contrib" > "${TARGET_PATH}/etc/apt/sources.list"
            echo "deb-src https://mirrors.ustc.edu.cn/kali kali-rolling main non-free non-free-firmware contrib" >> "${TARGET_PATH}/etc/apt/sources.list"
        fi

        echo "APT::Cache-Start 90000000;" >> "${TARGET_PATH}/etc/apt/apt.conf"
        ;;
    [Nn][Oo]|[Nn])
        echo "Will not set USTC mirror. Skipping update, upgrade, and installation."
        UPDATE=0
        UPGRADE=0
        INSTALL=0
        ;;
    *)
        echo "Aborting."
        exit 4
        ;;
esac

# -----------------
# 系统初始化与更新
# -----------------
if ping -c 1 -W 3000 223.5.5.5 > /dev/null 2>&1; then
    echo "Network reachable, starting operations..."

    # ==================== 新增：Kali Linux 特殊锁定逻辑 ====================
    if [ "$DIST_Linux" = "kali" ]; then
        echo "Kali Linux detected. Locking core packages inside chroot..."
        chroot "${TARGET_PATH}" /bin/bash -c "apt-mark hold systemd dbus-user-session udev dhcpcd-base libpam-systemd:amd64 dbus-system-bus-common cron-daemon-common systemd-sysv openssh-server openssh-client cron openssh-client-gssapi dbus openssh-sftp-server" || exit 1
    fi
    # =====================================================================

    if [ "$UPDATE" = "1" ]; then
        echo "Updating package cache"
        chroot "${TARGET_PATH}" /bin/bash -c "$UPDATE_CMD" || exit 1
    fi

    if [ "$INSTALL" = "1" ]; then
        echo "Installing nano and configuring locale"
        chroot "${TARGET_PATH}" /bin/bash -c "$INSTALL_CMD nano locales && sed -i 's/^# *\(zh_CN.UTF-8 UTF-8\)/\1/' /etc/locale.gen && locale-gen && update-locale LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8" || exit 1
    fi

    if [ "$UPGRADE" = "1" ]; then
        echo "Upgrading system packages"
        chroot "${TARGET_PATH}" /bin/bash -c "$UPGRADE_CMD" || exit 1
    fi
else
    echo "Network unreachable, skipping update and installation."
fi

# -----------------
# 清理阶段
# -----------------
echo "Cleaning up"
rm -f "${FILE}"

echo "All done."
echo "You can switch to ${DIST_FULLNAME} with \"chroot ${TARGET_PATH} /bin/bash\""
```

## 附录：运行 X11 软件

允许所有本地用户访问当前 X Server 实例：

```sh
# xhost +local:	# 此时处于 FreeBSD 系统
```

## 故障排除与未竟事宜

### 程序的命令行启动命令是什么？

按以下方法依次查找（以 `gedit` 为例）：

* 直接执行软件包名 `# gedit`；
* `whereis 软件包名`，定位后执行。`whereis gedit`；
* 通过软件图标定位，进入 **/usr/share/applications** 目录，根据软件包名找到对应文件，并使用文本编辑器（如 ee、nano）打开（**.desktop 文件** 是文本文件，而非软链接或图片），找到其中的程序启动命令并复制到终端运行即可。
* 通过 `find` 命令全局查找（如 `# find / -name gedit`）。

> 如何查找软件？
>
> ```bash
> # apt search --names-only XXX # 按名称搜索包含 XXX 的软件包
> ```
>
> 将 XXX 改为所需搜索的软件名即可。

### 缺少 .so 文件

* 先查看缺少哪些 .so 文件，通常不会只缺失一个。

```sh
# ldd /usr/bin/qq	# 查看可执行文件 qq 所依赖的动态链接库
	linux_vdso.so.1 (0x00007ffffffff000)
	libffmpeg.so => not found
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x0000000801061000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x0000000801066000)
	…………………………以下省略……………………………………
```

根据输出 `libffmpeg.so => not found`，判断缺失“libffmpeg.so”。

* 安装工具

```bash
# apt install apt-file   # 安装 apt-file 工具，用于查询文件所属的软件包
# apt-file update        # 更新 apt-file 的软件包索引数据库
```

* 查看 `libffmpeg.so` 文件属于哪个包：

```bash
# apt-file search libffmpeg.so	# 查询包含 libffmpeg.so 文件的软件包
qmmp: /usr/lib/qmmp/plugins/Input/libffmpeg.so
webcamoid-plugins: /usr/lib/x86_64-linux-gnu/avkys/submodules/MultiSink/libffmpeg.so
webcamoid-plugins: /usr/lib/x86_64-linux-gnu/avkys/submodules/MultiSrc/libffmpeg.so
webcamoid-plugins: /usr/lib/x86_64-linux-gnu/avkys/submodules/VideoCapture/libffmpeg.so
```

多个包都提供了该文件，任选一个安装即可。

```bash
# apt install webcamoid-plugins	# 安装 Webcamoid 的插件组件
```

* 按照上述路径复制文件，并刷新 ldd 缓存：

```sh
# cp /usr/lib/x86_64-linux-gnu/avkys/submodules/MultiSink/libffmpeg.so /usr/lib   # 将 libffmpeg.so 文件复制到系统库目录
# ldconfig                                                                     # 重新生成动态链接库缓存
```

* 再次查看可执行文件 **/usr/bin/qq** 所依赖的动态链接库：

```sh
# ldd /usr/bin/qq
	linux_vdso.so.1 (0x00007ffffffff000)
	libffmpeg.so => /lib/libffmpeg.so (0x0000000801063000)
	…………………………以下省略……………………………………
```

## 参考文献

* Debian Project. debootstrap(8)\[EB/OL]. \[2026-04-17]. <https://manpages.debian.org/stable/debootstrap/debootstrap.8.en.html>. debootstrap 工具手册页，用于从指定发行版仓库引导 Debian 基本系统。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-20-zhang-linux-jian-rong-ceng/di-20.3-jie-ubuntu-debian-kali-linux-jian-rong-ceng.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
