复制
#!/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\""