``` ├── .github/ ├── FUNDING.yml ├── CHANGES.txt ├── LICENSE ├── README.md ├── bin/ ├── dhm_tool ├── dhm_tool.txt ├── dtc ├── dtc_info.txt ├── dtc_source.txt ├── how_to_schedule.md ├── images/ ├── how_to_download.png ├── ihm.png ├── ram_warning.png ├── schedule1.png ├── schedule2.png ├── schedule3-2.png ├── schedule3.png ├── syno_hdd_db.png ├── syno_hdd_db1.png ├── syno_hdd_db2.png ├── syno_hdd_db_help.png ├── syno_hdd_db_help2.png ├── unknown.png ├── update-now-disabled.png ├── update-now-working.png ├── vendor_ids.png ├── my-other-scripts.md ├── syno_hdd_db.sh ├── syno_hdd_vendor_ids.txt ``` ## /.github/FUNDING.yml ```yml path="/.github/FUNDING.yml" github: 007revad buy_me_a_coffee: 007revad custom: ["https://www.paypal.me/007revad"] ``` ## /CHANGES.txt v3.6.111 - Added support for M.2 volumes for NVMe drives in PCIe adaptor cards for DSM 7.1.1 v3.6.110 - Bug fix for not finding SAS expansion units. Issue #413 v3.6.109 - Added -I, --ihm option to update IronWolf Health Management to 2.5.1 to support recent model IronWolf and IronWolf Pro drives. - For NAS with x86_64 CPUs only. - Installs IronWolf Health Management on '22 series and newer models that don't have IronWolf Health Management (untested). v3.5.108 - Prevent error message if /tmpRoot exists but does not contain /usr/syno/bin/synosetkeyvalue and /etc.defaults/synoinfo.conf. Issue #411 v3.5.107 - Bug fix for firmware version as "Found]" in db files. Issue #407 v3.5.106 - Bug fix for when script is not located on a volume. Issue #397 v3.5.105 - Bug fix for drives that return "HCST " as the model, like HGST drives do. Issue #389 v3.5.104 - Some disks will be blocked in special scenarios. PR #387 v3.5.103 - Bug fix getting size of large drives. Issue #368 - Run the script once with the --restore option to undue the previous changes then run the script as normal. v3.5.102 - Changed to use a faster method of detecting if an expansion unit is connected, for models with the syno_slot_mapping command. - Changed so XPE users using the hdddb addon don't need to reboot. v3.5.101 - Changed to support "--restore --ssd=restore" to restore write_mostly when restoring all other changes. Issue #340 - When using --restore you can also use --ssd=restore, -e or --email v3.5.98 - Changed to automatically download and install dtc if all of the following 4 conditions are met: 1. dtc is not already installed. 2. /bin/dtc or dtc are not in the same folder as the script. 3. The script needs dtc. 4. The script is running from task scheduler. - Bug fix for "Enable write_mostly on slow internal drives so DSM runs from the fast internal drive(s)." Issue #340 - Improved output to make it clear which drive(s) have most_writely set. v3.5.97 - Changed silently skip empty .db.new files with showing an error. Issue #175 - Changed to warn if db file is 0 bytes. v3.5.96 - Added option to set write_mostly for your internal HDDs so DSM will normally read from your faster internal SSD(s). - It can automatically set DSM to read from your internal SSDs. - Or you can tell the script which internal drive(s) DSM should read from. Thanks to Xeroxxx for the writemostly suggestion and their writeup here: https://www.techspark.de/speed-up-synology-dsm-with-hdd-ssd/ v3.5.94 - Updated to support newer drive db versions. - Synology added size_gb in a recent host v7 version (in SynoOfflinePack 764). - Synology added barebone_installable_v2 in the latest host v7 version (in SynoOfflinePack 787). - Bug fix when restoring where memcheck service was only re-enabled on DVA models. - Changed to add leading 0 to short vids reported by drive. - Sets 2 vids in case DSM uses the short one (e.g. 0x05dc=brand and 0x5dc=brand). Note: You may need to run syno_hdd_db without the -n or --noupdate option, then update the drive database from "Storage Manager > HDD/SSD > Settings > Advanced > Update Now" then run syno_hdd_db with your preferred options. v3.5.93 - Bug fix for false "Failed to delete tmp files" log entries when script updates itself. Issue #312 - Bug first appeared in v3.1.64 v3.5.92 - Changed to support M.2 SATA SSDs in M2D18 or M2D17. - Change -s, --show option to show changes for each different drive model. v3.5.91 - Changed to not exit if no SATA or SAS drives found. Issue #303 - Now only exits if no SATA, SAS or NVMe drives found. v3.5.90 - Changed to enable creating storage pools/volumes on NVMe drives in a PCIe M.2 adaptor in DSM 7.2 - Previously only supported DSM 7.2.1 - Changed to enable creating storage pools/volumes on NVMe drives in a PCIe M.2 adaptor even if PCIe M.2 adaptor not found. - This may allow creating NVMe volumes on 3rd party PCIe M.2 adaptors. - Bug fix for when there's multiple expansion unit models only the last expansion unit was processed. Issue #288 - Bug fix for when there's multiple M2 adaptor card models only the last M2 card was processed. - Bug fix for incorrectly matching model name variations as well as the exact model name. - e.g. RX1217 matched RX1217, RX1217rp and RX1217sas. v3.5.89 - Bug fix for -s, --showedits option with multiple of the same drive model but with different firmware versions. Issue #276 v3.5.88 - Changed how memory compatibility is disabled for older models. Issue #272 v3.4.87 - Fix Invalid json format syslog output #270 v3.4.86 - Hard coded /usr/syno/bin/ for Synology commands (to prevent $PATH issues). #249 v3.4.84 - Bug fix when script updates itself and user ran the script from ./scriptname.sh v3.4.83 - Fix for drives that exist in the drive database already but have "compatibility not_support". - Affected drives were showing as "Incompatible" in storage manager. - Need to use the -i or --incompatible option. v3.4.82 - Fix for drives that exist in the drive database already but have "compatibility unverified". Issue #224 - Affected drives were showing as "Unverified" in storage manager. v3.4.81 - Bug fix for false "This script is NOT running on a Synology NAS!" if uname is installed from Entware. Issue #218 v3.4.80 - Bug fix for chmod failed on changes.txt - Improved help message. v3.4.78 - Added check that script is running on Synology NAS. v3.4.77 - Include smart_test_ignore and smart_attr_ignore in db files. - Now saves changes.txt as _changes.txt when updating the script. - To not overwrite changes.txt if my other scripts are in the same folder. - Bug fix for detecting if script is located on M.2 drive. - Bug fix for error when -s or --showedits option was used. Issue #200 - Minor bug fix. v3.3.73 - Bug fix for vendor id. v3.3.72 - Bug fix for enabling creating storage pools in Storage Manager for M.2 drives in PCIe adaptor cards. - Bug fix for not copying syno_hdd_db_vendors.txt to script location when script updates itself. - Bug fix for checking if script located on NVMe drive. v3.3.70 - Now enables creating storage pools in Storage Manager for M.2 drives in PCIe adaptor cards: - E10M20-T1, M2D20, M2D18 and M2D17. - DSM 7.2.1 and above only. - Script needs to run after each boot. - Added new vendor ids for Apacer, aigo, Lexar and Transcend NVMe drives. - Now includes syno_hdd_vendor.txt so users can add their NVMe drive's vendor id. - syno_hdd_vendor.txt needs to be in the same folder as syno_hdd_db.sh - Now warns if script is located on an M.2 volume. v3.2.69 - Added KIOXIA vendor id. - Bug fix for wrong version number, which caused an update loop. v3.2.68 - Updated so E10M20-T1, M2D20, M2D18 and M2D17 now work in models that use device tree and are using: - DSM 7.2 Update 2 and 3, 7.2.1, 7.2.1 Update 1, 2 and 3. Issue #132, #148 - Now edits model.dtb instead of downloading a pre-edited version. - Improvements to --restore option. - Fix for Unknown vendor causing "Unsupported firmware version" warning. Issue #161 - Now supports NVMe drives that show as Unknown brand in storage manager: Issue #161 - ADATA, Corsair, Gigabyte, HS/MAXIO, MSI, Netac, Phison, PNY - SK Hynix, Solidigm, SPCC/Lexar, TEAMGROUP, UMIS, ZHITAI - Fixed bug where memory was shown in MB but with GB unit. - Removed -i, --immutable option. - Minor bug fixes. v3.1.65 - Bug fix for NVMe drives with / in the model name for non-device tree Synology models. Issue #154 v3.1.64 - Added -e --email option to disable coloured output to make task scheduler emails easier to read. - Bug fix for script not updating itself if .sh file had been renamed. - Bug fix for missing executable permissions if .sh file had been renamed. - Bug fix to prevent update loop if script's .tar.gz file already exists in /tmp. - Bug fix to prevent update failing if script's temp folder already exists in /tmp. - Now only copies CHANGES.txt to script location if script is located on a volume, to prevent putting CHANGES.txt on system partition (/usr/bin, /usr/sbin, /root etc.) v3.1.63 - Added support to disable unsupported memory warnings on DVA models. #136 v3.1.62 - Fixed bug where newly connected expansion units weren't found until up to 24 hours later. Issue #124 v3.1.61 - Added enabling E10M20-T1, M2D20 and M2D18 for DS1821+, DS1621+ and DS1520+. - Added enabling M2D18 for RS822RP+, RS822+, RS1221RP+ and RS1221+ for older DSM versions. - Fixed enabling E10M20-T1, M2D20 and M2D18 cards in models that don't officially support them. - Fixed bugs where the calculated amount of installed memory could be incorrect: - If last memory socket was empty an invalid unit of bytes could be used. Issue #106 - When dmidecode returned MB for one ram module and GB for another ram module. Issue #107 - Fixed bug displaying the max memory setting if total installed memory was less than the max memory. Issue #107 - Fixed bug where sata1 drive firmware version was wrong if there was a sata10 drive. v3.0.56 - Minor bug fix for checking amount of installed memory. v3.0.55 - Now enables any installed Synology M.2 PCIe cards for models that don't officially support them. - You can use a M2D20, M2D18, M2D17 or E10M20-T1 on any model with a PCIe slot (not Mini PCIe). - Now the script reloads itself after updating. - Added -i, --immutable option to enable immutable snapshots on models older than '20 series running DSM 7.2. - Added -w, --wdda option to disable WDDA (to prevent warnings when WD drives have been running more than 3 years). - Added "You may need to reboot" message when NVMe drives were detected. - Added --autoupdate=[age] option to auto update synology_hdd_db x days after new version released. - Autoupdate logs update success or errors to DSM system log. - Changed help to show -r, --ram also sets max memory to the amount of installed memory. - Changed the "No M.2 cards found" to "No M.2 PCIe cards found" to make it clearer. - Changed to skip checking the amount of installed memory in DSM 6 (because it was never working in DSM 6). - Fixed HDD/SSD firmware versions always being 4 characters long (for DSM 7.2 and 6.2.4 Update 7). - Fixed detecting amount of installed memory (for DSM 7.2 which now reports GB instead of MB). - Fixed USB drives sometimes being detected as internal drives (for DSM 7.2). - Fixed error if /run/synostorage/disks/nvme0n1/m2_pool_support doesn't exist yet (for DSM 7.2). - Fixed drive db update still being disabled in /etc/synoinfo.conf after script run without -n or --noupdate option. - Fixed drive db update still being disabled in /etc/synoinfo.conf after script run with --restore option. - Fixed permissions on restored files being incorrect after script run with --restore option. - Fixed permissions on backup files. v2.2.47 - Updated reboot info in readme. - Added reboot message for DSM 7. - Bug fix for issue #77 (escape slashes in drive model name). - Added error sound. v2.2.45 - Minor bug fix. v2.2.44 - Added --restore info to --help - Updated restore option to download the latest db files from Synology. - Now warns you if you try to run it in sh with "sh scriptname.sh" v2.2.43 - Fixed DSM 6 bug where the drives were being duplicated in the .db files each time the script was run. - Fixed DSM 6 bug where the .db files were being duplicated as .dbr each time the db files were edited. v2.2.42 - Fixed bug where expansion units ending in RP or II were not detected. - Added a --restore option to undo all changes made by the script. - Now looks for and edits both v7 and non-v7 db files to solve issue #11 for RS '21 models running DSM 6.2.4. This will also ensure the script still works if: - Synology append different numbers to the db file names in DSM 8 etc. - The detected NAS model name does not match the .db files' model name. - Now backs up the .db.new files (as well as the .db files). - Now shows max memory in GB instead of MB. - Now shows status of "Support disk compatibility" setting even if it wasn't changed. - Now shows status of "Support memory compatibility" setting even if it wasn't changed. v2.1.38 - Improved shell output when editing max memory setting. - Changed method of checking if drive is a USB drive to prevent ignoring internal drives on RS models. - Changed to not run "synostgdisk --check-all-disks-compatibility" in DSM 6.2.3 (which has no synostgdisk). v2.1.37 - Now edits max supported memory to match the amount of memory installed, if installed memory is greater than the current max memory setting. - Minor improvements. v2.0.36 - Show the options used. - Thank you to Gummibando on reddit for their donation. v2.0.35 - Now allows creating M.2 storage pool and volume all from Storage Manager. v1.3.34 - Now always shows your drive entries in the host db file if -s or --showedits used instead of only if db file was edited during that run. - Changed to show usage if invalid long option used instead of continuing. v1.3.33 - Fixed bug inserting firmware version for already existing model. v1.3.32 - Changed to add drives' firmware version to the db files (to support data deduplication). - See https://github.com/007revad/Synology_enable_Deduplication - Changed to be able to edit existing drive entries in the db files to add the firmware version. - Now supports editing db files that don't currently have any drives listed. v1.2.31 - Bug fix. The --noupdate option was coded as --nodbupdate. Now either will work. - Bug fix. Re-enable drive db updates wasn't working in some instances. v1.2.30 - Fixed "download new version" failing if script was run via symlink or ./ v1.2.29 - Bug fix. v1.2.28 had v1.2.27 in the sh file so it always wanted to update! v1.2.28 - Fixed bug in getting the M.2 card model. v1.2.27 - Changed 'latest version check' to download and extract to /tmp then copy only the syno_hdd_db.sh and readme.txt files to the currrently running script's location. - Minor tweaks to the shell output. v1.2.25 - Minor bug fix. v1.2.24 - Bug fix. Ignoring removable drives was ignoring all drives in DSM 7 on a RS2421rp+. Fix issue #23. v1.2.23 - Changed to show if no M.2 cards were found, if M.2 drives were found. v1.2.22 - Changed 'latest version check' to download to /tmp and extract files to the script's location to fix issue #27. v1.2.21 - Reinstated removing brand from start of drive model to fix issue #24. v1.2.20 - Added a timeouts when checking for newer script version in case github is down or slow to fix issue #25. - Fixed change log (v1.2.19 and v1.2.18 were listed as v2.2.19 and v2.2.19). v1.2.19 - Minor change to check new version code. v1.2.18 - Minor shell output formatting fix. v1.2.17 - Added disable support memory compatibility option --ram or -r v1.2.16 - Changed to show the script version, Synology model and DSM version on each run to make it easier to debug any user's issues. v1.2.15 - Now finds your expansion units' model numbers and adds your drives to their db files. - Now adds your M.2 drives to your M.2 PCI card's db files (supports M2Dxx and E10M20-T1 and future models with similar model names). - Improved flags/options checking and added usage help (-h or --help) and version info (-v or --version). - Can now download the latest script version for you (if you have 'user home service' enabled in DSM). - Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf - To (hopefully) prevent losing your SSH created M2 volume when running this script on models that DSM 7.2 Beta does not list as supported for creating M2 volumes. - Added removal of " 00Y" from end of Samsung/Lenovo SSDs to fix issue #13. - Changed Synology NAS model detection to be more reliable (for models that came in different variations and report extra text after model). issue #2 and issue #10 - Changed checking drive_db_test_url setting to be more durable. - Fixed bug where removable drives were being added to the drive database. - Fixed bug where "M.2 volume support already enabled" message appeared when NAS had no M.2 drives. v1.1.14 - Minor bug fix. v1.1.13 - Fixed bug in v1.1.12 "check that M.2 volume support is enabled" v1.1.12 - Added check that M.2 volume support is enabled. v1.1.11 - Added support for M.2 SATA drives. - Can now skip processing M.2 drives by running script with the -m2 flag. - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. - Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. - Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). - Fixed script version check introduced in 1.0.7. v1.1.10 - Now makes DSM recheck disk compatibility so reboot not needed (DSM 7 only). - Fixed DSM 6 bug when DSM 6 used the old db file format. v1.1.9 - Added support for SAS drives. - Now gets HDD/SSD/SAS drive model number with smartctl instead of hdparm. v1.1.8 - Now prevents DSM auto updating the drive database. - Disable "support_disk_compatibility" (that was added in v1.0.6) is now optional. - Run script with -f or -force to disable "support_disk_compatibility". - If run without -f or -force "support_disk_compatibility" is re-enabled. v1.0.7 - Added message if newer script version is available. v1.0.6 - Added 2nd method of disabling disk compatibility to solve issue #1 and #4 for the few people where the original method didn't work. v1.0.5 - Changed to avoid issue #2 v1.0.4 - Now backs up the database file if there is no backup already. v1.0.3 Changed to avoid avoid error messages from previous change to search for sda and sata# drives in DSM 6 and DSM 7. - /dev/sata*: No such file or directory - /dev/sd*: No such file or directory v1.0.2 - Improved formatting when listing found drives. v1.0.1 - Fixed issue where drives weren't detected if: - NAS had been updated from DSM 6 to DSM 7 and still used sda, sdb etc. - Models like the DVA3219 that use sata# even in DSM 6. v1.0.0 - Initial release. ## /LICENSE ``` path="/LICENSE" MIT License Copyright (c) 2023 007revad Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` ## /README.md # Synology HDD db [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/paypalme/007revad) [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/007revad) [![committers.top badge](https://user-badge.committers.top/australia/007revad.svg)](https://user-badge.committers.top/australia/007revad) ### Description Add your SATA or SAS HDDs and SSDs plus SATA and NVMe M.2 drives to your Synology's compatible drive databases, including your Synology M.2 PCIe card and Expansion Unit databases. The script works in DSM 7, including DSM 7.2, and DSM 6. It also has a restore option to undo all the changes made by the script. #### What the script does: * Gets the Synology NAS model and DSM version (so it knows which db files to edit). * Gets a list of the HDD, SSD, SAS and NVMe drives installed in your Synology NAS. * Gets each drive's model number and firmware version. * Backs up the database files if there is no backup already. * Checks if each drive is already in the Synology's compatible-drive database. * Adds any missing drives to the Synology's compatible-drive database. * Optionally prevents DSM auto updating the drive database. * Optionally disable DSM's "support_disk_compatibility". * Optionally disable DSM's "support_memory_compatibility" to prevent non-Synology memory notifications. * Optionally edits max supported memory to match the amount of memory installed, if installed memory is greater than the current max memory setting. * DSM only uses the max memory setting when calculating the reserved RAM area size for SSD caches. * Optionally set write_mostly for your internal HDDs so DSM will normally read from your faster internal SSD(s). * It can automatically set DSM to read from your internal SSDs. * Or you can tell the script which internal drive(s) DSM should read from. * Optionally disables Western Digital Device Analytics (aka WDDA) to prevent DSM showing a [warning for WD drives that are 3 years old](https://arstechnica.com/gadgets/2023/06/clearly-predatory-western-digital-sparks-panic-anger-for-age-shaming-hdds). * DSM 7.2.1 already has WDDA disabled. * Enables M2D20, M2D18, M2D17 and E10M20-T1 if present on Synology NAS that don't officially support them. * Newer NAS models may also need [Synology_enable_M2_card](https://github.com/007revad/Synology_enable_M2_card) * Checks that M.2 volume support is enabled (on models that have M.2 slots or PCIe slots). * Enables creating M.2 storage pools and volumes from within Storage Manager in DSM 7.2 and later **(newer models only?)**. * Including M.2 drives in PCIe adaptor cards like M2D20, M2D18, M2D17 and E10M20-T1 for DSM 7.2 and above **(schedule the script to run boot)**. * Optionally update IronWolf Health Monitor to v2.5.1 to support recent model IronWolf and IronWolf Pro drives. **(NAS with x86_64 CPUs only)**. * Also installs IronWolf Health Management on '22 series and newer models that don't have IronWolf Health Management **(untested)**. * Makes DSM recheck disk compatibility so rebooting is not needed if you don't have M.2 drives (DSM 7 only). * **If you have M.2 drives you may need to reboot.** * Reminds you that you may need to reboot the Synology after running the script. * Checks if there is a newer version of this script and offers to download it for you. * The new version available messages time out so they don't prevent the script running if it is scheduled to run unattended. ### Download the script 1. Download the latest version _Source code (zip)_ from https://github.com/007revad/Synology_HDD_db/releases 2. Save the download zip file to a folder on the Synology. - Do ***NOT*** save the script to a M.2 volume. After a DSM or Storage Manager update the M.2 volume won't be available until after the script has run. 3. Unzip the zip file. Or via SSH as your regular user: ``` cd $HOME wget https://github.com/007revad/Synology_HDD_db/archive/refs/heads/main.zip -O syno_hdd_db.zip 7z x syno_hdd_db.zip cd Synology_HDD_db-main && ls -ali ``` ### Required files The following files from the downloaded zip file must be in the same folder: 1. syno_hdd_db.sh 2. syno_hdd_vendor_ids.txt 3. dtc or the bin folder containing dtc (only required if you have a E10M20-T1, M2D20 or M2D18 in a NAS that does not support them). ### When to run the script You would need to re-run the script after a DSM update. If you have DSM set to auto update the best option is to run the script every time the Synology boots, and the best way to do that is to setup a scheduled task to run the the script at boot-up. **Note:** After you first run the script you may need to reboot the Synology to see the effect of the changes. ### Options when running the script There are optional flags you can use when running the script: ```YAML -s, --showedits Show edits made to _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 and later 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 primarily 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 -I, --ihm Update IronWolf Health Management to 2.5.1 to support recent model IronWolf and IronWolf Pro drives. For NAS with x86_64 CPUs only. Also installs IHM on '22 series and newer models (untested) -h, --help Show this help message -v, --version Show the script version ``` **Notes:** - The -f or --force option is only needed if for some reason your drives still show as unsupported in storage manager. - Only use this option as last resort. - Using this option will prevent data deduplication from being available, and prevent firmware updates on Synology brand drives. - If you have some Synology drives and want to update their firmware run the script **without** --noupdate or -n then do the drive database update from Storage Manager and finally run the script again with your preferred options. ### Scheduling the script in Synology's Task Scheduler See How to schedule a script in Synology Task Scheduler ### Running the script via SSH [How to enable SSH and login to DSM via SSH](https://kb.synology.com/en-global/DSM/tutorial/How_to_login_to_DSM_with_root_permission_via_SSH_Telnet) You run the script in a shell with sudo -s or as root. ```YAML sudo -s /path-to-script/syno_hdd_db.sh -nr ``` **Note:** Replace /path-to-script/ with the actual path to the script on your Synology.

