#!/usr/bin/env bash set -u # Unbound variable errors are not allowed rploaderver="1.2.7.2" build="master" redpillmake="prod" modalias4="https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/$build/modules.alias.4.json.gz" modalias3="https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/$build/modules.alias.3.json.gz" timezone="UTC" ntpserver="pool.ntp.org" userconfigfile="/home/tc/user_config.json" configfile="/home/tc/redpill-load/config/pats.json" gitdomain="raw.githubusercontent.com" mshellgz="my.sh.gz" mshtarfile="https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/my.sh.gz" #Defaults smallfixnumber="0" kver3platforms="bromolow braswell avoton cedarview grantley" kver5platforms="epyc7002 v1000nk r1000nk geminilakenk" dsm6notsupported="geminilake v1000 purley braswell denverton broadwellntbap grantley" # 전역 변수로 플래그 설정 (한번 Y면 영구 유지) R8168_YN="N" R8168_DETECTED="N" # 한번만 체크하는 플래그 #Check if FRIEND kernel exists if [[ "$(uname -a | grep -c tcrpfriend)" -gt 0 ]]; then FRKRNL="YES" else FRKRNL="NO" fi BIOS_CNT="$(sudo fdisk -l | grep "BIOS" | wc -l )" [ $BIOS_CNT -eq 0 ] && BIOS_CNT="$(sudo fdisk -l | grep "EFI" | grep "127M" | wc -l )" [ $BIOS_CNT -eq 0 ] && BIOS_CNT="$(sudo fdisk -l | grep "*" | grep "83" | grep "127M" | wc -l )" function history() { cat < Options: update, postupdate, noconfig, noclean, manual, realmac, userdts - update : Option to handle updates to the m shell. - postupdate : Option to patch the restore loop after applying DSM 7.1.0-42661 after Update 2, no additional build required. - noconfig: SKIP automatic detection change processing such as SN/Mac/Vid/Pid/SataPortMap of user_config.json file. - noclean: SKIP the 💊 RedPill LKM/LOAD directory without clearing it with the Clean command. However, delete the Cache directory and loader.img. - manual: Options for manual extension processing and manual dtc processing in build action (skipping extension auto detection). - realmac : Option to use the NIC's real mac address instead of creating a virtual one. - userdts : Option to use the user-defined platform.dts file instead of auto-discovery mapping with dtcpatch. Please type Synology Model Name after ./$(basename ${0}) - for friend mode ./$(basename ${0}) DS918+-7.2.1-69057 ./$(basename ${0}) DS3617xs-7.2.1-69057 ./$(basename ${0}) DS3622xs+-7.2.1-69057 ./$(basename ${0}) DVA3221-7.2.1-69057 ./$(basename ${0}) DS920+-7.2.1-69057 ./$(basename ${0}) DS1621+-7.2.1-69057 ./$(basename ${0}) DS2422+-7.2.1-69057 ./$(basename ${0}) DVA1622-7.2.1-69057 ./$(basename ${0}) DS1520+-7.2.1-69057 ./$(basename ${0}) FS2500-7.2.1-69057 ./$(basename ${0}) DS1621xs+-7.2.1-69057 ./$(basename ${0}) RS4021xs+-7.2.1-69057 ./$(basename ${0}) DVA3219-7.2.1-69057 ./$(basename ${0}) RS3618xs-7.2.1-69057 ./$(basename ${0}) DS1019+-7.2.1-69057 ./$(basename ${0}) DS923+-7.2.1-69057 ./$(basename ${0}) DS723+-7.2.1-69057 ./$(basename ${0}) SA6400-7.2.1-69057 ./$(basename ${0}) DS720+-7.2.1-69057 ./$(basename ${0}) RS1221+-7.2.1-69057 ./$(basename ${0}) RS2423+-7.2.1-69057 ./$(basename ${0}) RS1619xs+-7.2.1-69057 ./$(basename ${0}) RS3621xs+-7.2.1-69057 ./$(basename ${0}) SA6400-7.2.1-69057 ./$(basename ${0}) DS916+-7.2.1-69057 ./$(basename ${0}) DS1821+-7.2.1-69057 ./$(basename ${0}) DS1819+-7.2.1-69057 ./$(basename ${0}) DS1823xs+-7.2.1-69057 ./$(basename ${0}) DS620slim+-7.2.1-69057 ex) Except for postupdate and userdts that must be used alone, the rest of the options can be used in combination. - When you want to build the loader while maintaining the already set SN/Mac/Vid/Pid/SataPortMap ./my DS3622xs+H noconfig - When you want to build the loader while maintaining the already set SN/Mac/Vid/Pid/SataPortMap and without deleting the downloaded DSM pat file. ./my DS3622xs+H noconfig noclean - When you want to build the loader while using the real MAC address of the NIC, with extended auto-detection disabled ./my DS3622xs+H realmac manual EOF } ################################################################################# # Verbose Mode Control for RedPill Bootloader Build # Usage: source verbose_control.sh ################################################################################# # Global Verbose Flag VERBOSE_MODE="OFF" VERBOSE_FLAG="" ################################################################################# # Progress Bar Display ################################################################################# show_progress_bar() { local current=$1 local total=$2 local step_name="$3" local width=24 local percentage=$((current * 100 / total)) local filled=$((width * current / total)) printf "[" > /dev/tty printf "%${filled}s" | tr ' ' '=' > /dev/tty printf "%$((width - filled))s" | tr ' ' '-' > /dev/tty printf "] %d%% (%d/%d) [%s]\n" "$percentage" "$current" "$total" "$step_name" > /dev/tty } ################################################################################# # Logging Functions ################################################################################# log_build_step() { local step_name="$1" local step_num="${2:-}" local total_steps="${3:-}" if [ "$VERBOSE_MODE" = "OFF" ]; then if [ -n "$step_num" ] && [ -n "$total_steps" ]; then show_progress_bar "$step_num" "$total_steps" "$step_name" fi else echo "[$(date '+%H:%M:%S')] ✓ $step_name" fi } log_error() { # Error is ALWAYS shown echo -e "\033[1;31m[ERROR] $(date '+%H:%M:%S'): $1\033[0m" } log_warning() { # Warning is ALWAYS shown echo -e "\033[1;33m[WARNING] $(date '+%H:%M:%S'): $1\033[0m" } log_success() { # Success is ALWAYS shown echo -e "\033[1;32m[SUCCESS] $(date '+%H:%M:%S'): $1\033[0m" } log_backup_step() { # Backup process is ALWAYS shown echo -e "\033[1;36m[BACKUP] $(date '+%H:%M:%S'): $1\033[0m" } ################################################################################# # Build with Progress Bar ################################################################################# make_with_progress() { local ldr_mode="${1}" local prevent_init="${2}" local build_cmd="" checkUserConfig if [ $? -ne 0 ]; then dialog --backtitle "`backtitle`" --title "Error loader building" 0 0 #--textbox "${LOG_FILE}" 0 0 return 1 fi usbidentify clear if [ "${prevent_init}" = "OFF" ]; then build_cmd="my ${MODEL}-${BUILD} noconfig ${ldr_mode}" else build_cmd="my ${MODEL}-${BUILD} noconfig ${ldr_mode} ${prevent_init}" fi set -o pipefail if [ "$VERBOSE_MODE" = "OFF" ]; then echo "Building bootloader..." eval "$build_cmd" 2>&1 | tee /home/tc/zlastbuild.log > /dev/null exit_code=${PIPESTATUS[0]} #echo "$output" | grep -E "(Preparing build environment|Handling DSM pat files|Collecting extensions|Creating bootloader image|Finalizing build)" else eval "$build_cmd" 2>&1 | tee /home/tc/zlastbuild.log exit_code=${PIPESTATUS[0]} fi set +o pipefail # Always show exit code if [ $exit_code -eq 0 ]; then log_success "Build completed successfully (Exit Code: $exit_code)" if [ -f /home/tc/custom-module/redpill.ko ]; then sudo rm -rf /home/tc/custom-module/redpill.ko fi st "finishloader" "Finished building" "Finished building the loader" log_build_step "Finished building" 12 12 else log_error "Build failed with exit code: $exit_code" show_backup_error_info fi echo "press any key to continue..." read answer rm -f /home/tc/buildstatus return $exit_code } ################################################################################# # Show Error Information ################################################################################# show_backup_error_info() { echo -e "\n\033[1;31m╔════════════════════════════════════════════╗\033[0m" echo -e "\033[1;31m║ BUILD ERROR INFORMATION ║\033[0m" echo -e "\033[1;31m╚════════════════════════════════════════════╝\033[0m" if [ -f /home/tc/zlastbuild.log ]; then echo -e "\n\033[1;33mLast 10 lines of build log:\033[0m" tail -10 /home/tc/zlastbuild.log | sed 's/^/ /' fi echo -e "\n\033[1;33mBackup status:\033[0m" echo " Checking for corrupted files..." ls -lh /mnt/${tcrppart}/*.pat 2>/dev/null | tail -5 } ################################################################################# # Toggle Verbose Mode Menu ################################################################################# toggle_verbose_menu() { local TMP_PATH="${TMP_PATH:-.}" local NEXT="r" while true; do clear echo "╔═══════════════════════════════════════════════════════════════╗" echo "║ VERBOSE MODE CONFIGURATION ║" echo "╚═══════════════════════════════════════════════════════════════╝" echo "" echo " Current Mode: $([ "$VERBOSE_MODE" = "ON" ] && echo -e '\033[1;32m[ON]\033[0m' || echo -e '\033[1;31m[OFF]\033[0m')" echo "" echo "┌─────────────────────────────────────────────────────────────┐" echo "│ 1. Enable Verbose Mode (Show all build output) │" echo "│ 2. Disable Verbose Mode (Show only progress & errors) │" echo "│ 3. Return to Main Menu │" echo "└─────────────────────────────────────────────────────────────┘" echo "" echo " [Mode Description]" echo "" if [ "$VERBOSE_MODE" = "ON" ]; then echo " ✓ VERBOSE ON - Current Setting" echo " • Displays all compilation steps" echo " • Shows detailed error messages" echo " • Displays backup process details" echo " • Slower console output (more I/O)" echo "" else echo " ✓ VERBOSE OFF - Current Setting" echo " • Progress bar display only" echo " • Displays errors and warnings" echo " • Displays backup process (always visible)" echo " • Fast, clean console output" echo "" fi read -p "Select option [1-3]: " choice case "$choice" in 1) VERBOSE_MODE="ON" VERBOSE_FLAG="-v" echo -e "\n\033[1;32m✓ Verbose mode enabled\033[0m" sleep 1.5 ;; 2) VERBOSE_MODE="OFF" VERBOSE_FLAG="" echo -e "\n\033[1;32m✓ Verbose mode disabled\033[0m" sleep 1.5 ;; 3) NEXT="r" return 0 ;; *) echo -e "\033[1;31m✗ Invalid selection\033[0m" sleep 1.5 ;; esac done } ################################################################################# # Backup with Always-Visible Progress ################################################################################# function backup_loader() { local backup_steps=5 log_backup_step "Starting backup process..." for i in $(seq 1 $backup_steps); do log_backup_step "Backing up config ($i/$backup_steps)" # Actual backup command here sleep 1 show_progress_bar "$i" "$backup_steps" "Backup in progress..." done log_backup_step "Backup completed successfully" } ################################################################################# # Get Current Verbose Status ################################################################################# get_verbose_status() { echo "$VERBOSE_MODE" } function getloaderdisk() { loaderdisk="" # Get the loader disk using the UUID "6234-C863" loaderdisk=$(sudo /sbin/blkid | grep "6234-C863" | cut -d ':' -f1 | sed 's/p\?3//g' | awk -F/ '{print $NF}' | head -n 1) # Get the loader disk using the UUID "6234-C863" ( injected bootloader ) if [[ $BIOS_CNT -eq 1 ]] && [ "$FRKRNL" = "YES" ]; then [ -z "$loaderdisk" ] && loaderdisk=$(sudo /sbin/blkid | grep "8765-4321" | cut -d ':' -f1 | sed 's/p\?7//g' | awk -F/ '{print $NF}' | head -n 1) fi # If the UUID "6234-C863" is not found, extract the disk name if [ -z "$loaderdisk" ]; then # Iterate through available disks to find a valid disk name while read -r edisk; do loaderdisk=$(echo ${edisk} | cut -c 1-12 | awk -F\/ '{print $3}') # Break the loop if a valid disk name is found [ -n "$loaderdisk" ] && break done < <(lsblk -ndo NAME | grep -v '^loop' | grep -v '^zram' | sed 's/^/\/dev\//') fi # Output the loader disk echo "LOADER DISK: $loaderdisk" } # ============================================================================== # Color Function # ============================================================================== function cecho () { # if [ -n "$3" ] # then # case "$3" in # black | bk) bgcolor="40";; # red | r) bgcolor="41";; # green | g) bgcolor="42";; # yellow | y) bgcolor="43";; # blue | b) bgcolor="44";; # purple | p) bgcolor="45";; # cyan | c) bgcolor="46";; # gray | gr) bgcolor="47";; # esac # else bgcolor="0" # fi code="\033[" case "$1" in black | bk) color="${code}${bgcolor};30m";; red | r) color="${code}${bgcolor};31m";; green | g) color="${code}${bgcolor};32m";; yellow | y) color="${code}${bgcolor};33m";; blue | b) color="${code}${bgcolor};34m";; purple | p) color="${code}${bgcolor};35m";; cyan | c) color="${code}${bgcolor};36m";; gray | gr) color="${code}${bgcolor};37m";; esac text="$color$2${code}0m" echo -e "$text" } function zeropadingver() { ZPADKVER=$(printf "%01d%03d%03d\n" $(echo "$1" | tr '.' ' ')) } function getvarsmshell() { # Set the path for the models.json file MODELS_JSON="/home/tc/models.json" # Define platform groups platforms="epyc7002 v1000nk r1000nk geminilakenk broadwellnk broadwell bromolow broadwellnkv2 broadwellntbap purley denverton apollolake r1000 v1000 geminilake avoton braswell cedarview grantley" # Initialize MODELS array MODELS=() # Extract models for each platform and add them to the mdl file for platform in $platforms; do models=$(jq -r ".$platform.models[]" "$MODELS_JSON" 2>/dev/null) if [ -n "$models" ]; then MODELS+=($models) fi done SUVP="" ORIGIN_PLATFORM="" tem="${1}" MODEL="$(echo ${tem} |cut -d '-' -f 1)" TARGET_REVISION="$(echo ${tem} |cut -d '-' -f 3)" if [ "$TARGET_REVISION" == "64570" ]; then TARGET_VERSION="$(echo ${tem} |cut -d '-' -f 2 | cut -c 1-3)" else TARGET_VERSION="$(echo ${tem} |cut -d '-' -f 2)" fi #echo "MODEL is $MODEL" TARGET_PLATFORM=$(echo "$MODEL" | sed 's/DS/ds/' | sed 's/RS/rs/' | sed 's/+/p/' | sed 's/DVA/dva/' | sed 's/FS/fs/' | sed 's/SA/sa/' ) SYNOMODEL="${TARGET_PLATFORM}_${TARGET_REVISION}" if ! echo ${MODELS[@]} | grep -qw ${MODEL}; then echo "This synology model not supported by TCRP." exit 99 fi if [ "$TARGET_REVISION" == "25556" ]; then KVER="4.4.59" SUVP="" elif [ "$TARGET_REVISION" == "42218" ]; then KVER="4.4.180" SUVP="" elif [ "$TARGET_REVISION" == "42661" ]; then KVER="4.4.180" SUVP="-1" elif [ "$TARGET_REVISION" == "42962" ]; then KVER="4.4.180" MODELS6="DS423+ DS723+ DS923+ DS1823xs+ RS3621xs+ RS4021xs+ RS3618xs SA6400" if echo ${MODELS6}| grep -qw ${MODEL}; then SUVP="-6" else SUVP="-1" fi elif [ "$TARGET_REVISION" == "64570" ]; then KVER="4.4.302" SUVP="-1" elif [ "$TARGET_REVISION" == "69057" ]; then KVER="4.4.302" SUVP="-1" elif [ "$TARGET_REVISION" == "72806" ]; then KVER="4.4.302" SUVP="" elif [ "$TARGET_REVISION" == "81180" ]; then KVER="4.4.302" SUVP="" elif [ "$TARGET_REVISION" == "86003" ]; then KVER="4.4.302" SUVP="" elif [ "$TARGET_REVISION" == "86009" ]; then KVER="4.4.302" SUVP="" else echo "Synology model revision not supported by TCRP." exit 0 fi zeropadingver ${KVER} #SFVAL=${SUVP:--0} # Extract models for each platform and add them to the mdl file for platform in $platforms; do # Initialize MODELS array MODELS=() models=$(jq -r ".$platform.models[]" "$MODELS_JSON" 2>/dev/null) if [ -n "$models" ]; then MODELS=($models) fi if echo ${MODELS[@]} | grep -qw ${MODEL}; then ORIGIN_PLATFORM="${platform}" if [ ${ORIGIN_PLATFORM} == "broadwell" ]; then if [ "$TARGET_REVISION" == "25556" ]; then KVER="3.10.105" fi fi if echo ${kver3platforms} | grep -qw ${ORIGIN_PLATFORM}; then if [ "$TARGET_REVISION" == "25556" ]; then KVER="3.10.105" else KVER="3.10.108" fi fi if echo ${kver5platforms} | grep -qw ${ORIGIN_PLATFORM}; then KVER="5.10.55" fi fi done case ${MODEL} in DS224+) permanent="WBR" serialstart="2350" suffix="alpha" ;; DS423+) permanent="VKR" serialstart="22A0" suffix="alpha" ;; DS718+) permanent="PEN" serialstart="1930" suffix="numeric" ;; DS720+) permanent="QWR" serialstart="2010 2110" suffix="alpha" ;; DS918+) permanent="PDN" serialstart="1910" suffix="numeric" ;; DS920+) permanent="SBR" serialstart="2030 2040 20C0 2150" suffix="alpha" ;; DS923+) permanent="TQR" serialstart="2270" suffix="alpha" ;; DS925+) permanent="YHR" serialstart="2520" suffix="alpha" ;; DS1019+) permanent="QXR" serialstart="1850 1880" suffix="numeric" ;; DS1520+) permanent="RYR" serialstart="2060" suffix="alpha" ;; DS1522+) permanent="TRR" serialstart="2270" suffix="alpha" ;; DS1621+) permanent="S7R" serialstart="2080" suffix="alpha" ;; DS1621xs+) permanent="RVR" serialstart="2070" suffix="alpha" ;; DS1819+) permanent="R5R" serialstart="1890" suffix="alpha" ;; DS1821+) permanent="SKR" serialstart="2110" suffix="alpha" ;; DS1823xs+) permanent="V5R" serialstart="2280" suffix="alpha" ;; DS2419+) permanent="QZA" serialstart="1880" suffix="alpha" ;; DS2422+) permanent="SLR" serialstart="2140 2180" suffix="alpha" ;; DS3615xs) permanent="LWN" serialstart="1130 1230 1330 1430" suffix="numeric" ;; DS3617xs) permanent="ODN" serialstart="1130 1230 1330 1430" suffix="numeric" ;; DS3622xs+) permanent="SQR" serialstart="2150" suffix="alpha" ;; DVA1622) permanent="UBR" serialstart="2030 2040 20C0 2150" suffix="alpha" ;; DVA3219) permanent="RFR" serialstart="1930 1940" suffix="alpha" ;; DVA3221) permanent="SJR" serialstart="2030 2040 20C0 2150" suffix="alpha" ;; FS2500) permanent="PSN" serialstart="1960" suffix="numeric" ;; FS6400) permanent="XXX" serialstart="0000" suffix="alpha" ;; HD6500) permanent="RUR" serialstart="20A0 21C0" suffix="alpha" ;; RS1221+) permanent="RWR" serialstart="20B0" suffix="alpha" ;; RS1619xs+) permanent="QPR" serialstart="1920" suffix="alpha" ;; RS2423RP+) permanent="V3R" serialstart="22B0" suffix="alpha" ;; RS3621xs+) permanent="SZR" serialstart="20A0" suffix="alpha" ;; RS4021xs+) permanent="T2R" serialstart="2160" suffix="alpha" ;; SA3200D) permanent="S4R" serialstart="19A0" suffix="alpha" ;; SA3400) permanent="RJR" serialstart="1970" suffix="alpha" ;; SA6400) permanent="W8R" serialstart="2350" suffix="alpha" ;; SA3410) permanent="UMR" serialstart="2270" suffix="alpha" ;; *) permanent="XXX" serialstart="0000" suffix="alpha" ;; esac } # Function READ_YN, cecho # Made by FOXBI # 2022.04.14 # # ============================================================================== # Y or N Function # ============================================================================== function READ_YN () { # ${1}:question ${2}:default while true; do read -n1 -p "${1}" Y_N case "$Y_N" in [Yy]* ) Y_N="y" echo -e "\n"; break ;; [Nn]* ) Y_N="n" echo -e "\n"; break ;; *) echo -e "Please answer in Y / y or N / n.\n" ;; esac done } function st() { echo -e "[$(date '+%T.%3N')]:-------------------------------------------------------------" >> /home/tc/buildstatus echo -e "\e[35m$1\e[0m \e[36m$2\e[0m $3" >> /home/tc/buildstatus } function mountvol () { # RAID 어레이가 이미 활성화되었는지 확인 if ! grep -q "active" /proc/mdstat 2>/dev/null; then echo -e "\e[32mInitializing RAID/LVM...\e[0m" sudo mdadm --assemble --scan sudo pvscan # PV(Physical Volume) scan sudo vgscan # VG(Volume Group) scan sudo vgchange -ay # VG Avtivate (--activationmode degraded Option Retry) fi lvm_volumes=() while IFS= read -r line; do path=$(echo "$line" | awk '{print $1}') size=$(echo "$line" | awk '{print $2}') # 볼륨 이름만 추출하여 사용자 친화적 표시 vol_name="${path##*/}" lvm_volumes+=("$path" "$vol_name ($size)") done < <(sudo lvs -o lv_dm_path,lv_size 2>/dev/null | grep volume) if [ ${#lvm_volumes[@]} -eq 0 ]; then echo "No Available Syno lvm Volume, press any key continue..." read -n 1 -s answer return 0 fi dialog --backtitle "`backtitle`" --colors \ --menu "Choose a Volume to mount.\Zn" 0 0 0 "${lvm_volumes[@]}" \ 2>${TMP_PATH}/resp [ $? -ne 0 ] && return resp=$(<${TMP_PATH}/resp) [ -z "${resp}" ] && return # 볼륨 이름 추출 (예: /dev/mapper/vg1000-lv → lv) vol_name="${resp##*-}" # LV 이름만 추출 mount_point="/mnt/${vol_name}" # 마운트 경로 생성 T=$(sudo blkid -o value -s TYPE "${resp}" 2>/dev/null) sudo mkdir -p "${mount_point}" if [ "$T" = "btrfs" ]; then sudo mount -t btrfs "${resp}" "${mount_point}" -o ro,degraded elif [ "$T" = "ext4" ]; then sudo mount -t ext4 "${resp}" "${mount_point}" fi if mountpoint -q "${mount_point}"; then echo -e "\e[32mMount success: ${resp} -> ${mount_point}\e[0m, press any key to continue..." else echo "Mount failed! Check filesystem type." fi read -n 1 -s answer return 0 } function open_md0() { # assemble and mount md0 sudo rm -f "${TMP_PATH}/menuz" sudo mkdir -p "${TMP_PATH}/mdX" num=$(echo $DSMROOTS | wc -w) sudo mdadm -C /dev/md0 -e 0.9 -amd -R -l1 --force -n$num $DSMROOTS 2>/dev/null T="$(sudo blkid -o value -s TYPE /dev/md0 2>/dev/null)" if [ "$FRKRNL" = "NO" ] && [ "$T" = "ext4" ]; then sudo tune2fs -O ^quota /dev/md0 fi sudo mount -t "${T:-ext4}" /dev/md0 "${TMP_PATH}/mdX" } function close_md0() { sudo umount "${TMP_PATH}/mdX" sudo mdadm --stop /dev/md0 sudo rm -rf "${TMP_PATH}/mdX" } ############################################################################### # Find and mount the DSM root filesystem function findDSMRoot() { local DSMROOTS="" if [ "$FRKRNL" = "YES" ]; then [ -z "${DSMROOTS}" ] && DSMROOTS="$(sudo mdadm --detail --scan 2>/dev/null | grep -E "name=SynologyNAS:0|name=DiskStation:0|name=SynologyNVR:0|name=BeeStation:0" | awk '{print $2}' | uniq)" [ -z "${DSMROOTS}" ] && DSMROOTS="$(sudo lsblk -pno KNAME,PARTN,FSTYPE,FSVER,LABEL | grep -E "sd[a-z]{1,2}1" | grep -w "linux_raid_member" | grep "0.9" | awk '{print $1}')" else if [ "$(which mdadm)_" == "_" ]; then tce-load -iw mdadm 2>&1 >/dev/null fi [ -z "${DSMROOTS}" ] && DSMROOTS="$(sudo fdisk -l | grep -E "sd[a-z]{1,2}1" | grep -E '16785407|4982527' | awk '{print $1}')" fi echo "${DSMROOTS}" return 0 } ############################################################################### # Reset DSM system password function changeDSMPassword() { DSMROOTS="$(findDSMRoot)" if [ -z "${DSMROOTS}" ]; then dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --msgbox "No DSM system partition(md0) found!\nPlease insert all disks before continuing." 0 0 return fi # assemble and mount md0 open_md0 [ $? -ne 0 ] && returnto "Assemble and mount md0 failed. Stop processing!!! " && return if [ -f "${TMP_PATH}/mdX/etc/shadow" ]; then while read -r L; do U=$(echo "${L}" | awk -F ':' '{if ($2 != "*" && $2 != "!!") print $1;}') [ -z "${U}" ] && continue E=$(echo "${L}" | awk -F ':' '{if ($8 == "1") print "disabled"; else print " ";}') grep -q "status=on" "${TMP_PATH}/mdX/usr/syno/etc/packages/SecureSignIn/preference/${U}/method.config" 2>/dev/null [ $? -eq 0 ] && S="SecureSignIn" || S=" " printf "\"%-36s %-10s %-14s\"\n" "${U}" "${E}" "${S}" >>"${TMP_PATH}/menuz" done <<<"$(sudo cat "${TMP_PATH}/mdX/etc/shadow" 2>/dev/null)" fi close_md0 if [ ! -f "${TMP_PATH}/menuz" ]; then dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --msgbox "All existing users have been disabled. Please try adding new user." 0 0 return fi dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --no-items --menu "Choose a user name" 0 0 20 --file "${TMP_PATH}/menuz" \ 2>"${TMP_PATH}/resp" [ $? -ne 0 ] && return USER="$(sudo cat "${TMP_PATH}/resp" 2>/dev/null | awk '{print $1}')" [ -z "${USER}" ] && return local STRPASSWD while true; do dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --inputbox "$(printf "Type a new password for user '%s'" "${USER}")" 0 70 "" \ 2>"${TMP_PATH}/resp" [ $? -ne 0 ] && break resp="$(sudo cat "${TMP_PATH}/resp" 2>/dev/null)" if [ -z "${resp}" ]; then dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --msgbox "Invalid password" 0 0 else STRPASSWD="${resp}" break fi done sudo rm -f "${TMP_PATH}/isOk" ( sudo mkdir -p "${TMP_PATH}/mdX" local NEWPASSWD NEWPASSWD="$(sudo openssl passwd -6 -salt "$(sudo openssl rand -hex 8)" "${STRPASSWD}")" # assemble and mount md0 open_md0 [ $? -ne 0 ] && returnto "Assemble and mount md0 failed. Stop processing!!! " && return sudo sed -i "s|^${USER}:[^:]*|${USER}:${NEWPASSWD}|" "${TMP_PATH}/mdX/etc/shadow" sudo sed -i "/^${USER}:/ s/^\(${USER}:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\)[^:]*:/\1:/" "${TMP_PATH}/mdX/etc/shadow" sudo sed -i "s|status=on|status=off|g" "${TMP_PATH}/mdX/usr/syno/etc/packages/SecureSignIn/preference/${USER}/method.config" 2>/dev/null sudo sync echo "true" >"${TMP_PATH}/isOk" close_md0 ) 2>&1 | dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --progressbox "Resetting ..." 20 100 if [ -f "${TMP_PATH}/isOk" ]; then MSG="$(printf "Reset password for user '%s' completed." "${USER}")" else MSG="$(printf "Reset password for user '%s' failed." "${USER}")" fi dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Change DSM New Password" \ --msgbox "${MSG}" 0 0 return } ############################################################################### # Add new DSM user function addNewDSMUser() { DSMROOTS="$(findDSMRoot)" if [ -z "${DSMROOTS}" ]; then dialog --title "Add New DSM User" \ --msgbox "No DSM system partition(md0) found!\nPlease insert all disks before continuing." 0 0 return fi MSG="Add to administrators group by default" dialog --title "Add New DSM User" \ --form "${MSG}" 8 60 3 \ "username:" 1 1 "" 1 10 50 0 \ "password:" 2 1 "" 2 10 50 0 \ 2>"${TMP_PATH}/resp" [ $? -ne 0 ] && return username=$(sudo sed -n '1p' "${TMP_PATH}/resp") password=$(sudo sed -n '2p' "${TMP_PATH}/resp") username_escaped=$(printf "%q" "$username") password_escaped=$(printf "%q" "$password") sudo rm -f "${TMP_PATH}/isOk" ( ONBOOTUP="" ONBOOTUP="${ONBOOTUP}if synouser --enum local | grep -q ^${username_escaped}\$; then synouser --setpw ${username_escaped} ${password_escaped}; else synouser --add ${username_escaped} ${password_escaped} mshell 0 user@mshell.com 1; fi\n" ONBOOTUP="${ONBOOTUP}synogroup --memberadd administrators ${username_escaped}\n" ONBOOTUP="${ONBOOTUP}echo \"DELETE FROM task WHERE task_name LIKE ''ONBOOTUP_ADDUSER'';\" | sqlite3 /usr/syno/etc/esynoscheduler/esynoscheduler.db\n" # assemble and mount md0 open_md0 [ $? -ne 0 ] && returnto "Assemble and mount md0 failed. Stop processing!!! " && return if [ -f "${TMP_PATH}/mdX/usr/syno/etc/esynoscheduler/esynoscheduler.db" ]; then sudo sqlite3 "${TMP_PATH}/mdX/usr/syno/etc/esynoscheduler/esynoscheduler.db" <"${TMP_PATH}/isOk" fi close_md0 ) 2>&1 | dialog --title "Add New DSM User" \ --progressbox "Adding ..." 20 100 if [ -f "${TMP_PATH}/isOk" ]; then MSG=$(printf "Add new user '%s' completed." "${username}") else MSG=$(printf "Add new user '%s' failed." "${username}") fi dialog --title "Add New DSM User" \ --msgbox "${MSG}" 0 0 return } ############################################################################### # CleanSystemPart function CleanSystemPart() { param="${1}" echo -n "(Warning) Do you want to ${param} the System Partition(md0)? [yY/nN] : " readanswer if [ "${answer}" = "Y" ] || [ "${answer}" = "y" ]; then DSMROOTS="$(findDSMRoot)" if [ -z "${DSMROOTS}" ]; then dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "${param} System Partition(md0)" \ --msgbox "No DSM system partition(md0) found!\nPlease insert all disks before continuing." 0 0 return fi sudo rm -f "${TMP_PATH}/isOk" # assemble and mount md0 open_md0 [ $? -ne 0 ] && returnto "Assemble and mount md0 failed. Stop processing!!! " && return if [ "${param}" = "clean" ]; then if [ -d "${TMP_PATH}/mdX/etc" ]; then removed=0 for dir in "@autoupdate" "upd@te" ".log.junior"; do path="${TMP_PATH}/mdX/${dir}/*" if ls $path 1>/dev/null 2>&1; then sudo rm -vrf ${TMP_PATH}/mdX/${dir}/* removed=1 fi done sudo sync if [ $removed -eq 0 ]; then echo "Nothing to remove file" else echo "true" >"${TMP_PATH}/isOk" fi echo "press any key to continue..." read answer fi else sudo rm -rf "${TMP_PATH}/mdX/" 2>/dev/null sudo sync echo "true" >"${TMP_PATH}/isOk" echo "press any key to continue..." read answer fi close_md0 if [ -f "${TMP_PATH}/isOk" ]; then MSG=$(printf "${param} System Partition(md0) completed.") else MSG=$(printf "${param} System Partition(md0) failed.") fi dialog --title "${param} System Partition(md0)" \ --msgbox "${MSG}" 0 0 return fi } ############################################################################### # Fix SmallFixNumber of Bootentry function fixBootEntry() { echo -n "(Warning) Do you want to fix Bootentry Update version? [yY/nN] : " readanswer if [ "${answer}" = "Y" ] || [ "${answer}" = "y" ]; then DSMROOTS="$(findDSMRoot)" if [ -z "${DSMROOTS}" ]; then dialog --backtitle "$(backtitle)" --colors --aspect 50 \ --title "Bootentry Update version correction" \ --msgbox "No DSM system partition(md0) found!\nPlease insert all disks before continuing." 0 0 return fi # assemble and mount md0 open_md0 [ $? -ne 0 ] && returnto "Assemble and mount md0 failed. Stop processing!!! " && return if [ -d "${TMP_PATH}/mdX/etc" ]; then . ${TMP_PATH}/mdX/etc/VERSION cat ${TMP_PATH}/mdX/etc/VERSION updateuserconfigfield "general" "smallfixnumber" "${smallfixnumber}" sudo sed -i "s/Update [0-9]/Update $smallfixnumber/g" "/mnt/${loaderdisk}1/boot/grub/grub.cfg" grep menuentry /mnt/${loaderdisk}1/boot/grub/grub.cfg echo "press any key to continue..." read answer fi close_md0 MSG=$(printf "Bootentry Update version correction completed.") dialog --title "Bootentry Update version correction" \ --msgbox "${MSG}" 0 0 return fi } ############################################################################### # Check DSM version of md0 function chkDsmversion() { DSMROOTS="$(findDSMRoot)" if [ -z "${DSMROOTS}" ]; then echo "There is no DSM" return 0 fi open_md0 || { returnto "Assemble and mount md0 failed (Maybe there's no synodisk)."; return 1; } if [ -d "${TMP_PATH}/mdX/etc" ]; then . "${TMP_PATH}/mdX/etc/VERSION" close_md0 || true if [ "${BUS}" == "block" ]; then echo "Preinstalled version on your DSM : ${productversion:-}" echo "Version you are attempting to install : ${TARGET_VERSION}" else printf "Preinstalled version on your DSM : ${productversion:-}\n" > /dev/tty printf "Version you are attempting to install : ${TARGET_VERSION}\n" > /dev/tty fi if [ "${productversion:-}" == "${TARGET_VERSION}" ]; then return 0 else if [ "${productversion:-}" == "7.3.1" ] && [ "${TARGET_VERSION}" == "7.3.2" ]; then msgalert "If your existing installed DSM version is 7.3.1 (or a false positive of 7.3.2) and the target loader version you want to build is 7.3.2, do you want to take the risk and proceed with the loader build? : " if [ "${ucode}" == "ko_KR" ]; then msgalert "기존 설치된 DSM 버전이 7.3.1(또는 7.3.2의 오탐지)이고 빌드할 타겟로더 버전이 7.3.2인 경우 위험을 감수하고 로더빌드를 진행하겠습니까? : " fi readanswer if [ "${answer}" = "Y" ] || [ "${answer}" = "y" ]; then return 0 else return 1 fi else return 1 fi fi else close_md0 || true return 0 fi } function getlatestmshell() { echo -n "Checking if a newer mshell version exists on the repo -> " if [ ! -f $mshellgz ]; then curl -ksL "$mshtarfile" -o $mshellgz fi curl -ksL "$mshtarfile" -o latest.mshell.gz CURRENTSHA="$(sha256sum $mshellgz | awk '{print $1}')" REPOSHA="$(sha256sum latest.mshell.gz | awk '{print $1}')" if [ "${CURRENTSHA}" != "${REPOSHA}" ]; then if [ "${1}" = "noask" ]; then confirmation="y" else echo -n "There is a newer version of m shell script on the repo should we use that ? [yY/nN]" read confirmation fi if [ "$confirmation" = "y" ] || [ "$confirmation" = "Y" ]; then echo "OK, updating, please re-run after updating" cp -f /home/tc/latest.mshell.gz /home/tc/$mshellgz rm -f /home/tc/latest.mshell.gz tar -zxvf $mshellgz echo "Updating m shell with latest updates" . /home/tc/functions.sh showlastupdate echo "y"|rploader backup echo "press any key to continue..." read answer else rm -f /home/tc/latest.mshell.gz fi else echo "Version is current" rm -f /home/tc/latest.mshell.gz fi } function get_tinycore9() { echo "Downloading tinycore 9.0..." sudo mkdir -p /mnt/${tcrppart}/v9/cde sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_9.0/corepure64.gz -o /mnt/${tcrppart}/v9/corepure64.gz sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_9.0/vmlinuz64 -o /mnt/${tcrppart}/v9/vmlinuz64 md5_corepure64=$(sudo md5sum /mnt/${tcrppart}/v9/corepure64.gz | awk '{print $1}') md5_vmlinuz64=$(sudo md5sum /mnt/${tcrppart}/v9/vmlinuz64 | awk '{print $1}') if [ ${md5_corepure64} = "3ec614287ca178d6c6f36887504716e4" ] && [ ${md5_vmlinuz64} = "9ad7991ef3bc49c4546741b91fc36443" ]; then echo "tinycore 9.0 md5 check is OK! ( corepure64.gz / vmlinuz64 ) " sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_9.0/cde.tgz -o /mnt/${tcrppart}/v9/cde.tgz sudo tar -zxvf /mnt/${tcrppart}/v9/cde.tgz --no-same-owner -C /mnt/${tcrppart}/v9/cde curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/mountvol.sh -o /home/tc/mountvol.sh chmod +x /home/tc/mountvol.sh #GRUB 부트엔트리 Default 값 조정 grub_cfg="/mnt/${loaderdisk}1/boot/grub/grub.cfg" entry_count=$(grep -c '^menuentry' "$grub_cfg") new_default=$((entry_count - 1)) sudo sed -i "/^set default=/cset default=\"${new_default}\"" "$grub_cfg" backuploader restart else return 1 fi } function get_tinycore() { cd /mnt/${tcrppart} echo "Downloading tinycore 14.0..." sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_14.0/corepure64.gz -o corepure64.gz_copy sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_14.0/vmlinuz64 -o vmlinuz64_copy md5_corepure64=$(sudo md5sum corepure64.gz_copy | awk '{print $1}') md5_vmlinuz64=$(sudo md5sum vmlinuz64_copy | awk '{print $1}') if [ ${md5_corepure64} = "f33c4560e3909a7784c0e83ce424ff5c" ] && [ ${md5_vmlinuz64} = "04cb17bbf7fbca9aaaa2e1356a936d7c" ]; then echo "tinycore 14.0 md5 check is OK! ( corepure64.gz / vmlinuz64 ) " sudo mv corepure64.gz_copy corepure64.gz sudo mv vmlinuz64_copy vmlinuz64 cd ~ return 0 else cd ~ return 1 fi } function update_tinycore() { echo "check update for tinycore 14.0..." md5_corepure64=$(sudo md5sum /mnt/${tcrppart}/corepure64.gz | awk '{print $1}') md5_vmlinuz64=$(sudo md5sum /mnt/${tcrppart}/vmlinuz64 | awk '{print $1}') if [ ${md5_corepure64} != "f33c4560e3909a7784c0e83ce424ff5c" ] || [ ${md5_vmlinuz64} != "04cb17bbf7fbca9aaaa2e1356a936d7c" ]; then echo "current tinycore version is not 14.0, update tinycore linux to 14.0..." get_tinycore if [ $? -eq 0 ]; then sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_14.0/etc/shadow -o /etc/shadow echo "etc/shadow" >> /opt/.filetool.lst backuploader restart fi fi } function update_motd() { echo "check update for /etc/motd" md5_motd=$(sudo md5sum /etc/motd | awk '{print $1}') if [ ${md5_motd} != "1ab94698bce5e6146fad3f71e743ca33" ]; then sudo curl -kL# https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/tinycore_14.0/etc/motd -o /etc/motd fi } function macgen() { echo if [ "$realmac" == 'Y' ] ; then mac2=$(/sbin/ifconfig eth1 | head -1 | awk '{print $NF}') echo "Real Mac2 Address : $mac2" echo "Notice : realmac option is requested, real mac2 will be used" else mac2="$(generateMacAddress ${1})" fi cecho y "Mac2 Address for Model ${1} : $mac2 " macaddress2=$(echo $mac2 | sed -s 's/://g') if [ $(cat user_config.json | grep "mac2" | wc -l) -gt 0 ]; then bf_mac2="$(cat user_config.json | grep "mac2" | cut -d ':' -f 2 | cut -d '"' -f 2)" cecho y "The Mac2 address : $bf_mac2 already exists. Change an existing value." json="$(jq --arg var "$macaddress2" '.extra_cmdline.mac2 = $var' user_config.json)" && echo -E "${json}" | jq . >user_config.json # sed -i "/mac2/s/'$bf_mac2'/'$macaddress2'/g" user_config.json else sed -i "/\"extra_cmdline\": {/c\ \"extra_cmdline\": {\"mac2\": \"$macaddress2\",\"netif_num\": \"2\", " user_config.json fi echo "After changing user_config.json" cat user_config.json } function generateMacAddress() { printf '00:11:32:%02X:%02X:%02X' $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) } function random() { printf "%06d" $(($RANDOM % 30000 + 1)) } function randomhex() { val=$(($RANDOM % 255 + 1)) echo "obase=16; $val" | bc } function generateRandomLetter() { for i in a b c d e f g h j k l m n p q r s t v w x y z; do echo $i done | sort -R | tail -1 } function generateRandomValue() { for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f g h j k l m n p q r s t v w x y z; do echo $i done | sort -R | tail -1 } function toupper() { echo $1 | tr '[:lower:]' '[:upper:]' } function generateSerial() { case ${suffix} in numeric) serialnum="$(echo "$serialstart" | tr ' ' '\n' | sort -R | tail -1)$permanent"$(random) ;; alpha) serialnum=$(toupper "$(echo "$serialstart" | tr ' ' '\n' | sort -R | tail -1)$permanent"$(generateRandomLetter)$(generateRandomValue)$(generateRandomValue)$(generateRandomValue)$(generateRandomValue)$(generateRandomLetter)) ;; *) serialnum="$(echo "$serialstart" | tr ' ' '\n' | sort -R | tail -1)$permanent"$(random) ;; esac echo $serialnum } function msgalert() { if [ "${BUS}" == "block" ]; then echo -e "\033[1;31m$1\033[0m" else printf "\033[1;35m%b\033[0m" "${1//\\n/\\r\\n}" > /dev/tty fi } function msgwarning() { echo -e "\033[1;33m$1\033[0m" } function msgnormal() { echo -e "\033[1;32m$1\033[0m" } function readanswer() { while true; do read answ case $answ in [Yy]* ) answer="$answ"; break;; [Nn]* ) answer="$answ"; break;; * ) msgwarning "Please answer yY/nN.";; esac done } function sync_usb_line() { # 현재 usb_line 추출 updated_usb_line=$(jq -r '.general.usb_line' "$userconfigfile") # extra_cmdline의 각 항목을 읽어서 처리 while IFS='=' read -r key value; do if [ -z "$value" ] || [ "$value" = "null" ]; then continue fi if echo "$updated_usb_line" | grep -q " ${key}="; then updated_usb_line=$(echo "$updated_usb_line" | sed "s/ ${key}=[^ ]*/ ${key}=${value}/g") elif echo "$updated_usb_line" | grep -q "^${key}="; then updated_usb_line=$(echo "$updated_usb_line" | sed "s/^${key}=[^ ]*/${key}=${value}/") else updated_usb_line="${updated_usb_line}${key}=${value} " fi done < <(jq -r '.extra_cmdline | to_entries[] | "\(.key)=\(.value)"' "$userconfigfile") # JSON 파일 업데이트 jq --arg new_line "$updated_usb_line" '.general.usb_line = $new_line' "$userconfigfile" > "${userconfigfile}.tmp" && mv "${userconfigfile}.tmp" "$userconfigfile" } ############################################################################### # Write to json config file function writeConfigKey() { block="$1" field="$2" value="$3" if [ -n "$1 " ] && [ -n "$2" ]; then jsonfile=$(jq ".$block+={\"$field\":\"$value\"}" $userconfigfile) echo $jsonfile | jq . >$userconfigfile sync_usb_line else echo "No values to update" fi } ############################################################################### # Delete field from json config file function DeleteConfigKey() { block="$1" field="$2" if [ -n "$1 " ] && [ -n "$2" ]; then jsonfile=$(jq "del(.$block.$field)" $userconfigfile) echo $jsonfile | jq . >$userconfigfile else echo "No values to remove" fi } function checkmachine() { if grep -q ^flags.*\ hypervisor\ /proc/cpuinfo; then MACHINE="VIRTUAL" HYPERVISOR=$(dmesg | grep -i "Hypervisor detected" | awk '{print $5}') echo "Machine is $MACHINE Hypervisor=$HYPERVISOR" else MACHINE="NON-VIRTUAL" fi if [ $(lspci -nn | grep -ie "\[0107\]" | wc -l) -gt 0 ]; then echo "Found SAS HBAs, Restrict use of DT Models." HBADETECT="ON" else HBADETECT="OFF" fi } function check_github() { echo -n "Checking GitHub Access -> " # nslookup $gitdomain 2>&1 >/dev/null curl --insecure -L -s https://raw.githubusercontent.com/about.html -O 2>&1 >/dev/null if [ $? -eq 0 ]; then echo "OK" else cecho g "Error: GitHub is unavailable. Please try again later." exit 99 fi } ############################################################################### # check for Sas module function checkforsas() { sasmods="mpt3sas hpsa mvsas" for sasmodule in $sasmods do echo "Checking existense of $sasmodule" for sas in `depmod -n 2>/dev/null |grep -i $sasmodule |grep pci|cut -d":" -f 2 | cut -c 6-9,15-18` do if [ `grep -i $sas /proc/bus/pci/devices |wc -l` -gt 0 ] ; then echo " => $sasmodule, device found, block eudev mode" BLOCK_EUDEV="Y" fi done done } ############################################################################### # check Intel or AMD function checkcpu() { if [ $(lscpu |grep Intel |wc -l) -gt 0 ]; then CPU="INTEL" else #if [ $(awk -F':' '/^model name/ {print $2}' /proc/cpuinfo | uniq | sed -e 's/^[ \t]*//' | grep -e N36L -e N40L -e N54L | wc -l) -gt 0 ]; then # CPU="HP" # LDRMODE="JOT" # writeConfigKey "general" "loadermode" "${LDRMODE}" #else CPU="AMD" #fi fi if [ $(lscpu |grep movbe |wc -l) -gt 0 ]; then AFTERHASWELL="ON" else AFTERHASWELL="OFF" fi if [ "$MACHINE" = "VIRTUAL" ] && [ "$HYPERVISOR" = "KVM" ]; then AFTERHASWELL="ON" fi } ############################################################################### # Get fastest url in list # @ - url list function _get_fastest() { local speedlist="" for I in $@; do speed=$(ping -c 1 -W 5 ${I} 2>/dev/null | awk '/time=/ {print $7}' | cut -d '=' -f 2) speedlist+="${I} ${speed:-999}\n" done fastest="$(echo -e "${speedlist}" | tr -s '\n' | sort -k2n | head -1 | awk '{print $1}')" echo "${fastest}" } function chkavail() { if [ $(df -h /mnt/${tcrppart} | grep mnt | awk '{print $4}' | grep G | wc -l) -gt 0 ]; then avail_str=$(df -h /mnt/${tcrppart} | grep mnt | awk '{print $4}' | sed -e 's/G//g' | cut -c 1-3) avail=$(echo "$avail_str 1000" | awk '{print $1 * $2}') else avail=$(df -h /mnt/${tcrppart} | grep mnt | awk '{print $4}' | sed -e 's/M//g' | cut -c 1-3) fi avail_num=$(($avail)) echo "Avail space ${avail_num}M on /mnt/${tcrppart}" } ############################################################################### # get bus of disk # 1 - device path function getBus() { BUS="" # usb/ata(sata/ide)/scsi [ -z "${BUS}" ] && BUS=$(udevadm info --query property --name "${1}" 2>/dev/null | grep ID_BUS | cut -d= -f2 | sed 's/ata/sata/') # usb/sata(sata/ide)/nvme [ -z "${BUS}" ] && BUS=$(lsblk -dpno KNAME,TRAN 2>/dev/null | grep "${1} " | awk '{print $2}') #Spaces are intentional # usb/scsi(sata/ide)/virtio(scsi/virtio)/mmc/nvme/loop block [ -z "${BUS}" ] && BUS=$(lsblk -dpno KNAME,SUBSYSTEMS 2>/dev/null | grep "${1} " | awk '{print $2}' | awk -F':' '{print (NF>1) ? $2 : $0}') #Spaces are intentional # empty is block [ -z "${BUS}" ] && BUS="block" echo "${BUS}" [ "${BUS}" = "nvme" ] && [[ "${loaderdisk}" != *p ]] && loaderdisk="${loaderdisk}p" [ "${BUS}" = "mmc" ] && [[ "${loaderdisk}" != *p ]] && loaderdisk="${loaderdisk}p" [ "${BUS}" = "block" ] && [[ "${loaderdisk}" != *p ]] && loaderdisk="${loaderdisk}p" } ############################################################################### # git clone redpill-load function gitdownload() { git config --global http.sslVerify false if [ -d "/home/tc/redpill-load" ]; then cecho y "Loader sources already downloaded, pulling latest !!!" cd /home/tc/redpill-load git pull if [ $? -ne 0 ]; then cd /home/tc rploader clean git clone -b master --single-branch https://github.com/PeterSuh-Q3/redpill-load.git #git clone -b master --single-branch https://giteas.duckdns.org/PeterSuh-Q3/redpill-load.git fi cd /home/tc else git clone -b master --single-branch https://github.com/PeterSuh-Q3/redpill-load.git #git clone -b master --single-branch https://giteas.duckdns.org/PeterSuh-Q3/redpill-load.git fi } function _pat_process() { PATURL="${URL}" PAT_FILE="${SYNOMODEL}.pat" PAT_PATH="${patfile}" #mirrors=("global.synologydownload.com" "global.download.synology.com" "cndl.synology.cn") mirrors=("global.synologydownload.com" "global.download.synology.com") fastest=$(_get_fastest "${mirrors[@]}") echo "fastest = " "${fastest}" mirror="$(echo ${PATURL} | sed 's|^http[s]*://\([^/]*\).*|\1|')" echo "mirror = " "${mirror}" if echo "${mirrors[@]}" | grep -wq "${mirror}" && [ "${mirror}" != "${fastest}" ]; then echo "Based on the current network situation, switch to ${fastest} mirror to downloading." PATURL="$(echo ${PATURL} | sed "s/${mirror}/${fastest}/")" fi # Discover remote file size echo "BUS type = ${BUS} (Discover remote file size)" if [[ $BIOS_CNT -eq 1 ]] && [ "$FRKRNL" = "YES" ]; then msgnormal "Skip Checking Pat files on xTCRP with Synoboot Injected." else if [ "${BUS}" != "block" ]; then SPACELEFT=$(df --block-size=1 | awk '/'${loaderdisk}'3/{print $4}') # Check disk space left FILESIZE=$(curl -k -sLI "${PATURL}" | grep -i Content-Length | awk '{print$2}') FILESIZE=$(echo "${FILESIZE}" | tr -d '\r') SPACELEFT=$(echo "${SPACELEFT}" | tr -d '\r') FILESIZE_FORMATTED=$(printf "%'d" "${FILESIZE}") SPACELEFT_FORMATTED=$(printf "%'d" "${SPACELEFT}") FILESIZE_MB=$((FILESIZE / 1024 / 1024)) SPACELEFT_MB=$((SPACELEFT / 1024 / 1024)) echo "FILESIZE = ${FILESIZE_FORMATTED} bytes (${FILESIZE_MB} MB)" echo "SPACELEFT = ${SPACELEFT_FORMATTED} bytes (${SPACELEFT_MB} MB)" if [ 0${FILESIZE} -ge 0${SPACELEFT} ]; then # No disk space to download, change it to RAMDISK echo "No adequate space on ${local_cache} to download file into cache folder, clean up PAT file now ....." if [ "$FRKRNL" = "NO" ]; then sudo sh -c "sudo rm -vf $(ls -t ${local_cache}/*.pat | head -n 1)" else sudo sh -c "rm -vf $(ls -t ${local_cache}/*.pat | head -n 1)" fi fi fi fi echo "PATURL = " "${PATURL}" STATUS=$(sudo curl -k -w "%{http_code}" -L "${PATURL}" -o "${PAT_PATH}" --progress-bar) if [ $? -ne 0 -o ${STATUS} -ne 200 ]; then sudo rm -f "${PAT_PATH}" echo "Check internet or cache disk space.\nError: ${STATUS}" exit 99 fi } function setnetwork() { if [ -f /opt/eth*.sh ] && [ "$(grep dhcp /opt/eth*.sh | wc -l)" -eq 0 ]; then ipset="static" ipgw="$(route | grep default | head -1 | awk '{print $2}')" ipprefix="$(grep /sbin/ifconfig /opt/eth*.sh | head -1 | awk '{print "ipcalc -p " $3 " " $5 }' | sh - | awk -F= '{print $2}')" myip="$(grep /sbin/ifconfig /opt/eth*.sh | head -1 | awk '{print $3 }')" ipaddr="${myip}/${ipprefix}" ipgw="$(grep route /opt/eth*.sh | head -1 | awk '{print $5 }')" ipdns="$(grep nameserver /opt/eth*.sh | head -1 | awk '{print $3 }')" ipproxy="$(env | grep -i http | awk -F= '{print $2}' | uniq)" for field in ipset ipaddr ipgw ipdns ipproxy; do jsonfile=$(jq ".ipsettings+={\"$field\":\"${!field}\"}" $userconfigfile) echo $jsonfile | jq . >$userconfigfile done fi } function check_r8168_once() { if [ "$R8168_DETECTED" != "Y" ] && [[ "$DRIVER" == r816* ]]; then R8168_YN="Y" R8168_DETECTED="Y" elif [ "$R8168_DETECTED" != "Y" ]; then R8168_YN="N" fi } function getip() { ethdevs=$(ls /sys/class/net/ | grep eth || true) for eth in $ethdevs; do DRIVER=$(ls -ld /sys/class/net/${eth}/device/driver 2>/dev/null | awk -F '/' '{print $NF}') if [ $(ls -l /sys/class/net/${eth}/device | grep "0000:" | wc -l) -gt 0 ]; then BUSID=$(ls -ld /sys/class/net/${eth}/device 2>/dev/null | awk -F '0000:' '{print $NF}') else BUSID="" fi IP="$(/sbin/ifconfig ${eth} | grep inet | awk '{print $2}' | awk -F \: '{print $2}')" HWADDR="$(/sbin/ifconfig ${eth} | grep HWaddr | awk '{print $5}')" if [ -f /sys/class/net/${eth}/device/vendor ] && [ -f /sys/class/net/${eth}/device/device ]; then VENDOR=$(cat /sys/class/net/${eth}/device/vendor | sed 's/0x//') DEVICE=$(cat /sys/class/net/${eth}/device/device | sed 's/0x//') if [ ! -z "${VENDOR}" ] && [ ! -z "${DEVICE}" ]; then MATCHDRIVER=$(echo "$(matchpciidmodule ${VENDOR} ${DEVICE})") if [ ! -z "${MATCHDRIVER}" ]; then if [ "${MATCHDRIVER}" != "${DRIVER}" ]; then DRIVER=${MATCHDRIVER} fi fi fi fi check_r8168_once echo "IP Addr : $(msgnormal "${IP}"), ${HWADDR}, ${BUSID}, ${eth} (${DRIVER})" done } function listpci() { lspci -n | while read line; do bus="$(echo $line | cut -c 1-7)" class="$(echo $line | cut -c 9-12)" vendor="$(echo $line | cut -c 15-18)" device="$(echo $line | cut -c 20-23)" #echo "PCI : $bus Class : $class Vendor: $vendor Device: $device" case $class in # 0100) # echo "Found SCSI Controller : pciid ${vendor}d0000${device} Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; # 0106) # echo "Found SATA Controller : pciid ${vendor}d0000${device} Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; # 0101) # echo "Found IDE Controller : pciid ${vendor}d0000${device} Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; 0104) msgnormal "RAID bus Controller : Required Extension : $(matchpciidmodule ${vendor} ${device})" echo `lspci -nn |grep ${vendor}:${device}|awk 'match($0,/0104/) {print substr($0,RSTART+7,100)}'`| sed 's/\['"$vendor:$device"'\]//' | sed 's/(rev 05)//' ;; 0107) msgnormal "SAS Controller : Required Extension : $(matchpciidmodule ${vendor} ${device})" echo `lspci -nn |grep ${vendor}:${device}|awk 'match($0,/0107/) {print substr($0,RSTART+7,100)}'`| sed 's/\['"$vendor:$device"'\]//' | sed 's/(rev 03)//' ;; # 0200) # msgnormal "Ethernet Interface : Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; # 0680) # msgnormal "Ethernet Interface : Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; # 0300) # echo "Found VGA Controller : pciid ${vendor}d0000${device} Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; # 0c04) # echo "Found Fibre Channel Controller : pciid ${vendor}d0000${device} Required Extension : $(matchpciidmodule ${vendor} ${device})" # ;; esac done } function monitor() { getloaderdisk if [ -z "${loaderdisk}" ]; then echo "Not Supported Loader BUS Type, program Exit!!!" exit 99 fi getBus "${loaderdisk}" [ "$(mount | grep /dev/${loaderdisk}1 | wc -l)" -eq 0 ] && mount /dev/${loaderdisk}1 [ "$(mount | grep /dev/${loaderdisk}2 | wc -l)" -eq 0 ] && mount /dev/${loaderdisk}2 HYPERVISOR=$(dmesg | grep -i "Hypervisor detected" | awk '{print $5}') while true; do clear echo -e "-------------------------------System Information----------------------------" echo -e "Hostname:\t\t"$(hostname) echo -e "uptime:\t\t\t"$(uptime | awk '{print $3}' | sed 's/,//')" min" echo -e "Manufacturer:\t\t"$(cat /sys/class/dmi/id/chassis_vendor) echo -e "Product Name:\t\t"$(cat /sys/class/dmi/id/product_name) echo -e "Version:\t\t"$(cat /sys/class/dmi/id/product_version) echo -e "Serial Number:\t\t"$(sudo cat /sys/class/dmi/id/product_serial) echo -e "Operating System:\t"$(grep PRETTY_NAME /etc/os-release | awk -F \= '{print $2}') echo -e "Kernel:\t\t\t"$(uname -r) echo -e "Processor Name:\t\t"$(awk -F':' '/^model name/ {print $2}' /proc/cpuinfo | uniq | sed -e 's/^[ \t]*//') echo -e "Machine Type:\t\t"$( vserver=$(lscpu | grep Hypervisor | wc -l) [ $vserver -gt 0 ] && echo -e "VM (${HYPERVISOR})\n" || echo -e "Physical\n" [ -d /sys/firmware/efi ] && echo ": EFI" || echo ": LEGACY(CSM,BIOS)" ) msgnormal "CPU Threads:\t\t"$(nproc) echo -e "Current Date Time:\t"$(date) #msgnormal "System Main IP:\t\t"$(/sbin/ifconfig | grep inet | grep -v 127.0.0.1 | awk '{print $2}' | awk -F \: '{print $2}' | tr '\n' ',' | sed 's#,$##') getip listpci echo -e "-------------------------------Loader boot entries---------------------------" grep -i menuentry /mnt/${loaderdisk}1/boot/grub/grub.cfg | awk -F \' '{print $2}' echo -e "-------------------------------CPU / Memory----------------------------------" msgnormal "Total Memory (MB):\t"$(cat /proc/meminfo |grep MemTotal | awk '{printf("%.2f"), $2/1000}') echo -e "Swap Usage:\t\t"$(free | awk '/Swap/{printf("%.2f%"), $3/$2*100}') echo -e "CPU Usage:\t\t"$(cat /proc/stat | awk '/cpu/{printf("%.2f%\n"), ($2+$4)*100/($2+$4+$5)}' | awk '{print $0}' | head -1) echo -e "-------------------------------Disk Usage >80%-------------------------------" df -Ph /mnt/${loaderdisk}1 /mnt/${loaderdisk}2 /mnt/${loaderdisk}3 echo "Press ctrl-c to exit" sleep 10 done } function savesession() { lastsessiondir="/mnt/${tcrppart}/lastsession" echo -n "Saving user session for future use. " [ ! -d ${lastsessiondir} ] && sudo mkdir ${lastsessiondir} echo -n "Saving current extensions " if [ "$FRKRNL" = "NO" ]; then cat /home/tc/redpill-load/custom/extensions/*/*json | jq '.url' >${lastsessiondir}/extensions.list else echo fi [ -f ${lastsessiondir}/extensions.list ] && echo " -> OK !" echo -n "Saving current user_config.json " if [ "$FRKRNL" = "NO" ]; then cp /home/tc/user_config.json ${lastsessiondir}/user_config.json else sudo cp /home/tc/user_config.json ${lastsessiondir}/user_config.json fi [ -f ${lastsessiondir}/user_config.json ] && echo " -> OK !" } function copyextractor() { #m shell mofified local_cache="/mnt/${tcrppart}/auxfiles" echo "making directory ${local_cache}" [ ! -d ${local_cache} ] && mkdir ${local_cache} echo "making directory ${local_cache}/extractor" [ ! -d ${local_cache}/extractor ] && sudo mkdir ${local_cache}/extractor [ ! -f /home/tc/extractor.gz ] && sudo curl -kL -# "https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/master/extractor.gz" -o /home/tc/extractor.gz sudo tar -zxvf /home/tc/extractor.gz -C ${local_cache}/extractor if [ "${BUS}" = "block" ]; then git clone https://github.com/technorabilia/syno-extract-system-patch.git cd syno-extract-system-patch sudo docker build --tag syno-extract-system-patch . sudo mkdir -p ~/data/in sudo mkdir -p ~/data/out fi echo "Copying required libraries to local lib directory" sudo cp /mnt/${tcrppart}/auxfiles/extractor/lib* /lib/ echo "Linking lib to lib64" [ ! -h /lib64 ] && sudo ln -s /lib /lib64 echo "Copying executable" sudo cp /mnt/${tcrppart}/auxfiles/extractor/scemd /bin/syno_extract_system_patch echo "pigz copy for multithreaded compression" sudo cp /mnt/${tcrppart}/auxfiles/extractor/pigz /usr/bin/pigz } function downloadextractor() { st "extractor" "Extraction tools" "Extraction Tools downloaded" [ "${BUS}" != "block" ] && log_build_step "Extraction tools" 3 12 # loaderdisk="$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3)" # tcrppart="$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3)3" local_cache="/mnt/${tcrppart}/auxfiles" temp_folder="/tmp/synoesp" #m shell mofified copyextractor if [ -d ${local_cache/extractor /} ] && [ -f ${local_cache}/extractor/scemd ]; then msgnormal "Found extractor locally cached" else echo "Getting required extraction tool" echo "------------------------------------------------------------------" echo "Checking tinycore cache folder" [ -d $local_cache ] && echo "Found tinycore cache folder, linking to home/tc/custom-module" && [ ! -h /home/tc/custom-module ] && sudo ln -s $local_cache /home/tc/custom-module echo "Creating temp folder /tmp/synoesp" mkdir ${temp_folder} if [ -d /home/tc/custom-module ] && [ -f /home/tc/custom-module/*42218*.pat ]; then patfile=$(ls /home/tc/custom-module/*42218*.pat | head -1) echo "Found custom pat file ${patfile}" echo "Processing old pat file to extract required files for extraction" tar -C${temp_folder} -xf /${patfile} rd.gz else curl -kL https://global.download.synology.com/download/DSM/release/7.0.1/42218/DSM_DS3622xs%2B_42218.pat -o /home/tc/oldpat.tar.gz [ -f /home/tc/oldpat.tar.gz ] && tar -C${temp_folder} -xf /home/tc/oldpat.tar.gz rd.gz fi echo "Entering synoesp" cd ${temp_folder} xz -dc rd 2>/dev/null || echo "extract rd.gz" echo "finish" cpio -idm &1 || echo "extract rd" mkdir extract mkdir /mnt/${tcrppart}/auxfiles && cd /mnt/${tcrppart}/auxfiles echo "Copying required files to local cache folder for future use" mkdir /mnt/${tcrppart}/auxfiles/extractor for file in usr/lib/libcurl.so.4 usr/lib/libmbedcrypto.so.5 usr/lib/libmbedtls.so.13 usr/lib/libmbedx509.so.1 usr/lib/libmsgpackc.so.2 usr/lib/libsodium.so usr/lib/libsynocodesign-ng-virtual-junior-wins.so.7 usr/syno/bin/scemd; do echo "Copying $file to /mnt/${tcrppart}/auxfiles" cp $file /mnt/${tcrppart}/auxfiles/extractor done fi echo "Removing temp folder /tmp/synoesp" rm -rf $temp_folder if [ "${BUS}" != "block" ]; then msgnormal "Checking if tool is accessible" if [ -d ${local_cache/extractor /} ] && [ -f ${local_cache}/extractor/scemd ]; then /bin/syno_extract_system_patch 2>&1 >/dev/null else /bin/syno_extract_system_patch fi if [ $? -eq 255 ]; then echo "Executed succesfully"; else echo "Cound not execute"; fi fi } function testarchive() { archive="$1" if [ "${BUS}" != "block" ]; then archiveheader="$(od -bcN2 ${archive} | awk 'NR==1 {print $3; exit}')" case ${archiveheader} in 105) echo "${archive}, is a Tar file" isencrypted="no" return 0 ;; 255) echo "File ${archive}, is encrypted" isencrypted="yes" return 1 ;; 213) echo "File ${archive}, is a compressed tar" isencrypted="no" ;; 057) echo "File ${archive}, is a compressed tar (from GNU friend kernel)" isencrypted="no" ;; *) echo "Could not determine if file ${archive} is encrypted or not, maybe corrupted" ls -ltr ${archive} echo ${archiveheader} exit 99 ;; esac else if [ ${TARGET_REVISION} -gt 42218 ]; then echo "Found build request for revision greater than 42218" echo "File ${archive}, is encrypted" isencrypted="yes" return 1 else echo "Found build request for revision less equal than 42218" echo "${archive}, is a Tar file" isencrypted="no" return 0 fi fi } function processpat() { # loaderdisk="$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3)" # tcrppart="$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3)3" if [[ $BIOS_CNT -eq 1 ]] && [ "$FRKRNL" = "YES" ]; then local_cache="/dev/shm" else local_cache="/mnt/${tcrppart}/auxfiles" fi temp_pat_folder="/tmp/pat" temp_dsmpat_folder="/tmp/dsmpat" setplatform if [ ! -d "${temp_pat_folder}" ]; then msgnormal "Creating temp folder ${temp_pat_folder} " mkdir ${temp_pat_folder} && sudo mount -t tmpfs -o size=512M tmpfs ${temp_pat_folder} && cd ${temp_pat_folder} mkdir ${temp_dsmpat_folder} && sudo mount -t tmpfs -o size=512M tmpfs ${temp_dsmpat_folder} fi echo "Checking for cached pat file" [ -d $local_cache ] && msgnormal "Found tinycore cache folder, linking to home/tc/custom-module" && [ ! -h /home/tc/custom-module ] && sudo ln -s $local_cache /home/tc/custom-module if [ -d ${local_cache} ] && [ -f ${local_cache}/*${SYNOMODEL}*.pat ] || [ -f ${local_cache}/*${MODEL}*${TARGET_REVISION}*.pat ]; then [ -f /home/tc/custom-module/*${SYNOMODEL}*.pat ] && patfile=$(ls /home/tc/custom-module/*${SYNOMODEL}*.pat | head -1) [ -f ${local_cache}/*${MODEL}*${TARGET_REVISION}*.pat ] && patfile=$(ls /home/tc/custom-module/*${MODEL}*${TARGET_REVISION}*.pat | head -1) msgnormal "Found locally cached pat file ${patfile}" st "iscached" "Caching pat file" "Patfile ${SYNOMODEL}.pat is cached" [ "${BUS}" != "block" ] && log_build_step "Caching pat file" 4 12 testarchive "${patfile}" if [ ${isencrypted} = "no" ]; then echo "File ${patfile} is already decrypted" msgnormal "Copying file to /home/tc/redpill-load/cache folder" sudo mv -f ${patfile} /home/tc/redpill-load/cache/ elif [ ${isencrypted} = "yes" ]; then [ -f /home/tc/redpill-load/cache/${SYNOMODEL}.pat ] && testarchive /home/tc/redpill-load/cache/${SYNOMODEL}.pat if [ -f /home/tc/redpill-load/cache/${SYNOMODEL}.pat ] && [ ${isencrypted} = "no" ]; then echo "Decrypted file is already cached in : /home/tc/redpill-load/cache/${SYNOMODEL}.pat" else if [ "${BUS}" = "block" ]; then echo "Copying encrypted pat file : ${patfile} to ~/data/in" sudo mv -f ${patfile} ~/data/in/${SYNOMODEL}.pat echo "Extracting encrypted pat file : ~/data/in/${SYNOMODEL}.pat to ~/data/out" sudo docker run --rm -v ~/data:/data syno-extract-system-patch /data/in/${SYNOMODEL}.pat /data/out/. || echo "extract latest pat" rsync -a --remove-source-files ~/data/out/ ${temp_pat_folder}/ else echo "Copying encrypted pat file : ${patfile} to ${temp_dsmpat_folder}" sudo mv -f ${patfile} ${temp_dsmpat_folder}/${SYNOMODEL}.pat echo "Extracting encrypted pat file : ${temp_dsmpat_folder}/${SYNOMODEL}.pat to ${temp_pat_folder}" sudo /bin/syno_extract_system_patch ${temp_dsmpat_folder}/${SYNOMODEL}.pat ${temp_pat_folder} || echo "extract latest pat" fi echo "Decrypted pat file tar compression in progress ${SYNOMODEL}.pat to /home/tc/redpill-load/cache folder (multithreaded comporession)" mkdir -p /home/tc/redpill-load/cache/ echo "threads = ${threads}" if [ "${BUS}" = "block" ]; then cd ${temp_pat_folder} && tar -cf ${temp_dsmpat_folder}/${SYNOMODEL}.pat ./ && cp -f ${temp_dsmpat_folder}/${SYNOMODEL}.pat /home/tc/redpill-load/cache/${SYNOMODEL}.pat else if [ "$FRKRNL" = "NO" ]; then cd ${temp_pat_folder} && sudo sh -c "tar -cf - ./ | pigz -p ${threads} > ${temp_dsmpat_folder}/${SYNOMODEL}.pat" && sudo cp -f ${temp_dsmpat_folder}/${SYNOMODEL}.pat /home/tc/redpill-load/cache/${SYNOMODEL}.pat else cd ${temp_pat_folder} && sudo sh -c "tar -cf ${temp_dsmpat_folder}/${SYNOMODEL}.pat ./" && sudo cp -f ${temp_dsmpat_folder}/${SYNOMODEL}.pat /home/tc/redpill-load/cache/${SYNOMODEL}.pat fi fi fi patfile="/home/tc/redpill-load/cache/${SYNOMODEL}.pat" else echo "Something went wrong, please check cache files" exit 99 fi cd /home/tc/redpill-load/cache st "patextraction" "Pat file extracted" "VERSION:${BUILD}" [ "${BUS}" != "block" ] && log_build_step "Pat file extracted" 5 12 sudo tar xvf /home/tc/redpill-load/cache/${SYNOMODEL}.pat ./VERSION && . ./VERSION && cat ./VERSION && rm ./VERSION os_md5=$(md5sum /home/tc/redpill-load/cache/${SYNOMODEL}.pat | awk '{print $1}') msgnormal "Pat file md5sum is : $os_md5" echo -n "Checking config file existence -> " if [ -f "/home/tc/redpill-load/config/pats.json" ]; then echo "OK" else echo "No config file(pats.json) found, The download may be corrupted or may not be run the original repo. Please re-download from original repo." exit 99 fi msgnormal "Editing config file !!!!!" echo -n "Verifying config file -> " verifyid=$(jq -e -r ".\"${MODEL}\" | to_entries | map(select(.key | startswith(\"${BUILD}\"))) | map(.value.sum) | .[0]" "${configfile}") sed -i "s/${verifyid}/$os_md5/" ${configfile} verifyid="$os_md5" if [ "$os_md5" == "$verifyid" ]; then echo "OK ! " else echo "config file, os md5 verify FAILED, check ${configfile} " exit 99 fi msgnormal "Clearing temp folders" sudo umount ${temp_pat_folder} && sudo rm -rf ${temp_pat_folder} sudo umount ${temp_dsmpat_folder} && sudo rm -rf ${temp_dsmpat_folder} return else echo "Could not find pat file locally cached" pat_url=$(jq -e -r ".\"${MODEL}\" | to_entries | map(select(.key | startswith(\"${BUILD}\"))) | map(.value.url) | .[0]" "${configfile}") echo -e "Configfile: $configfile \nPat URL : $pat_url" echo "Downloading pat file from URL : ${pat_url} " chkavail if [ $avail_num -le 370 ]; then echo "No adequate space on ${local_cache} to download file into cache folder, clean up the space and restart" exit 99 fi [ -n $pat_url ] && curl -kL ${pat_url} -o "/${local_cache}/${SYNOMODEL}.pat" patfile="/${local_cache}/${SYNOMODEL}.pat" if [ -f ${patfile} ]; then testarchive ${patfile} else echo "Failed to download PAT file $patfile from ${pat_url} " exit 99 fi if [ "${isencrypted}" = "yes" ]; then echo "File ${patfile}, has been cached but its encrypted, re-running decrypting process" processpat else return fi fi } function addrequiredexts() { echo "Processing add_extensions entries found on models.json file : ${EXTENSIONS}" for extension in ${EXTENSIONS_SOURCE_URL}; do echo "Adding extension ${extension} " cd /home/tc/redpill-load/ && ./ext-manager.sh add "$(echo $extension | sed -s 's/"//g' | sed -s 's/,//g')" if [ $? -ne 0 ]; then echo "FAILED : Processing add_extensions failed check the output for any errors" rploader clean exit 99 fi done if echo ${kver5platforms} | grep -qw ${ORIGIN_PLATFORM}; then vkersion=${major}${minor}_${KVER} else vkersion=${KVER} fi for extension in ${EXTENSIONS}; do echo "Updating extension : ${extension} contents for platform, kernel : ${ORIGIN_PLATFORM}, ${vkersion} " platkver="$(echo ${ORIGIN_PLATFORM}_${vkersion} | sed 's/\.//g')" echo "platkver = ${platkver}" cd /home/tc/redpill-load/ && ./ext-manager.sh _update_platform_exts ${platkver} ${extension} if [ $? -ne 0 ]; then echo "FAILED : Processing add_extensions failed check the output for any errors" rploader clean exit 99 fi done #m shell only #Use user define dts file instaed of dtbpatch ext now #if [ ${ORIGIN_PLATFORM} = "geminilake" ] || [ ${ORIGIN_PLATFORM} = "v1000" ] || [ ${ORIGIN_PLATFORM} = "r1000" ]; then # echo "For user define dts file instaed of dtbpatch ext" # patchdtc # echo "Patch dtc is superseded by fbelavenuto dtbpatch" #fi } function updateuserconfig() { echo "Checking user config for general block" generalblock="$(jq -r -e '.general' $userconfigfile)" if [ "$generalblock" = "null" ] || [ -n "$generalblock" ]; then echo "Result=${generalblock}, File does not contain general block, adding block" for field in model version smallfixnumber redpillmake zimghash rdhash usb_line sata_line; do jsonfile=$(jq ".general+={\"$field\":\"\"}" $userconfigfile) echo $jsonfile | jq . >$userconfigfile done fi } function updateuserconfigfield() { block="$1" field="$2" value="$3" if [ -n "$1 " ] && [ -n "$2" ]; then jsonfile=$(jq ".$block+={\"$field\":\"$value\"}" $userconfigfile) echo $jsonfile | jq . >$userconfigfile else echo "No values to update specified" fi } function postupdate() { # loaderdisk="$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3)" cd /home/tc updateuserconfig setnetwork updateuserconfigfield "general" "model" "$MODEL" updateuserconfigfield "general" "version" "${BUILD}" updateuserconfigfield "general" "smallfixnumber" "${smallfixnumber}" updateuserconfigfield "general" "redpillmake" "${redpillmake}-${TAG}" echo "Creating temp ramdisk space" && mkdir /home/tc/ramdisk echo "Mounting partition ${loaderdisk}1" && sudo mount /dev/${loaderdisk}1 echo "Mounting partition ${loaderdisk}2" && sudo mount /dev/${loaderdisk}2 zimghash=$(sha256sum /mnt/${loaderdisk}2/zImage | awk '{print $1}') updateuserconfigfield "general" "zimghash" "$zimghash" rdhash=$(sha256sum /mnt/${loaderdisk}2/rd.gz | awk '{print $1}') updateuserconfigfield "general" "rdhash" "$rdhash" zimghash=$(sha256sum /mnt/${loaderdisk}2/zImage | awk '{print $1}') updateuserconfigfield "general" "zimghash" "$zimghash" rdhash=$(sha256sum /mnt/${loaderdisk}2/rd.gz | awk '{print $1}') updateuserconfigfield "general" "rdhash" "$rdhash" echo "Backing up $userconfigfile " cp $userconfigfile /mnt/${loaderdisk}3 cd /home/tc/ramdisk echo "Extracting update ramdisk" if [ $(od /mnt/${loaderdisk}2/rd.gz | head -1 | awk '{print $2}') == "000135" ]; then sudo unlzma -c /mnt/${loaderdisk}2/rd.gz | cpio -idm 2>&1 >/dev/null else sudo cat /mnt/${loaderdisk}2/rd.gz | cpio -idm 2>&1 >/dev/null fi . ./etc.defaults/VERSION && echo "Found Version : ${productversion}-${buildnumber}-${smallfixnumber}" # echo -n "Do you want to use this for the loader ? [yY/nN] : " # readanswer # if [ "$answer" == "y" ] || [ "$answer" == "Y" ]; then echo "Extracting redpill ramdisk" if [ $(od /mnt/${loaderdisk}3/rd.gz | head -1 | awk '{print $2}') == "000135" ]; then sudo unlzma -c /mnt/${loaderdisk}3/rd.gz | cpio -idm RD_COMPRESSED="yes" else sudo cat /mnt/${loaderdisk}3/rd.gz | cpio -idm fi . ./etc.defaults/VERSION && echo "The new smallupdate version will be : ${productversion}-${buildnumber}-${smallfixnumber}" # echo -n "Do you want to use this for the loader ? [yY/nN] : " # readanswer # if [ "$answer" == "y" ] || [ "$answer" == "Y" ]; then echo "Recreating ramdisk " if [ "$RD_COMPRESSED" = "yes" ]; then sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root | xz -9 --format=lzma >../rd.gz else sudo find . 2>/dev/null | sudo cpio -o -H newc -R root:root >../rd.gz fi cd .. echo "Adding fake sign" && sudo dd if=/dev/zero of=rd.gz bs=68 count=1 conv=notrunc oflag=append echo "Putting ramdisk back to the loader partition ${loaderdisk}1" && sudo cp -f rd.gz /mnt/${loaderdisk}3/rd.gz echo "Removing temp ramdisk space " && rm -rf ramdisk echo "Done" # else # echo "Removing temp ramdisk space " && rm -rf ramdisk # exit 0 # fi # fi } function getgrubbkg() { curl -kLO# "https://github.com/PeterSuh-Q3/tinycore-redpill/raw/main/grub/grubbkg.cfg" if [ ! -f /home/tc/grubbkg.png ]; then curl -kLO# "https://github.com/PeterSuh-Q3/tinycore-redpill/raw/main/grub/grubbkg.png" sudo cp -vf /home/tc/grubbkg.png /mnt/${loaderdisk}3/grubbkg.png fi } function getbspatch() { chmod 777 /home/tc/tools/bspatch if [ "$FRKRNL" = "YES" ]; then if [ ! -f /usr/bin/bspatch ]; then echo "bspatch does not exist, copy from tools" sudo cp -vf /home/tc/tools/bspatch /usr/bin/ fi else if [ ! -f /usr/local/bin/bspatch ]; then echo "bspatch does not exist, copy from tools" sudo cp -vf /home/tc/tools/bspatch /usr/local/bin/ fi fi } function getpigz() { if [ ! -n "$(which pigz)" ]; then echo "pigz does not exist, bringing over from repo" curl -skLO "https://raw.githubusercontent.com/PeterSuh-Q3/tinycore-redpill/$build/tools/pigz" chmod 777 /home/tc/pigz sudo cp -vf /home/tc/pigz /usr/bin/ fi } function removemodelexts() { echo "Entering redpill-load directory to remove exts" cd /home/tc/redpill-load/ echo "Removing all exts directories..." sudo rm -rf /home/tc/redpill-load/custom/extensions/* #echo "Removing model exts directories..." #for modelextdir in ${EXTENSIONS}; do # if [ -d /home/tc/redpill-load/custom/extensions/${modelextdir} ]; then # echo "Removing : ${modelextdir}" # sudo rm -rf /home/tc/redpill-load/custom/extensions/${modelextdir} # fi #done } function getPlatforms() { platform_versions=$(jq -s '.[0].build_configs=(.[1].build_configs + .[0].build_configs | unique_by(.id)) | .[0]' custom_config.json | jq -r '.build_configs[].id') echo "platform_versions=$platform_versions" } function selectPlatform() { platform_selected=$(jq -r ".${1}" models.json) echo "platform_selected=${platform_selected}" } function getValueByJsonPath() { local JSONPATH=${1} local CONFIG=${2} jq -c -r "${JSONPATH}" <<<${CONFIG} } function readConfig() { if [ ! -e custom_config.json ]; then cat global_config.json else jq -s '.[0].build_configs=(.[1].build_configs + .[0].build_configs | unique_by(.id)) | .[0]' custom_config.json fi } function setplatform() { SYNOMODEL=${TARGET_PLATFORM}_${TARGET_REVISION} #MODEL=$(echo "${TARGET_PLATFORM}" | sed 's/ds/DS/' | sed 's/rs/RS/' | sed 's/p/+/' | sed 's/dva/DVA/' | sed 's/fs/FS/' | sed 's/sa/SA/' ) #ORIGIN_PLATFORM="$(echo $platform_selected | jq -r -e '.platform_name')" } function getvars() { KVER="$(jq -r -e '.general.kver' $userconfigfile)" CONFIG=$(readConfig) selectPlatform $1 GETTIME=$(curl -k -v -s https://google.com/ 2>&1 | grep Date | sed -e 's/< Date: //') INTERNETDATE=$(date +"%d%m%Y" -d "$GETTIME") LOCALDATE=$(date +"%d%m%Y") #EXTENSIONS="$(echo $platform_selected | jq -r -e '.add_extensions[]')" EXTENSIONS="$(echo $platform_selected | jq -r -e '.add_extensions[]' | grep json | awk -F: '{print $1}' | sed -s 's/"//g')" #EXTENSIONS_SOURCE_URL="$(echo $platform_selected | jq '.add_extensions[] .url')" EXTENSIONS_SOURCE_URL="$(echo $platform_selected | jq '.add_extensions[]' | grep json | awk '{print $2}')" #TARGET_PLATFORM="$(echo $platform_selected | jq -r -e '.id | split("-")' | jq -r -e .[0])" #TARGET_VERSION="$(echo $platform_selected | jq -r -e '.id | split("-")' | jq -r -e .[1])" #TARGET_REVISION="$(echo $platform_selected | jq -r -e '.id | split("-")' | jq -r -e .[2])" tcrppart="${tcrpdisk}3" local_cache="/mnt/${tcrppart}/auxfiles" usbpart1uuid=$(/sbin/blkid /dev/${tcrpdisk}1 | awk '{print $3}' | sed -e "s/\"//g" -e "s/UUID=//g") usbpart3uuid="6234-C863" [ ! -h /lib64 ] && sudo ln -s /lib /lib64 sudo chown -R tc:staff /home/tc getgrubbkg getbspatch getpigz if [ "${offline}" = "NO" ]; then echo "Redownload the latest module.alias.4.json file ..." echo curl -ksL "$modalias4" -o modules.alias.4.json.gz [ -f modules.alias.4.json.gz ] && gunzip -f modules.alias.4.json.gz fi [ ! -d ${local_cache} ] && sudo mkdir -p ${local_cache} [ -h /home/tc/custom-module ] && unlink /home/tc/custom-module [ ! -h /home/tc/custom-module ] && sudo ln -s $local_cache /home/tc/custom-module if [ -z "$TARGET_PLATFORM" ] || [ -z "$TARGET_VERSION" ] || [ -z "$TARGET_REVISION" ]; then echo "Error : Platform not found " showhelp exit 99 fi if echo ${kver3platforms} | grep -qw ${ORIGIN_PLATFORM}; then KERNEL_MAJOR="3" MODULE_ALIAS_FILE="modules.alias.3.json" else KERNEL_MAJOR="4" MODULE_ALIAS_FILE="modules.alias.4.json" fi setplatform threads="$(nproc)" [ -z "$threads" ] && threads="1" #echo "Platform : $platform_selected" echo "Verbose Mode : $VERBOSE_MODE" echo "Rploader Version : ${rploaderver}" echo "Extensions : $EXTENSIONS " echo "Extensions URL : $EXTENSIONS_SOURCE_URL" echo "TARGET_PLATFORM : $TARGET_PLATFORM" echo "TARGET_VERSION : $TARGET_VERSION" echo "TARGET_REVISION : $TARGET_REVISION" echo "KERNEL_MAJOR : $KERNEL_MAJOR" echo "MODULE_ALIAS_FILE : $MODULE_ALIAS_FILE" echo "SYNOMODEL : $SYNOMODEL" echo "MODEL : $MODEL" echo "KERNEL VERSION : $KVER" echo "Local Cache Folder : $local_cache" echo "CPU THREADS : $threads" echo "DATE Internet : $INTERNETDATE Local : $LOCALDATE" if [ "${offline}" = "NO" ]; then if [ "$INTERNETDATE" != "$LOCALDATE" ]; then echo "ERROR ! System DATE is not correct" synctime echo "Current time after communicating with NTP server ${ntpserver} : $(date) " fi LOCALDATE=$(date +"%d%m%Y") if [ "$INTERNETDATE" != "$LOCALDATE" ]; then echo "Sync with NTP server ${ntpserver} : $(date) Fail !!!" echo "ERROR !!! The system date is incorrect." exit 99 fi fi #getvarsmshell "$MODEL" } function cleanloader() { echo "Clearing local redpill files" sudo rm -rf /home/tc/redpill* sudo rm -rf /home/tc/*tgz } function backupxtcrp() { TGZ_FILE="${1}/xtcrp.tgz" BACKUP_FILE="/dev/shm/xtcrp.tgz.bak" TAR_UNZIPPED="/dev/shm/xtcrp.tar" SOURCE_FILE="/home/tc/user_config.json" if [ -f "$TGZ_FILE" ]; then if [ ! -f "$SOURCE_FILE" ]; then echo "Error: Source file ${SOURCE_FILE} does not exist!" exit 1 fi echo "Adding ${SOURCE_FILE} to ${TGZ_FILE} !!!" # 백업 생성 sudo cp "$TGZ_FILE" "$BACKUP_FILE" sudo cp "$TGZ_FILE" /dev/shm/xtcrp.tgz # Decompress the existing archive if ! sudo gunzip /dev/shm/xtcrp.tgz; then echo "Error: Failed to decompress ${TGZ_FILE}. Restoring backup." sudo mv "$BACKUP_FILE" "$TGZ_FILE" exit 1 fi # Add the file to the archive with relative path if ! sudo tar --append -C "$(dirname "$SOURCE_FILE")" --file="$TAR_UNZIPPED" "$(basename "$SOURCE_FILE")"; then echo "Error: Failed to add ${SOURCE_FILE} to archive." sudo mv "$BACKUP_FILE" "$TGZ_FILE" exit 1 fi # Compress the archive again and save with the original name if ! sudo sh -c "gzip -c $TAR_UNZIPPED > $TGZ_FILE"; then echo "Error: Failed to compress ${TAR_UNZIPPED}. Restoring original file." sudo mv "$BACKUP_FILE" "$TGZ_FILE" exit 1 fi # Replace original file with compressed archive and clean up temporary files sudo rm -f "$TAR_UNZIPPED" "$BACKUP_FILE" echo "Successfully added ${SOURCE_FILE} to ${TGZ_FILE}." else echo "Error: Target archive ${TGZ_FILE} does not exist!" fi } # ============================================================================ # 개선된 backuploader() 함수 # # 기능 개선사항: # 1. /mnt/${tcrppart} 여유공간 사전 계산 # 2. xtcrp.tgz 및 mydata.tgz를 /dev/shm/ 에서 압축 # 3. 용량 초과 시 /mnt/${tcrppart}/auxfiles/*.pat 파일 임의 1개 삭제 # 4. 기존 sudo 권한 삭제 로직 참조 # ============================================================================ function backuploader() { # Define the path to the file local FILE_PATH="/opt/.filetool.lst" sudo ln -sf /home/tc/menu.sh /usr/bin/menu.sh sudo ln -sf /home/tc/monitor.sh /usr/bin/monitor.sh sudo ln -sf /home/tc/ntp.sh /usr/bin/ntp.sh # Define the patterns to be added PATTERNS=("etc/motd" "usr/bin/menu.sh" "usr/bin/monitor.sh" "usr/bin/ntp.sh" "usr/sbin/sz" "usr/sbin/rz" "usr/local/bin/bspatch" "usr/bin/pigz") # 파일이 존재하고 FILE_PATH에 없는 경우만 추가 for pattern in "${PATTERNS[@]}"; do if [ -f "/$pattern" ]; then # 중복 확인 후 추가 if [ -f "$FILE_PATH" ] && grep -qF "$pattern" "$FILE_PATH"; then echo "Already exists in list: $pattern" >&2 else echo "$pattern" >> "$FILE_PATH" echo "Added to backup list: $pattern" >&2 fi else echo "File not found, skipping: /$pattern" >&2 fi done 2>/dev/null # 전체 오류 출력 억제 local thread=$(nproc) local backup_path="/mnt/${tcrppart}" local auxfiles_path="${backup_path}/auxfiles" local shm_path="/dev/shm" # 로깅 함수 (기존 코드와 호환) local log_prefix="[BACKUP]" echo "${log_prefix} Backup loader process starting..." # ======================================================================== # STEP 1: /mnt/${tcrppart}의 여유공간 계산 # ======================================================================== echo "${log_prefix} Calculating available space on ${backup_path}..." local avail_space_kb=$(df "${backup_path}" | tail -1 | awk '{print $4}') local avail_space_mb=$((avail_space_kb / 1024)) echo "${log_prefix} Available space: ${avail_space_mb} MB" # 필요한 최소 여유공간 (버퍼: 100MB) local min_required_space=$((150 + 100)) # xtcrp.tgz + mydata.tgz + 버퍼 if [ ${avail_space_mb} -lt ${min_required_space} ]; then echo "${log_prefix} WARNING: Low disk space (${avail_space_mb}MB < ${min_required_space}MB)" echo "${log_prefix} Will attempt to free up space by removing old .pat files..." fi # ======================================================================== # STEP 2: /dev/shm에서 xtcrp.tgz 압축 # ======================================================================== echo "${log_prefix} Compressing xtcrp to ${shm_path}/xtcrp.tgz..." local xtcrp_shm="${shm_path}/xtcrp.tgz" local xtcrp_dest="${backup_path}/xtcrp.tgz" # 기존 /dev/shm 파일 정리 if [ -f "${xtcrp_shm}" ]; then sudo rm -f "${xtcrp_shm}" fi # xtcrp 압축 (ramdisk에서 수행하여 속도 향상) if [ "${BUS}" != "block" ]; then # BIOS_CNT가 1이고 FRKRNL이 YES인 경우 특별 처리 if [ ${BIOS_CNT} -eq 1 ] && [ "${FRKRNL}" = "YES" ]; then backupxtcrp "${backup_path}" return $? else # 표준 백업: tar + pigz 사용 if ! sudo sh -c "cd . && tar -cf - . | pigz -p ${thread}" > "${xtcrp_shm}" 2>/dev/null; then echo "${log_prefix} ERROR: Failed to create xtcrp.tgz in ${shm_path}!" return 1 fi fi else # BUS == block 인 경우 if ! sudo sh -c "cd . && tar -cf - . | pigz -p ${thread}" > "${xtcrp_shm}" 2>/dev/null; then echo "${log_prefix} ERROR: Failed to create xtcrp.tgz in ${shm_path}!" return 1 fi fi echo "${log_prefix} xtcrp.tgz created successfully in ${shm_path}" # ======================================================================== # STEP 3: /dev/shm에서 mydata.tgz 압축 # ======================================================================== echo "${log_prefix} Compressing mydata to ${shm_path}/mydata.tgz..." local mydata_shm="${shm_path}/mydata.tgz" local mydata_dest="${backup_path}/mydata.tgz" # 기존 /dev/shm 파일 정리 if [ -f "${mydata_shm}" ]; then sudo rm -f "${mydata_shm}" fi if [ "${FRKRNL}" = "YES" ]; then # 기존 mydata.tgz가 있으면 먼저 처리 if [ -f "${mydata_dest}" ]; then local home_size=$(du -sh /home/tc | awk '{print $1}') echo "${log_prefix} Current /home/tc size: ${home_size}" echo "${log_prefix} Please ensure using latest 1GB img before backup" echo "${log_prefix} Note: Keep /home/tc size less than 1GB for image compatibility" # 기존 파일에 새로운 userconfig.json 추가 echo "${log_prefix} Adding updated userconfig.json to mydata.tgz..." # /dev/shm에서 압축 (속도 향상) if ! sudo sh -c \ "cd /home/tc && \ tar -cf - -T /opt.filetool.lst -X /opt.xfiletool.lst | \ pigz -p ${thread}" > "${mydata_shm}" 2>/dev/null; then echo "${log_prefix} ERROR: Failed to create mydata.tgz in ${shm_path}!" return 1 fi else echo "${log_prefix} Creating new mydata.tgz..." if ! sudo sh -c \ "cd /home/tc && \ tar -cf - -T /opt.filetool.lst -X /opt.xfiletool.lst | \ pigz -p ${thread}" > "${mydata_shm}" 2>/dev/null; then echo "${log_prefix} ERROR: Failed to create mydata.tgz in ${shm_path}!" return 1 fi fi else sudo /bin/tar -C / -T /opt/.filetool.lst -X /opt/.xfiletool.lst -cf - | pigz -p ${thread} > ${shm_path}/mydata.tgz fi echo "${log_prefix} mydata.tgz created successfully in ${shm_path}" # ======================================================================== # STEP 4: /dev/shm 파일 크기 확인 및 공간 부족 시 처리 # ======================================================================== echo "${log_prefix} Checking total backup size..." local xtcrp_size=0 local mydata_size=0 local total_backup_size=0 if [ -f "${xtcrp_shm}" ]; then xtcrp_size=$(stat -f%z "${xtcrp_shm}" 2>/dev/null || stat -c%s "${xtcrp_shm}" 2>/dev/null) xtcrp_size=$((xtcrp_size / 1024 / 1024)) # Convert to MB fi if [ -f "${mydata_shm}" ]; then mydata_size=$(stat -f%z "${mydata_shm}" 2>/dev/null || stat -c%s "${mydata_shm}" 2>/dev/null) mydata_size=$((mydata_size / 1024 / 1024)) # Convert to MB fi total_backup_size=$((xtcrp_size + mydata_size)) echo "${log_prefix} Backup sizes - xtcrp: ${xtcrp_size}MB, mydata: ${mydata_size}MB, total: ${total_backup_size}MB" echo "${log_prefix} Available space: ${avail_space_mb}MB" # 여유공간이 부족한 경우 처리 if [ ${avail_space_mb} -lt $((total_backup_size + 50)) ]; then echo "${log_prefix} WARNING: Insufficient space detected!" echo "${log_prefix} Attempting to free space by removing old .pat files..." # 여유공간 충분할 때까지 .pat 파일 삭제 while [ ${avail_space_mb} -lt $((total_backup_size + 50)) ]; do if [ ! -d "${auxfiles_path}" ]; then echo "${log_prefix} ERROR: ${auxfiles_path} directory not found!" return 1 fi # .pat 파일 목록 확인 local pat_files=($(find "${auxfiles_path}" -maxdepth 1 -name "*.pat" -type f 2>/dev/null)) if [ ${#pat_files[@]} -eq 0 ]; then echo "${log_prefix} ERROR: No .pat files found to delete!" echo "${log_prefix} Backup aborted due to insufficient space!" return 1 fi # 임의의 .pat 파일 선택 (RANDOM 사용) local random_idx=$((RANDOM % ${#pat_files[@]})) local pat_file_to_delete="${pat_files[${random_idx}]}" local pat_filename=$(basename "${pat_file_to_delete}") echo "${log_prefix} Deleting ${pat_filename}..." # sudo 권한으로 파일 삭제 (기존 로직 참조) if sudo rm -vf "${pat_file_to_delete}" 2>/dev/null; then local pat_size=$(stat -f%z "${pat_file_to_delete}" 2>/dev/null || stat -c%s "${pat_file_to_delete}" 2>/dev/null) pat_size=$((pat_size / 1024 / 1024)) echo "${log_prefix} Successfully deleted ${pat_filename} (${pat_size}MB recovered)" # 여유공간 재계산 avail_space_kb=$(df "${backup_path}" | tail -1 | awk '{print $4}') avail_space_mb=$((avail_space_kb / 1024)) echo "${log_prefix} Available space after cleanup: ${avail_space_mb}MB" else echo "${log_prefix} ERROR: Failed to delete ${pat_filename}!" return 1 fi done fi # ======================================================================== # STEP 5: /dev/shm에서 최종 목적지로 파일 이동 # ======================================================================== echo "${log_prefix} Moving backup files to ${backup_path}..." backup_loader # xtcrp.tgz 이동 if [ -f "${xtcrp_shm}" ]; then if sudo dd if="${xtcrp_shm}" of="${xtcrp_dest}" conv=fsync status=progress 2>/dev/null; then echo "${log_prefix} xtcrp.tgz moved successfully" else echo "${log_prefix} ERROR: Failed to move xtcrp.tgz!" return 1 fi fi # mydata.tgz 이동 if [ -f "${mydata_shm}" ]; then if sudo dd if="${mydata_shm}" of="${mydata_dest}" conv=fsync status=progress 2>/dev/null; then echo "${log_prefix} mydata.tgz moved successfully" else echo "${log_prefix} ERROR: Failed to move mydata.tgz!" return 1 fi fi # ======================================================================== # STEP 6: /dev/shm 정리 및 마무리 # ======================================================================== echo "${log_prefix} Cleaning up temporary files..." sudo rm -f "${xtcrp_shm}" "${mydata_shm}" # fsync로 디스크 동기화 sync sudo sync if [ $? -eq 0 ]; then echo "${log_prefix} Backup completed successfully!" return 0 else echo "${log_prefix} ERROR: Backup completed with errors!" return 1 fi } function backuploader_old() { thread=$(nproc) if [ "${BUS}" != "block" ]; then #Apply pigz for fast backup getpigz # backup xtcrp together if [[ $BIOS_CNT -eq 1 ]] && [ "$FRKRNL" = "YES" ]; then backupxtcrp "/mnt/${tcrppart}" return else sudo sh -c "tar -cf - ./ | pigz -p ${thread} > /mnt/${tcrppart}/xtcrp.tgz" if [ $? -ne 0 ]; then cecho r "An error occurred while backing up the loader!!!" else cecho y "Successfully backed up the loader!!!" fi fi if [ "$FRKRNL" = "YES" ]; then TGZ_FILE="/mnt/${tcrppart}/mydata.tgz" TAR_UNZIPPED="/mnt/${tcrppart}/mydata.tar" SOURCE_FILE="/home/tc/user_config.json" # Check if the compressed file exists if [ -f "$TGZ_FILE" ]; then echo "Adding ${SOURCE_FILE} to ${TGZ_FILE} !!!" # Decompress the existing archive sudo gunzip "$TGZ_FILE" # Add the file to the archive sudo tar --append -C / --file="$TAR_UNZIPPED" "$SOURCE_FILE" # Compress the archive again and save with the original name sudo sh -c "gzip -c $TAR_UNZIPPED > $TGZ_FILE" # Remove the decompressed temporary file sudo rm "$TAR_UNZIPPED" fi return fi #if [ $(cat /usr/bin/filetool.sh | grep pigz | wc -l ) -eq 0 ]; then # sudo sed -i "s/\-czvf/\-cvf \- \| pigz -p "${thread}" \> \/dev\/shm\/\${MYDATA}.tgz \&\& cp \/dev\/shm\/\${MYDATA}.tgz /g" /usr/bin/filetool.sh # sudo sed -i "s/\-czf/\-cf \- \| pigz -p "${thread}" \> \/dev\/shm\/\${MYDATA}.tgz \&\& cp \/dev\/shm\/\${MYDATA}.tgz /g" /usr/bin/filetool.sh #fi fi # loaderdisk=$(mount | grep -i optional | grep cde | awk -F / '{print $3}' | uniq | cut -c 1-3) homesize=$(du -sh /home/tc | awk '{print $1}') echo "Please make sure you are using the latest 1GB img before using backup option" echo "Current /home/tc size is $homesize , try to keep it less than 1GB as it might not fit into your image" echo "Should i update the $loaderdisk with your current files [Yy/Nn]" readanswer if [ -n "$answer" ] && [ "$answer" = "Y" ] || [ "$answer" = "y" ]; then # Define the path to the file FILE_PATH="/opt/.filetool.lst" sudo ln -sf /home/tc/menu.sh /usr/bin/menu.sh sudo ln -sf /home/tc/monitor.sh /usr/bin/monitor.sh sudo ln -sf /home/tc/ntp.sh /usr/bin/ntp.sh # Define the patterns to be added PATTERNS=("etc/motd" "usr/bin/menu.sh" "usr/bin/monitor.sh" "usr/bin/ntp.sh" "usr/sbin/sz" "usr/sbin/rz" "usr/local/bin/bspatch" "usr/bin/pigz") # 파일이 존재하고 FILE_PATH에 없는 경우만 추가 for pattern in "${PATTERNS[@]}"; do if [ -f "/$pattern" ]; then # 중복 확인 후 추가 if [ -f "$FILE_PATH" ] && grep -qF "$pattern" "$FILE_PATH"; then echo "Already exists in list: $pattern" >&2 else echo "$pattern" >> "$FILE_PATH" echo "Added to backup list: $pattern" >&2 fi else echo "File not found, skipping: /$pattern" >&2 fi done 2>/dev/null # 전체 오류 출력 억제 cecho y "Backing up home files to /mnt/${tcrppart}/mydata.tgz" sudo /bin/tar -C / -T /opt/.filetool.lst -X /opt/.xfiletool.lst -cf - | pigz -p ${thread} > /dev/shm/mydata.tgz backup_loader sudo dd if=/dev/shm/mydata.tgz of=/mnt/${tcrppart}/mydata.tgz conv=fsync status=progress if [ $? -ne 0 ]; then echo "Error: Couldn't backup files" fi else echo "OK, keeping last status" fi } function checkfilechecksum() { local FILE="${1}" local EXPECTED_SHA256="${2}" local SHA256_RESULT=$(sha256sum ${FILE}) if [ "${SHA256_RESULT%% *}" != "${EXPECTED_SHA256}" ]; then echo "The ${FILE} is corrupted, expected sha256 checksum ${EXPECTED_SHA256}, got ${SHA256_RESULT%% *}" #rm -f "${FILE}" #echo "Deleted corrupted file ${FILE}. Please re-run your action!" echo "Please delete the file ${FILE} manualy and re-run your command!" exit 99 fi } function tinyentry() { cat </dev/null | grep -i "DMI:" | head -1 | sed 's/\[.*\] DMI: //i')" echo "CPU : $(awk -F': ' '/model name/ {print $2}' /proc/cpuinfo | uniq)" echo "MEM : $(awk '/MemTotal:/ {printf "%.2f", $2 / 1024}' /proc/meminfo) MB" echo "" set color_normal=light-cyan/black echo "Cmdline:" echo "${CMD_LINE}" echo "" echo "Access http://find.synology.com/ or http://${IP}:5000 to connect the DSM via web." echo "" } EOF } function tcrpjotentry() { cat < [extension manager arguments] Actions: build, ext, download, clean, listmod, serialgen, identifyusb, patchdtc, satamap, backup, backuploader, restoreloader, restoresession, mountdsmroot, postupdate, mountshare, version, monitor, getgrubconf, help ---------------------------------------------------------------------------------------- Available platform versions: ---------------------------------------------------------------------------------------- $(getPlatforms) ---------------------------------------------------------------------------------------- Check custom_config.json for platform settings. EOF } function showhelp() { cat < [extension manager arguments] Actions: build, ext, download, clean, listmod, serialgen, identifyusb, patchdtc, satamap, backup, backuploader, restoreloader, restoresession, mountdsmroot, postupdate, mountshare, version, monitor, bringfriend, downloadupgradepat, help - build