From 23561c9717fab4be8d52950bba0b07a6933785db Mon Sep 17 00:00:00 2001 From: Dave Russell <39733752+007revad@users.noreply.github.com> Date: Thu, 4 Dec 2025 16:37:27 +1100 Subject: [PATCH 1/4] Add script to stop packages on NVMe volumes during shutdown Companion script for syno_hdd_db.sh to schedule as root to run at shutdown to stop packages that are installed on an NVMe volume. --- syno_hdd_shutdown.sh | 411 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 syno_hdd_shutdown.sh diff --git a/syno_hdd_shutdown.sh b/syno_hdd_shutdown.sh new file mode 100644 index 0000000..01c94f1 --- /dev/null +++ b/syno_hdd_shutdown.sh @@ -0,0 +1,411 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2002,2207 +#------------------------------------------------------------------------------------ +# Companion script for syno_hdd_db +# Schedule companion script to run as root at shut-down +# +# https://www.synology-forum.de/threads/neue-version-7-3-2-86009.140586/post-1265124 +#------------------------------------------------------------------------------------ +# TODO +# Check running on DSM version that needs it +# What to do if @database is on the NVMe volume? + +scriptver="v1.0.0" +script=Synology_HDD_shutdown +#repo="007revad/Synology_HDD_db" +scriptname=syno_hdd_shutdown + +ding(){ + printf \\a +} + +# Save options used for getopt +args=("$@") + +if [[ $1 == "--trace" ]] || [[ $1 == "-t" ]]; then + trace="yes" +fi + +# Check script is running as root +if [[ $( whoami ) != "root" ]]; then + ding + echo -e "ERROR This script must be run as sudo or root!" + exit 1 # Not running as sudo or root +fi + +# Get NAS model +model=$(cat /proc/sys/kernel/syno_hw_version) +#modelname="$model" + + +# Show script version +#echo -e "$script $scriptver\ngithub.com/$repo\n" +echo "$script $scriptver" + +# Get DSM full version +productversion=$(synogetkeyvalue /etc.defaults/VERSION productversion) +buildphase=$(synogetkeyvalue /etc.defaults/VERSION buildphase) +buildnumber=$(synogetkeyvalue /etc.defaults/VERSION buildnumber) +smallfixnumber=$(synogetkeyvalue /etc.defaults/VERSION smallfixnumber) + +# Get CPU arch and platform_name +arch="$(uname -m)" +platform_name=$(synogetkeyvalue /etc.defaults/synoinfo.conf platform_name) + +# Show DSM full version and model +if [[ $buildphase == GM ]]; then buildphase=""; fi +if [[ $smallfixnumber -gt "0" ]]; then smallfix="-$smallfixnumber"; fi +echo "$model DSM $productversion-$buildnumber$smallfix $buildphase" + +# Show CPU arch and platform_name +echo "CPU $platform_name $arch" + +# Show options used +if [[ ${#args[@]} -gt "0" ]]; then + echo -e "Using options: ${args[*]}\n" +else + echo "" +fi + +# Check Synology has synonvme +if ! which synonvme >/dev/null; then + ding + echo "${model} does not have synonvme!" + exit 2 # NAS model does support NVMe +fi + +# Check Synology has libsynonvme.so.1 +if [[ ! -e /usr/lib/libsynonvme.so ]]; then + ding + echo "${model} does not have libsynonvme.so.1!" + exit 2 # NAS model does support NVMe +fi + +#set -x + +# Get script location +# https://stackoverflow.com/questions/59895/ +source=${BASH_SOURCE[0]} +while [ -L "$source" ]; do # Resolve $source until the file is no longer a symlink + scriptpath=$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd ) + source=$(readlink "$source") + # If $source was a relative symlink, we need to resolve it + # relative to the path where the symlink file was located + [[ $source != /* ]] && source=$scriptpath/$source +done +scriptpath=$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd ) +scriptfile=$( basename -- "$source" ) +echo "Running from: ${scriptpath}/$scriptfile" + +# Warn if script located on M.2 drive +scriptvol=$(echo "$scriptpath" | cut -d"/" -f2) +vg=$(lvdisplay | grep /volume_"${scriptvol#volume}" | cut -d"/" -f3) +md=$(pvdisplay | grep -B 1 -E '[ ]'"$vg" | grep /dev/ | cut -d"/" -f3) +if cat /proc/mdstat | grep "$md" | grep nvme >/dev/null; then + ding + echo -e "WARNING Don't store this script on an NVMe volume!" + exit 3 # Script is stored on NVMe volume +fi + +shutdown_log="${scriptpath}/${scriptname}.log" +# Delete old shutdown_log +if [[ -f "$shutdown_log" ]]; then + rm "$shutdown_log" +fi + +progbar(){ + # $1 is pid of process + # $2 is string to echo + string="$2" + local dots + local progress + dots="" + while [[ -d /proc/$1 ]]; do + dots="${dots}." + progress="$dots" + if [[ ${#dots} -gt "10" ]]; then + dots="" + progress=" " + fi + echo -ne " ${2}$progress\r"; /usr/bin/sleep 0.3 + done +} + +progstatus(){ + # $1 is return status of process + # $2 is string to echo + # $3 line number function was called from + local tracestring + local pad + tracestring="${FUNCNAME[0]} called from ${FUNCNAME[1]} $3" + pad=$(printf -- ' %.0s' {1..80}) + [ "$trace" == "yes" ] && printf '%.*s' 80 "${tracestring}${pad}" && echo "" + if [[ $1 == "0" ]]; then + echo -e "$2 " + else + ding + echo -e "Line ${LINENO}: ERROR $2 failed!" + echo "$tracestring ($scriptver)" + if [[ $exitonerror != "no" ]]; then + exit 1 # Skip exit if exitonerror != no + fi + fi + exitonerror="" + #echo "return: $1" # debug +} + +package_status(){ + # $1 is package name + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" +# local code + synopkg status "${1}" >/dev/null + code="$?" + # DSM 7.2 0 = started, 17 = stopped, 255 = not_installed, 150 = broken + # DSM 6 to 7.1 0 = started, 3 = stopped, 4 = not_installed, 150 = broken + if [[ $code == "0" ]]; then + #echo "$1 is started" # debug + return 0 + elif [[ $code == "17" ]] || [[ $code == "3" ]]; then + #echo "$1 is stopped" # debug + return 1 + elif [[ $code == "255" ]] || [[ $code == "4" ]]; then + #echo "$1 is not installed" # debug + return 255 + elif [[ $code == "150" ]]; then + #echo "$1 is broken" # debug + return 150 + else + return "$code" + fi +} + +package_is_running(){ + # $1 is package name + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" + synopkg is_onoff "${1}" >/dev/null + code="$?" + return "$code" +} + +wait_status(){ + # Wait for package to finish stopping or starting + # $1 is package + # $2 is start or stop + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" + local num + if [[ $2 == "start" ]]; then + state="0" + elif [[ $2 == "stop" ]]; then + state="1" + fi + if [[ $state == "0" ]] || [[ $state == "1" ]]; then + num="0" + package_status "$1" + while [[ $? != "$state" ]]; do + sleep 1 + num=$((num +1)) + if [[ $num -gt "20" ]]; then + break + fi + package_status "$1" + done + fi +} + +package_stop(){ + # $1 is package name + # $2 is package display name + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" + # Docker can take 12 minutes to stop 70 containers + timeout 30m synopkg stop "$1" >/dev/null & + pid=$! + string="Stopping ${2}" + progbar "$pid" "$string" + wait "$pid" + progstatus "$?" "$string" "line ${LINENO}" + + # Allow package processes to finish stopping + wait_status "$1" stop & + pid=$! + string="Waiting for ${2} to stop" + progbar "$pid" "$string" + wait "$pid" + progstatus "$?" "$string" "line ${LINENO}" +} + +stop_packages(){ + # Check package is running + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" + if package_is_running "$pkg"; then + + # Stop package + package_stop "$pkg" "$pkg_name" + + # Check package stopped + if package_is_running "$pkg"; then + #stop_pkg_fail="yes" + ding + echo -e "Line ${LINENO}: ERROR Failed to stop ${pkg_name}!" +# echo "${pkg_name} status $code" + #process_error="yes" + return 1 + else + echo "$pkg" >> "$shutdown_log" + #stop_pkg_fail="" + fi + + if [[ $pkg == "ContainerManager" ]] || [[ $pkg == "Docker" ]]; then + # Stop containerd-shim + killall containerd-shim >/dev/null 2>&1 + fi +# else +# skip_start="yes" + fi +} + +skip_dev_tools(){ + # $1 is $package + [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" + local skip1 + local skip2 + skip1="$(synogetkeyvalue "/var/packages/${package}/INFO" startable)" + skip2="$(synogetkeyvalue "/var/packages/${package}/INFO" ctl_stop)" + if [[ $skip1 == "no" ]] || [[ $skip2 == "no" ]]; then + return 0 + else + return 1 + fi +} + + +# Get list of volumes with shared folders +readarray -t shares_array < <(synoshare --enum | tail -n +5) +for share in "${shares_array[@]}"; do + +#echo "share: $share" # debug ################################################ + + if [[ $buildnumber -gt "64570" ]]; then + # DSM 7.2.1 and later + # synoshare --get-real-path is case insensitive + path="$(synoshare --get-real-path "$share" | cut -d"/" -f2)" + else + # DSM 7.2 and earlier + # synoshare --getmap is case insensitive + path="$(synoshare --getmap web_packages | grep volume | cut -d"[" -f2 | cut -d"]" -f1)" + # I could also have used: + # web_pkg_path=$(/usr/syno/sbin/synoshare --get web_packages | tr '[]' '\n' | sed -n "9p") + fi + + # Ignore external USB and eSATA volumes + if echo "$path" | grep -q -E 'volume[0-9]'; then + volumes_array+=("$path") + fi +done + +#echo -e "\nvolumes_array:" # debug ################## +#for v in "${volumes_array[@]}"; do echo "$v"; done # debug ################## +#echo -e "\n" # debug ################## + +# Sort array to remove duplicates +IFS=$'\n' +volumes_array_sorted=($(sort -u <<<"${volumes_array[*]}")) +unset IFS + +#echo -e "\nvolumes_array_sorted:" # debug ########### +#for v in "${volumes_array_sorted[@]}"; do echo "$v"; done # debug ########### +#echo -e "\n" # debug ########### + +#exit + +# Check there is an NVMe volume +nvme_vols=() +for vol in "${volumes_array_sorted[@]}"; do + +#echo "$vol" # debug ######################################################### + + vg=$(lvdisplay | grep /volume_"${vol#volume}" | cut -d"/" -f3) + md=$(pvdisplay | grep -B 1 -E '[ ]'"$vg" | grep /dev/ | cut -d"/" -f3) + if cat /proc/mdstat | grep "$md" | grep nvme >/dev/null; then + nvme_vols_qty=$((nvme_vols_qty +1)) + nvme_vols+=("$vol") + fi +done +if [[ $nvme_vols_qty -lt "0" ]]; then + ding + echo -e "No NVMe volumes found." + exit 4 # Script not needed +fi + + +#echo "nvme_vols_qty $nvme_vols_qty" # debug ###################### +#for v in "${nvme_vols[@]}"; do echo "$v"; done # debug ###################### +#echo "" # debug ###################### + +#exit + + +# Get list of packages installed on NVMe volume +if ! cd /var/packages; then + ding + echo -e "Failed to cd to /var/packages!" + exit 5 # Failed to cd to /var/packages +fi +declare -A package_names +declare -A package_names_rev +#package_infos=( ) +while IFS= read -r -d '' link && IFS= read -r -d '' target; do + if [[ ${link##*/} == "target" ]] && echo "$target" | grep -q 'volume'; then + # Check symlink target exists + if [[ -a "/var/packages${link#.}" ]] ; then + + # Skip broken packages with no INFO file + package="$(printf %s "$link" | cut -d'/' -f2 )" + if [[ -f "/var/packages/${package}/INFO" ]]; then + package_volume="$(printf %s "$target" | cut -d'/' -f1,2 )" + +#echo "package_volume: $package_volume" # debug ############################### + + # Check if package is on NVMe volume + # shellcheck disable=SC2076 + if [[ "/${nvme_vols[*]}" =~ "$package_volume" ]]; then + package_name="$(synogetkeyvalue "/var/packages/${package}/INFO" displayname)" + if [[ -z "$package_name" ]]; then + package_name="$(synogetkeyvalue "/var/packages/${package}/INFO" package)" + fi + +#echo "package_name: $package_name" # debug ############################### + + # Skip packages that are dev tools with no data + if ! skip_dev_tools "$package"; then + #package_infos+=("${package_volume}|${package_name}") + package_names["${package_name}"]="${package}" + package_names_rev["${package}"]="${package_name}" + fi + fi + fi + fi + fi +done < <(find . -maxdepth 2 -type l -printf '%p\0%l\0') + +#echo -e "\npackage_infos:" +#for p in "${package_infos[@]}"; do echo "$p"; done + +#echo -e "\npackage_names:" +#for p in "${package_names[@]}"; do echo "$p"; done + +#echo -e "\npackage_names_rev:" +#for p in "${package_names_rev[@]}"; do echo "$p"; done + + +# Loop through pkgs_sorted array and process package +for pkg in "${package_names[@]}"; do + pkg_name="${package_names_rev["$pkg"]}" + #process_error="" + stop_packages + +#echo "stop_package: $pkg" # debug ############################################ + +done + + + From 0d6a701aa15978dd836b2c02afa74d660faaea44 Mon Sep 17 00:00:00 2001 From: Dave Russell <39733752+007revad@users.noreply.github.com> Date: Sun, 7 Dec 2025 11:24:10 +1100 Subject: [PATCH 2/4] Bug fix for DSM 7.2 and earlier Fixed hard coded web_packages instead of "$share" --- syno_hdd_shutdown.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/syno_hdd_shutdown.sh b/syno_hdd_shutdown.sh index 01c94f1..40ea1e2 100644 --- a/syno_hdd_shutdown.sh +++ b/syno_hdd_shutdown.sh @@ -291,9 +291,9 @@ for share in "${shares_array[@]}"; do else # DSM 7.2 and earlier # synoshare --getmap is case insensitive - path="$(synoshare --getmap web_packages | grep volume | cut -d"[" -f2 | cut -d"]" -f1)" + path="$(synoshare --getmap "$share" | grep volume | cut -d"[" -f2 | cut -d"]" -f1)" # I could also have used: - # web_pkg_path=$(/usr/syno/sbin/synoshare --get web_packages | tr '[]' '\n' | sed -n "9p") + # web_pkg_path=$(/usr/syno/sbin/synoshare --get "$share" | tr '[]' '\n' | sed -n "9p") fi # Ignore external USB and eSATA volumes From 840c147edf93d1ea6a7fbf956f1ad71cf4dfca0c Mon Sep 17 00:00:00 2001 From: Dave Russell <39733752+007revad@users.noreply.github.com> Date: Thu, 11 Dec 2025 06:02:33 +1100 Subject: [PATCH 3/4] Update CHANGES.txt with version 3.6.113 details --- CHANGES.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 78cf5aa..e954a6b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,11 @@ +v3.6.113 +- Added check that DSM 7.3 db file was successfully compacted. +- Added drive's firmware version to messages. +- Improved checking if drive and firmware version were successfully added to db file. +- Bug fix for adding duplicate drive if 2 or more of the same drive model had different firmware versions. + - Also removes duplicate drive entries if they exist (before correctly editing the file). +- Bug fix adding size_gb to to drive firmware version entries instead of just the "default" key section. + v3.6.112 - Bug fix for DSM 7.3 and later where new database files have a space after each : and , From 8bbeaeec7d26b6900542b55e5568f4ca3b079d40 Mon Sep 17 00:00:00 2001 From: Dave Russell <39733752+007revad@users.noreply.github.com> Date: Thu, 11 Dec 2025 10:04:08 +1100 Subject: [PATCH 4/4] Update script version and add duplicate check function v3.6.113 - Added check that DSM 7.3 db file was successfully compacted. - Added drive's firmware version to messages. - Improved checking if drive and firmware version were successfully added to db file. - Bug fix for adding duplicate drive if 2 or more of the same drive model had different firmware versions. - Also removes duplicate drive entries if they exist (before correctly editing the file). - Bug fix adding size_gb to to drive firmware version entries instead of just the "default" key section. --- syno_hdd_db.sh | 158 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 24 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 5638efe..edff033 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -29,7 +29,7 @@ # /var/packages/StorageManager/target/ui/storage_panel.js -scriptver="v3.6.112" +scriptver="v3.6.113" script=Synology_HDD_db repo="007revad/Synology_HDD_db" scriptname=syno_hdd_db @@ -1327,12 +1327,98 @@ backupdb(){ compactdb(){ - # Compact database file if needed (DSM 7.3 and later) - if grep -q ': ' "$1" && grep -q ', ' "$1"; then - jq -c . "$1" > "$1.compact" && chmod 644 "$1.compact" - jq -c . "$1.compact" > "$1" && chmod 644 "$1" + # Compact database file if needed + local lines + lines=$(wc -l "$1" | cut -d" " -f1) + if (grep -q ': ' "$1" && grep -q ', ' "$1") || [[ $lines -gt 1 ]]; then + # DSM 7.3 and later or pretty-print style + cp -p "$1" "$1.tmp" && jq -c . "$1.tmp" > "$1" && chmod 644 "$1" && rm "$1.tmp" + + # Check database is now compact + lines=$(wc -l "$1" | cut -d" " -f1) + if (grep -q ': ' "$1" && grep -q ', ' "$1") || [[ $lines -gt 1 ]]; then + echo -e "${Error}ERROR${Off} Failed to compact ${1##*/}!" >&2 + return 1 + else + return 0 + fi fi - return 0 +} + + +# Python based function to remove duplicates using EOF method +check_and_merge_dupes(){ + local file="$1" + local count + local i + local array + + [[ -z "$file" ]] && { echo "ERROR No file specified"; return 1; } + + # Detect duplicate 2nd-level keys (drive models) in json (db) file + # jq removes the duplicates so we start with an array of drive models + readarray -t array < <(jq . "$file" | grep -e '^ "' | cut -d'"' -f2) + + # Loop through array of drives in db file checking for duplicates + for i in "${array[@]}"; do + # Check if more than 1 of each drive in db file + #count=$(grep -Eo "\"$i\"" "$file" | wc -l) + count=$(grep -Foc "$i" "$file") + if [[ $count -gt 1 ]]; then + + # Python 3 and 2.7 compatible HERE document + python < /dev/null; then + echo -e "Added ${Yellow}$hdmodel ($fwrev)${Off} to ${Cyan}$(basename -- "$2")${Off}" + editcount "$2" + else + echo -e "\n${Error}ERROR{Off} Failed to add $hdmodel ($fwrev) to $(basename -- "$2")${Off}" + fi else - echo -e "\n${Error}ERROR 6a${Off} Failed to update $(basename -- "$2")${Off}" + echo -e "\n${Error}ERROR 6a${Off} Failed to add $hdmodel ($fwrev) to $(basename -- "$2")${Off}" #exit 6 fi elif [[ $1 == "insert" ]]; then # model and default exists #if sed -i "s/\"$hdmodel\":{/\"$hdmodel\":{$fwstrng/" "$2"; then # insert firmware if sed -i "s/\"${hdmodel//\//\\/}\":{/\"${hdmodel//\//\\/}\":{$fwstrng/" "$2"; then # insert firmware - echo -e "Updated ${Yellow}$hdmodel${Off} in ${Cyan}$(basename -- "$2")${Off}" - #editcount "$2" + if jq -e --arg hdmodel "$hdmodel" --arg fwrev "$fwrev" \ + '.disk_compatbility_info[$hdmodel] | has($fwrev)' "$2" > /dev/null; then + echo -e "Updated ${Yellow}$hdmodel ($fwrev)${Off} in ${Cyan}$(basename -- "$2")${Off}" + #editcount "$2" + else + echo -e "\n${Error}ERROR{Off} Failed to update $hdmodel for ($fwrev) in $(basename -- "$2")" + fi else - echo -e "\n${Error}ERROR 6b${Off} Failed to update $(basename -- "$2")${Off}" + echo -e "\n${Error}ERROR 6b${Off} Failed to update $hdmodel for ($fwrev) in $(basename -- "$2")" #exit 6 fi @@ -1398,10 +1496,15 @@ editdb7(){ #if sed -i "s/{}/{\"$hdmodel\":{$fwstrng${default}}/" "$2"; then # empty #if sed -i "s/{}/{\"${hdmodel//\//\\/}\":{$fwstrng${default}}/" "$2"; then # empty if sed -i "s/{}/{\"${hdmodel//\//\\/}\":{$fwstrng${default}/" "$2"; then # empty - echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" - editcount "$2" + if jq -e --arg hdmodel "$hdmodel" --arg fwrev "$fwrev" \ + '.disk_compatbility_info[$hdmodel] | has($fwrev)' "$2" > /dev/null; then + echo -e "Added ${Yellow}$hdmodel ($fwrev)${Off} to ${Cyan}$(basename -- "$2")${Off}" + editcount "$2" + else + echo -e "\n${Error}ERROR{Off} Failed to add $hdmodel ($fwrev) to $(basename -- "$2")" + fi else - echo -e "\n${Error}ERROR 6c${Off} Failed to update $(basename -- "$2")${Off}" + echo -e "\n${Error}ERROR 6c${Off} Failed to add $hdmodel ($fwrev) to $(basename -- "$2")" #exit 6 fi fi @@ -1423,11 +1526,13 @@ updatedb(){ if [[ $dbtype -gt "6" ]]; then # db type 7 used from DSM 7.1 and later - if grep -q "$hdmodel"'":{"'"$fwrev" "$2"; then - echo -e "${Yellow}$hdmodel${Off} already exists in ${Cyan}$(basename -- "$2")${Off}" >&2 + if jq -e --arg hdmodel "$hdmodel" --arg fwrev "$fwrev" \ + '.disk_compatbility_info[$hdmodel] | has($fwrev)' "$2" > /dev/null; then + echo -e "${Yellow}$hdmodel ($fwrev)${Off} already exists in ${Cyan}$(basename -- "$2")${Off}" >&2 else - common_string=\"size_gb\":$size_gb, - common_string="$common_string"\"compatibility_interval\":[{ + #common_string=\"size_gb\":$size_gb, + #common_string="$common_string"\"compatibility_interval\":[{ + common_string=\"compatibility_interval\":[{ common_string="$common_string"\"compatibility\":\"support\", common_string="$common_string"\"not_yet_rolling_status\":\"support\", common_string="$common_string"\"fw_dsm_update_status_notify\":false, @@ -1440,7 +1545,8 @@ updatedb(){ fwstrng="$fwstrng$common_string" fwstrng="$fwstrng"}]}, - default=\"default\":{ + #default=\"default\":{ + default=\"default\":{\"size_gb\":$size_gb, default="$default$common_string" default="$default"}]}}} @@ -1451,7 +1557,7 @@ updatedb(){ #echo "Edit empty db file:" # debug editdb7 "empty" "$2" - elif grep -q '"'"$hdmodel"'":' "$2"; then + elif jq -e --arg hdmodel "$hdmodel" '.disk_compatbility_info[$hdmodel]' "$2" >/dev/null; then # Replace "WD40PURX-64GVNY0":{ with "WD40PURX-64GVNY0":{"80.00A80":{ ... }}}, #echo "Insert firmware version:" # debug editdb7 "insert" "$2" @@ -1497,7 +1603,7 @@ updatedb(){ #if sed -i "s/$startstring/$startstring$string/" "$2"; then #if sed -i "s/${startstring//\//\\/}/${startstring//\//\\/}$string/" "$2"; then if sed -i "s/$startstring/$startstring${string//\//\\/}/" "$2"; then - echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" + echo -e "Added ${Yellow}$hdmodel$ ($fwrev){Off} to ${Cyan}$(basename -- "$2")${Off}" else ding echo -e "\n${Error}ERROR 8${Off} Failed to update $(basename -- "$2")${Off}" >&2 @@ -1535,11 +1641,13 @@ while [[ $num -lt "${#hdds[@]}" ]]; do for i in "${!eunitdb1list[@]}"; do backupdb "${eunitdb1list[i]}" &&\ compactdb "${eunitdb1list[i]}" &&\ + check_and_merge_dupes "${eunitdb1list[i]}" &&\ updatedb "${hdds[$num]}" "${eunitdb1list[i]}" done for i in "${!eunitdb2list[@]}"; do backupdb "${eunitdb2list[i]}" &&\ compactdb "${eunitdb2list[i]}" &&\ + check_and_merge_dupes "${eunitdb2list[i]}" &&\ updatedb "${hdds[$num]}" "${eunitdb2list[i]}" done #------------------------------------------------ @@ -1562,11 +1670,13 @@ while [[ $num -lt "${#nvmes[@]}" ]]; do for i in "${!m2carddb1list[@]}"; do backupdb "${m2carddb1list[i]}" &&\ compactdb "${m2carddb1list[i]}" &&\ + check_and_merge_dupes "${m2carddb1list[i]}" &&\ updatedb "${nvmes[$num]}" "${m2carddb1list[i]}" done for i in "${!m2carddb2list[@]}"; do backupdb "${m2carddb2list[i]}" &&\ compactdb "${m2carddb2list[i]}" &&\ + check_and_merge_dupes "${m2carddb2list[i]}" &&\ updatedb "${nvmes[$num]}" "${m2carddb2list[i]}" done #------------------------------------------------