#!/bin/sh
ROOT_DIR=/compat
DIST=rocky
DIST_FULLNAME="Rocky Linux"
VER=10
SUB_VER=2
TIME_VER="latest"
SORT=Base
FILE=Rocky-${VER}-WSL-${SORT}.${TIME_VER}.x86_64.wsl
SUBDIR=""
URL=https://mirrors.ustc.edu.cn/${DIST}/${VER}.${SUB_VER}/images/x86_64
UPDATE_CMD="dnf makecache"
UPGRADE_CMD="dnf upgrade -y"
INSTALL_CMD="dnf install -y"
UPDATE=1
UPGRADE=1
INSTALL=1
# Create target directory in advance
TARGET_PATH="${ROOT_DIR}/${DIST}"
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. Check if checksum file exists
if [ ! -f "CHECKSUM" ]; then
echo "Error: CHECKSUM file is missing." >&2
return 1
fi
# 3. Extract the expected hash value for the corresponding file from CHECKSUM
local expected_hash
expected_hash=$(grep "(${FILE})" CHECKSUM | awk '{print $NF}')
if [ -z "${expected_hash}" ]; then
echo "Warning: No checksum found for ${FILE} in CHECKSUM file." >&2
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
echo " -> Status: [ OK ] Checksum matched perfectly."
return 0
else
echo " -> Status: [ FAILED ] Checksum mismatch!"
return 1
fi
}
# Core prerequisite: download the latest CHECKSUM verification manifest
echo "Updating verification manifest (CHECKSUM)..."
fetch "${URL}/CHECKSUM"
if [ ! -f "CHECKSUM" ]; then
echo "Critical Error: Failed to download CHECKSUM manifest from remote server." >&2
exit 1
fi
# Step 1: Check if a valid file already exists locally
if check_integrity; then
echo "Skipping download as valid archive is already present."
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 "Cleaning up corrupted cache and retrying download 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: Installation aborted due to persistent checksum failures." >&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
# 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 \
-e "s|^mirrorlist=|#mirrorlist=|g" \
-e "s|^#baseurl=http://dl.rockylinux.org/\$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g" \
-i.bak \
/etc/yum.repos.d/rocky-extras.repo \
/etc/yum.repos.d/rocky.repo'
;;
[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
# In FreeBSD, the unit of ping -W parameter is milliseconds
if ping -c 1 -W 3000 223.5.5.5 > /dev/null 2>&1; then
echo "Network reachable, starting package operations..."
# 1. Update package cache
if [ "$UPDATE" = "1" ]; then
echo "Updating package cache..."
chroot "${TARGET_PATH}" /bin/bash -c "${UPDATE_CMD}" || exit 1
fi
# 2. Upgrade system packages
if [ "$UPGRADE" = "1" ]; then
echo "Upgrading system packages..."
chroot "${TARGET_PATH}" /bin/bash -c "${UPGRADE_CMD}" || exit 1
fi
# 3. Install tools and language packs
if [ "$INSTALL" = "1" ]; then
echo "Installing nano and language packs..."
chroot "${TARGET_PATH}" /bin/bash -c "${INSTALL_CMD} nano langpacks-en glibc-all-langpacks" || exit 1
fi
else
echo "Network unreachable, skipping updates 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\""