If you run the script with the --showedits flag it will show you the changes it made to the Synology's compatible-drive database. Obviously this is only useful if you run the script in a shell. ```YAML sudo -s /path-to-script/syno_hdd_db.sh -nr --showedits ``` **Note:** Replace /path-to-script/ with the actual path to the script on your Synology.

### Troubleshooting | Issue | Cause | Solution | |-------|-------|----------| | /usr/bin/env: ‘bash\r’: No such file or directory | File has Mac line endings! | [Download latest zip file](https://github.com/007revad/Synology_HDD_db/releases) | | Cursor sits there doing nothing | File has Windows line endings! | [Download latest zip file](https://github.com/007revad/Synology_HDD_db/releases) | | syntax error near unexpected token | You downloaded the webpage! | [Download latest zip file](https://github.com/007revad/Synology_HDD_db/releases) | If you get a "No such file or directory" error check the following: 1. Make sure you downloaded the zip or rar file to a folder on your Synology (not on your computer). 2. Make sure you unpacked the zip or rar file that you downloaded and are trying to run the syno_hdd_db.sh file. 3. If the path to the script contains any spaces you need to enclose the path/scriptname in double quotes: ```YAML sudo -s "/volume1/my scripts/syno_hdd_db.sh -n" ``` 4. Set the script file as executable: ```YAML sudo chmod +x "/volume1/scripts/syno_hdd_db.sh" ``` ### vendor_ids.txt You only need to edit syno_hdd_vendor_ids.txt if the script warns you about a missing vendor id. If DSM doesn't know the brand of your NVMe drives they will show up in Storage Manager as Unknown brand, and Unrecognised firmware version.

