arc-addons/hdddb/all/usr/bin/hdddb.sh
AuxXxilium 5cd825ad13 tree: bugfix
Signed-off-by: AuxXxilium <info@auxxxilium.tech>
2024-10-24 18:23:26 +02:00

2247 lines
80 KiB
Bash
Executable File

#!/usr/bin/env bash
# shellcheck disable=SC1083,SC2054,SC2121,SC2207
#--------------------------------------------------------------------------------------------------
# Github: https://github.com/007revad/Synology_HDD_db
# Script verified at https://www.shellcheck.net/
#
# To run in task manager as root (manually or scheduled):
# /volume1/scripts/syno_hdd_db.sh # replace /volume1/scripts/ with path to script
#
# To run in a shell (replace /volume1/scripts/ with path to script):
# sudo -i /volume1/scripts/syno_hdd_db.sh
# or
# sudo -i /volume1/scripts/syno_hdd_db.sh -showedits
# or
# sudo -i /volume1/scripts/syno_hdd_db.sh -force -showedits
#--------------------------------------------------------------------------------------------------
# https://smarthdd.com/database/
# RECENT CHANGES
# Make DSM read md0 and md1 from SSD drive(s) if internal SSD and HDD are installed.
# https://github.com/007revad/Synology_HDD_db/issues/318
# https://www.techspark.de/speed-up-synology-dsm-with-hdd-ssd/
# https://raid.wiki.kernel.org/index.php/Write-mostly
# TODO
# Enable SMART Attributes button on Storage Manager
# disabled:e.healthInfoDisabled
# enabled:e.healthInfoDisabled
# /var/packages/StorageManager/target/ui/storage_panel.js
scriptver="v3.5.103"
script=Synology_HDD_db
repo="007revad/Synology_HDD_db"
scriptname=syno_hdd_db
# Check BASH variable is bash
if [ ! "$(basename "$BASH")" = bash ]; then
echo "This is a bash script. Do not run it with $(basename "$BASH")"
printf \\a
exit 1
fi
# Check script is running on a Synology NAS
if ! /usr/bin/uname -a | grep -q -i synology; then
echo "This script is NOT running on a Synology NAS!"
echo "Copy the script to a folder on the Synology"
echo "and run it from there."
exit 1
fi
ding(){
printf \\a
}
usage(){
cat <<EOF
$script $scriptver - by 007revad
Usage: $(basename "$0") [options]
Options:
-s, --showedits Show edits made to <model>_host db and db.new file(s)
-n, --noupdate Prevent DSM updating the compatible drive databases
-r, --ram Disable memory compatibility checking (DSM 7.x only)
and sets max memory to the amount of installed memory
-f, --force Force DSM to not check drive compatibility
Do not use this option unless absolutely needed
-i, --incompatible Change incompatible drives to supported
Do not use this option unless absolutely needed
-w, --wdda Disable WD Device Analytics to prevent DSM showing
a false warning for WD drives that are 3 years old
DSM 7.2.1 already has WDDA disabled
-p, --pcie Enable creating volumes on M2 in unknown PCIe adaptor
-e, --email Disable colored text in output scheduler emails
-S, --ssd=DRIVE Enable write_mostly on internal HDDs so DSM primary
reads from internal SSDs or your specified drives
-S automatically sets internal SSDs as DSM preferred
--ssd=DRIVE requires the fast drive(s) as argument,
or restore as the argument to reset drives to default
--ssd=sata1 or --ssd=sata1,sata2 or --ssd=sda etc
--ssd=restore
--restore Undo all changes made by the script (except -S --ssd)
To restore all changes including write_mostly use
--restore --ssd=restore
--autoupdate=AGE Auto update script (useful when script is scheduled)
AGE is how many days old a release must be before
auto-updating. AGE must be a number: 0 or greater
-h, --help Show this help message
-v, --version Show the script version
EOF
exit 0
}
scriptversion(){
cat <<EOF
$script $scriptver - by 007revad
See https://github.com/$repo
EOF
exit 0
}
# Save options used
args=("$@")
# Check for flags with getopt
if options="$(getopt -o Sabcdefghijklmnopqrstuvwxyz0123456789 -l \
ssd:,restore,showedits,noupdate,nodbupdate,m2,force,incompatible,ram,pcie,wdda,email,autoupdate:,help,version,debug \
-- "$@")"; then
eval set -- "$options"
while true; do
case "$1" in
-d|--debug) # Show and log debug info
debug=yes
;;
-e|--email) # Disable colour text in task scheduler emails
color=no
;;
--restore) # Restore changes from backups
restore=yes
if $(echo "${args[@]}" | grep -q -- '--ssd=restore'); then
ssd_restore=yes
fi
#break
;;
-s|--showedits) # Show edits done to host db file
showedits=yes
;;
-S) # Enable writemostly for md0 and md1
ssd=yes
;;
--ssd) # Enable writemostly for md0 and md1
ssd=yes
if [[ ${2,,} == "restore" ]]; then
ssd_restore=yes
else
IFS=$','
for d in $2; do ssds_writemostly+=("${d,,}"); done
unset IFS
fi
shift
;;
-n|--nodbupdate|--noupdate) # Disable disk compatibility db updates
nodbupdate=yes
;;
-m|--m2) # Don't add M.2 drives to db files
m2=no
;;
-f|--force) # Disable "support_disk_compatibility"
force=yes
;;
-i|--incompatible) # Change incompatible drives to supported
incompatible=yes
;;
-r|--ram) # Disable "support_memory_compatibility"
ram=yes
;;
-w|--wdda) # Disable "support_wdda"
wdda=no
;;
-p|--pcie) # Enable creating volumes on M2 in unknown PCIe adaptor
forcepci=yes
;;
--autoupdate) # Auto update script
autoupdate=yes
if [[ $2 =~ ^[0-9]+$ ]]; then
delay="$2"
shift
else
delay="0"
fi
;;
-h|--help) # Show usage options
usage
;;
-v|--version) # Show script version
scriptversion
;;
--)
shift
break
;;
*) # Show usage options
echo -e "Invalid option '$1'\n"
usage "$1"
;;
esac
shift
done
else
echo
usage
fi
if [[ $debug == "yes" ]]; then
set -x
export PS4='`[[ $? == 0 ]] || echo "\e[1;31;40m($?)\e[m\n "`:.$LINENO:'
fi
# Shell Colors
if [[ $color != "no" ]]; then
#Black='\e[0;30m' # ${Black}
Red='\e[0;31m' # ${Red}
#Green='\e[0;32m' # ${Green}
Yellow='\e[0;33m' # ${Yellow}
#Blue='\e[0;34m' # ${Blue}
#Purple='\e[0;35m' # ${Purple}
Cyan='\e[0;36m' # ${Cyan}
#White='\e[0;37m' # ${White}
Error='\e[41m' # ${Error}
Off='\e[0m' # ${Off}
else
echo "" # For task scheduler email readability
fi
# Check script is running as root
if [[ $( whoami ) != "root" ]]; then
ding
echo -e "${Error}ERROR${Off} This script must be run as sudo or root!"
exit 1
fi
# Get DSM major version
dsm=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION majorversion)
if [[ $dsm -gt "6" ]]; then
version="_v$dsm"
fi
# Get Synology 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=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION productversion)
buildphase=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION buildphase)
buildnumber=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION buildnumber)
smallfixnumber=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION smallfixnumber)
# 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"
# Convert model to lower case
model=${model,,}
# Check for dodgy characters after model number
if [[ $model =~ 'pv10-j'$ ]]; then # GitHub issue #10
modelname=${modelname%??????}+ # replace last 6 chars with +
model=${model%??????}+ # replace last 6 chars with +
echo -e "\nUsing model: $model"
elif [[ $model =~ '-j'$ ]]; then # GitHub issue #2
modelname=${modelname%??} # remove last 2 chars
model=${model%??} # remove last 2 chars
echo -e "\nUsing model: $model"
fi
# Get StorageManager version
storagemgrver=$(/usr/syno/bin/synopkg version StorageManager)
# Show StorageManager version
if [[ $storagemgrver ]]; then echo -e "StorageManager $storagemgrver\n"; fi
# Show host drive db version
if [[ -f "/var/lib/disk-compatibility/${model}_host_v7.version" ]]; then
echo -n "${model}_host_v7 version "
cat "/var/lib/disk-compatibility/${model}_host_v7.version"
echo -e "\n"
fi
if [[ -f "/var/lib/disk-compatibility/${model}_host.version" ]]; then
echo -n "${model}_host version "
cat "/var/lib/disk-compatibility/${model}_host.version"
echo -e "\n"
fi
# Show options used
if [[ ${#args[@]} -gt "0" ]]; then
echo "Using options: ${args[*]}"
fi
#echo "" # To keep output readable
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
pause(){
# When debugging insert pause command where needed
read -s -r -n 1 -p "Press any key to continue..."
read -r -t 0.1 -s -e -- # Silently consume all input
stty echo echok # Ensure read didn't disable echoing user input
echo -e "\n"
}
#------------------------------------------------------------------------------
# Check latest release with GitHub API
syslog_set(){
if [[ ${1,,} == "info" ]] || [[ ${1,,} == "warn" ]] || [[ ${1,,} == "err" ]]; then
if [[ $autoupdate == "yes" ]]; then
# Add entry to Synology system log
/usr/syno/bin/synologset1 sys "$1" 0x11100000 "$2"
fi
fi
}
# Get latest release info
# Curl timeout options:
# https://unix.stackexchange.com/questions/94604/does-curl-have-a-timeout
release=$(curl --silent -m 10 --connect-timeout 5 \
"https://api.github.com/repos/$repo/releases/latest")
# Release version
tag=$(echo "$release" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
shorttag="${tag:1}"
# Release published date
published=$(echo "$release" | grep '"published_at":' | sed -E 's/.*"([^"]+)".*/\1/')
published="${published:0:10}"
published=$(date -d "$published" '+%s')
# Today's date
now=$(date '+%s')
# Days since release published
age=$(((now - published)/(60*60*24)))
# 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"
#echo "Script location: $scriptpath" # debug
#echo "Source: $source" # debug
#echo "Script filename: $scriptfile" # debug
#echo "tag: $tag" # debug
#echo "scriptver: $scriptver" # debug
# 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)
# shellcheck disable=SC2002 # Don't warn about "Useless cat"
if cat /proc/mdstat | grep "$md" | grep -q nvme; then
echo -e "\n${Yellow}WARNING${Off} Don't store this script on an NVMe volume!"
fi
cleanup_tmp(){
cleanup_err=
# Delete downloaded .tar.gz file
if [[ -f "/tmp/$script-$shorttag.tar.gz" ]]; then
if ! rm "/tmp/$script-$shorttag.tar.gz"; then
echo -e "${Error}ERROR${Off} Failed to delete"\
"downloaded /tmp/$script-$shorttag.tar.gz!" >&2
cleanup_err=1
fi
fi
# Delete extracted tmp files
if [[ -d "/tmp/$script-$shorttag" ]]; then
if ! rm -r "/tmp/$script-$shorttag"; then
echo -e "${Error}ERROR${Off} Failed to delete"\
"downloaded /tmp/$script-$shorttag!" >&2
cleanup_err=1
fi
fi
# Add warning to DSM log
if [[ $cleanup_err ]]; then
syslog_set warn "$script update failed to delete tmp files"
fi
}
if ! printf "%s\n%s\n" "$tag" "$scriptver" |
sort --check=quiet --version-sort >/dev/null ; then
echo -e "\n${Cyan}There is a newer version of this script available.${Off}"
echo -e "Current version: ${scriptver}\nLatest version: $tag"
scriptdl="$scriptpath/$script-$shorttag"
if [[ -f ${scriptdl}.tar.gz ]] || [[ -f ${scriptdl}.zip ]]; then
# They have the latest version tar.gz downloaded but are using older version
echo "You have the latest version downloaded but are using an older version"
sleep 10
elif [[ -d $scriptdl ]]; then
# They have the latest version extracted but are using older version
echo "You have the latest version extracted but are using an older version"
sleep 10
else
if [[ $autoupdate == "yes" ]]; then
if [[ $age -gt "$delay" ]] || [[ $age -eq "$delay" ]]; then
echo "Downloading $tag"
reply=y
else
echo "Skipping as $tag is less than $delay days old."
fi
else
echo -e "${Cyan}Do you want to download $tag now?${Off} [y/n]"
read -r -t 30 reply
fi
if [[ ${reply,,} == "y" ]]; then
# Delete previously downloaded .tar.gz file and extracted tmp files
cleanup_tmp
if cd /tmp; then
url="https://github.com/$repo/archive/refs/tags/$tag.tar.gz"
if ! curl -JLO -m 30 --connect-timeout 5 "$url"; then
echo -e "${Error}ERROR${Off} Failed to download"\
"$script-$shorttag.tar.gz!"
syslog_set warn "$script $tag failed to download"
else
if [[ -f /tmp/$script-$shorttag.tar.gz ]]; then
# Extract tar file to /tmp/<script-name>
if ! tar -xf "/tmp/$script-$shorttag.tar.gz" -C "/tmp"; then
echo -e "${Error}ERROR${Off} Failed to"\
"extract $script-$shorttag.tar.gz!"
syslog_set warn "$script failed to extract $script-$shorttag.tar.gz!"
else
# Set script sh files as executable
if ! chmod a+x "/tmp/$script-$shorttag/"*.sh ; then
permerr=1
echo -e "${Error}ERROR${Off} Failed to set executable permissions"
syslog_set warn "$script failed to set permissions on $tag"
fi
# Copy new script sh file to script location
if ! cp -p "/tmp/$script-$shorttag/${scriptname}.sh" "${scriptpath}/${scriptfile}";
then
copyerr=1
echo -e "${Error}ERROR${Off} Failed to copy"\
"$script-$shorttag sh file(s) to:\n $scriptpath/${scriptfile}"
syslog_set warn "$script failed to copy $tag to script location"
fi
# Copy new syno_hdd_vendor_ids.txt file
vidstxt="syno_hdd_vendor_ids.txt"
if [[ $scriptpath =~ /volume* ]]; then
if [[ ! -f "$scriptpath/$vidstxt" ]]; then # Don't overwrite file
# Copy new syno_hdd_vendor_ids.txt file to script location
if ! cp -p "/tmp/$script-$shorttag/$vidstxt" "$scriptpath"; then
if [[ $autoupdate != "yes" ]]; then copyerr=1; fi
echo -e "${Error}ERROR${Off} Failed to copy"\
"$script-$shorttag/$vidstxt to:\n $scriptpath"
else
# Set permissions on syno_hdd_vendor_ids.txt
if ! chmod 755 "$scriptpath/$vidstxt"; then
if [[ $autoupdate != "yes" ]]; then permerr=1; fi
echo -e "${Error}ERROR${Off} Failed to set permissions on:"
echo "$scriptpath/$vidstxt"
fi
vids_txt=", syno_hdd_vendor_ids.txt"
fi
fi
fi
# Copy new CHANGES.txt file to script location (if script on a volume)
if [[ $scriptpath =~ /volume* ]]; then
# Set permissions on CHANGES.txt
if ! chmod 664 "/tmp/$script-$shorttag/CHANGES.txt"; then
permerr=1
echo -e "${Error}ERROR${Off} Failed to set permissions on:"
echo "$scriptpath/CHANGES.txt"
fi
# Copy new CHANGES.txt file to script location
if ! cp -p "/tmp/$script-$shorttag/CHANGES.txt"\
"${scriptpath}/${scriptname}_CHANGES.txt";
then
if [[ $autoupdate != "yes" ]]; then copyerr=1; fi
echo -e "${Error}ERROR${Off} Failed to copy"\
"$script-$shorttag/CHANGES.txt to:\n $scriptpath"
else
changestxt=" and changes.txt"
fi
fi
# Delete downloaded tmp files
cleanup_tmp
# Notify of success (if there were no errors)
if [[ $copyerr != 1 ]] && [[ $permerr != 1 ]]; then
echo -e "\n$tag ${scriptfile}$vids_txt$changestxt downloaded to: ${scriptpath}\n"
syslog_set info "$script successfully updated to $tag"
# Reload script
printf -- '-%.0s' {1..79}; echo # print 79 -
exec "${scriptpath}/$scriptfile" "${args[@]}"
else
syslog_set warn "$script update to $tag had errors"
fi
fi
else
echo -e "${Error}ERROR${Off}"\
"/tmp/$script-$shorttag.tar.gz not found!"
#ls /tmp | grep "$script" # debug
syslog_set warn "/tmp/$script-$shorttag.tar.gz not found"
fi
fi
cd "$scriptpath" || echo -e "${Error}ERROR${Off} Failed to cd to script location!"
else
echo -e "${Error}ERROR${Off} Failed to cd to /tmp!"
syslog_set warn "$script update failed to cd to /tmp"
fi
fi
fi
fi
#------------------------------------------------------------------------------
# Set file variables
if [[ -f /etc.defaults/model.dtb ]]; then # Is device tree model
# Get syn_hw_revision, r1 or r2 etc (or just a linefeed if not a revision)
hwrevision=$(cat /proc/sys/kernel/syno_hw_revision)
# If syno_hw_revision is r1 or r2 it's a real Synology,
# and I need to edit model_rN.dtb instead of model.dtb
if [[ $hwrevision =~ r[0-9] ]]; then
#echo "hwrevision: $hwrevision" # debug
hwrev="_$hwrevision"
fi
dtb_file="/etc.defaults/model${hwrev}.dtb"
dtb2_file="/etc/model${hwrev}.dtb"
#dts_file="/etc.defaults/model${hwrev}.dts"
dts_file="/tmp/model${hwrev}.dts"
fi
adapter_cards="/usr/syno/etc.defaults/adapter_cards.conf"
adapter_cards2="/usr/syno/etc/adapter_cards.conf"
dbpath=/var/lib/disk-compatibility/
synoinfo="/etc.defaults/synoinfo.conf"
if [[ $buildnumber -gt 64570 ]]; then
# DSM 7.2.1 and later
#strgmgr="/var/packages/StorageManager/target/ui/storage_panel.js"
strgmgr="/usr/local/packages/@appstore/StorageManager/ui/storage_panel.js"
elif [[ $buildnumber -ge 64561 ]]; then
# DSM 7.2
strgmgr="/usr/syno/synoman/webman/modules/StorageManager/storage_panel.js"
fi
vidfile="/usr/syno/etc.defaults/pci_vendor_ids.conf"
vidfile2="/usr/syno/etc/pci_vendor_ids.conf"
set_writemostly(){
# $1 is writemostly or -writemostly
# $2 is sata1 or sas1 or sda etc
local model
# Show drive model
model="$(cat /sys/block/"${2}"/device/model | xargs)"
echo -e "${Yellow}$model${Off}"
if [[ ${1::2} == "sd" ]]; then
# sda etc
# md0 DSM system partition
echo "$1" > /sys/block/md0/md/dev-"${2}"1/state
# Show setting
echo -n " $2 DSM partition: "
cat /sys/block/md0/md/dev-"${2}"1/state
# md1 DSM swap partition
echo "$1" > /sys/block/md1/md/dev-"${2}"2/state
# Show setting
echo -n " $2 Swap partition: "
cat /sys/block/md1/md/dev-"${2}"2/state
else
# sata1 or sas1 etc
# md0 DSM system partition
echo "$1" > /sys/block/md0/md/dev-"${2}"p1/state
# Show setting
echo -n " $2 DSM partition: "
cat /sys/block/md0/md/dev-"${2}"p1/state
# md1 DSM swap partition
echo "$1" > /sys/block/md1/md/dev-"${2}"p2/state
# Show setting
echo -n " $2 Swap partition: "
cat /sys/block/md1/md/dev-"${2}"p2/state
fi
}
#------------------------------------------------------------------------------
# Restore changes from backups
if [[ $restore == "yes" ]]; then
dbbaklist=($(find $dbpath -maxdepth 1 \( -name "*.db.new.bak" -o -name "*.db.bak" \)))
# Sort array
IFS=$'\n'
dbbakfiles=($(sort <<<"${dbbaklist[*]}"))
unset IFS
echo ""
if [[ ${#dbbakfiles[@]} -gt "0" ]] || [[ -f ${synoinfo}.bak ]] ||\
[[ -f ${dtb_file}.bak ]] || [[ -f ${adapter_cards}.bak ]] ; then
# Restore synoinfo.conf from backup
if [[ -f ${synoinfo}.bak ]]; then
keyvalues=("support_disk_compatibility" "support_memory_compatibility")
keyvalues+=("mem_max_mb" "supportnvme" "support_m2_pool" "support_wdda")
for v in "${!keyvalues[@]}"; do
defaultval="$(/usr/syno/bin/synogetkeyvalue ${synoinfo}.bak "${keyvalues[v]}")"
currentval="$(/usr/syno/bin/synogetkeyvalue ${synoinfo} "${keyvalues[v]}")"
if [[ $currentval != "$defaultval" ]]; then
if /usr/syno/bin/synosetkeyvalue "$synoinfo" "${keyvalues[v]}" "$defaultval";
then
echo "Restored ${keyvalues[v]} = $defaultval"
fi
fi
done
fi
# Delete "drive_db_test_url=127.0.0.1" line (and line break) from synoinfo.conf
sed -i "/drive_db_test_url=*/d" "$synoinfo"
sed -i "/drive_db_test_url=*/d" /etc/synoinfo.conf
# Restore adapter_cards.conf from backup
# /usr/syno/etc.defaults/adapter_cards.conf
if [[ -f ${adapter_cards}.bak ]]; then
if cp -p "${adapter_cards}.bak" "${adapter_cards}"; then
echo "Restored ${adapter_cards}"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore ${adapter_cards}!\n"
fi
# /usr/syno/etc/adapter_cards.conf
if cp -p "${adapter_cards}.bak" "${adapter_cards2}"; then
echo -e "Restored ${adapter_cards2}"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore ${adapter_cards2}!\n"
fi
# Make sure they don't lose E10M20-T1 network connection
modelrplowercase=${modelname//RP/rp}
/usr/syno/bin/set_section_key_value ${adapter_cards} E10M20-T1_sup_nic "$modelrplowercase"
/usr/syno/bin/set_section_key_value ${adapter_cards2} E10M20-T1_sup_nic "$modelrplowercase"
fi
# Restore model.dtb from backup
if [[ -f ${dtb_file}.bak ]]; then
# /etc.default/model.dtb
if cp -p "${dtb_file}.bak" "${dtb_file}"; then
echo "Restored ${dtb_file}"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore ${dtb_file}!\n"
fi
# Restore /etc/model.dtb from /etc.default/model.dtb
if cp -p "${dtb_file}.bak" "${dtb2_file}"; then
echo -e "Restored ${dtb2_file}"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore ${dtb2_file}!\n"
fi
fi
# Restore storage_panel.js from backup
if [[ $buildnumber -gt 64570 ]]; then
# DSM 7.2.1 and later
strgmgrver="$(/usr/syno/bin/synopkg version StorageManager)"
elif [[ $buildnumber -ge 64561 ]]; then
# DSM 7.2
strgmgrver="${buildnumber}${smallfixnumber}"
fi
if [[ -f "${strgmgr}.$strgmgrver" ]]; then
if cp -p "${strgmgr}.$strgmgrver" "$strgmgr"; then
echo "Restored $(basename -- "$strgmgr")"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore $(basename -- "$strgmgr")!\n"
fi
else
echo "No backup of $(basename -- "$strgmgr") found."
fi
echo ""
# Restore .db files from backups
for f in "${!dbbakfiles[@]}"; do
replaceme="${dbbakfiles[f]%.bak}" # Remove .bak
if cp -p "${dbbakfiles[f]}" "$replaceme"; then
echo "Restored $(basename -- "$replaceme")"
else
restoreerr=1
echo -e "${Error}ERROR${Off} Failed to restore $(basename -- "$replaceme")!\n"
fi
done
# Delete any .dbr and .db.newr files left by previous script versions
for f in "${dbpath}"*dbr; do
if [[ -f $f ]]; then
rm "$f" >/dev/null
fi
done
for f in "${dbpath}"*db.newr; do
if [[ -f $f ]]; then
rm "$f" >/dev/null
fi
done
# Update .db files from Synology
/usr/syno/bin/syno_disk_db_update --update
# Enable SynoMemCheck.service if disabled
memcheck="/usr/lib/systemd/system/SynoMemCheck.service"
if [[ $(/usr/syno/bin/synogetkeyvalue "$memcheck" ExecStart) == "/bin/true" ]]; then
/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart /usr/syno/bin/syno_mem_check
fi
if [[ -z $restoreerr ]]; then
echo -e "\nRestore successful."
fi
# Restore writemostly if set
if [[ $ssd_restore == "yes" ]]; then
# Get array of internal drives
readarray -t internal_drives < <(synodisk --enum -t internal | grep 'Disk path' | cut -d"/" -f3)
# Restore all internal drives to just in_sync
echo -e "\nRestoring internal drive's state"
for idrive in "${internal_drives[@]}"; do
md0="/sys/block/md0/md/dev-"
md1="/sys/block/md1/md/dev-"
if [[ ${idrive::2} == "sd" ]]; then
# sda etc
# Check DSM system and swap partitions
if grep -q "write_mostly" "${md0}$idrive"1/state ||\
grep -q "write_mostly" "${md1}$idrive"2/state; then
set_writemostly -writemostly "$idrive"
fi
else
# sata1 or sas1 etc
# Check DSM system and swap partitions
if grep -q "write_mostly" "${md0}$idrive"p1/state ||\
grep -q "write_mostly" "${md1}$idrive"p2/state; then
set_writemostly -writemostly "$idrive"
fi
fi
done
fi
else
echo "Nothing to restore."
fi
exit
fi
#------------------------------------------------------------------------------
# Get list of installed SATA, SAS and M.2 NVMe/SATA drives,
# PCIe M.2 cards and connected Expansion Units.
vendor_from_id(){
# Vendor ids missing in /usr/syno/etc.defaults/pci_vendor_ids.conf
# $1 is vendor id
# https://devicehunt.com/all-pci-vendors
# https://pci-ids.ucw.cz/
vendor=""
case "${1,,}" in
0x10ec) vendor=TEAMGROUP ;;
0x025e) vendor=Solidigm ;;
0x1458) vendor=Gigabyte ;;
0x1462) vendor=MSI ;;
0x196e) vendor=PNY ;;
0x1987) vendor=Phison ;;
0x1b1c) vendor=Corsair ;;
0x1c5c) vendor="SK Hynix" ;;
0x1cc4) vendor=UMIS ;;
0x1cfa) vendor=Corsair ;; # Memory only?
0x1d97) vendor=SPCC/Lexar ;; # 2 brands with same vid
0x1dbe) vendor=ADATA ;;
0x1e0f) vendor=KIOXIA ;;
0x1e49) vendor=ZHITAI ;;
0x1e4b) vendor=HS/MAXIO ;; # 2 brands with same vid
0x1f40) vendor=Netac ;;
0x1bdc) vendor=Apacer;;
0x0ed1) vendor=aigo ;;
0x05dc) vendor=Lexar ;;
0x1d79) vendor=Transcend;;
*)
# Get vendor from syno_hdd_vendor_ids.txt
vidlist="$scriptpath/syno_hdd_vendor_ids.txt"
if [[ -r "$vidlist" ]]; then
val=$(/usr/syno/bin/synogetkeyvalue "$vidlist" "$1")
if [[ -n "$val" ]]; then
vendor="$val"
else
echo -e "\n${Yellow}WARNING${Off} No vendor found for vid $1" >&2
echo -e "You can add ${Cyan}$1${Off} and your drive's vendor to: " >&2
echo "$vidlist" >&2
fi
else
echo -e "\n${Error}ERROR{OFF} $vidlist not found!" >&2
fi
;;
esac
}
set_vendor(){
# Add missing vendors to /usr/syno/etc.defaults/pci_vendor_ids.conf
if [[ $vendor ]]; then
# DS1817+, DS1517+, RS1219+, RS818+ don't have pci_vendor_ids.conf
if [[ "$vidfile" ]]; then
if ! grep -q "$vid" "$vidfile"; then
/usr/syno/bin/synosetkeyvalue "$vidfile" "${vid,,}" "$vendor"
val=$(/usr/syno/bin/synogetkeyvalue "$vidfile" "${vid,,}")
if [[ $val == "${vendor}" ]]; then
echo -e "\nAdded $vendor to pci_vendor_ids" >&2
else
echo -e "\nFailed to add $vendor to pci_vendor_ids!" >&2
fi
fi
if ! grep -q "$vid" "$vidfile2"; then
/usr/syno/bin/synosetkeyvalue "$vidfile2" "${vid,,}" "$vendor"
fi
# Add leading 0 to short vid (change 0x5dc to 0x05dc)
if [[ ${#vid} -eq "5" ]]; then
vid="0x0${vid: -3}"
fi
if ! grep -q "$vid" "$vidfile"; then
/usr/syno/bin/synosetkeyvalue "$vidfile" "${vid,,}" "$vendor"
fi
if ! grep -q "$vid" "$vidfile2"; then
/usr/syno/bin/synosetkeyvalue "$vidfile2" "${vid,,}" "$vendor"
fi
fi
fi
}
get_vid(){
# $1 is /dev/nvme0n1 etc
if [[ $1 ]]; then
vid=$(nvme id-ctrl "$1" | grep -E ^vid | awk '{print $NF}')
if [[ $vid ]]; then
val=$(/usr/syno/bin/synogetkeyvalue "$vidfile" "${vid,,}")
if [[ -z $val ]]; then
vendor_from_id "$vid" && set_vendor
fi
fi
fi
}
fixdrivemodel(){
# Remove " 00Y" from end of Samsung/Lenovo SSDs # Github issue #13
if [[ $1 =~ MZ.*' 00Y' ]]; then
hdmodel=$(printf "%s" "$1" | sed 's/ 00Y.*//')
fi
# Brands that return "BRAND <model>" and need "BRAND " removed.
if [[ $1 =~ ^[A-Za-z]{3,7}' '.* ]]; then
# See Smartmontools database in /var/lib/smartmontools/drivedb.db
hdmodel=${hdmodel#"WDC "} # Remove "WDC " from start of model name
hdmodel=${hdmodel#"HGST "} # Remove "HGST " from start of model name
hdmodel=${hdmodel#"TOSHIBA "} # Remove "TOSHIBA " from start of model name
# Old drive brands
hdmodel=${hdmodel#"Hitachi "} # Remove "Hitachi " from start of model name
hdmodel=${hdmodel#"SAMSUNG "} # Remove "SAMSUNG " from start of model name
hdmodel=${hdmodel#"FUJISTU "} # Remove "FUJISTU " from start of model name
elif [[ $1 =~ ^'APPLE HDD '.* ]]; then
# Old drive brands
hdmodel=${hdmodel#"APPLE HDD "} # Remove "APPLE HDD " from start of model name
fi
}
get_size_gb(){
# $1 is /sys/block/sata1 or /sys/block/nvme0n1 etc
local disk_size_gb
disk_size_gb=$(synodisk --info /dev/"$(basename -- "$1")" | grep 'Total capacity' | awk '{print int($4 * 1.073741824)}')
echo "$disk_size_gb"
}
getdriveinfo(){
# $1 is /sys/block/sata1 etc
# Skip USB drives
usb=$(grep "$(basename -- "$1")" /proc/mounts | grep "[Uu][Ss][Bb]" | cut -d" " -f1-2)
if [[ ! $usb ]]; then
# Get drive model
hdmodel=$(cat "$1/device/model")
hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space
# Fix dodgy model numbers
fixdrivemodel "$hdmodel"
# Get drive firmware version
#fwrev=$(cat "$1/device/rev")
#fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space
device=/dev/"$(basename -- "$1")"
#fwrev=$(/usr/syno/bin/syno_hdd_util --ssd_detect | grep "$device " | awk '{print $2}') # GitHub issue #86, 87
# Account for SSD drives with spaces in their model name/number
fwrev=$(/usr/syno/bin/syno_hdd_util --ssd_detect | grep "$device " | awk '{print $(NF-3)}') # GitHub issue #86, 87
# Get M.2 SATA SSD firmware version
if [[ -z $fwrev ]]; then
dev=/dev/"$(basename -- "$1")"
fwrev=$(smartctl -a -d sat -T permissive "$dev" | grep -i firmware | awk '{print $NF}')
fi
# Get drive GB size
size_gb=$(get_size_gb "$1")
if [[ $hdmodel ]] && [[ $fwrev ]]; then
if /usr/syno/bin/synodisk --enum -t cache | grep -q /dev/"$(basename -- "$1")"; then
# Is SATA M.2 SSD
nvmelist+=("${hdmodel},${fwrev},${size_gb}")
else
hdlist+=("${hdmodel},${fwrev},${size_gb}")
fi
drivelist+=("${hdmodel}")
fi
fi
}
getm2info(){
# $1 is /sys/block/nvme0n1 etc
nvmemodel=$(cat "$1/device/model")
nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space
if [[ $2 == "nvme" ]]; then
nvmefw=$(cat "$1/device/firmware_rev")
elif [[ $2 == "nvc" ]]; then
nvmefw=$(cat "$1/device/rev")
fi
nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space
# Get drive GB size
size_gb=$(get_size_gb "$1")
if [[ $nvmemodel ]] && [[ $nvmefw ]]; then
nvmelist+=("${nvmemodel},${nvmefw},${size_gb}")
drivelist+=("${nvmemodel}")
fi
}
getcardmodel(){
# Get M.2 card model (if M.2 drives found)
# $1 is /dev/nvme0n1 etc
if [[ ${#nvmelist[@]} -gt "0" ]]; then
cardmodel=$(/usr/syno/bin/synodisk --m2-card-model-get "$1")
if [[ $cardmodel =~ M2D[0-9][0-9] ]]; then
# M2 adaptor card
if [[ -f "${model}_${cardmodel,,}${version}.db" ]]; then
m2carddblist+=("${model}_${cardmodel,,}${version}.db") # M.2 card's db file
fi
if [[ -f "${model}_${cardmodel,,}.db" ]]; then
m2carddblist+=("${model}_${cardmodel,,}.db") # M.2 card's db file
fi
m2cardlist+=("$cardmodel") # M.2 card
elif [[ $cardmodel =~ E[0-9][0-9]+M.+ ]]; then
# Ethernet + M2 adaptor card
if [[ -f "${model}_${cardmodel,,}${version}.db" ]]; then
m2carddblist+=("${model}_${cardmodel,,}${version}.db") # M.2 card's db file
fi
if [[ -f "${model}_${cardmodel,,}.db" ]]; then
m2carddblist+=("${model}_${cardmodel,,}.db") # M.2 card's db file
fi
m2cardlist+=("$cardmodel") # M.2 card
fi
fi
}
m2_pool_support(){
# M.2 drives in M2 adaptor card do not officially support storage pools
if [[ -f /run/synostorage/disks/"$(basename -- "$1")"/m2_pool_support ]]; then # GitHub issue #86, 87
echo -n 1 > /run/synostorage/disks/"$(basename -- "$1")"/m2_pool_support
fi
}
m2_drive(){
# $1 is nvme1 etc
# $2 is drive type (nvme or nvc)
if [[ $m2 != "no" ]]; then
# Check if is NVMe or SATA M.2 SSD
if /usr/syno/bin/synodisk --enum -t cache | grep -q /dev/"$(basename -- "$1")"; then
if [[ $2 == "nvme" ]] || [[ $2 == "nvc" ]]; then
# Fix unknown vendor id if needed. GitHub issue #161
# "Failed to get disk vendor" from synonvme --vendor-get
# causes "Unsupported firmware version" warning.
get_vid /dev/"$(basename -- "$1")"
# Get M2 model and firmware version
getm2info "$1" "$2"
fi
# Get M.2 card model if in M.2 card
getcardmodel /dev/"$(basename -- "$1")"
# Enable creating M.2 storage pool and volume in Storage Manager
m2_pool_support "$1"
rebootmsg=yes # Show reboot message at end
fi
fi
}
for d in /sys/block/*; do
# $d is /sys/block/sata1 etc
case "$(basename -- "${d}")" in
sd*|hd*)
if [[ $d =~ [hs]d[a-z][a-z]?$ ]]; then
getdriveinfo "$d"
fi
;;
sas*)
if [[ $d =~ sas[0-9][0-9]?[0-9]?$ ]]; then
getdriveinfo "$d"
fi
;;
sata*)
if [[ $d =~ sata[0-9][0-9]?[0-9]?$ ]]; then
getdriveinfo "$d"
# In case it's a SATA M.2 SSD in device tree model NAS
# M.2 SATA drives in M2D18 or M2S17
m2_drive "$d"
fi
;;
nvme*)
if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then
m2_drive "$d" "nvme"
fi
;;
nvc*) # M.2 SATA drives (in PCIe M2D18 or M2S17 only?)
if [[ $d =~ nvc[0-9][0-9]?$ ]]; then
m2_drive "$d" "nvc"
fi
;;
esac
done
# Sort hdlist array into new hdds array to remove duplicates
if [[ ${#hdlist[@]} -gt "0" ]]; then
while IFS= read -r -d '' x; do
hdds+=("$x")
done < <(printf "%s\0" "${hdlist[@]}" | sort -uz)
fi
# Show hdds if hdds array isn't empty
if [[ ${#hdds[@]} -eq "0" ]]; then
echo -e "No SATA or SAS drives found\n"
else
echo -e "\nHDD/SSD models found: ${#hdds[@]}"
num="0"
while [[ $num -lt "${#hdds[@]}" ]]; do
echo "${hdds[num]} GB"
num=$((num +1))
done
echo
fi
# Sort nvmelist array into new nvmes array to remove duplicates
if [[ ${#nvmelist[@]} -gt "0" ]]; then
while IFS= read -r -d '' x; do
nvmes+=("$x")
done < <(printf "%s\0" "${nvmelist[@]}" | sort -uz)
fi
# Show nvmes if nvmes array isn't empty
if [[ $m2 != "no" ]]; then
if [[ ${#nvmes[@]} -eq "0" ]]; then
echo -e "No M.2 drives found\n"
else
m2exists="yes"
echo "M.2 drive models found: ${#nvmes[@]}"
num="0"
while [[ $num -lt "${#nvmes[@]}" ]]; do
echo "${nvmes[num]} GB"
num=$((num +1))
done
echo
fi
fi
# Exit if no drives found
if [[ ${#hdds[@]} -eq "0" ]] && [[ ${#nvmes[@]} -eq "0" ]]; then
ding
echo -e "\n${Error}ERROR${Off} No drives found!" && exit 2
fi
# M.2 card db files
# Sort m2carddblist array into new m2carddbs array to remove duplicates
if [[ ${#m2carddblist[@]} -gt "0" ]]; then
while IFS= read -r -d '' x; do
m2carddbs+=("$x")
done < <(printf "%s\0" "${m2carddblist[@]}" | sort -uz)
fi
# M.2 cards
# Sort m2cardlist array into new m2cards array to remove duplicates
if [[ ${#m2cardlist[@]} -gt "0" ]]; then
while IFS= read -r -d '' x; do
m2cards+=("$x")
done < <(printf "%s\0" "${m2cardlist[@]}" | sort -uz)
fi
# Check m2cards array isn't empty
if [[ $m2 != "no" ]]; then
if [[ ${#m2cards[@]} -eq "0" ]]; then
echo -e "No M.2 PCIe cards found\n"
else
echo "M.2 PCIe card models found: ${#m2cards[@]}"
num="0"
while [[ $num -lt "${#m2cards[@]}" ]]; do
echo "${m2cards[num]}"
num=$((num +1))
done
echo
fi
fi
# Expansion units
# eSATA and InfiniBand ports both appear in syno_slot_mapping as:
# Esata port count: 1
# Eunit port 1 - RX1214
# Only device tree models have syno_slot_mapping
if which syno_slot_mapping >/dev/null; then
eunitlist=($(syno_slot_mapping | grep 'Eunit port' | awk '{print $5}'))
else
# Create new /var/log/diskprediction log to ensure newly connected ebox is in latest log
# Otherwise the new /var/log/diskprediction log is only created a midnight.
/usr/syno/bin/syno_disk_data_collector record
# Get list of connected expansion units (aka eunit/ebox)
path="/var/log/diskprediction"
# shellcheck disable=SC2012
file=$(ls $path | tail -n1)
eunitlist=($(grep -Eowi "([FRD]XD?[0-9]{3,4})(rp|ii|sas){0,2}" "$path/$file" | uniq))
fi
# Sort eunitlist array into new eunits array to remove duplicates
if [[ ${#eunitlist[@]} -gt "0" ]]; then
while IFS= read -r -d '' x; do
eunits+=("$x")
done < <(printf "%s\0" "${eunitlist[@]}" | sort -uz)
fi
# Check eunits array isn't empty
if [[ ${#eunits[@]} -eq "0" ]]; then
echo -e "No Expansion Units found\n"
else
#eunitexists="yes"
echo "Expansion Unit models found: ${#eunits[@]}"
num="0"
while [[ $num -lt "${#eunits[@]}" ]]; do
echo "${eunits[num]}"
num=$((num +1))
done
echo
fi
#------------------------------------------------------------------------------
# Check databases and add our drives if needed
# Host db files
db1list=($(find "$dbpath" -maxdepth 1 -name "*_host*.db"))
db2list=($(find "$dbpath" -maxdepth 1 -name "*_host*.db.new"))
#db1list=($(find "$dbpath" -maxdepth 1 -regextype posix-extended\
# -iregex ".*_host(_v7)?.db"))
#db2list=($(find "$dbpath" -maxdepth 1 -regextype posix-extended\
# -iregex ".*_host(_v7)?.db.new"))
# Expansion Unit db files
for i in "${!eunits[@]}"; do
#eunitdb1list+=($(find "$dbpath" -maxdepth 1 -name "${eunits[i],,}*.db"))
eunitdb1list+=($(find "$dbpath" -maxdepth 1 -regextype posix-extended\
-iregex ".*${eunits[i],,}(_v7)?.db"))
#eunitdb2list+=($(find "$dbpath" -maxdepth 1 -name "${eunits[i],,}*.db.new"))
eunitdb2list+=($(find "$dbpath" -maxdepth 1 -regextype posix-extended\
-iregex ".*${eunits[i],,}(_v7)?.db.new"))
done
# M.2 Card db files
for i in "${!m2cards[@]}"; do
m2carddb1list+=($(find "$dbpath" -maxdepth 1 -name "*_${m2cards[i],,}*.db"))
m2carddb2list+=($(find "$dbpath" -maxdepth 1 -name "*_${m2cards[i],,}*.db.new"))
done
if [[ ${#db1list[@]} -eq "0" ]]; then
ding
echo -e "${Error}ERROR 4${Off} Host db file not found!" && exit 4
fi
# Don't check .db.new as new installs don't have a .db.new file
getdbtype(){
# Detect drive db type
# Synology misspelt compatibility as compatbility
if grep -q -F '{"disk_compatbility_info":' "$1"; then
# DSM 7 drive db files start with {"disk_compatbility_info":
dbtype=7
elif grep -q -F '{"success":1,"list":[' "$1"; then
# DSM 6 drive db files start with {"success":1,"list":[
dbtype=6
elif [[ ! $1 =~ .*'.db.new' ]]; then
if [[ $(stat -c%s "$1") -eq "0" ]]; then
echo -e "${Error}ERROR${Off} $(basename -- "${1}") is 0 bytes!" >&2
else
echo -e "${Error}ERROR${Off} Unknown database type $(basename -- "${1}")!" >&2
fi
dbtype=1
else
dbtype=1
fi
#echo "db type: $dbtype" >&2 # debug
}
backupdb(){
# Backup database file if needed
if [[ ! -f "$1.bak" ]]; then
if [[ $(basename "$1") == "synoinfo.conf" ]]; then
echo "" >&2 # Formatting for stdout
fi
if [[ $2 == "long" ]]; then
fname="$1"
else
fname=$(basename -- "${1}")
fi
if cp -p "$1" "$1.bak"; then
echo -e "Backed up ${fname}" >&2
else
echo -e "${Error}ERROR 5${Off} Failed to backup ${fname}!" >&2
return 1
fi
fi
# Fix permissions if needed
octal=$(stat -c "%a %n" "$1" | cut -d" " -f1)
if [[ ! $octal -eq 644 ]]; then
chmod 644 "$1"
fi
return 0
}
# Backup host database file if needed
for i in "${!db1list[@]}"; do
backupdb "${db1list[i]}" ||{
ding
exit 5
}
done
for i in "${!db2list[@]}"; do
backupdb "${db2list[i]}" ||{
ding
exit 5 # maybe don't exit for .db.new file
}
done
#------------------------------------------------------------------------------
# Edit db files
editcount(){
# Count drives added to host db files
if [[ $1 =~ .*\.db$ ]]; then
db1Edits=$((db1Edits +1))
elif [[ $1 =~ .*\.db.new ]]; then
db2Edits=$((db2Edits +1))
fi
}
editdb7(){
if [[ $1 == "append" ]]; then # model not in db file
#if sed -i "s/}}}/}},\"$hdmodel\":{$fwstrng$default/" "$2"; then # append
if sed -i "s/}}}/}},\"${hdmodel//\//\\/}\":{$fwstrng$default/" "$2"; then # append
echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}"
editcount "$2"
else
echo -e "\n${Error}ERROR 6a${Off} Failed to update $(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"
else
echo -e "\n${Error}ERROR 6b${Off} Failed to update $(basename -- "$2")${Off}"
#exit 6
fi
elif [[ $1 == "empty" ]]; then # db file only contains {}
#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"
else
echo -e "\n${Error}ERROR 6c${Off} Failed to update $(basename -- "$2")${Off}"
#exit 6
fi
fi
}
updatedb(){
hdmodel=$(printf "%s" "$1" | cut -d"," -f 1)
fwrev=$(printf "%s" "$1" | cut -d"," -f 2)
size_gb=$(printf "%s" "$1" | cut -d"," -f 3)
#echo arg1 "$1" >&2 # debug
#echo arg2 "$2" >&2 # debug
#echo hdmodel "$hdmodel" >&2 # debug
#echo fwrev "$fwrev" >&2 # debug
# Check if db file is new or old style
getdbtype "$2"
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
else
common_string=\"size_gb\":$size_gb,
common_string="$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,
common_string="$common_string"\"barebone_installable\":true,
common_string="$common_string"\"barebone_installable_v2\":\"auto\",
common_string="$common_string"\"smart_test_ignore\":false,
common_string="$common_string"\"smart_attr_ignore\":false
fwstrng=\"$fwrev\":{
fwstrng="$fwstrng$common_string"
fwstrng="$fwstrng"}]},
default=\"default\":{
default="$default$common_string"
default="$default"}]}}}
# Synology misspelt compatibility as compatbility
if grep -q '"disk_compatbility_info":{}' "$2"; then
# Replace "disk_compatbility_info":{} with
# "disk_compatbility_info":{"WD40PURX-64GVNY0":{"80.00A80":{ ... }}},"default":{ ... }}}}
#echo "Edit empty db file:" # debug
editdb7 "empty" "$2"
elif grep -q '"'"$hdmodel"'":' "$2"; then
# Replace "WD40PURX-64GVNY0":{ with "WD40PURX-64GVNY0":{"80.00A80":{ ... }}},
#echo "Insert firmware version:" # debug
editdb7 "insert" "$2"
else
# Add "WD40PURX-64GVNY0":{"80.00A80":{ ... }}},"default":{ ... }}}
#echo "Append drive and firmware:" # debug
editdb7 "append" "$2"
fi
fi
# Edit existing drives in db with compatibility:unverified # Issue #224
if grep -q 'unverified' "$2"; then
sed -i 's/unverified/support/g' "$2"
if ! grep -q 'unverified' "$2"; then
echo -e "Edited unverified drives in ${Cyan}$(basename -- "$2")${Off}" >&2
fi
fi
# Edit existing drives in db with compatibility:not_support
if [[ $incompatible == "yes" ]]; then
if grep -q 'not_support' "$2"; then
sed -i 's/not_support/support/g' "$2"
if ! grep -q 'not_support' "$2"; then
echo -e "Edited incompatible drives in ${Cyan}$(basename -- "$2")${Off}" >&2
fi
fi
fi
elif [[ $dbtype -eq "6" ]]; then
# db type 6 used up to DSM 7.0.1
if grep -q "$hdmodel" "$2"; then
echo -e "${Yellow}$hdmodel${Off} already exists in ${Cyan}$(basename -- "$2")${Off}" >&2
else
# example:
# {"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]},
# Don't need to add firmware version?
#string="{\"model\":\"${hdmodel}\",\"firmware\":\"${fwrev}\",\"rec_intvl\":\[1\]},"
string="{\"model\":\"${hdmodel}\",\"firmware\":\"\",\"rec_intvl\":\[1\]},"
# {"success":1,"list":[
startstring="{\"success\":1,\"list\":\["
# example:
# {"success":1,"list":[{"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]},
#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}"
else
ding
echo -e "\n${Error}ERROR 8${Off} Failed to update $(basename -- "$2")${Off}" >&2
exit 8
fi
fi
fi
}
# Fix ,, instead of , bug caused by v3.3.75
if [[ "${#db1list[@]}" -gt "0" ]]; then
for i in "${!db1list[@]}"; do
sed -i "s/,,/,/" "${db1list[i]}"
done
fi
if [[ "${#db2list[@]}" -gt "0" ]]; then
for i in "${!db2list[@]}"; do
sed -i "s/,,/,/" "${db2list[i]}"
done
fi
# HDDs and SATA SSDs
num="0"
while [[ $num -lt "${#hdds[@]}" ]]; do
for i in "${!db1list[@]}"; do
updatedb "${hdds[$num]}" "${db1list[i]}"
done
for i in "${!db2list[@]}"; do
updatedb "${hdds[$num]}" "${db2list[i]}"
done
#------------------------------------------------
# Expansion Units
for i in "${!eunitdb1list[@]}"; do
backupdb "${eunitdb1list[i]}" &&\
updatedb "${hdds[$num]}" "${eunitdb1list[i]}"
done
for i in "${!eunitdb2list[@]}"; do
backupdb "${eunitdb2list[i]}" &&\
updatedb "${hdds[$num]}" "${eunitdb2list[i]}"
done
#------------------------------------------------
num=$((num +1))
done
# M.2 NVMe/SATA drives
num="0"
while [[ $num -lt "${#nvmes[@]}" ]]; do
for i in "${!db1list[@]}"; do
updatedb "${nvmes[$num]}" "${db1list[i]}"
done
for i in "${!db2list[@]}"; do
updatedb "${nvmes[$num]}" "${db2list[i]}"
done
#------------------------------------------------
# M.2 adaptor cards
for i in "${!m2carddb1list[@]}"; do
backupdb "${m2carddb1list[i]}" &&\
updatedb "${nvmes[$num]}" "${m2carddb1list[i]}"
done
for i in "${!m2carddb2list[@]}"; do
backupdb "${m2carddb2list[i]}" &&\
updatedb "${nvmes[$num]}" "${m2carddb2list[i]}"
done
#------------------------------------------------
num=$((num +1))
done
#------------------------------------------------------------------------------
# Enable unsupported Synology M2 PCIe cards
enable_card(){
# $1 is the file
# $2 is the section
# $3 is the card model and mode
if [[ -f $1 ]] && [[ -n $2 ]] && [[ -n $3 ]]; then
backupdb "$adapter_cards" long
backupdb "$adapter_cards2" long
# Check if section exists
if ! grep -q '^\['"$2"'\]$' "$1"; then
echo -e "Section [$2] not found in $(basename -- "$1")!" >&2
return
fi
# Check if already enabled
#
# No idea if "cat /proc/sys/kernel/syno_hw_version" returns upper or lower case RP
# "/usr/syno/etc.defaults/adapter_cards.conf" uses lower case rp but upper case RS
# So we'll convert RP to rp when needed.
#
modelrplowercase=${modelname//RP/rp}
val=$(/usr/syno/bin/get_section_key_value "$1" "$2" "$modelrplowercase")
if [[ $val != "yes" ]]; then
# /usr/syno/etc.defaults/adapter_cards.conf
if /usr/syno/bin/set_section_key_value "$1" "$2" "$modelrplowercase" yes; then
# /usr/syno/etc/adapter_cards.conf
/usr/syno/bin/set_section_key_value "$adapter_cards2" "$2" "$modelrplowercase" yes
echo -e "Enabled ${Yellow}$3${Off} for ${Cyan}$modelname${Off}" >&2
rebootmsg=yes
else
echo -e "${Error}ERROR 9${Off} Failed to enable $3 for ${modelname}!" >&2
fi
else
echo -e "${Yellow}$3${Off} already enabled for ${Cyan}$modelname${Off}" >&2
fi
fi
}
dts_m2_card(){
# $1 is the card model
# $2 is the dts file
# Remove last }; so we can append to dts file
sed -i '/^};/d' "$2"
# Append PCIe M.2 card node to dts file
if [[ $1 == E10M20-T1 ]] || [[ $1 == M2D20 ]]; then
cat >> "$2" <<EOM2D
$1 {
compatible = "Synology";
model = "synology_${1,,}";
power_limit = "14.85,14.85";
m2_card@1 {
nvme {
pcie_postfix = "00.0,08.0,00.0";
port_type = "ssdcache";
};
};
m2_card@2 {
nvme {
pcie_postfix = "00.0,04.0,00.0";
port_type = "ssdcache";
};
};
};
};
EOM2D
elif [[ $1 == M2D18 ]]; then
cat >> "$2" <<EOM2D18
M2D18 {
compatible = "Synology";
model = "synology_m2d18";
power_limit = "9.9,9.9";
m2_card@1 {
ahci {
pcie_postfix = "00.0,03.0,00.0";
ata_port = <0x00>;
};
nvme {
pcie_postfix = "00.0,04.0,00.0";
port_type = "ssdcache";
};
};
m2_card@2 {
ahci {
pcie_postfix = "00.0,03.0,00.0";
ata_port = <0x01>;
};
nvme {
pcie_postfix = "00.0,05.0,00.0";
port_type = "ssdcache";
};
};
};
};
EOM2D18
elif [[ $1 == M2D17 ]]; then
cat >> "$2" <<EOM2D17
M2D17 {
compatible = "Synology";
model = "synology_m2d17";
power_limit = "9.9,9.9";
m2_card@1 {
ahci {
pcie_postfix = "00.0,03.0,00.0";
ata_port = <0x00>;
};
};
m2_card@2 {
ahci {
pcie_postfix = "00.0,03.0,00.0";
ata_port = <0x01>;
};
};
};
};
EOM2D17
fi
}
is_schedule_running(){
# $1 is script's filename. e.g. syno_hdd_db.sh etc
local file="/usr/syno/etc/esynoscheduler/esynoscheduler.db"
local rows offset task status pid result
# Get number of rows in database
rows=$(sqlite3 "${file}" <<ECNT
SELECT COUNT(*) from task;
.quit
ECNT
)
# Check if script is running from task scheduler
offset="0"
while [[ $rows != "$offset" ]]; do
task=$(sqlite3 "$file" "SELECT operation FROM task WHERE rowid = (SELECT rowid FROM task LIMIT 1 OFFSET ${offset});")
if echo "$task" | grep -q "$1"; then
status=$(sqlite3 "$file" "SELECT status FROM task WHERE rowid = (SELECT rowid FROM task LIMIT 1 OFFSET ${offset});")
pid=$(echo "$status" | cut -d"[" -f2 | cut -d"]" -f1)
if [[ $pid -gt "0" ]]; then
result=$((result +pid))
fi
fi
offset=$((offset +1))
done
[ -n "$result" ] || return 1
}
install_binfile(){
# install_binfile <file> <file-url> <destination> <chmod> <bundled-path> <hash>
# example:
# file_url="https://raw.githubusercontent.com/${repo}/main/bin/dtc"
# install_binfile dtc "$file_url" /usr/bin/dtc a+x bin/dtc
if [[ -f "${scriptpath}/$5" ]]; then
binfile="${scriptpath}/$5"
echo -e "\nInstalling ${1}"
elif [[ -f "${scriptpath}/$(basename -- "$5")" ]]; then
binfile="${scriptpath}/$(basename -- "$5")"
echo -e "\nInstalling ${1}"
else
# Download binfile
if [[ $autoupdate == "yes" ]]; then
reply=y
elif is_schedule_running "$(basename -- "$0")"; then
reply=y
else
echo -e "\nNeed to download ${1}"
echo -e "${Cyan}Do you want to download ${1}?${Off} [y/n]"
read -r -t 30 reply
fi
if [[ ${reply,,} == "y" ]]; then
echo -e "\nDownloading ${1}"
if ! curl -kL -m 30 --connect-timeout 5 "$2" -o "/tmp/$1"; then
echo -e "${Error}ERROR${Off} Failed to download ${1}!"
return
fi
binfile="/tmp/${1}"
printf "Downloaded md5: "
md5sum -b "$binfile" | awk '{print $1}'
md5=$(md5sum -b "$binfile" | awk '{print $1}')
if [[ $md5 != "$6" ]]; then
echo "Expected md5: $6"
echo -e "${Error}ERROR${Off} Downloaded $1 md5 hash does not match!"
exit 1
fi
else
echo -e "${Error}ERROR${Off} Cannot add M2 PCIe card without ${1}!"
exit 1
fi
fi
# Set binfile executable
chmod "$4" "$binfile"
# Copy binfile to destination
cp -p "$binfile" "$3"
}
edit_modeldtb(){
# $1 is E10M20-T1 or M2D20 or M2D18 or M2D17
if [[ -f /etc.defaults/model.dtb ]]; then # Is device tree model
# Check if dtc exists and is executable
if [[ ! -x $(which dtc) ]]; then
md5hash="01381dabbe86e13a2f4a8017b5552918"
branch="main"
file_url="https://raw.githubusercontent.com/${repo}/${branch}/bin/dtc"
# install_binfile <file> <file-url> <destination> <chmod> <bundled-path> <hash>
install_binfile dtc "$file_url" /usr/sbin/dtc "a+x" bin/dtc "$md5hash"
fi
# Check again if dtc exists and is executable
if [[ -x /usr/sbin/dtc ]]; then
# Backup model.dtb
backupdb "$dtb_file" long
# Output model.dtb to model.dts
dtc -q -I dtb -O dts -o "$dts_file" "$dtb_file" # -q Suppress warnings
chmod 644 "$dts_file"
# Edit model.dts
for c in "${cards[@]}"; do
# Edit model.dts if needed
if ! grep -q "$c" "$dtb_file"; then
dts_m2_card "$c" "$dts_file"
echo -e "Added ${Yellow}$c${Off} to ${Cyan}model${hwrev}.dtb${Off}" >&2
else
echo -e "${Yellow}$c${Off} already exists in ${Cyan}model${hwrev}.dtb${Off}" >&2
fi
done
# Compile model.dts to model.dtb
dtc -q -I dts -O dtb -o "$dtb_file" "$dts_file" # -q Suppress warnings
# Set owner and permissions for model.dtb
chmod a+r "$dtb_file"
chown root:root "$dtb_file"
cp -pu "$dtb_file" "$dtb2_file" # Copy dtb file to /etc
rebootmsg=yes
else
echo -e "${Error}ERROR${Off} Missing /usr/sbin/dtc or not executable!" >&2
fi
fi
}
for c in "${m2cards[@]}"; do
case "$c" in
E10M20-T1)
echo ""
enable_card "$adapter_cards" E10M20-T1_sup_nic "E10M20-T1 NIC"
enable_card "$adapter_cards" E10M20-T1_sup_nvme "E10M20-T1 NVMe"
#enable_card "$adapter_cards" E10M20-T1_sup_sata "E10M20-T1 SATA"
cards=(E10M20-T1) && edit_modeldtb
;;
M2D20)
echo ""
enable_card "$adapter_cards" M2D20_sup_nvme "M2D20 NVMe"
cards=(M2D20) && edit_modeldtb
;;
M2D18)
echo ""
enable_card "$adapter_cards" M2D18_sup_nvme "M2D18 NVMe"
enable_card "$adapter_cards" M2D18_sup_sata "M2D18 SATA"
cards=(M2D18) && edit_modeldtb
;;
M2D17)
echo ""
enable_card "$adapter_cards" M2D17_sup_sata "M2D17 SATA"
cards=(M2D17) && edit_modeldtb
;;
*)
echo "Unknown M2 card type: $c"
;;
esac
done
#------------------------------------------------------------------------------
# Set or restore writemostly
if [[ $ssd == "yes" ]]; then
# Get array of internal drives
readarray -t internal_drives < <(synodisk --enum -t internal | grep 'Disk path' | cut -d"/" -f3)
if [[ $ssd_restore == "yes" ]]; then
# Restore all internal drives to just in_sync
echo -e "\nRestoring internal drive's state"
for idrive in "${internal_drives[@]}"; do
#if ! grep -q "write_mostly"; then
set_writemostly -writemostly "$idrive"
#fi
done
elif [[ ${#ssds_writemostly[@]} -gt "0" ]]; then
# User specified their fast drive(s)
echo -e "\nSetting slow internal HDDs state to write_mostly"
for idrive in "${internal_drives[@]}"; do
if [[ ! ${ssds_writemostly[*]} =~ $idrive ]]; then
set_writemostly writemostly "$idrive"
fi
done
else
# Get list of internal HDDs and qty of SSDs
internal_ssd_qty="0"
for idrive in "${internal_drives[@]}"; do
if synodisk --isssd /dev/"${idrive:?}" >/dev/null; then
# exit code 0 = is not SSD
# exit code 1 = is SSD
# Add internal HDDs to array
internal_hdds+=("$idrive")
else
# Count number of internal 2.5 inch SSDs
internal_ssd_qty=$((internal_ssd_qty +1))
fi
done
# Set HDDs to writemostly if there's also internal SSDs
if [[ $internal_ssd_qty -gt "0" ]] && [[ ${#internal_hdds[@]} -gt "0" ]]; then
# There are internal SSDs and HDDs
echo -e "\nSetting internal HDDs state to write_mostly"
for idrive in "${internal_hdds[@]}"; do
set_writemostly writemostly "$idrive"
done
fi
fi
fi
#------------------------------------------------------------------------------
# Edit /etc.defaults/synoinfo.conf
# Backup synoinfo.conf if needed
backupdb "$synoinfo" ||{
ding
exit 9
}
# Optionally disable "support_disk_compatibility"
sdc=support_disk_compatibility
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo $sdc)"
if [[ $force == "yes" ]]; then
if [[ $setting == "yes" ]]; then
# Disable support_disk_compatibility
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$sdc" "no"
setting="$(/usr/syno/bin/synogetkeyvalue "$synoinfo" $sdc)"
if [[ $setting == "no" ]]; then
echo -e "\nDisabled support disk compatibility."
fi
elif [[ $setting == "no" ]]; then
echo -e "\nSupport disk compatibility already disabled."
fi
else
if [[ $setting == "no" ]]; then
# Enable support_disk_compatibility
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$sdc" "yes"
setting="$(/usr/syno/bin/synogetkeyvalue "$synoinfo" $sdc)"
if [[ $setting == "yes" ]]; then
echo -e "\nRe-enabled support disk compatibility."
fi
elif [[ $setting == "yes" ]]; then
echo -e "\nSupport disk compatibility already enabled."
fi
fi
# Optionally disable memory compatibility warnings
smc=support_memory_compatibility
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo $smc)"
settingbak="$(/usr/syno/bin/synogetkeyvalue $synoinfo.bak $smc)"
if [[ -z $settingbak ]] || [[ -z $setting ]]; then
# For older models that don't use "support_memory_compatibility"
memcheck="/usr/lib/systemd/system/SynoMemCheck.service"
memcheck_value="$(/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart)"
if [[ $ram == "yes" ]]; then
if [[ $memcheck_value == "/usr/syno/bin/syno_mem_check" ]]; then
# Disable SynoMemCheck.service
/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart /bin/true
memcheck_value="$(/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart)"
if [[ $memcheck_value == "/bin/true" ]]; then
echo -e "\nDisabled SynoMemCheck memory compatibility."
fi
elif [[ $memcheck_value == "/bin/true" ]]; then
echo -e "\nSynoMemCheck memory compatibility already disabled."
fi
else
if [[ $memcheck_value == "/bin/true" ]]; then
# Enable SynoMemCheck.service
/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart /usr/syno/bin/syno_mem_check
memcheck_value="$(/usr/syno/bin/synosetkeyvalue "$memcheck" ExecStart)"
if [[ $memcheck_value == "/usr/syno/bin/syno_mem_check" ]]; then
echo -e "\nRe-enabled SynoMemCheck memory compatibility."
fi
elif [[ $memcheck_value == "/usr/syno/bin/syno_mem_check" ]]; then
echo -e "\nSynoMemCheck memory compatibility already enabled."
fi
fi
else
# Disable "support_memory_compatibility" (not for older models)
if [[ $ram == "yes" ]]; then
if [[ $setting == "yes" ]]; then
# Disable support_memory_compatibility
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$smc" "no"
setting="$(/usr/syno/bin/synogetkeyvalue "$synoinfo" $smc)"
if [[ $setting == "no" ]]; then
echo -e "\nDisabled support memory compatibility."
fi
elif [[ $setting == "no" ]]; then
echo -e "\nSupport memory compatibility already disabled."
fi
else
if [[ $setting == "no" ]]; then
# Enable support_memory_compatibility
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$smc" "yes"
setting="$(/usr/syno/bin/synogetkeyvalue "$synoinfo" $smc)"
if [[ $setting == "yes" ]]; then
echo -e "\nRe-enabled support memory compatibility."
fi
elif [[ $setting == "yes" ]]; then
echo -e "\nSupport memory compatibility already enabled."
fi
fi
fi
# Optionally set mem_max_mb to the amount of installed memory
if [[ $dsm -gt "6" ]]; then # DSM 6 as has no dmidecode
if [[ $ram == "yes" ]] && [[ -f /usr/sbin/dmidecode ]]; then
# Get total amount of installed memory
#IFS=$'\n' read -r -d '' -a array < <(dmidecode -t memory | grep "[Ss]ize") # GitHub issue #86, 87
IFS=$'\n' read -r -d '' -a array < <(dmidecode -t memory |\
grep -E "[Ss]ize: [0-9]+ [MG]{1}[B]{1}$") # GitHub issue #86, 87, 106
if [[ ${#array[@]} -gt "0" ]]; then
num="0"
while [[ $num -lt "${#array[@]}" ]]; do
check=$(printf %s "${array[num]}" | awk '{print $1}')
if [[ ${check,,} == "size:" ]]; then
ramsize=$(printf %s "${array[num]}" | awk '{print $2}') # GitHub issue #86, 87
bytes=$(printf %s "${array[num]}" | awk '{print $3}') # GitHub issue #86, 87
if [[ $ramsize =~ ^[0-9]+$ ]]; then # Check $ramsize is numeric # GitHub issue #86, 87
if [[ $bytes == "GB" ]]; then # DSM 7.2 dmidecode returned GB
ramsize=$((ramsize * 1024)) # Convert to MB # GitHub issue #107
fi
if [[ $ramtotal ]]; then
ramtotal=$((ramtotal +ramsize))
else
ramtotal="$ramsize"
fi
fi
fi
num=$((num +1))
done
fi
# Set mem_max_mb to the amount of installed memory
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo mem_max_mb)"
settingbak="$(/usr/syno/bin/synogetkeyvalue ${synoinfo}.bak mem_max_mb)" # GitHub issue #107
if [[ $ramtotal =~ ^[0-9]+$ ]]; then # Check $ramtotal is numeric
if [[ $ramtotal -gt "$setting" ]]; then
/usr/syno/bin/synosetkeyvalue "$synoinfo" mem_max_mb "$ramtotal"
# Check we changed mem_max_mb
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo mem_max_mb)"
if [[ $ramtotal == "$setting" ]]; then
#echo -e "\nSet max memory to $ramtotal MB."
ramgb=$((ramtotal / 1024))
echo -e "\nSet max memory to $ramgb GB."
else
echo -e "\n${Error}ERROR${Off} Failed to change max memory!"
fi
elif [[ $setting -gt "$ramtotal" ]] && [[ $setting -gt "$settingbak" ]]; # GitHub issue #107
then
# Fix setting is greater than both ramtotal and default in syninfo.conf.bak
/usr/syno/bin/synosetkeyvalue "$synoinfo" mem_max_mb "$settingbak"
# Check we restored mem_max_mb
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo mem_max_mb)"
if [[ $settingbak == "$setting" ]]; then
#echo -e "\nSet max memory to $ramtotal MB."
ramgb=$((ramtotal / 1024))
echo -e "\nRestored max memory to $ramgb GB."
else
echo -e "\n${Error}ERROR${Off} Failed to restore max memory!"
fi
elif [[ $ramtotal == "$setting" ]]; then
#echo -e "\nMax memory already set to $ramtotal MB."
ramgb=$((ramtotal / 1024))
echo -e "\nMax memory already set to $ramgb GB."
else [[ $ramtotal -lt "$setting" ]]
#echo -e "\nMax memory is set to $setting MB."
ramgb=$((setting / 1024))
echo -e "\nMax memory is set to $ramgb GB."
fi
else
echo -e "\n${Error}ERROR${Off} Total memory size is not numeric: '$ramtotal'"
fi
fi
fi
# Enable nvme support
# shellcheck disable=SC2010 # Don't warn about "Don't use ls | grep"
if ls /dev | grep -q nvme; then
if [[ $m2 != "no" ]]; then
# Check if nvme support is enabled
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo supportnvme)"
enabled=""
if [[ ! $setting ]]; then
# Add supportnvme="yes"
/usr/syno/bin/synosetkeyvalue "$synoinfo" supportnvme "yes"
enabled="yes"
elif [[ $setting == "no" ]]; then
# Change supportnvme="no" to "yes"
/usr/syno/bin/synosetkeyvalue "$synoinfo" supportnvme "yes"
enabled="yes"
elif [[ $setting == "yes" ]]; then
echo -e "\nNVMe support already enabled."
fi
# Check if we enabled nvme support
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo supportnvme)"
if [[ $enabled == "yes" ]]; then
if [[ $setting == "yes" ]]; then
echo -e "\nEnabled NVMe support."
else
echo -e "\n${Error}ERROR${Off} Failed to enable NVMe support!"
fi
fi
fi
fi
# Enable m2 volume support
# shellcheck disable=SC2010 # Don't warn about "Don't use ls | grep"
if ls /dev | grep -q "nv[cm]"; then
if [[ $m2 != "no" ]]; then
if [[ $m2exists == "yes" ]]; then
# Check if m2 volume support is enabled
smp=support_m2_pool
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo ${smp})"
enabled=""
if [[ ! $setting ]]; then
# Add support_m2_pool="yes"
#echo 'support_m2_pool="yes"' >> "$synoinfo"
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$smp" "yes"
enabled="yes"
elif [[ $setting == "no" ]]; then
# Change support_m2_pool="no" to "yes"
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$smp" "yes"
enabled="yes"
elif [[ $setting == "yes" ]]; then
echo -e "\nM.2 volume support already enabled."
fi
# Check if we enabled m2 volume support
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo ${smp})"
if [[ $enabled == "yes" ]]; then
if [[ $setting == "yes" ]]; then
echo -e "\nEnabled M.2 volume support."
else
echo -e "\n${Error}ERROR${Off} Failed to enable m2 volume support!"
fi
fi
fi
fi
fi
# Edit synoinfo.conf to prevent drive db updates
dtu=drive_db_test_url
url="$(/usr/syno/bin/synogetkeyvalue $synoinfo ${dtu})"
disabled=""
if [[ $nodbupdate == "yes" ]]; then
if [[ ! $url ]]; then
# Add drive_db_test_url="127.0.0.1"
#echo 'drive_db_test_url="127.0.0.1"' >> "$synoinfo"
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$dtu" "127.0.0.1"
[ -d /tmpRoot ] && /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1"
disabled="yes"
elif [[ $url != "127.0.0.1" ]]; then
# Edit drive_db_test_url=
/usr/syno/bin/synosetkeyvalue "$synoinfo" "$dtu" "127.0.0.1"
[ -d /tmpRoot ] && /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1"
disabled="yes"
fi
# Check if we disabled drive db auto updates
url="$(/usr/syno/bin/synogetkeyvalue $synoinfo drive_db_test_url)"
if [[ $disabled == "yes" ]]; then
if [[ $url == "127.0.0.1" ]]; then
echo -e "\nDisabled drive db auto updates."
else
echo -e "\n${Error}ERROR${Off} Failed to disable drive db auto updates!"
fi
else
echo -e "\nDrive db auto updates already disabled."
fi
else
# Re-enable drive db updates
#if [[ $url == "127.0.0.1" ]]; then
if [[ $url ]]; then
# Delete "drive_db_test_url=127.0.0.1" line (inc. line break)
sed -i "/drive_db_test_url=*/d" "$synoinfo"
sed -i "/drive_db_test_url=*/d" /etc/synoinfo.conf
# Check if we re-enabled drive db auto updates
url="$(/usr/syno/bin/synogetkeyvalue $synoinfo drive_db_test_url)"
if [[ $url != "127.0.0.1" ]]; then
echo -e "\nRe-enabled drive db auto updates."
else
echo -e "\n${Error}ERROR${Off} Failed to enable drive db auto updates!"
fi
else
echo -e "\nDrive db auto updates already enabled."
fi
fi
# Optionally disable "support_wdda"
setting="$(/usr/syno/bin/synogetkeyvalue $synoinfo support_wdda)"
if [[ $wdda == "no" ]]; then
if [[ $setting == "yes" ]]; then
# Disable support_wdda
/usr/syno/bin/synosetkeyvalue "$synoinfo" support_wdda "no"
setting="$(/usr/syno/bin/synogetkeyvalue "$synoinfo" support_wdda)"
if [[ $setting == "no" ]]; then
echo -e "\nDisabled support WDDA."
fi
elif [[ $setting == "no" ]]; then
echo -e "\nSupport WDDA already disabled."
fi
fi
# Enable creating pool on drives in M.2 adaptor card
if [[ -f "$strgmgr" ]] && [[ $buildnumber -gt 42962 ]]; then
# DSM 7.2 and later
if [[ ${#m2cards[@]} -gt "0" ]] || [[ $forcepci == "yes" ]]; then
if grep -q 'notSupportM2Pool_addOnCard' "$strgmgr"; then
# Backup storage_panel.js"
if [[ $buildnumber -gt 64570 ]]; then
# DSM 7.2.1 and later
strgmgrver="$(/usr/syno/bin/synopkg version StorageManager)"
elif [[ $buildnumber -ge 64561 ]]; then
# DSM 7.2
strgmgrver="${buildnumber}${smallfixnumber}"
fi
echo ""
if [[ ! -f "${strgmgr}.$strgmgrver" ]]; then
if cp -p "$strgmgr" "${strgmgr}.$strgmgrver"; then
echo -e "Backed up $(basename -- "$strgmgr")"
else
echo -e "${Error}ERROR${Off} Failed to backup $(basename -- "$strgmgr")!"
fi
fi
sed -i 's/notSupportM2Pool_addOnCard:this.T("disk_info","disk_reason_m2_add_on_card"),//g' "$strgmgr"
sed -i 's/},{isConditionInvalid:0<this.pciSlot,invalidReason:"notSupportM2Pool_addOnCard"//g' "$strgmgr"
# Check if we edited file
if ! grep -q 'notSupportM2Pool_addOnCard' "$strgmgr"; then
echo -e "Enabled creating pool on drives in M.2 adaptor card."
else
echo -e "${Error}ERROR${Off} Failed to enable creating pool on drives in M.2 adaptor card!"
fi
else
echo -e "\nCreating pool in UI on drives in M.2 adaptor card already enabled."
fi
fi
fi
#------------------------------------------------------------------------------
# Finished
show_changes(){
# $1 is drive_model,firmware_version,size_gb
drive_model="$(printf "%s" "$1" | cut -d"," -f 1)"
echo -e "\n$drive_model:"
jq -r --arg drive_model "$drive_model" '.disk_compatbility_info[$drive_model]' "${db1list[0]}"
}
# Show the changes
if [[ ${showedits,,} == "yes" ]]; then
# HDDs/SSDs
for d in "${hdds[@]}"; do
show_changes "$d"
done
# NVMe drives
for d in "${nvmes[@]}"; do
show_changes "$d"
done
fi
# Make Synology check disk compatibility
if [[ -f /usr/syno/sbin/synostgdisk ]]; then # DSM 6.2.3 does not have synostgdisk
/usr/syno/sbin/synostgdisk --check-all-disks-compatibility
status=$?
if [[ $status -eq "0" ]]; then
echo -e "\nDSM successfully checked disk compatibility."
rebootmsg=yes # Show reboot message at end
else
# Ignore DSM 6.2.4 as it returns 255 for "synostgdisk --check-all-disks-compatibility"
# and DSM 6.2.3 and lower have no synostgdisk command
if [[ $dsm -gt "6" ]]; then
echo -e "\nDSM ${Red}failed${Off} to check disk compatibility with exit code $status"
rebootmsg=yes # Show reboot message at end
fi
fi
fi
# Show reboot message if required
if [[ $dsm -eq "6" ]] || [[ $rebootmsg == "yes" ]]; then
echo -e "\nYou may need to ${Cyan}reboot the Synology${Off} to see the changes."
fi
exit