|
|
楼主 |
发表于 2026-2-8 17:55
|
显示全部楼层
#!/bin/bash
#================================================================================================
#
# This file is licensed under the terms of the GNU General PublicF
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the remake fnnas
# https://github.com/ophub/fnnas
#
# Function: Install fnnas to eMMC for Amlogic box
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2022- https://github.com/7Ji/ampart
# Copyright (C) 2021- https://github.com/ophub/fnnas
#
# Command: fnnas-install [-m yes/no] [-a yes/no] [-l yes/no]
# Optional parameters: -m = use mainline u-boot (default: no)
# -a = use ampart partition table adjustment tool (default: yes)
# -l = show a list of all devices (default: no)
#
# Examples:
# Use mainline u-boot : fnnas-install -m yes
# Disable ampart tool : fnnas-install -a no
# Show all available devices: fnnas-install -l yes
#
#======================================== Functions list ========================================
#
# error_msg : Output error message
# check_depends : Check dependencies
# init_var : Initialize all variables
# ampart_tool : Repartition using ampart
# search_aml_model : Search the model list
# show_aml_model : Display the model list
# show_partition_menu : Display disk option info
# partition_sizing : Determine partition sizes
# create_partition : Create emmc partition
# copy_bootfs : Copy bootfs partition files
# copy_rootfs : Copy rootfs partition files
#
#==================================== Set default parameters ====================================
#
# Use mainline u-boot by default (-m)
auto_mainline_uboot="no"
# Use ampart partition tool by default (-a)
use_ampart="no"
# Show all device list by default (-l)
show_all_list="no"
# Set install list profile
model_conf="/etc/model_database.conf"
# Add custom fnnas firmware information
ophub_release_file="/etc/ophub-release"
# Add fnnas configuration file
fnnas_conf="/etc/fnnas.conf"
# Set the installation file preprocessing directory
tmp_path="/ddbr"
# Set font color
STEPS="[\033[95m STEPS \033[0m]"
INFO="[\033[94m INFO \033[0m]"
SUCCESS="[\033[92m SUCCESS \033[0m]"
OPTIONS="[\033[93m OPTIONS \033[0m]"
ERROR="[\033[91m ERROR \033[0m]"
IDX="\033[4;93m3\033[0m"
#
#================================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "${ERROR} ${1}"
exit 1
}
# Check dependencies
check_depends() {
echo -e "${STEPS} Checking dependencies..."
is_missing="0"
necessary_packages=("tar" "hexdump" "mkfs.vfat" "mkfs.ext4" "mkfs.btrfs" "parted" "losetup" "fdisk" "lsblk")
install_packages=("tar" "bsdextrautils" "dosfstools" "e2fsprogs" "btrfs-progs" "parted" "mount" "fdisk" "util-linux")
i="1"
for package in ${necessary_packages}; do
[[ -n "$(which "${package}" 2>/dev/null)" ]] || is_missing="1"
((i++))
done
if [[ "${is_missing}" -eq "1" ]]; then
echo -e "${INFO} Installing necessary dependencies."
sudo apt-get update
sudo apt-get install -y ${install_packages}
[[ "${?}" -eq "0" ]] || error_msg "Failed to install dependencies, aborting!"
else
echo -e "${INFO} Dependency check completed. Proceeding installation..."
fi
}
# Initialize all variables
init_var() {
echo -e "${STEPS} Initializing the environment..."
# If it is followed by [ : ], it means that the option requires a parameter value
get_all_ver="$(getopt "m:a:l:" "${@}")"
while [[ -n "${1}" ]]; do
case "${1}" in
-m | --Mainline_u-boot)
if [[ -n "${2}" ]]; then
[[ "${2}" == "yes" ]] && auto_mainline_uboot="yes" || auto_mainline_uboot="no"
shift
else
error_msg "Invalid -m parameter [ ${2} ]!"
fi
;;
-a | --Ampart_tool)
if [[ -n "${2}" ]]; then
[[ "${2}" == "yes" ]] && use_ampart="yes" || use_ampart="no"
shift
else
error_msg "Invalid -a parameter [ ${2} ]!"
fi
;;
-l | --List_all)
if [[ -n "${2}" ]]; then
[[ "${2}" == "yes" ]] && show_all_list="yes" || show_all_list="no"
shift
else
error_msg "Invalid -l parameter [ ${2} ]!"
fi
;;
*)
error_msg "Invalid option [ ${1} ]!"
;;
esac
shift
done
# Display settings results
echo -e "${INFO} Use mainline u-boot: [ ${auto_mainline_uboot} ]"
echo -e "${INFO} Use ampart tool: [ ${use_ampart} ]"
echo -e "${INFO} Show all devices: [ ${show_all_list} ]"
# Find a list of devices of the same family
SEARCH_FAMILY=""
[[ "${show_all_list}" == "no" ]] && {
[[ -s "${ophub_release_file}" ]] || error_msg "[ ${ophub_release_file} ] file is missing!"
source "${ophub_release_file}" && SEARCH_FAMILY="$(basename ${FAMILY})"
[[ -n "${SEARCH_FAMILY}" ]] && SEARCH_FAMILY=" {SEARCH_FAMILY}:"
}
# Check if the ${fnnas_conf} file exists
if [[ -f "${fnnas_conf}" ]]; then
source "${fnnas_conf}"
else
# Set root partition size limit (Unit: GiB)
echo "rootfs_limit_gib=\"16\"" >"${fnnas_conf}"
echo "rootfs_resize=\"yes\"" >>"${fnnas_conf}"
rootfs_limit_gib="16"
rootfs_resize="yes"
fi
# Ensure variables are set
[[ -n "${rootfs_limit_gib}" ]] || rootfs_limit_gib="16"
[[ -n "${rootfs_resize}" ]] || rootfs_resize="yes"
MG="${rootfs_limit_gib}GiB"
# Check if the ${model_conf} file exists
[[ -s "${model_conf}" ]] || error_msg "[ ${model_conf} ] file is missing!"
model_database="$(cat ${model_conf} | sed -e 's/NA//g' -e 's/NULL//g' -e 's/[ ][ ]*//g' | grep -E "^[0-9]{1,3}:.*${SEARCH_FAMILY}.*")"
if [[ -z "${model_database}" ]]; then
if [[ "${SEARCH_FAMILY}" == ":meson-gxbb:" ]]; then
error_msg "The [ s905 ] series do not support writing to eMMC. Please use it via USB."
else
error_msg "The [ ${SEARCH_FAMILY} ] series in the [ ${model_conf} ] file is empty and does not support write to eMMC!"
fi
fi
# Check if current system is booted from eMMC
root_devname="$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print substr($3, 1, length($3)-2)}')"
if lsblk -l | grep -E "^${root_devname}boot0" >/dev/null; then
error_msg "Current system is already installed to eMMC!"
fi
# Find emmc disk, first find emmc containing boot0 partition
install_emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?boot0)' | sed "s/boot0//g")"
# Find emmc disk, find emmc that does not contain the boot0 partition
[[ -z "${install_emmc}" ]] && install_emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?)' | grep -vE ^${root_devname} | sort -u)"
# Check if emmc exists
[[ -z "${install_emmc}" ]] && error_msg "Internal eMMC storage was't found in this device!"
# Location of emmc
DEV_EMMC="/dev/${install_emmc}"
echo -e "${INFO} Internal eMMC : [ ${DEV_EMMC} ]"
# Create a file preprocessing directory
DIR_INSTALL="${tmp_path}/install"
[[ -d "${DIR_INSTALL}" ]] && rm -rf ${DIR_INSTALL}
mkdir -p ${DIR_INSTALL} && chmod 777 ${tmp_path}
# Regenerate new machine-id
rm -f /etc/machine-id /var/lib/dbus/machine-id
dbus-uuidgen --ensure=/etc/machine-id
dbus-uuidgen --ensure
# Generate New BOOT_UUID
BOOT_UUID="$(cat /proc/sys/kernel/random/uuid)"
[[ -z "${BOOT_UUID}" ]] && BOOT_UUID="$(uuidgen)"
[[ -z "${BOOT_UUID}" ]] && error_msg "The uuidgen is invalid, cannot continue."
FAT_ID_RAW=$(echo "${BOOT_UUID}" | tr -d '-' | cut -c1-8)
FAT_ID_FSTAB=$(echo "${FAT_ID_RAW}" | awk '{print toupper(substr($0,1,4) "-" substr($0,5,4))}')
# Generate New ROOTFS UUID
ROOTFS_UUID="$(cat /proc/sys/kernel/random/uuid)"
[[ -z "${ROOTFS_UUID}" ]] && ROOTFS_UUID="$(uuidgen)"
[[ -z "${ROOTFS_UUID}" ]] && error_msg "The new UUID is invalid, cannot continue."
# Get kernel TEXT_OFFSET, For u-boot.ext and u-boot.emmc
# With TEXT_OFFSET patch is [ 0108 ], without TEXT_OFFSET patch is [ 0000 ] and need to ues [ UBOOT_OVERLOAD ] file.
NEED_OVERLOAD="yes"
[[ "$(hexdump -n 15 -x "/boot/zImage" 2>/dev/null | head -n 1 | awk '{print $7}')" == "0108" ]] && NEED_OVERLOAD="no"
}
# Project repository: https://github.com/7Ji/ampart
# Download from: https://github.com/7Ji/ampart/re ... 2-aarch64-static.gz
# Function description: ampart is a partitioning tool which can modify the proprieary partition table on internal eMMC.
ampart_tool() {
# declare the partition layout
local snapshot_expected='data::-1:4'
# Note there's no quote around ${snapshot_expected}
ampart "${DEV_EMMC}" --mode dclone ${snapshot_expected} &>/dev/null
if ((${?})); then
# Handle the situation where ampart fails to change the layout
return 1
fi
local log="$(ampart "${DEV_EMMC}" --mode dsnapshot 2>/dev/null)"
if ((${?})); then
# Handle the situation where ampart fails to read the new partitions
return 2
fi
local snapshots
readarray -d $'\n' -t snapshots <<<"${log}"
# compare snapshots, 0 here refers to the decimal one
if [[ "${snapshots[0]}" == "${snapshot_expected}" ]]; then
# Successfully written the partitions
return 0
else
# Result partitions different, maybe should handle it
return 3
fi
}
# Search the model list
search_aml_model() {
local search_soc_id="${1}"
local ret_count="$(echo "${model_database}" | grep -E "^${search_soc_id}:" | wc -l)"
if [[ "${ret_count}" -eq "1" ]]; then
echo "${model_database}" | grep -E "^${search_soc_id}:"
fi
}
# Functions: Displays a list of supported amlogic devices
# Configure: View ${model_database}
# 1.ID 2.MODEL 3.SOC 4.FDTFILE 5.UBOOT_OVERLOAD 6.MAINLINE_UBOOT 7.BOOTLOADER_IMG 8.DESCRIPTION
# 9.KERNEL_TAGS 10.PLATFORM 11.FAMILY 12.BOOT_CONF 13.CONTRIBUTORS 14.BOARD 15.BUILD
show_aml_model() {
echo -e "${STEPS} Start selecting device..."
# Define split line style
split_line="-----------------------------------------------------------------------------------------------------"
# Print header information
printf "%-s\n" "${split_line}"
printf "%-5s %-10s %-45s %-50s\n" ID SOC MODEL DTB
printf "%-s\n" "${split_line}"
# Print device list
echo "${model_database}" | awk -F':' '{print $1,$3,$2,$4}' | while read line; do
# Print device information
printf "%-5s %-10s %-45s %-50s\n" $(echo "${line}")
# Add a split line every 10 lines
[[ "$(echo ${line} | awk '{print $1}')" == *"0" ]] && printf "%-s\n" "${split_line}"
done
# Print custom options and end split lines
printf "%-5s %-10s %-45s %-50s\n" 0 Other Customize Enter-custom-dtb-name
printf "%-s\n" "${split_line}"
# Display device options
echo -ne "${OPTIONS} Please Input ID: "
read boxid
if [[ "${boxid}" -eq "0" ]]; then
read -p " lease Input SoC Name(such as s9xxx): " AMLOGIC_SOC
AMLOGIC_SOC="${AMLOGIC_SOC}"
#
read -p " lease Input DTB Name(such as meson-xxx.dtb): " FDTFILE
FDTFILE="${FDTFILE}"
#
read -p " lease Input UBOOT_OVERLOAD Name(such as u-boot-xxx.bin): " UBOOT_OVERLOAD
UBOOT_OVERLOAD="${UBOOT_OVERLOAD}"
#
read -p " lease Input MAINLINE_UBOOT Name(such as xxx-u-boot.bin.sd.bin): " MAINLINE_UBOOT
MAINLINE_UBOOT="${MAINLINE_UBOOT}"
#
read -p " lease Input BOOTLOADER_IMG Name(such as xxx-bootloader.img): " BOOTLOADER_IMG
BOOTLOADER_IMG="${BOOTLOADER_IMG}"
else
ret="$(search_aml_model "${boxid}")"
[[ -z "${ret}" ]] && error_msg "Input error, exit!"
MODEL_NAME="$(echo "${ret}" | awk -F ':' '{print $2}')"
AMLOGIC_SOC="$(echo "${ret}" | awk -F ':' '{print $3}')"
FDTFILE="$(echo "${ret}" | awk -F ':' '{print $4}')"
UBOOT_OVERLOAD="$(echo "${ret}" | awk -F ':' '{print $5}')"
MAINLINE_UBOOT="$(echo "${ret}" | awk -F ':' '{print $6}')"
BOOTLOADER_IMG="$(echo "${ret}" | awk -F ':' '{print $7}')"
fi
echo -e "${INFO} Input Box ID: [ ${boxid} ]"
echo -e "${INFO} Model Name: [ ${MODEL_NAME} ]"
echo -e "${INFO} FDTFILE: [ ${FDTFILE} ]"
echo -e "${INFO} MAINLINE_UBOOT: [ ${MAINLINE_UBOOT} ]"
echo -e "${INFO} BOOTLOADER_IMG: [ ${BOOTLOADER_IMG} ]"
echo -e "${INFO} UBOOT_OVERLOAD: [ ${UBOOT_OVERLOAD} ]"
echo -e "${INFO} NEED_OVERLOAD: [ ${NEED_OVERLOAD} ]"
# Check dtb file
[[ -n "${FDTFILE}" && -f "/boot/dtb/amlogic/${FDTFILE}" ]] || error_msg "The [ ${FDTFILE} ] is missing, aborting!"
# Check UBOOT_OVERLOAD file
[[ -n "${UBOOT_OVERLOAD}" && -f "/boot/${UBOOT_OVERLOAD}" ]] || error_msg "The [ ${UBOOT_OVERLOAD} ] is missing, aborting!"
}
# Show partition menu
show_partition_menu() {
cat <<EOF
┌────────────────────────────────────────────────────────────────────────┐
│ Remaining disk space is greater than ${MG}. │
├───────────┬────────────────────────────────────────────────────────────┤
│ Optional │ Description │
├───────────┼────────────────────────────────────────────────────────────┤
│ 1 │ Rootfs partition limit to ${MG}. │
│ 2 │ [default] Rootfs partition expand to full disk (100%). │
│ 3 │ Retain current Rootfs size (Preserve P3 Data). │
│ ≥16 │ Enter a number (GiB) to specify Rootfs partition size. │
└───────────┴────────────────────────────────────────────────────────────┘
EOF
}
# Determine partition sizes
partition_sizing() {
# Use the ampart partition tool
AMPART_STATUS="no"
[[ -x "/usr/bin/ampart" && "${use_ampart}" == "yes" ]] && {
ampart_tool
[[ "${?}" -eq "0" ]] && AMPART_STATUS="yes" && echo -e "${STEPS} Successfully partitioned internal eMMC with amaprt."
}
# Set partition size (Unit: MiB)
if [[ "${AMPART_STATUS}" == "yes" ]]; then
BLANK1="117" # After using the ampart to part disk, space after [ 117 MiB ] could be used.
BOOT="512"
BLANK2="0"
elif [[ "${AMLOGIC_SOC}" == "s912" && "${boxid}" -eq "213" ]]; then
BLANK1="700" # OneCloudPro-V1.2
BOOT="512"
BLANK2="220"
elif [[ "${AMLOGIC_SOC}" == "s912" && "${boxid}" -eq "214" ]]; then
BLANK1="256" # new OneCloudPro-V1.2 based on base image android_tv_onethingcloud-money-maker-pro-3rd-s912.tar.xz
BOOT="256"
BLANK2="0"
elif [[ "${AMLOGIC_SOC}" == "s912" || "${AMLOGIC_SOC}" == "s905d" ]]; then
BLANK1="68"
BOOT="512"
BLANK2="220"
elif [[ "${AMLOGIC_SOC}" == "s905x" ]]; then
BLANK1="700"
BOOT="512"
BLANK2="0"
elif [[ "${AMLOGIC_SOC}" == "s905l3a" && "${boxid}" -eq "304" ]]; then
BLANK1="570" # e900v22c/d: The first [ 570 MiB ] is not writable.
BOOT="512"
BLANK2="0"
elif [[ "${AMLOGIC_SOC}" == "s905l3a" && "${boxid}" -eq "305" ]]; then
BLANK1="108" # CM311-1a-YST: Must skip [ 108 MiB ]
BOOT="512" # A total of [ 1024 MiB ] can be used in this block, gave up [ 1024-512=512 MiB ]
BLANK2="778" # Rootfs partition could be set after [ 1398 MiB ] of the total disk, Multi-backward offset 100 MiB, [ 1398-108-512=778 MiB ]
elif [[ "${AMLOGIC_SOC}" == "s905l3b" ]]; then
BLANK1="128" # https://github.com/janko888/MBH-M30xA
BOOT="513" # M302A/M304A, Compatible with Android 4 and Android 9 firmware
BLANK2="720"
elif [[ "${FDTFILE}" == "meson-sm1-skyworth-lb2004-a4091.dtb" ]]; then
BLANK1="108" # Tencent Aurora 3Pro: Must skip [ 108 MiB ]
BOOT="512" # A total of [ 768 MiB ] can be used in this block, gave up [ 768-512=256 MiB ]
BLANK2="562" # Rootfs partition could be set after [ 1182 MiB ] of the total disk, [ 1182-108-512=562 MiB ]
elif [[ "${boxid}" -eq "525" ]]; then
BLANK1="108" # Whale(S905X3): Must skip [ 108 MiB ]
BOOT="512" # A total of [ 1024 MiB ] can be used in this block, gave up [ 1024-512=512 MiB ]
BLANK2="650" # Rootfs partition could be set after [ 1270 MiB ] of the total disk, [ 1270-108-512=650 MiB ]
elif [[ "${boxid}" -eq "409" || "${boxid}" -eq "410" ]]; then
BLANK1="700" # WXY-OES(A311D), WXY-OES-Plus(s922x): Must skip [ 700 MiB ]
BOOT="512"
BLANK2="0"
else
BLANK1="68"
BOOT="512" # S905x3: A total of [ 1120 MiB ] can be used in this block, and the remaining [ 608 MiB ] can be used.
BLANK2="770" # Rootfs partition could be set after [ 1350 MiB ] of the total disk.
fi
# Calculate partition size limits(Unit: MiB)
ROOTFS_START_MiB="$((BLANK1 + BOOT + BLANK2))"
MAX_SIZE_MiB="$((rootfs_limit_gib * 1024))"
TARGET_END_MiB="$((ROOTFS_START_MiB + MAX_SIZE_MiB))"
# Calculate target end position in bytes
TARGET_END_BYTES="$((TARGET_END_MiB * 1024 * 1024))"
# Get disk size in bytes
DISK_SIZE_BYTES="$(lsblk -b -n -o SIZE -d "${DEV_EMMC}")"
[[ "${DISK_SIZE_BYTES}" =~ ^[0-9]+$ ]] || DISK_SIZE_BYTES="0"
[[ "${DISK_SIZE_BYTES}" -le "0" ]] && error_msg "Failed to get eMMC disk size."
# Calculate the remaining disk space size
FREE_SIZE_BYTES="$((DISK_SIZE_BYTES - (ROOTFS_START_MiB * 1024 * 1024)))"
FREE_SIZE_GiB="$((FREE_SIZE_BYTES / 1024 / 1024 / 1024))"
echo -e "${INFO} eMMC Disk Free Size: [ ${FREE_SIZE_GiB}GiB ]."
# Detect current P3 size if it exists
if lsblk "${DEV_EMMC}p3" >/dev/null 2>&1; then
# Get P2 size in bytes
P2_SIZE_BYTES="$(lsblk -b -n -o SIZE "${DEV_EMMC}p2" | head -n1)"
# Convert to GiB for display
P2_SIZE_GiB="$((P2_SIZE_BYTES / 1024 / 1024 / 1024))"
# Try to get exact end position from parted
P2_END_EXACT="$(parted -s "${DEV_EMMC}" unit B print 2>/dev/null | grep "^ 2" | awk '{print $3}' | tr -d 'B')"
# Get P3 size in bytes
P3_SIZE_BYTES="$(lsblk -b -n -o SIZE "${DEV_EMMC}p3" | head -n1)"
# Convert to GiB for display
P3_SIZE_GiB="$((P3_SIZE_BYTES / 1024 / 1024 / 1024))"
fi
# Default root end position
ROOTFS_END="100%"
# Select partition expansion strategy
if [[ "${FREE_SIZE_BYTES}" -gt "${TARGET_END_BYTES}" ]]; then
if [[ -n "${P2_END_EXACT}" && "${P3_SIZE_GiB}" -ge "1" ]]; then
show_partition_menu
echo -e "${INFO} Found System Partition (P2): ${P2_SIZE_GiB} GiB, Data Partition (P3): ${P3_SIZE_GiB} GiB."
echo -e " Input ${IDX} to inherit current partition layout and PRESERVE data on P3."
echo -ne "${OPTIONS} Please Input ID(1/2/3) or Size(16 ~ ${FREE_SIZE_GiB}): "
else
show_partition_menu | grep -v '│ 3 │'
echo -ne "${OPTIONS} Please Input ID(1/2) or Size(16 ~ ${FREE_SIZE_GiB}): "
fi
read deskid
# Validate user input
deskid="$(echo "${deskid}" | tr -cd '0-9.' | cut -d. -f1)"
[[ -z "${deskid}" || ! "${deskid}" =~ ^[0-9]+$ ]] && deskid="2"
echo -e "${INFO} Input ID or Size: [ ${deskid} ]"
# Determine partition expansion strategy
if [[ "${deskid}" == "1" ]]; then
ROOTFS_END="${TARGET_END_MiB}MiB"
echo -e "${INFO} Strategy: Limit Rootfs to ${rootfs_limit_gib}GiB."
elif [[ "${deskid}" == "2" ]]; then
ROOTFS_END="100%"
echo -e "${INFO} Strategy: Expand Rootfs to Full Disk."
elif [[ "${deskid}" == "3" && -n "${P2_END_EXACT}" ]]; then
ROOTFS_END="${P2_END_EXACT}B"
echo -e "${INFO} Strategy: Keeping exact previous partition layout to preserve P3."
elif [[ "${deskid}" -ge "${rootfs_limit_gib}" && "${deskid}" -le "${FREE_SIZE_GiB}" ]]; then
CUSTOM_SIZE_MiB="$((deskid * 1024))"
ROOTFS_END="$((ROOTFS_START_MiB + CUSTOM_SIZE_MiB))MiB"
echo -e "${INFO} Strategy: Custom Rootfs size to ${deskid}GiB."
else
ROOTFS_END="100%"
echo -e "${INFO} Strategy: Expand Rootfs to Full Disk."
fi
fi
}
# Nuclear re-partition function
redo_partitions() {
echo -e "${INFO} Re-initializing partition table (Nuclear Option)..."
# Stop all active LVM/RAID groups
vgchange -an >/dev/null 2>&1
dmsetup remove_all >/dev/null 2>&1
mdadm --stop --scan >/dev/null 2>&1
# Unmount everything forcefully
for i in $(seq 1 16); do
umount -f "${DEV_EMMC}p${i}" >/dev/null 2>&1
umount -l "${DEV_EMMC}p${i}" >/dev/null 2>&1
done
# Violently clear MBR (To break the kernel lock)
dd if=/dev/zero of="${DEV_EMMC}" bs=512 count=1 conv=fsync 2>/dev/null
sync
partprobe "${DEV_EMMC}" 2>/dev/null
sleep 3
# Recreate all partitions
parted -s "${DEV_EMMC}" mklabel msdos
parted -s "${DEV_EMMC}" mkpart primary fat32 $((BLANK1))MiB $((BLANK1 + BOOT - 1))MiB
parted -s "${DEV_EMMC}" mkpart primary btrfs ${ROOTFS_START_MiB}MiB ${ROOTFS_END}
}
# Create emmc partition
create_partition() {
cd /
echo -e "${STEPS} Partitioning eMMC..."
# Backup the bootloader, necessary for system recovery
[[ -d "/usr/lib/u-boot" ]] || mkdir -p /usr/lib/u-boot
MYBOX_UBOOT="/usr/lib/u-boot/mybox-bootloader.img"
if [[ ! -f "${MYBOX_UBOOT}" ]]; then
echo -e "${INFO} Start backing up the default bootloader."
dd if="${DEV_EMMC}" of="${MYBOX_UBOOT}" bs=1M count=4 conv=fsync
[[ "${?}" -eq "0" ]] || error_msg "Using dd to backup [ ${MYBOX_UBOOT} ] failed."
else
MAGIC_SIG="$(head -c 512 "${MYBOX_UBOOT}" 2>/dev/null | tail -c 2 | hexdump -e '1/1 "%02x"' 2>/dev/null || true)"
if [[ "${MAGIC_SIG}" != "55aa" ]]; then
echo -e "${INFO} Existing backup is invalid (No 55aa signature). Re-backing up..."
dd if="${DEV_EMMC}" of="${MYBOX_UBOOT}" bs=1M count=4 conv=fsync
[[ "${?}" -eq "0" ]] || error_msg "Using dd to backup [ ${MYBOX_UBOOT} ] failed."
else
echo -e "${INFO} Bootloader backup file [ ${MYBOX_UBOOT} ] already exists."
fi
fi
echo -e "${INFO} Checking and stopping active LVM/RAID groups..."
# Stop all active LVM/RAID groups
vgchange -an >/dev/null 2>&1
dmsetup remove_all >/dev/null 2>&1
mdadm --stop --scan >/dev/null 2>&1
# Unmount all mounted partitions on the eMMC
for i in $(seq 1 16); do
if lsblk "${DEV_EMMC}p${i}" >/dev/null 2>&1; then
umount -f "${DEV_EMMC}p${i}" >/dev/null 2>&1
umount -l "${DEV_EMMC}p${i}" >/dev/null 2>&1
fi
done
# Try to wipe existing filesystem signatures
if command -v wipefs >/dev/null 2>&1; then
# Wipe first two partitions only (Do NOT wipe the main device/MBR)
for i in 1 2; do
[[ -b "${DEV_EMMC}p${i}" ]] && wipefs -a "${DEV_EMMC}p${i}" >/dev/null 2>&1
done
fi
sync
partprobe "${DEV_EMMC}" 2>/dev/null
sleep 3
# Clear emmc disk data (Modified to preserve Partition 3+)
echo -e "${INFO} Deleting only BOOT and ROOTFS partitions (p1, p2)..."
for i in 1 2; do
if lsblk "${DEV_EMMC}p${i}" >/dev/null 2>&1; then
parted -s ${DEV_EMMC} rm ${i}
[[ "${?}" -eq "0" ]] || error_msg "Failed to delete partition [ ${i} ]."
echo -e "${INFO} Partition ${i} deleted."
fi
done
echo -e "${INFO} Start creating partitions..."
if ! parted -s "${DEV_EMMC}" print >/dev/null 2>&1; then
echo -e "${INFO} No partition table found. Creating msdos label."
parted -s "${DEV_EMMC}" mklabel msdos
else
echo -e "${INFO} Partition table exists. Trying to preserve partition 3+..."
fi
# Create BOOTFS partition
P1_RECREATED="no"
echo -e "${INFO} Creating BOOTFS partition..."
if ! parted -s "${DEV_EMMC}" mkpart primary fat32 $((BLANK1))MiB $((BLANK1 + BOOT - 1))MiB 2>/dev/null; then
echo -e "${INFO} Failed to create BOOTFS partition. Invoking Nuclear Re-partition..."
redo_partitions
[[ "${?}" -eq "0" ]] || error_msg "Failed to create BOOTFS partition after MBR wipe."
P1_RECREATED="yes"
fi
# Create Rootfs partition
if [[ "${P1_RECREATED}" != "yes" ]]; then
echo -e "${INFO} Creating Rootfs partition..."
if ! parted -s "${DEV_EMMC}" mkpart primary btrfs ${ROOTFS_START_MiB}MiB ${ROOTFS_END} 2>/dev/null; then
echo -e "${INFO} Overlap detected. Invoking Nuclear Re-partition to apply new size..."
redo_partitions
[[ "${?}" -eq "0" ]] || error_msg "Failed to create Rootfs partition after re-initialization."
fi
fi
# Inform the kernel of partition table changes
sync
partprobe "${DEV_EMMC}" 2>/dev/null
sleep 3
# Write bootloader
if [[ -n "${MAINLINE_UBOOT}" && -f "/usr/lib/u-boot/${MAINLINE_UBOOT}" && "${auto_mainline_uboot}" == "yes" ]]; then
echo -e "${INFO} 01. Write Mainline bootloader: [ ${MAINLINE_UBOOT} ]"
dd if="/usr/lib/u-boot/${MAINLINE_UBOOT}" of="${DEV_EMMC}" conv=fsync bs=1 count=444
dd if="/usr/lib/u-boot/${MAINLINE_UBOOT}" of="${DEV_EMMC}" conv=fsync bs=512 skip=1 seek=1
elif [[ -n "${BOOTLOADER_IMG}" && -f "/usr/lib/u-boot/${BOOTLOADER_IMG}" ]]; then
echo -e "${INFO} 02. Write Android bootloader: [ ${BOOTLOADER_IMG} ]"
dd if="/usr/lib/u-boot/${BOOTLOADER_IMG}" of="${DEV_EMMC}" conv=fsync bs=1 count=444
dd if="/usr/lib/u-boot/${BOOTLOADER_IMG}" of="${DEV_EMMC}" conv=fsync bs=512 skip=1 seek=1
elif [[ -n "${MYBOX_UBOOT}" && -f "${MYBOX_UBOOT}" ]]; then
echo -e "${INFO} 03. Write the mybox bootloader: [ ${MYBOX_UBOOT} ]"
dd if="${MYBOX_UBOOT}" of="${DEV_EMMC}" conv=fsync bs=1 count=444
dd if="${MYBOX_UBOOT}" of="${DEV_EMMC}" conv=fsync bs=512 skip=1 seek=1
fi
[[ "${?}" -eq "0" ]] || error_msg "Failed to write bootloader using [ dd ]."
# Generate a random disk signature and write it to the eMMC at offset 440
dd if=/dev/urandom of="${DEV_EMMC}" bs=1 count=4 seek=440 conv=notrunc status=none
sync && sleep 3
}
# Copy bootfs partition files
copy_bootfs() {
cd /
echo -e "${STEPS} Processing BOOTFS partition..."
PART_BOOT="${DEV_EMMC}p1"
if grep -q ${PART_BOOT} /proc/mounts; then
echo -e "${INFO} Unmounting BOOT partition."
umount -f ${PART_BOOT}
[[ "${?}" -eq "0" ]] || error_msg "Failed to umount [ ${PART_BOOT} ]."
fi
echo -e "${INFO} Formatting BOOTFS partition..."
sleep 1
mkfs.vfat -F 32 -i "${FAT_ID_RAW}" -n "BOOT_EMMC" ${PART_BOOT}
[[ "${?}" -eq "0" ]] || error_msg "Failed to format BOOTFS with [ mkfs.vfat ]."
mount -o rw ${PART_BOOT} ${DIR_INSTALL}
[[ "${?}" -eq "0" ]] || error_msg "Failed to mount BOOTFS partition."
echo -e "${INFO} Copying BOOTFS ..."
cp -rf /boot/* ${DIR_INSTALL}
# Remove useless files
rm -rf ${DIR_INSTALL}/'System Volume Information'
rm -f ${DIR_INSTALL}/s9*
rm -f ${DIR_INSTALL}/aml*
# Replace eMMC boot files
[[ -f "${DIR_INSTALL}/boot-emmc.scr" ]] && mv -f ${DIR_INSTALL}/boot-emmc.scr ${DIR_INSTALL}/boot.scr
[[ -f "${DIR_INSTALL}/boot-emmc.cmd" ]] && mv -f ${DIR_INSTALL}/boot-emmc.cmd ${DIR_INSTALL}/boot.cmd
[[ -f "${DIR_INSTALL}/boot-emmc.ini" ]] && mv -f ${DIR_INSTALL}/boot-emmc.ini ${DIR_INSTALL}/boot.ini
[[ -f "${DIR_INSTALL}/boot.ini" ]] && sed -i "s|u-boot.ext|u-boot.emmc|g" ${DIR_INSTALL}/boot.ini
# Set new rootfs mount string
uenv_mount_string="UUID=${ROOTFS_UUID} rootflags=compress=zstd:1 rootfstype=btrfs"
# Update [ /boot/uEnv.txt ] settings
uenv_conf_file="${DIR_INSTALL}/uEnv.txt"
[[ -f "${uenv_conf_file}" ]] && {
echo -e "${INFO} Update the [ uEnv.txt ] file."
BOOT_CONF="uEnv.conf"
sed -i "s|root=.*console=ttyAML0|root=${uenv_mount_string} console=ttyAML0|g" ${uenv_conf_file}
sed -i "s|meson.*.dtb|${FDTFILE}|g" ${uenv_conf_file}
}
# Update [ /boot/extlinux/extlinux.conf ] settings
boot_extlinux_file="${DIR_INSTALL}/extlinux/extlinux.conf"
[[ -f "${boot_extlinux_file}" ]] && {
echo -e "${INFO} Update the [ extlinux.conf ] file."
BOOT_CONF="extlinux.conf"
sed -i "s|root=.*console=ttyAML0|root=${uenv_mount_string} console=ttyAML0|g" ${boot_extlinux_file}
sed -i "s|meson.*.dtb|${FDTFILE}|g" ${boot_extlinux_file}
}
# Copy u-boot.ext and u-boot.emmc
if { [[ "${NEED_OVERLOAD}" == "yes" || "${auto_mainline_uboot}" == "yes" ]]; } &&
{ [[ -n "${UBOOT_OVERLOAD}" && -f "${DIR_INSTALL}/${UBOOT_OVERLOAD}" ]]; }; then
echo -e "${INFO} Copy [ ${UBOOT_OVERLOAD} ] to u-boot.emmc"
if [[ -f "${DIR_INSTALL}/u-boot.ext" ]]; then
cp -f ${DIR_INSTALL}/u-boot.ext ${DIR_INSTALL}/u-boot.emmc
else
cp -f ${DIR_INSTALL}/${UBOOT_OVERLOAD} ${DIR_INSTALL}/u-boot.ext
cp -f ${DIR_INSTALL}/${UBOOT_OVERLOAD} ${DIR_INSTALL}/u-boot.emmc
fi
chmod +x ${DIR_INSTALL}/u-boot.ext
chmod +x ${DIR_INSTALL}/u-boot.emmc
fi
sync && sleep 3
umount -f ${DIR_INSTALL}
[[ "${?}" -eq "0" ]] || error_msg "Failed to umount [ ${DIR_INSTALL} ]."
}
# Copy rootfs partition files
copy_rootfs() {
cd /
echo -e "${STEPS} Start processing the rootfs partition..."
PART_ROOT="${DEV_EMMC}p2"
if grep -q ${PART_ROOT} /proc/mounts; then
echo -e "${INFO} Unmounting ROOT partition."
umount -f ${PART_ROOT}
[[ "${?}" -eq "0" ]] || error_msg "Failed to umount [ ${PART_ROOT} ]."
fi
echo -e "${INFO} Formatting ROOTFS ..."
mkfs.btrfs -f -U ${ROOTFS_UUID} -L "ROOTFS_EMMC" -m single ${PART_ROOT}
[[ "${?}" -eq "0" ]] || error_msg "Failed to format ROOTFS with [ mkfs.btrfs ]"
mount -t btrfs -o compress=zstd:1 ${PART_ROOT} ${DIR_INSTALL}
[[ "${?}" -eq "0" ]] || error_msg "Failed to mount ROOTFS."
echo -e "${INFO} Copying ROOTFS ..."
# Create relevant directories
mkdir -p ${DIR_INSTALL}/{boot/,dev/,media/,mnt/,proc/,run/,sys/,tmp/}
chmod 1777 ${DIR_INSTALL}/tmp
# Copy the relevant directory
COPY_SRC="etc home opt root selinux srv usr var"
for src in ${COPY_SRC}; do
if [[ -d "${src}" ]]; then
echo -e "${INFO} Copying [ ${src} ] ..."
tar -cf - ${src} | (
cd ${DIR_INSTALL}
tar -xpf -
)
fi
done
# Create relevant symbolic link
ln -sf usr/bin ${DIR_INSTALL}/bin
ln -sf usr/lib ${DIR_INSTALL}/lib
ln -sf usr/sbin ${DIR_INSTALL}/sbin
echo -e "${INFO} Generate the new fstab file."
rm -f ${DIR_INSTALL}/etc/fstab
cat >${DIR_INSTALL}/etc/fstab <<EOF
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=${ROOTFS_UUID} / btrfs defaults,noatime,compress=zstd:1 0 1
UUID=${FAT_ID_FSTAB} /boot vfat defaults,noatime,errors=remount-ro 0 2
tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
echo -e "${INFO} Update parameters related to the releases file."
ophub_config_file="${DIR_INSTALL}${ophub_release_file}"
sed -i "s|^MODEL_ID=.*|MODEL_ID='${boxid}'|g" ${ophub_config_file}
sed -i "s|^MODEL_NAME=.*|MODEL_NAME='${MODEL_NAME}'|g" ${ophub_config_file}
sed -i "s|^SOC=.*|SOC='${AMLOGIC_SOC}'|g" ${ophub_config_file}
sed -i "s|^FDTFILE=.*|FDTFILE='${FDTFILE}'|g" ${ophub_config_file}
sed -i "s|^MAINLINE_UBOOT=.*|MAINLINE_UBOOT='/usr/lib/u-boot/${MAINLINE_UBOOT}'|g" ${ophub_config_file}
sed -i "s|^BOOTLOADER_IMG=.*|BOOTLOADER_IMG='/usr/lib/u-boot/${BOOTLOADER_IMG}'|g" ${ophub_config_file}
sed -i "s|^UBOOT_OVERLOAD=.*|UBOOT_OVERLOAD='${UBOOT_OVERLOAD}'|g" ${ophub_config_file}
sed -i "s|^ROOTFS_TYPE=.*|ROOTFS_TYPE='btrfs'|g" ${ophub_config_file}
sed -i "s|^BOOT_CONF=.*|BOOT_CONF='${BOOT_CONF}'|g" ${ophub_config_file}
sed -i "s|^DISK_TYPE=.*|DISK_TYPE='emmc'|g" ${ophub_config_file}
sed -i "s|^MLUBOOT_STATUS=.*|MLUBOOT_STATUS='${auto_mainline_uboot}'|g" ${ophub_config_file}
sed -i "s|^AMPART_STATUS=.*|AMPART_STATUS='${AMPART_STATUS}'|g" ${ophub_config_file}
# Update fnnas.conf to disable rootfs resize on first boot
echo -e "${INFO} Update parameters related to the fnnas configuration file."
fnnas_conf_file="${DIR_INSTALL}${fnnas_conf}"
sed -i "s|^rootfs_resize=.*|rootfs_resize=\"no\"|g" "${fnnas_conf_file}"
sync && sleep 3
umount -f ${DIR_INSTALL}
[[ "${?}" -eq "0" ]] || error_msg "Failed to umount [ ${DIR_INSTALL} ]."
}
# Check script permission
[[ "$(id -u)" == "0" ]] || error_msg " lease run this script as root: [ sudo $0 ]"
echo -e "${STEPS} Installing fnnas to internal eMMC..."
# Check dependencies
check_depends
# Initialize all variables
init_var "${@}"
# Display the model list
show_aml_model
# Determine partition sizes
partition_sizing
# Create emmc partition
create_partition
# Copy bootfs partition files
copy_bootfs
# Copy rootfs partition files
copy_rootfs
echo -e "${SUCCESS} Installation successful. Run [ poweroff ], remove the installation media then re-insert the power supply to boot new system."
exit 0
|
|