In this case the script will show you the vendor ID and advise you to add it to the syno_hdd_vendor_ids.txt file.

### Ironwolf Health Ironwolf Health working with the latest version of Ironwolf Health Monitor.


### Credits - The idea for this script came from a comment made by Empyrealist on the Synology subreddit. - Thanks for the assistance from Alex_of_Chaos on the Synology subreddit. - Thanks to dwabraxus and aferende for help detecting connected expansion units. - Thanks to bartoque on the Synology subreddit for the tip on making the script download the latest release from GitHub. - Thanks to nicolerenee for pointing out the easiest way to enable creating M.2 storage pools and volumes in Storage Manager. - Thanks to Xeroxxx for the writemostly suggestion and their writeup here: https://www.techspark.de/speed-up-synology-dsm-with-hdd-ssd/ ### Donators Thank you to the PayPal and Buy Me a Coffee donators, GitHub sponsors and hardware donators | | | | | |--------------------|--------------------|----------------------|----------------------| | Pat A Phillips | Craikeybaby | Jason DeCorte | Salovaara Antti Sakari | | Jérôme MORIN | Sven Bauer | Fabien Vallet | Fabio Petgola | | lonestar6262 | Netchoice | Fabio Cecchinato | Jacek | | Dugan Audio LLC | MikeSx | Toregev | M. Verhoef | | Philipp Ehmeier | Adrian Playle | Daniel Meda | Richard Wilhelm | | Mika255 | Ralf Edelwein | Martin | Alexander Habisreitinger | | jrn | Marcus Wojtusik | Will (war59312) | Christopher Maglio | | Flow | Jake Morrison | tsnyder | zhangchi198 | | leadadri | Gary Plumbridge | frogger1805 | ctrlaltdelete | | CannotTouch | Kevin Staude | Alistair Hathaway | 8347 | | BrattishPlaque | Chris Bunnell | dansimau | Bsih | | Tim Trace | Michel VIEUX-PERNON | R De Jong | Rick | | Klaus-Dieter Fahlbusch | Amarand Agasi | someone61986 | Alexander Machatschek | | Yeong​Nuno | Joe | Torben Schreiter | Anthony McMurray | | Abhishek | Steven Haskell | Malte Müller | Aaron Thomas | | DENNIS BRAZIL | kunvanimals | Arnaud Costermans | dealchecker | | Michael Carras | Alan | speedyyyyyy | Jordi Chavarria Fibla | | Qwerty.xyz | Max | Mark Rohde | Someone | | vaadmin | Sebastiaan Mulder | Nico Stark | Oleksandr Antonishak | | Marcel Siemienowski | Dave Smart | dweagle79 | lingyinsam | | Vojtech Filkorn | Craig Sadler | Po-Chia Chen | Jean-François Fruhauf | | Sven 'ctraltdelete' | Thomas Horn | Christian | Simon Azzouni | | Lee Booy | Bünyamin Olgun | Hartmut Heinbach | Alexander Gundermann | | Björn Schöninger | Nico Scherer | Patrick Hoekstra | Alex Joyce | | Marcus Ackermann | Lorenz Schmid | enil-kil | Xaver Zöllner | | Jan Bublitz | Darren O'Connor | Charles Young | J Davis | | Jürg Baiker | Joshua Gillispie | bizIT Hirschberg | Jordan Crawford | | Tyler Teal | Voluntary Commerce LLC | Ez Hosting | Alec Wilhere | | Reece Lyne | Enric Escudé Santana | Yunhao Zhang | Matthias Gerhardt | | Darryl Harper | Mikescher | Matthias Pfaff | cpharada | | Neil Tapp | zen1605 | Kleissner Investments | Angel Scandinavia | | B Collins | Peter jackson | Mir Hekmat | Andrew Tapp | | Peter Weißflog | Joseph Skup | Dirk Kurfuerst | Gareth Locke | | Rory de Ruijter | Nathan O'Farrell | Harry Bos | Mark-Philipp Wolfger | | Filip Kraus | John Pham | Alejandro Bribian Rix | Daniel Hofer | | Bogdan-Stefan Rotariu | Kevin Boatswain | anschluss-org | Yemeth | | Patrick Thomas | Manuel Marquez Corral | Evrard Franck | Chad Palmer | | 侯​永政 | CHEN​HAN-YING | Eric Wells | Massimiliano Pesce | | JasonEMartin | Gerrit Klussmann | Alain Aube | Robert Kraut | | Charles-Edouard Poisnel | Oliver Busch | anonymous donors | private sponsors | ## /bin/dhm_tool Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/bin/dhm_tool ## /bin/dhm_tool.txt stx_ihm from QNAP firmware, renamed dhm_tool for Synology DSM SeaDragon_DHMr - Seagate drive utilities Copyright (c) 2017-2021 Seagate Technology LLC and/or its Affiliates, All Rights Reserved SeaDragon_DHMr Version: 2.5.1-2_2_3 X86_64 Build Date: Oct 3 2022 MD5 cf67c1d5006913297f85ca7f9d1795ba SHA-1 163b384afabc491c97f3aa4ee7916601a9a680dd SHA-256 86dd0e3c5ded507d23dfeb2ca04a2e086c97a86e2ab96dc6fdeab686a8202795 SHA-384 3d806909d445605787ceb155bc1555e01d02efe324378c9c71e6b53d91bba6bf8dbadef38dd882b43caf8dbd93eaff6c SHA-512 a2d87d91fd4cc298708946c9a611027dce290ba17a48c65e712b5d7e72ba04c6b5303c90efeb178a8fc690241b405691a15cc88200ab3b28319198df6bd6ad16 ## /bin/dtc Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/bin/dtc ## /bin/dtc_info.txt MD5 01381dabbe86e13a2f4a8017b5552918 SHA-1 f24a4c06b4865a5948eddc2f43fcdb7700398c7d SHA-256 14f7f87a5822050eab7c30a064912a6efe99f49bf6b896bbb38c2ba003803e78 Vhash 4885c57da971db5c59998566ee02855f SSDEEP 1536:ZJ048w/2Iaosz0SlWcCyeyudm5gupvatDVF4Utc3Lyk+pboAZ4NMMy6MajiRTrbc:0hfosz0j0ehm57vaTDc3Lmo/iRTrM4q TLSH T13EE33D02F3648C7DD4F85B34469A82B7A7B4F8455232171F7B4097192F86F688F2A9E3 https://www.virustotal.com/gui/file/14f7f87a5822050eab7c30a064912a6efe99f49bf6b896bbb38c2ba003803e78/detection ## /bin/dtc_source.txt dtc-1.6.1 source code - Author David Gibson https://git.kernel.org/pub/scm/utils/dtc/dtc.git ## /how_to_schedule.md # How to schedule a script in Synology Task Scheduler To schedule a script to run on your Synology at boot-up or shut-down follow these steps: **Note:** You can setup a schedule task and leave it disabled, so it only runs when you select the task in the Task Scheduler and click on the Run button. 1. Go to **Control Panel** > **Task Scheduler** > click **Create** > and select **Triggered Task**. 2. Select **User-defined script**. 3. Enter a task name. 4. Select **root** as the user (The script needs to run as root). 5. Select **Boot-up** as the event that triggers the task. 6. Leave **Enable** ticked. 7. Click **Task Settings**. 8. Optionally you can tick **Send run details by email** and **Send run details only when the script terminates abnormally** then enter your email address. 9. In the box under **User-defined script** type the path to the script. - e.g. If you saved the script to a shared folder on volume1 called "scripts" you'd type: - **/volume1/scripts/syno_hdd_db.sh -nr --autoupdate=3** - For information on the options see [Options](README.md#options) 11. Click **OK** to save the settings. Here's some screenshots showing what needs to be set:

