#!/bin/bash #====================================================================================== # Function: Install openwrt to emmc for Amlogic S9xxx STB # Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit # Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic #====================================================================================== # # The script supports directly setting parameters for installation, skipping interactive selection # openwrt-install-amlogic ${AUTO_MAINLINE_UBOOT} ${ID} ${FDTFILE}:${SOC}:${UBOOT_OVERLOAD} ${SHARED_FSTYPE} # E.g: openwrt-install-amlogic yes 11 auto ext4 # E.g: openwrt-install-amlogic no 99 meson-gxl-s905d-phicomm-n1.dtb:s905d:u-boot-n1.bin ext4 # Tip: When custom dtb file, set ${SOC_ID} to 99, and parameter ${FDTFILE}:${SOC}:${UBOOT_OVERLOAD} must be set # Tip: ${SHARED_FSTYPE}: Shared partition can be ext4, xfs, btrfs, f2fs # You can also execute the script directly, and interactively select related functions # E.g: openwrt-install-amlogic # #====================================================================================== # Encountered a serious error, abort the script execution error_msg() { echo -e "[ERROR] ${1}" exit 1 } # Get the partition name of the root file system get_root_partition_name() { local paths=("/" "/overlay" "/rom") local partition_name for path in "${paths[@]}"; do partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}') [[ -n "${partition_name}" ]] && break done [[ -z "${partition_name}" ]] && error_msg "Cannot find the root partition!" echo "${partition_name}" } # Receive one-key command related parameters AUTO_MAINLINE_UBOOT="${1}" ZSTD_LEVEL="6" op_release="/etc/flippy-openwrt-release" # For [luci-app-amlogic] input parameter: DTB, SOC & UBOOT_OVERLOAD # When there is no input parameter, select manually SPECIFY_ID="" SPECIFY_SOC="" SPECIFY_DTB="" SPECIFY_UBOOT="" [[ -n "${2}" ]] && { SPECIFY_ID="${2}" if [[ "${2}" -eq "99" ]]; then if [[ -n "${3}" ]]; then # E.g: meson-gxl-s905d-phicomm-n1.dtb:s905d:u-boot-n1.bin SPECIFY_DTB="$(echo "${3}" | awk -F ':' '{print $1}')" SPECIFY_SOC="$(echo "${3}" | awk -F ':' '{print $2}')" SPECIFY_UBOOT="$(echo "${3}" | awk -F ':' '{print $3}')" else error_msg "Please enter the DTB file name!" fi fi } # shared partition can be ext4, xfs, btrfs, f2fs SHARED_FSTYPE="${4}" echo "AUTO_MAINLINE_UBOOT: ${AUTO_MAINLINE_UBOOT}" echo "SPECIFY_DTB: ${SPECIFY_DTB}" echo "SPECIFY_SOC: ${SPECIFY_SOC}" echo "SPECIFY_UBOOT: ${SPECIFY_UBOOT}" echo "SHARED_FSTYPE: ${SHARED_FSTYPE}" # Current device model MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') if [[ -z "${MYDEVICE_NAME}" ]]; then error_msg "The device name is empty and cannot be recognized." elif [[ ! -f "${op_release}" ]]; then error_msg "The [ ${op_release} ] file is missing." else echo -e "Current device: ${MYDEVICE_NAME} [ amlogic ]" sleep 3 fi # Find the device name of / root_devname="$(get_root_partition_name)" if lsblk -l | grep -E "^${root_devname}boot0" >/dev/null; then error_msg "you are running in emmc mode, please boot system with usb or tf card!" fi install_emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?boot0)' | sed "s/boot0//g")" if [[ "${install_emmc}" == "" ]]; then error_msg "No emmc can be found to install the openwrt system!" fi # EMMC DEVICE NAME EMMC_NAME="${install_emmc}" EMMC_DEVPATH="/dev/${EMMC_NAME}" echo ${EMMC_DEVPATH} EMMC_SIZE=$(lsblk -l -b -o NAME,SIZE | grep ${EMMC_NAME} | sort | uniq | head -n1 | awk '{print $2}') echo "${EMMC_NAME} : ${EMMC_SIZE} bytes" ROOT_NAME=$(lsblk -l -o NAME,MAJ:MIN,MOUNTPOINT | grep -e '/$' | awk '{print $1}') echo "ROOTFS: ${ROOT_NAME}" BOOT_NAME=$(lsblk -l -o NAME,MAJ:MIN,MOUNTPOINT | grep -e '/boot$' | awk '{print $1}') echo "BOOT: ${BOOT_NAME}" # box model database # The field separator is : # " " or "" or NA or NULL means this field is null # The fields list: # 1. id # 2. model name # 3. SOC # 4. FDTFILE # 5. UBOOT_OVERLOAD # 6. MAINLINE_UBOOT # 7. ANDROID_UBOOT # 8. brief description # # allow use external modal database if [[ -f "/etc/model_database.txt" ]]; then model_database="$(cat /etc/model_database.txt)" else error_msg "[ /etc/model_database.txt ] file is missing." fi function display_database() { while read -r line; do if [[ "$line" =~ ^# ]]; then # Process comment lines, starting with # line="${line/#+\s+/}" echo "$line >>>" else # Process data lines, starting with id IFS=':' read -r -a fields <<<"$line" printf "%5s %-48s%-10s%-s\n" "${fields[0]}" "${fields[1]}" "${fields[2]}" "${fields[7]}" fi done < <(echo "${model_database}") } function search_model() { local id="${1}" local ret_count="$(echo "${model_database}" | awk -F ':' "\$1~/^$id\$/ {print \$0}" | wc -l)" if [[ "${ret_count}" -eq "1" ]]; then echo "${model_database}" | awk -F ':' "\$1~/^$id\$/ {print \$0}" | sed -e 's/NA//g' -e 's/NULL//g' -e 's/[ ][ ]*//g' fi } echo "Please select s9xxx box model:" echo "----------------------------------------------------------------------------------------------------" display_database echo "----------------------------------------------------------------------------------------------------" # For [luci-app-amlogic] input parameter: SOC & DTB # When there is no input parameter, select manually if [[ -n "${SPECIFY_ID}" ]]; then boxtype="${SPECIFY_ID}" else echo -n "Please choose: " read boxtype fi if [[ "${boxtype}" -eq "99" ]]; then FDTFILE="${SPECIFY_DTB}" AMLOGIC_SOC="${SPECIFY_SOC}" UBOOT_OVERLOAD="${SPECIFY_UBOOT}" MAINLINE_UBOOT="" ANDROID_UBOOT="" elif [[ "${boxtype}" -eq "0" ]]; then read -p "Please Input SoC Name(such as s9xxx): " AMLOGIC_SOC AMLOGIC_SOC="${AMLOGIC_SOC}" read -p "Please Input DTB Name(such as meson-xxx.dtb): " FDTFILE FDTFILE="${FDTFILE}" read -p "Please Input UBOOT_OVERLOAD Name(such as u-boot-xxx.bin): " UBOOT_OVERLOAD UBOOT_OVERLOAD="${UBOOT_OVERLOAD}" read -p "Please Input MAINLINE_UBOOT Name(such as /lib/u-boot/xxx-u-boot.bin.sd.bin): " MAINLINE_UBOOT MAINLINE_UBOOT="${MAINLINE_UBOOT}" read -p "Please Input ANDROID_UBOOT Name(such as /lib/u-boot/xxx-bootloader.img): " ANDROID_UBOOT ANDROID_UBOOT="${ANDROID_UBOOT}" else ret="$(search_model ${boxtype})" if [[ -z "${ret}" ]]; then error_msg "Input error, exit!" fi # 3. soc # 4. FDTFILE # 5. UBOOT_OVERLOAD # 6. MAINLINE_UBOOT # 7. ANDROID_UBOOT 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}')" ANDROID_UBOOT="$(echo "${ret}" | awk -F ':' '{print $7}')" fi if [[ -z "${FDTFILE}" || ! -f "/boot/dtb/amlogic/${FDTFILE}" ]]; then error_msg "/boot/dtb/amlogic/${FDTFILE} does not exist!" fi echo "AMLOGIC_SOC Value [ ${AMLOGIC_SOC} ]" echo "FDTFILE Value [ ${FDTFILE} ]" echo "UBOOT_OVERLOAD Value [ ${UBOOT_OVERLOAD} ]" echo "MAINLINE_UBOOT Value [ ${MAINLINE_UBOOT} ]" echo "ANDROID_UBOOT Value [ ${ANDROID_UBOOT} ]" sed -i "s|^SOC=.*|SOC='${AMLOGIC_SOC}'|g" ${op_release} 2>/dev/null sed -i "s|^FDTFILE=.*|FDTFILE='${FDTFILE}'|g" ${op_release} 2>/dev/null sed -i "s|^UBOOT_OVERLOAD=.*|UBOOT_OVERLOAD='${UBOOT_OVERLOAD}'|g" ${op_release} 2>/dev/null sed -i "s|^MAINLINE_UBOOT=.*|MAINLINE_UBOOT='${MAINLINE_UBOOT}'|g" ${op_release} 2>/dev/null sed -i "s|^ANDROID_UBOOT=.*|ANDROID_UBOOT='${ANDROID_UBOOT}'|g" ${op_release} 2>/dev/null K510="1" [[ "$(hexdump -n 15 -x "/boot/zImage" 2>/dev/null | head -n 1 | awk '{print $7}')" == "0108" ]] && K510="0" echo -e "K510 [ ${K510} ]" # backup old bootloader if [[ ! -f "/root/BackupOldBootloader.img" ]]; then echo "Backup bootloader -> [ BackupOldBootloader.img ] ... " dd if=/dev/$EMMC_NAME of=/root/BackupOldBootloader.img bs=1M count=4 conv=fsync echo "Backup bootloader complete." echo fi swapoff -a # umount all other mount points MOUNTS=$(lsblk -l -o MOUNTPOINT) for mnt in $MOUNTS; do if [ "$mnt" == "MOUNTPOINT" ]; then continue fi if [ "$mnt" == "" ]; then continue fi if [ "$mnt" == "/" ]; then continue fi if [ "$mnt" == "/boot" ]; then continue fi if [ "$mnt" == "/opt" ]; then continue fi if [ "$mnt" == "[SWAP]" ]; then echo "swapoff -a" swapoff -a continue fi if echo $mnt | grep $EMMC_NAME; then echo "umount -f $mnt" umount -f $mnt if [ $? -ne 0 ]; then error_msg "$mnt Cannot be uninstalled, the installation process is aborted." fi fi done # Delete old partition if exists p=$(lsblk -l | grep -e "${EMMC_NAME}p" | wc -l) echo "A total of [ $p ] old partitions on EMMC will be deleted" >/tmp/fdisk.script while [ $p -ge 1 ]; do echo "d" >>/tmp/fdisk.script if [ $p -gt 1 ]; then echo "$p" >>/tmp/fdisk.script fi p=$((p - 1)) done # you can change ROOT size(MB) >= 320 ROOT1="1280" ROOT2="1280" if [[ "${AMLOGIC_SOC}" == "s912" ]] && [[ "${boxtype}" == "213" || "${boxtype}" == "2e" ]]; then BOOT="512" BLANK1="700" BLANK2="220" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s912" || "${AMLOGIC_SOC}" == "s905d" ]]; then BOOT="512" BLANK1="68" BLANK2="220" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s905x" ]]; then BOOT="160" BLANK1="700" BLANK2="0" BLANK3="0" BLANK4="0" elif [[ "${FDTFILE}" == "meson-sm1-skyworth-lb2004-a4091.dtb" ]]; then BOOT="512" BLANK1="108" BLANK2="562" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s905l3a" ]] && [[ "${boxtype}" == "304" || "${boxtype}" == "34" ]]; then # e900v22c/d(s905l3a) BOOT="256" BLANK1="570" BLANK2="0" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s905l3a" ]] && [[ "${boxtype}" == "305" || "${boxtype}" == "33" ]]; then # CM311-1a-YST(s905l3a) BOOT="512" BLANK1="108" BLANK2="778" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s905l3b" ]]; then # M302A/M304A(s905l3b) BOOT="512" BLANK1="128" BLANK2="720" BLANK3="0" BLANK4="0" elif [[ "${AMLOGIC_SOC}" == "s905x3" ]] && [[ "${boxtype}" == "525" || "${boxtype}" == "5n" ]]; then # Whale(s905x3) BOOT="512" BLANK1="108" BLANK2="650" BLANK3="0" BLANK4="0" elif [[ "${boxtype}" =~ ^(409|410|49|4a)$ ]]; then # WXY-OES(A311D):409/49, WXY-OES-PLUS(S922X):410/4a BOOT="512" BLANK1="700" BLANK2="0" BLANK3="0" BLANK4="0" else BOOT="160" BLANK1="68" BLANK2="0" BLANK3="162" BLANK4="0" fi DST_TOTAL_MB=$((EMMC_SIZE / 1024 / 1024)) start1=$((BLANK1 * 2048)) end1=$((start1 + (BOOT * 2048) - 1)) start2=$(((BLANK2 * 2048) + end1 + 1)) end2=$((start2 + (ROOT1 * 2048) - 1)) start3=$(((BLANK3 * 2048) + end2 + 1)) end3=$((start3 + (ROOT2 * 2048) - 1)) start4=$(((BLANK4 * 2048) + end3 + 1)) end4=$((DST_TOTAL_MB * 2048 - 1)) cat >>/tmp/fdisk.script </dev/null if [ $? -ne 0 ]; then echo "The fdisk partition fails, Please try again." dd if=/root/BackupOldBootloader.img of=/dev/${EMMC_NAME} conv=fsync && sync dd if=/dev/zero of=/dev/${EMMC_NAME} bs=512 count=1 && sync exit 1 fi echo "Partition complete." # write some zero data to part begin seek=$((start1 / 2048)) dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync seek=$((start2 / 2048)) dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync seek=$((start3 / 2048)) dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync seek=$((start4 / 2048)) dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync #Mainline U-BOOT detection FLASH_MAINLINE_UBOOT=0 if [[ -n "${MAINLINE_UBOOT}" && -f "${MAINLINE_UBOOT}" ]]; then cat </dev/null echo "format rootfs1 partiton..." ROOTFS1_UUID=$(/usr/bin/uuidgen) mkfs.btrfs -f -U ${ROOTFS1_UUID} -L EMMC_ROOTFS1 -m single /dev/${EMMC_NAME}p2 mkdir -p /mnt/${EMMC_NAME}p2 sleep 2 umount -f /mnt/${EMMC_NAME}p2 2>/dev/null echo "format rootfs2 partiton..." ROOTFS2_UUID=$(/usr/bin/uuidgen) mkfs.btrfs -f -U ${ROOTFS2_UUID} -L EMMC_ROOTFS2 -m single /dev/${EMMC_NAME}p3 mkdir -p /mnt/${EMMC_NAME}p3 sleep 2 umount -f /mnt/${EMMC_NAME}p3 2>/dev/null # mount and copy echo "Wait for the boot file system to mount ... " i=1 max_try=10 while [ $i -le $max_try ]; do mount -t vfat /dev/${EMMC_NAME}p1 /mnt/${EMMC_NAME}p1 2>/dev/null sleep 2 mnt=$(lsblk -l -o MOUNTPOINT | grep /mnt/${EMMC_NAME}p1) if [ "$mnt" == "" ]; then if [ $i -lt $max_try ]; then echo "Not mounted successfully, try again ..." i=$((i + 1)) else error_msg "Cannot mount the boot file system, give up!" fi else echo "Successfully mounted." echo "copy boot ..." cd /mnt/${EMMC_NAME}p1 rm -rf /boot/'System Volume Information/' (cd /boot && tar cf - .) | tar xf - sync echo "Edit uEnv.txt ..." [[ -f "uEnv.txt" ]] && { sed -i -E \ -e "s|/dtb/amlogic.*|/dtb/amlogic/${FDTFILE}|" \ -e "s|UUID=[^ ]*|UUID=${ROOTFS1_UUID}|" \ -e "s|rootflags=compress=zstd:[^ ]*|rootflags=compress=zstd:${ZSTD_LEVEL}|" \ uEnv.txt } # Replace the extlinux/extlinux.conf if it exists [[ -f "extlinux/extlinux.conf" ]] && { sed -i -E \ -e "s|/dtb/amlogic.*|/dtb/amlogic/${FDTFILE}|" \ -e "s|UUID=[^ ]*|UUID=${ROOTFS1_UUID}|" \ -e "s|rootflags=compress=zstd:[^ ]*|rootflags=compress=zstd:${ZSTD_LEVEL}|" \ extlinux/extlinux.conf } rm -f s905_autoscript* aml_autoscript* if [ ${K510} -eq 1 ]; then if [ -f ${UBOOT_OVERLOAD} ]; then cp -f -v ${UBOOT_OVERLOAD} u-boot.emmc elif [ -f "u-boot.ext" ]; then cp -f -v u-boot.ext u-boot.emmc fi fi mv -f boot-emmc.ini boot.ini mv -f boot-emmc.cmd boot.cmd mv -f boot-emmc.scr boot.scr sync echo "complete." cd / umount -f /mnt/${EMMC_NAME}p1 break fi done echo "complete." echo "Wait for the rootfs file system to mount ... " i=1 while [ $i -le $max_try ]; do mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} /dev/${EMMC_NAME}p2 /mnt/${EMMC_NAME}p2 2>/dev/null sleep 2 mnt=$(lsblk -l -o MOUNTPOINT | grep /mnt/${EMMC_NAME}p2) if [ "$mnt" == "" ]; then if [ $i -lt $max_try ]; then echo "Not mounted successfully, try again ..." i=$((i + 1)) else error_msg "Cannot mount rootfs file system, give up!" fi else echo "Successfully mounted" echo "Create folder ... " cd /mnt/${EMMC_NAME}p2 btrfs subvolume create etc mkdir -p bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www .reserved .snapshots ln -sf lib/ lib64 ln -sf tmp/ var sync echo "complete." COPY_SRC="root etc bin sbin lib opt usr www" echo "Copy data ... " for src in $COPY_SRC; do echo "copy [ $src ] ..." (cd / && tar cf - $src) | tar xf - sync done echo "Copy complete." sync cat >etc/docker/daemon.json </dev/null rm -rf usr/bin/AdGuardHome && ln -sf /mnt/${EMMC_NAME}p4/AdGuardHome usr/bin/ >/dev/null echo "Edit configuration file ..." #cd /mnt/${EMMC_NAME}p2/usr/bin/ #rm -f openwrt-install-amlogic openwrt-update-amlogic cd /mnt/${EMMC_NAME}p2/etc/rc.d ln -sf ../init.d/dockerd S99dockerd rm -f S??shortcut-fe if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then ln -sf ../init.d/shortcut-fe S99shortcut-fe fi fi cd /mnt/${EMMC_NAME}p2/etc cat >fstab <fstab < .snapshots/etc-000" cd /mnt/${EMMC_NAME}p2 && btrfs subvolume snapshot -r etc .snapshots/etc-000 sync cd / umount -f /mnt/${EMMC_NAME}p2 break fi done echo "complete." echo "Create a shared file system." mkdir -p /mnt/${EMMC_NAME}p4 # When there is no input parameter, select manually if [[ -n "${SHARED_FSTYPE}" ]]; then TARGET_SHARED_FSTYPE=${SHARED_FSTYPE} else cat </dev/null mount -t btrfs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4 ;; 3 | f2fs) mkfs.f2fs -f -l EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null mount -t f2fs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4 ;; 4 | xfs) mkfs.xfs -f -L EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null mount -t xfs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4 ;; *) mkfs.ext4 -F -L EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null mount -t ext4 /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4 ;; esac mkdir -p /mnt/${EMMC_NAME}p4/docker /mnt/${EMMC_NAME}p4/AdGuardHome/data sync echo "Successful installed, please unplug the USB, re-insert the power supply to start the openwrt." exit 0