#!/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
# Create target directory in advance
TARGET_PATH="${ROOT_DIR}/${DIST_Linux}"
mkdir -p "${TARGET_PATH}"
echo "Starting ${DIST_FULLNAME} installation"
sleep 0.5
# Check Linux module
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
# Check 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
# =====================================================================
# Download and extraction main logic
# =====================================================================
echo "${DIST_FULLNAME} will be installed in ${TARGET_PATH}"
# Dynamic integrity verification
check_integrity() {
# 1. Target file does not exist, return failure directly
[ -f "${FILE}" ] || return 1
# 2. Checksum file does not exist, return failure directly
if [ ! -f "SHA256SUMS" ]; then
echo "Error: SHA256SUMS file is missing." >&2
return 1
fi
# 3. Extract the expected hash value from SHA256SUMS
local expected_hash
expected_hash=$(grep "${FILE}" SHA256SUMS | awk '{print $1}')
if [ -z "${expected_hash}" ]; then
return 1
fi
# 4. Get the local actual hash value
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
# Print SHA256 comparison list
echo "========================================================"
echo " Verifying checksum for: ${FILE}"
echo "--------------------------------------------------------"
echo " Expected SHA256: ${expected_hash}"
echo " Actual SHA256: ${actual_hash}"
echo "========================================================"
# 5. String comparison
if [ "${expected_hash}" = "${actual_hash}" ]; then
return 0
else
return 1
fi
}
# Download the latest checksum file first
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
# Step 1: Check if a valid file already exists locally
if check_integrity; then
echo "Valid basic system archive detected locally. Skipping download."
else
# If the file exists but verification fails, the previous download was incomplete; attempt to resume
if [ -f "${FILE}" ]; then
echo "Local file exists but is incomplete or invalid. Attempting to resume download..."
else
echo "Downloading basic system..."
fi
# First download: use -r parameter to enable resume
fetch -r "${URL}/${FILE}"
# Step 2: Verify after download; if failed, retry once
if ! check_integrity; then
echo "Checksum mismatch after download. Cleaning up corrupted cache and retrying one last time..."
# Clean up potentially corrupted resume fragments, retry full download
rm -f "${FILE}"
fetch "${URL}/${FILE}"
# Final verification: if still failed, terminate script
if ! check_integrity; then
echo "Error: Checksum verification failed again after retry. Installation aborted." >&2
exit 1
fi
fi
fi
# Step 3: Extract the base system
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"
# Modify the compatibility layer default path
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
# If it already exists, update it
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"
# Set Linux kernel version, otherwise chroot will prompt 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
# Configure 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
# Set USTC mirror source
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 is used to set the default apt cache size; increase as prompted
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
# Update, upgrade, and install software
# Check network connectivity
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"
# Install language packs and generate locale; exit if installation fails
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
# Cleanup
echo "Cleaning up"
rm -f ${FILE}
echo "All done."
echo "You can switch to ${DIST_FULLNAME} with \"chroot ${TARGET_PATH} /bin/bash\""