## /images/how_to_download.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/how_to_download.png ## /images/ihm.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/ihm.png ## /images/ram_warning.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/ram_warning.png ## /images/schedule1.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/schedule1.png ## /images/schedule2.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/schedule2.png ## /images/schedule3-2.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/schedule3-2.png ## /images/schedule3.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/schedule3.png ## /images/syno_hdd_db.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/syno_hdd_db.png ## /images/syno_hdd_db1.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/syno_hdd_db1.png ## /images/syno_hdd_db2.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/syno_hdd_db2.png ## /images/syno_hdd_db_help.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/syno_hdd_db_help.png ## /images/syno_hdd_db_help2.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/syno_hdd_db_help2.png ## /images/unknown.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/unknown.png ## /images/update-now-disabled.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/update-now-disabled.png ## /images/update-now-working.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/update-now-working.png ## /images/vendor_ids.png Binary file available at https://raw.githubusercontent.com/007revad/Synology_HDD_db/refs/heads/main/images/vendor_ids.png ## /my-other-scripts.md ## All my scripts #### Contents - [Plex](#plex) - [Synology docker](#synology-docker) - [Synology recovery](#synology-recovery) - [Other Synology scripts](#other-synology-scripts) - [Synology hardware restrictions](#synology-hardware-restrictions) - [How To Guides](#how-to-guides) - [Synology dev](#synology-dev) ## ### Plex - **Synology_Plex_Backup** - A script to backup Plex to a tgz file foror DSM 7 and DSM 6. - Works for Plex Synology package and Plex in docker. - **Asustor_Plex_Backup** - Backup your Asustor's Plex Media Server settings and database. - **Linux_Plex_Backup** - Backup your Linux Plex Media Server's settings and database. - **Plex_Server_Sync** - Sync your main Plex server database & metadata to a backup Plex server. - Works for Synology, Asustor, Linux and supports Plex package or Plex in docker.               [Back to Contents](#contents) ### Synology docker - **Synology_Docker_export** - Export all Synology Container Manager or Docker containers' settings as json files to your docker shared folder. - **Synology_ContainerManager_IPv6** - Enable IPv6 for Container Manager's bridge network. - **ContainerManager_for_all_armv8** - Script to install Container Manager on a RS819, DS119j, DS418, DS418j, DS218, DS218play or DS118. - **Docker_Autocompose** - Create .yml files from your docker existing containers. - **Synology_docker_cleanup** - Remove orphan docker btrfs subvolumes and images in Synology DSM 7 and DSM 6.               [Back to Contents](#contents) ### Synology recovery - **Synology_DSM_reinstall** - Easily re-install the same DSM version without losing any data or settings. - **Synology_Recover_Data** - A script to make it easy to recover your data from your Synology's drives using a computer. - **Synology clear drive error** - Clear drive critical errors so DSM will let you use the drive. - **Synology_DSM_Telnet_Password** - Synology DSM Recovery Telnet Password of the Day generator. - **Syno_DSM_Extractor_GUI** - Windows GUI for extracting Synology DSM 7 pat files and spk package files.               [Back to Contents](#contents) ### Other Synology scripts - **Synology_app_mover** - Easily move Synology packages from one volume to another volume. - **Video_Station_for_DSM_722** - Script to install Video Station in DSM 7.2.2 - **SS_Motion_Detection** - Installs previous Surveillance Station and Advanced Media Extensions versions so motion detection and HEVC are supported. - **Synology_Config_Backup** - Backup and export your Synology DSM configuration. - **Synology_CPU_temperature** - Get and log Synology NAS CPU temperature via SSH. - **Synology_SMART_info** - Show Synology smart test progress or smart health and attributes. - **Synology_Cleanup_Coredumps** - Cleanup memory core dumps from crashed processes. - **Synology_toggle_reset_button** - Script to disable or enable the reset button and show current setting. - **Synology_Download_Station_Chrome_Extension** - Download Station Chrome Extension. - **Seagate_lowCurrentSpinup** - This script avoids the need to buy and install a higher wattage power supply when using multiple large Seagate SATA HDDs.               [Back to Contents](#contents) ### Synology hardware restrictions - **Synology_HDD_db** - Add your SATA or SAS HDDs and SSDs plus SATA and NVMe M.2 drives to your Synology's compatible drive databases, including your Synology M.2 PCIe card and Expansion Unit databases. - **Synology_enable_M2_volume** - Enable creating volumes with non-Synology M.2 drives. - Enable Health Info for non-Synology NVMe drives (not in DSM 7.2.1 or later). - **Synology_M2_volume** - Easily create an M.2 volume on Synology NAS. - **Synology_enable_M2_card** - Enable Synology M.2 PCIe cards in Synology NAS that don't officially support them. - **Synology_enable_eunit** - Enable an unsupported Synology eSATA Expansion Unit models. - **Synology_enable_Deduplication** - Enable deduplication with non-Synology SSDs and unsupported NAS models. - **Synology_SHR_switch** - Easily switch between SHR and RAID Groups, or enable RAID F1. - **Synology_enable_sequential_IO** - Enables sequential I/O for your SSD caches, like DSM 6 had. - **Synology_Information_Wiki** - Information about Synology hardware.               [Back to Contents](#contents) ### How To Guides - **Synology_SSH_key_setup** - How to setup SSH key authentication for your Synology.               [Back to Contents](#contents) ### Synology dev - **Download_Synology_Archive** - Download all or part of the Synology archive. - **Syno_DSM_Extractor_GUI** - Windows GUI for extracting Synology DSM 7 pat files and spk package files. - **ScriptNotify** - DSM 7 package to allow your scripts to send DSM notifications. - **DTC_GUI_for_Windows** - GUI for DTC.exe for Windows.               [Back to Contents](#contents) ## /syno_hdd_db.sh ```sh path="/syno_hdd_db.sh" #!/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.6.111" 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 <_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 and later 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 primarily 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 -I, --ihm Update IronWolf Health Management to 2.5.1 to support recent model IronWolf and IronWolf Pro drives. For NAS with x86_64 CPUs only Installs IHM on '22 series and newer models (untested) -h, --help Show this help message -v, --version Show the script version EOF exit 0 } scriptversion(){ cat <0; i--)) do printf -v f "%s%s()" "$f" "${FUNCNAME[i]}" done printf "$y%s:%04d$c%s$n " "${BASH_SOURCE[1]##*/}" "$lineno" "$f" } if [[ $debug == "yes" ]]; then PS4='\r$(PS4func $LINENO)' set -o xtrace 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" # Get CPU platform_name #platform_name=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/synoinfo.conf platform_name) # Get CPU arch arch="$(uname -m)" # 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 $arch 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 get_script_vol() { local script_root vol_num vg_name script_root="${scriptpath#/*}" script_root="${script_root%%/*}" if [[ $script_root =~ ^volume ]] then vol_num="${script_root:6}" vg_name=$(lvs --noheadings --select=lv_name="volume_$vol_num" --options=vg_name) vg_name="${vg_name// }" vol_name=$(pvs --noheadings --select=vg_name="$vg_name" --options=pv_name) vol_name="${vol_name// }" else vol_name=$(df --output=source "/$script_root" |sed 1d) fi } get_script_vol # sets $vol_name to /dev/whatever if grep -qE "^${vol_name#/dev/} .+ nvme" /proc/mdstat 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/ 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 42962 ]]; then # DSM 7.1.1 to 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 42962 ]]; then # DSM 7.1.1 to 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 " 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 # Chinese brand? hdmodel=${hdmodel#"HCST "} # Remove "HCST " from start of model name. Issue #389 # 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")" 2>/dev/null | 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 firmware version with smartctl if $fwrev null # for M.2 SATA SSD and SAS drives. Github issue #407 if [[ -z $fwrev ]]; then dev=/dev/"$(basename -- "$1")" fwrev=$(smartctl -a -d ata -T permissive "$dev" | grep -i firmware | awk '{print $NF}') fi # Get drive GB size size_gb=$(get_size_gb "$1") if [[ -n "$size_gb" ]]; then # PR #187 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 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 ebox_conected=$(synodisk --enum -t ebox) if [[ $ebox_conected ]]; then # Only device tree models have syno_slot_mapping # eSATA and InfiniBand ports both appear in syno_slot_mapping as: # Esata port count: 1 # Eunit port 1 - RX1214 if which syno_slot_mapping >/dev/null; then # syno_slot_mapping does not find SAS eunits eunitlist=($(syno_slot_mapping | grep 'Eunit port' | awk '{print $5}')) fi if [[ ${#eunitlist[@]} -eq "0" ]]; then # 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 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" <> "$2" <; }; 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" <; }; }; 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}" < # 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 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" # Junior boot #[ -d /tmpRoot ] && /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1" if [ -f /tmpRoot/usr/syno/bin/synosetkeyvalue ] && [ -f /tmpRoot/etc.defaults/synoinfo.conf ]; then /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1" fi disabled="yes" elif [[ $url != "127.0.0.1" ]]; then # Edit drive_db_test_url= /usr/syno/bin/synosetkeyvalue "$synoinfo" "$dtu" "127.0.0.1" # Junior boot #[ -d /tmpRoot ] && /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1" if [ -f /tmpRoot/usr/syno/bin/synosetkeyvalue ] && [ -f /tmpRoot/etc.defaults/synoinfo.conf ]; then /tmpRoot/usr/syno/bin/synosetkeyvalue /tmpRoot/etc.defaults/synoinfo.conf "$dtu" "127.0.0.1" fi 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.1.1 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 42962 ]]; then # DSM 7.1.1 to 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 install_binfile dhm_tool "$file_url" /usr/syno/sbin/dhm_tool "755" bin/dhm_tool "$md5hash" else # Check if dhm_tool needs updating dhm_version="$(dhm_tool --version | grep "Utility Version" | awk '{print $NF}')" if ! printf "%s\n%s\n" "2.5.1" "$dhm_version" | sort --check=quiet --version-sort >/dev/null ; then # Backup existing dhm_tool backupdb "/usr/syno/sbin/dhm_tool" # Update dhm_tool md5hash="cf67c1d5006913297f85ca7f9d1795ba" branch="main" file_url="https://raw.githubusercontent.com/${repo}/${branch}/bin/dhm_tool" # install_binfile install_binfile dhm_tool "$file_url" /usr/syno/sbin/dhm_tool "755" bin/dhm_tool "$md5hash" # Check dhm_tool updated dhm_version="$(dhm_tool --version | grep "Utility Version" | awk '{print $NF}')" if [[ $dhm_version == "2.5.1" ]]; then echo "Updated IronWolf Health Management." else echo "${Error}ERROR${Off} Failed to update IronWolf Health Management!" fi else echo "IronWolf Health Management already updated." fi 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 ``` ## /syno_hdd_vendor_ids.txt # You can add your drive's vendor id and vendor name here. # # Only edit this file if the script warns you about a missing vendor id. 0x025e="Solidigm" 0x05dc="Lexar" 0x0ed1="aigo" 0x10ec="TEAMGROUP" 0x137e="Patriot" 0x1458="Gigabyte" 0x1462="MSI" 0x196e="PNY" 0x1987="Phison" 0x1b1c="Corsair" 0x1bdc="Apacer" 0x1c5c="SK Hynix" 0x1cc4="UMIS" 0x1cfa="Corsair" 0x1d79="Transcend" 0x1dbe="ADATA" 0x1e0f="KIOXIA" 0x1e49="ZHITAI" 0x1e4b="FIKWOT" 0x1f40="Netac" The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.