├── .github └── FUNDING.yml ├── CHANGES.txt ├── LICENSE ├── README.md ├── images ├── app.png ├── app2.png ├── app3.png ├── app4.png ├── app5.png ├── app6.png ├── auto_option.png ├── backup.png ├── docker.png ├── help_option.png ├── how_to_download_generic.png ├── icons │ ├── -Copyright_info.txt │ ├── ActiveBackup-GSuite_64.png │ ├── ActiveBackup-Office365_64.png │ ├── ActiveBackup_business_64.png │ ├── ActiveInsight_64.png │ ├── AntiVirus-McAfee_64.png │ ├── ArchiwareP5_64.png │ ├── AudioStation_64.png │ ├── Authenticator_64.png │ ├── AvrCenter_64.png │ ├── AvrLogger_64.png │ ├── BitDefenderForMailPlus_64.png │ ├── C2IdentityLDAPAgent_64.png │ ├── CMS_64.png │ ├── Calendar_64.png │ ├── ChannelsDVR_64.png │ ├── Chat_64.png │ ├── CloudSync_64.png │ ├── CodecPack_64.png │ ├── Contacts_64.png │ ├── ContainerManager_64.png │ ├── DNSServer_64.png │ ├── DdbBackup_64.png │ ├── DirectoryServerForWindowsDomain_64.png │ ├── DirectoryServer_64.png │ ├── DocumentViewer_64.png │ ├── EmbyServer_64.png │ ├── FileStation_64.png │ ├── Git_64.png │ ├── GlacierBackup_64.png │ ├── GoodSync_64.png │ ├── HybridShare_64.png │ ├── HyperBackupVault_64.png │ ├── HyperBackup_64.png │ ├── Joomla_64.png │ ├── KodExplorer_64.png │ ├── LogAnalysis_64.png │ ├── MEGAcmd_64.png │ ├── MailClient_64.png │ ├── MailPlus-Server_64.png │ ├── MailServer_64.png │ ├── MailStation_64.png │ ├── MariaDB10_64.png │ ├── MediaServer_64.png │ ├── MediaWiki_72.png │ ├── MinimServer_64.png │ ├── Mosquitto_64.png │ ├── NBR-Transporter_64.png │ ├── NBR_64.png │ ├── Node.js_cropped.png │ ├── NoteStation_64.png │ ├── PACS_64.png │ ├── PDFViewer_64.png │ ├── PHP_64.png │ ├── Perl_64.png │ ├── PhotoStation_64.png │ ├── PrestoServer_64.png │ ├── ProxyServer_64.png │ ├── Python_64.png │ ├── RadiusServer_64.png │ ├── RagicBuilder_64.png │ ├── SANManager_64.png │ ├── SSOServer_64.png │ ├── SnapshotReplication_64.png │ ├── Sonarr_64.png │ ├── Sony_BraviaSignage_64.png │ ├── Spreadsheet_64.png │ ├── StorageAnalyzer_64.png │ ├── SurveillanceStation_64.png │ ├── SynoFinder_64.png │ ├── SynoSmisProvider_64.png │ ├── SynologyApplicationService_64.png │ ├── SynologyDrive_64.png │ ├── Tailscale_64.png │ ├── TeamViewer_64.png │ ├── TextEditor_64.png │ ├── USBCopy_64.png │ ├── UniversalSearch_64.png │ ├── UniversalViewer_64.png │ ├── VPNCenter_64.png │ ├── VideoStation_64.png │ ├── VirtualHere_64.png │ ├── VirtualManagement_64.png │ ├── WebDAVServer_64.png │ ├── WebStation_64.png │ ├── WebTools-48.png │ ├── Wordpress_64.png │ ├── anti_virus_64.png │ ├── apache_64.png │ ├── bb-qq_64.png │ ├── diagnosis_64.png │ ├── docker_64.png │ ├── domotz_64.png │ ├── download_station_64.png │ ├── elephantdrive_64.png │ ├── exFAT-Free_72.png │ ├── ffmpeg_72.png │ ├── gateone-64.png │ ├── iDrive_72.png │ ├── jackett-64.png │ ├── jellyfin-64.png │ ├── log_center_64.png │ ├── mediainfo-64.png │ ├── medusa-64.png │ ├── mono_64.png │ ├── photos_64.png │ ├── phpMyAdmin_72.png │ ├── plexmediaserver_48.png │ ├── radarr-64.png │ ├── resiliosync-48.png │ ├── shellinabox-48.png │ ├── storage_manager_64.png │ ├── syncthing-64.png │ ├── synocli_72.png │ ├── transmission-64.png │ ├── tvheadend-64.png │ └── vtigerCRM_64.png ├── list_option.png ├── move_shared_folder.png ├── pkg_center_64_blurr.png ├── thumbnail.png └── updated_list.png ├── moving_extras.md ├── my-other-scripts.md ├── syno_app_mover.conf └── syno_app_mover.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: 007revad 2 | buy_me_a_coffee: 007revad 3 | custom: ["https://www.paypal.me/007revad"] 4 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | v4.2.89 2 | - Bug fix for Container Manager. Skip syslog-ng.ctl 0 byte file. Issue #186 3 | 4 | v4.2.88 5 | - Bug fix for Antivirus Essential. Now also processes @quarantine (and .quarantine if it exists). Issue #182 6 | 7 | v4.2.87 8 | - Bug fix for moving jellyfin. Issue #171 9 | 10 | v4.2.86 11 | - Now prunes dangling and unused docker images before checking the required space. 12 | - Bug fix for "prune_dangling: command not found”. #167 13 | 14 | v4.2.84 15 | - Bug fix for script stopping when trying to move extra `@folders` if they don't exist. Issue #164 16 | 17 | v4.2.83 18 | - Changed to only skip backup or restore if a backup or restore was done in the last "skip_minutes" and "All" is selected. Issue #158 19 | - Bug fix for restoring from a USB backup. Issue #158 20 | - Bug fix for wrong error message when restoring from USB drive and `@folder`is missing. Issue #158 21 | - Bug fix for logfile missing the scriptname. 22 | - Bug fix for some models returning extra characters after their model name. 23 | 24 | v4.2.82 25 | - Added information on the --auto=all option to --help and the readme. 26 | 27 | v4.2.81 28 | - Bug fix for checking if pgsql service started okay (introduced in v4.2.80). Issue #153 29 | 30 | v4.2.80 31 | - Bug fix for starting and stopping pgsql service in DSM 6. Issue #151 #150 32 | 33 | v4.2.78 34 | - Changed timeout for starting and stopping apps from 5 minutes to 30 minutes. Issue #140 35 | - Container Manager with lots of containers takes longer than 5 minutes to stop or start. 36 | - Changed to only use the timeout when there is more than 1 app to backup or restore. Issue #140 37 | - Bug fix for 'bad array subscript' when app is missing it's INFO file. Issue #138 38 | - Bug fix for checking free space on USB drives. Issue #138 39 | - Bug fix for log filename starting with "scriptname" instead of "syno_app_mover". 40 | 41 | v4.2.75 42 | - Added `@database` as an app that can be moved. 43 | - Only needed if moving all apps to a different volume so you can delete the old volume. 44 | 45 | v4.1.74 46 | - Added logging (syno_app_mover_YY-mm-dd_H-M.log saved in same folder as syno_app_mover.sh). 47 | - Added USB Copy as a movable app to show how to move USB Copy's database (in move mode only). 48 | - Changed to not refuse to move Container Manager or Docker to different file system. 49 | - Now warns that you'll need to migrate the containers, and some may fail to migrate. 50 | 51 | v4.0.73 52 | - Can now be scheduled in Task Scheduler to backup a package or multiple packages. Issue #105 53 | - Run the script with the -h or --help option to see how. 54 | - Added exclude option in syno_app_mover.conf so you can exclude specified apps when "all" mode is selected. 55 | - Updated instructions in conf file. 56 | - Added -h, --help option. 57 | - Added --autoupdate=AGE option to auto update the script (useful when script is scheduled) 58 | - AGE is how many days old a release must be before auto-updating. AGE must be a number: 0 or greater 59 | - Added --list option to show installed app's system names (names needed for scheduling backups). 60 | - Also shows if there are any broken packages (broken 'target' symlink or missing volume). 61 | - Now checks the size of selected app(s) and the free space on target volume. 62 | - Changed to use rsync instead of cp for backups to make backing up the same package again faster. 63 | - Now exports Container Manager/Docker container's settings to the docker shared folder. Thanks ctrlaltdelete 64 | - e.g. /volume1/docker/app_mover_exports 65 | - Includes new delete_older and ignored_containers options in syno_app_mover.conf 66 | - Changed to prevent moving, backing up or restoring Container Manager or Docker between different file systems. 67 | - Now deletes unused and dangling docker images before restoring. 68 | - Now deletes dangling docker images before moving or backing up. 69 | - Changed to work if PATH contains /opt/bin;/opt/sbin; with incompatible binaries. Issue #125 70 | - e.g. If Entware is installed (which installs busybox). 71 | - Changed to allow "moving" or backing up apps when volume is read only. Issue #122 72 | - If source volume is read only: 73 | - Copies apps to target volume instead of trying to move them, when move selected. 74 | - Skips exporting container settings, as Docker or Container Manager cannot be started when volume is read only. 75 | - Skips removing docker dangling and unused images. 76 | - Bug fix for moving Synology Drive. Issue #126 77 | - Bug fix for packages with spaces in their name (DSM 6 Plex Media Server). 78 | - Bug fix for bad array subscript when a broken package exists. Issue #117 79 | 80 | v3.1.60 81 | - Now warns processing could take a long time if the folder is larger than 1GB. 82 | - Previously warned only for `@docker` and `@download` and regardless of folder size. 83 | 84 | v3.0.59 85 | - Added check that USB partition is ext3, ext4 or btrfs when backup is selected and target is a USB drive. 86 | 87 | v3.0.58 88 | - Added info and progress after stopping and starting packages. 89 | - On a slow NAS the script could appear to have frozen for up to 20 seconds. 90 | 91 | v3.0.56 92 | - Bug fix DSM 6 getting @docker or @download folder size. Issue #88 93 | 94 | v3.0.55 95 | - Bug fix for `synoshare: unrecognized option '--get-real-path'` error in DSM 7.2. Issue #76 96 | 97 | v3.0.54 98 | - Bug fix for `synoshare: unrecognized option '--get-real-path'` error in DSM 7.0 and 7.1. Issue #76 99 | 100 | v3.0.53 101 | - Bug fix for checking target volume free space when there's a symlink on the volume. Issue #72 102 | - e.g. A symlink pointing to folder on same volume, another volume, another device or visible snapshots. 103 | 104 | v3.0.52 105 | - Bug fix for DSM 6 where some packages have an extra symlink that needs editing: 106 | - chromaprint, ffmpeg, git, jackett, mediainfo, mono, python310, syncthing, synocli-misc and transmission 107 | 108 | v3.0.51 109 | - Bug fix for checking free space on USB drives. Issue #63 110 | 111 | v3.0.50 112 | - Bug fix for Hyper backup where moving `@img_bkp_cache` could cause an error. Issue #54 113 | - Bug fix Container Manager and Docker where moving `@docker` could cause an error. Issues #34 #38 #46 114 | - Changed to not exit on error moving app's `@folders`. 115 | - Changed from hardcoded 50GB buffer to user configurable buffer (used when checking if there's enough space to move folder). 116 | - Bug fix for message showing `@download` if not enough space on target volume to move `@docker`. 117 | 118 | v3.0.49 119 | - Bug fix for Synology Drive still using `@synologydrive` on the original volume. Issue #55 120 | - Now deletes `@eaDir` folders to try to prevent `mv: cannot remove '/volume#/@': Operation not permitted`. Issue #54 121 | 122 | v3.0.47 123 | - Added instructions on how to move photo shared folder if it exists. 124 | 125 | v3.0.46 126 | - DSM 6 to 7.1.1 bug fix where script incorrectly showed package failed to stop error. Issue #44 127 | - DSM 6 to 7.1.1 bug fix for not detecting when package was not installed (for Restore mode). 128 | 129 | v3.0.45 130 | - Added backup and restore modes. 131 | - Includes syno_app_mover.conf file to set the backup location. 132 | - Skips packages that are development tools with no data: Node.js, Perl, PHP, python3, SynoCli etc. 133 | - Restore mode warns if installed package version does not match backup package version. 134 | - DSM 6 backup and restore still WIP. 135 | - When backup or restore selected asks if you want to backup or restore all packages. 136 | - Added skip restore or backup if last restore or backup was less than n minutes ago. 137 | - Set skip_minutes in syno_app_mover.conf 138 | - Suggests changing volume location in app's settings for each app with volume settings. 139 | - Shows how to move shared folder for each app with a shared folder. 140 | - Changed so that cursor does not cover first letter when progress bar is showing. 141 | - Now shows package's display name. 142 | - Now shows how long the script took. 143 | - Now automatically selects the target volume if there are only 2 volumes. 144 | - Now only starts package if the script stopped it. 145 | - Added 5 minute timeout to stopping, and starting, packages. 146 | - Added warning that moving `@docker` and `@download` can take a long time. 147 | - Now checks if there's enough space to move `@docker` 148 | - Now checks if there's enough space to move `@download` 149 | - Now asks if you want to backup `@download` 150 | - Added reminder to edit docker volume settings if user moved shared folders that docker uses. 151 | - Added how to export/import database for packages that use MariaDB. 152 | - Now checks package status after uninstalling or installing package. 153 | - Now confirms that folder was created when creating a folder. 154 | - Now copies files/folders with same permissions when copying `@docker` to `@docker_backup`. 155 | - Changed package selection to avoid invalid key presses. 156 | - Added line number to error messages for easier debugging. 157 | - Bug fix for moving Calendar. Issue #39 158 | 159 | v2.0.7 160 | - Bug fix for cannot stat '/volume1/@SynologyDrive': No such file or directory. 161 | 162 | v2.0.6 163 | - Confirmed working for 73 packages. 164 | - Updated to work correctly with the following packages that have extra folders or symlinks: 165 | - Active Backup for Business, Active Backup for Google Workspace, Active Backup for Microsoft 365, 166 | Synology Chat Server, Container Manager, Glacier Backup, MailPlus Server, Mail Server, Node.js, 167 | Presto File Server, Surveillance Station, Synology Application Service, Synology Drive, WebDAV Server, 168 | Virtual Machine Manager. 169 | - Moving Container Manager now includes your images and containers. 170 | - It also asks if you want to backup the `@docker` folder (just in case). 171 | - Added a progress bar so you know the script is still working on long running processes. 172 | - Now shows the current volume for each package. Issue #12 Thanks woozu-shin 173 | - Now stops dependant packages when moving a package with dependencies. 174 | - Then later starts the dependant packages that the script stopped. 175 | - Now asks if you want to start the package (in case you want to move it's shared folder first). 176 | - Now instructs how to move packages' shared folder(s) for the following packages: 177 | - Active Backup for Business, Audio Station, Synology Chat Server, Cloud Sync, Synology MailPlus Server, 178 | MinimServer, Plex Media Server, Surveillance Station and Video Station. 179 | - Now instructs how to change the packages' database location for the following packages: 180 | - Cloud Sync, Download Station, Note Station, Synology Drive and Virtual Machine Manager. 181 | - Now if package is ContainerManager or Docker: 182 | - Offers to backup `@docker`. 183 | - Moves `@docker` if there's enough space on the target volume. 184 | - Instructs how to move your docker shared folder. 185 | - Now gets the permissions of the original folder to set on the new target folder. 186 | - Now checks if there's a new version of the script and asks if you want the script to update itself. 187 | - Fixed bug which allowed typing an invalid package selection. 188 | - Fixed bug which allowed typing an invalid volume selection. 189 | 190 | v1.0.4 191 | - Fix bug for handling only two volumes in NAS. 192 | 193 | v1.0.3 194 | - Bug fix for moving PlexMediaServer package also tried to move Bug fix for PlexMediaServer shared folder. 195 | 196 | v1.0.2 197 | - Renamed to syno_app_mover. 198 | 199 | v1.0.1 200 | - Initial release. 201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Dave Russell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Synology app mover 2 | 3 | 4 | 5 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/paypalme/007revad) 6 | [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/007revad) 7 | [![committers.top badge](https://user-badge.committers.top/australia/007revad.svg)](https://user-badge.committers.top/australia/007revad) 8 | 9 | ### Description 10 | 11 | Easily move Synology packages from one volume to another volume 12 | 13 | You just select the package and the destination volume and the script will stop the app, move it, update the symlinks then start the app. 14 | 15 | Handy for moving packages to an SSD volume, or to another volume so you can delete the original volume. 16 | 17 | **Now** includes [Backup and Restore modes](/images/backup.png). 18 | 19 | - Supports DSM 7. Not fully tested with DSM 6. 20 | - If backing up to a USB drive the partition's file system should be ext3, ext4 of btrfs. 21 | 22 | ### Packages confirmed working 23 | 24 | **NOTE:** Just in case, you should backup your docker compose files or portainer stacks. 25 | 26 |
27 | Click here to see list 28 | 29 | 30 | 31 | The icons in this table are [Copyright © 2004-2024 Synology Inc.](https://kb.synology.com/en-br/DSM/help/DSM/Home/about?version=7) or Copyright the 3rd party package developer. 32 | 33 | | Package Center Name | System Name | Result | 34 | |---------------------|-------------|--------| 35 | | Active Backup for Business | ActiveBackup | OK | 36 | | Active Backup for Google Workspace | ActiveBackup-GSuite | OK | 37 | | Active Backup for Microsoft 365 | ActiveBackup-Office365 | OK | 38 | | Advanced Media Extensions | CodecPack | OK | 39 | | AntiVirus by McAfee | AntiVirus-McAfee | OK | 40 | | AntiVirus Essential | AntiVirus | OK - [Use v4.2.88 or later](https://github.com/007revad/Synology_app_mover/releases) | 41 | | Apache HTTP Server 2.4 | Apache2.4 | OK | 42 | | AQC111 driver | aqc111 | OK - 3rd party package [link](https://github.com/bb-qq/aqc111) | 43 | | Audio Station | AudioStation | OK | 44 | | AvrLogger | AvrLogger | OK - community package [link](https://luenepiet.de/public/Synology/AvrLogger%20(SPK)/) | 45 | | Bitdefender for MailPlus | BitDefenderForMailPlus | OK I think | 46 | | C2 Identity LDAP Server | C2IdentityLDAPAgent | OK | 47 | | Central Management System | CMS | OK | 48 | | Channels DVR | ChannelsDVR | OK - 3rd party package [link](https://getchannels.com/dvr-server/#synology) | 49 | | Cloud Sync | CloudSync | OK | 50 | | Container Manager 24.0.2 | ContainerManager | ? | 51 | | Container Manager 20.10.23 | ContainerManager | OK | 52 | | DNS Server | DNSServer | OK | 53 | | Docker | Docker | OK | 54 | | Document Viewer | DocumentViewer | OK | 55 | | Download Station | DownloadStation | OK | 56 | | Emby Server | EmbyServer | OK | 57 | | exFAT Access | exFAT-Free | OK | 58 | | FFmpeg | ffmpeg# | OK - community package | 59 | | Git | git | OK - community package | 60 | | Git Server | Git | OK | 61 | | Glacier Backup | GlacierBackup | OK - Need to run backup task again | 62 | | Hyper Backup | HyperBackup | OK | 63 | | Hyper Backup Vault | HyperBackupVault | OK | 64 | | Jellyfin | jellyfin | OK | 65 | | LDAP Server | DirectoryServer | OK | 66 | | LogAnalysis | LogAnalysis | OK - community package [link](https://github.com/toafez/LogAnalysis) | 67 | | Log Center | LogCenter | OK | 68 | | Mail Station | MailStation | OK | 69 | | MariaDB 10 | MariaDB10 | OK | 70 | | Media Server | MediaServer | OK | 71 | | MediaInfo | mediainfo | OK - community package | 72 | | MinimServer | MinimServer | OK | 73 | | Mosquitto | mosquitto | OK - community package | 74 | | phpMyAdmin | phpMyAdmin | OK | 75 | | Node.js | Node.js_v## | OK | 76 | | Note Station | NoteStation | OK | 77 | | PDF Viewer | PDFViewer | OK | 78 | | Perl | Perl | OK | 79 | | PHP | PHP#.# | OK | 80 | | Plex Media Server | PlexMediaServer | OK | 81 | | Presto File Server | PrestoServer | OK | 82 | | Proxy Server | ProxyServer | OK | 83 | | Python 3.9 | Python3.9 | OK | 84 | | RTL8152/RTL8153 driver | r8152 | OK - 3rd party package [link](https://github.com/bb-qq/r8152) | 85 | | RADIUS Server | RadiusServer | OK | 86 | | SMI-S Provider | SynoSmisProvider | OK | 87 | | Snapshot Replication | SnapshotReplication | OK | 88 | | SSO Server | SSOServer | OK | 89 | | Storage Analyzer | StorageAnalyzer | OK | 90 | | Surveillance Station | SurveillanceStation | OK | 91 | | SynoCli Tools | synocli-"toolname" | OK - community package | 92 | | Synology Application Service | SynologyApplicationService | OK | 93 | | Synology Calendar | Calendar | OK | 94 | | Synology Chat Server | Chat | OK | 95 | | Synology Contacts | Contacts | OK | 96 | | Synology Directory Server | DirectoryServerForWindowsDomain | OK | 97 | | Synology Drive Server | SynologyDrive | OK | 98 | | Synology Mail Server | MailServer | OK | 99 | | Synology MailPlus | MailPlus | OK | 100 | | Synology MailPlus Server | MailPlus-Server | OK I think | 101 | | Synology Office | Spreadsheet | OK | 102 | | Synology Photos | SynologyPhotos | OK | 103 | | Tailscale | Tailscale | OK | 104 | | Text Editor | TextEditor | OK | 105 | | Universal Viewer | UniversalViewer | OK | 106 | | USB Copy | USBCopy | see [moving_extras](moving_extras.md) 107 | | Video Station | VideoStation | OK | 108 | | Virtual Machine Manager | Virtualization | OK | 109 | | VPN Server | VPNCenter | OK | 110 | | Web Station | WebStation | OK | 111 | | WebDAV Server | WebDAVServer | OK | 112 | 113 |
114 | 115 | #### Packages not tested 116 | 117 |
118 | Click here to see list 119 | 120 | 121 | 122 | The icons in this table are [Copyright © 2004-2024 Synology Inc.](https://kb.synology.com/en-br/DSM/help/DSM/Home/about?version=7) or Copyright the 3rd party package developer. 123 | 124 | | Package | Result / Notes | 125 | |---------|--------| 126 | | Archiware P5 | | 127 | | BRAVIA Signage | Won't install in Container Manager. It checks if Docker is installed | 128 | | Container Manager 24.0.2 | | 129 | | Data Deposit Box | | 130 | | Diagnosis Tool | | 131 | | Domotz Network Monitoring | | 132 | | ElephantDrive | | 133 | | GateOne | | 134 | | GoodSync | | 135 | | IDrive | | 136 | | Jackett | community package | 137 | | Joomla | | 138 | | KodiExplorer | | 139 | | MediaWiki | | 140 | | Medusa | community package [link](https://github.com/BenjV/SYNO-packages) | 141 | | MEGAcmd | | 142 | | Mono | community package | 143 | | NAKIVO Backup and Replication | | 144 | | NAKIVO Transporter | | 145 | | PACS | | 146 | | Photo Station | DSM 6 | 147 | | Radarr | community package | 148 | | Ragic Cloud DB | | 149 | | Resilo Sync | | 150 | | Shellinabox | community package | 151 | | Sonarr | community package | 152 | | Syncthing | | 153 | | TeamViewer | | 154 | | Transmission | community package | 155 | | Tvheadend | community package | 156 | | VirtualHere | | 157 | | vtigerCRM | | 158 | | WebTools | community package | 159 | | Wordpress | | 160 | 161 |
162 | 163 | ### Download the script 164 | 165 | 1. Download the latest version _Source code (zip)_ from https://github.com/007revad/Synology_app_mover/releases 166 | 2. Save the download zip file to a folder on the Synology. 167 | 3. Unzip the zip file. 168 | 169 | ### Set backup location 170 | 171 | If you want to use use the [backup and restore options](/images/backup.png) you need edit the included **syno_app_mover.conf** file to set the location to backup to. 172 | 173 | The **syno_app_mover.conf** file must be in the same folder as the **syno_app_mover.sh file**. 174 | 175 | **Other options in syno_app_mover.conf** 176 | ```YAML 177 | # buffer is used when checking if target volume has enough space 178 | # Add 50 GB buffer so we don't fill the target volume 179 | 180 | buffer=50 181 | 182 | # The backuppath is only used by Backup and Restore modes 183 | # backuppath should be in the format of /volume/sharename/folder 184 | # For example: 185 | # backuppath="/volume1/backups" 186 | # 187 | # Note: The script will create a syno_app_mover folder in backuppath 188 | 189 | backuppath="/volume1/backups" 190 | 191 | # Skip backup if previous backup was done less than x minutes ago 192 | # Set to "0" to always backup 193 | # skip_minutes is in minutes 194 | 195 | skip_minutes=360 196 | 197 | # exclude setting for use when auto="all" option is used to skip specified apps 198 | # For example: 199 | # exclude="ContainerManager" 200 | # exclude="DownloadStation,ContainerManager,HyperBackup" 201 | # 202 | # Note: You need to use the app's system name 203 | # Run syno_app_mover.sh with the --list option to see your app's system names 204 | 205 | exclude= 206 | 207 | # For Docker or Container Manager's container settings json exports 208 | # Set delete_older to age in days before old exports are deleted 209 | # Set ignored_containers to a list of containers to not export settings 210 | # For example: 211 | # delete_older=7 212 | # ignored_containers="libraspeed-1,netdata" 213 | # 214 | # Note you need use the container's docker name. To see their names via SSH use: 215 | # sudo docker ps -a --format "{{.Names}}" 216 | 217 | delete_older=30 218 | ignored_containers= 219 | ``` 220 | 221 | ### To run the script via SSH 222 | 223 | [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) 224 | 225 | ```YAML 226 | sudo -s /volume1/scripts/syno_app_mover.sh 227 | ``` 228 | 229 | **Note:** Replace /volume1/scripts/ with the path to where the script is located. 230 | 231 | ### Options when running the script 232 | 233 | There are optional flags you can use when running the script: 234 | ```YAML 235 | -h, --help Show this help message 236 | -v, --version Show the script version 237 | --autoupdate=AGE Auto update script (useful when script is scheduled) 238 | AGE is how many days old a release must be before 239 | auto-updating. AGE must be a number: 0 or greater 240 | 241 | --auto=APP Automatically backup APP (for scheduling backups) 242 | APP can be a single app or a comma separated list 243 | APP can also be 'all' to backup all apps (except 244 | any you excluded in the syno_app_mover.conf) 245 | Examples: 246 | --auto=radarr 247 | --auto=Calender,ContainerManager,radarr 248 | --auto=all 249 | 250 | APP names need to be the app's system name 251 | View the system names with the --list option 252 | 253 | --list Display installed apps' system names 254 | ``` 255 | 256 | ### Troubleshooting 257 | 258 | If the script won't run check the following: 259 | 260 | 1. Make sure you download the zip file and unzipped it to a folder on your Synology (not on your computer). 261 | 2. If the path to the script contains any spaces you need to enclose the path/scriptname in double quotes: 262 | ```YAML 263 | sudo -s "/volume1/my scripts/syno_app_mover.sh" 264 | ``` 265 | 3. Make sure you unpacked the zip or rar file that you downloaded and are trying to run the syno_app_mover.sh file. 266 | 4. Set the script file as executable: 267 | ```YAML 268 | sudo chmod +x "/volume1/scripts/syno_app_mover.sh" 269 | ``` 270 | 271 | ### Video - moving Container Manager 272 | 273 | 274 | 275 | https://github.com/007revad/Synology_app_mover/assets/e308839a-1a3d-402b-9920-dc98901c1234 276 | 277 | ### DSM 7 screenshots 278 | 279 |

Moving a package (with dependencies)

280 |

281 | 282 |
283 | 284 |

Moving packages with shared folders

285 |

286 |

287 | 288 |
289 | 290 |

Moving a package that has a volume location setting

291 |

292 | 293 |
294 | 295 |

Moving Active Backup for Business

296 |

297 | 298 |
299 | 300 |

Backing up Audio Station

301 |

302 | 303 |
304 | 305 |

Backing up with the --auto option

306 |

307 | 308 |
309 | 310 |

Output with --list option

311 |

312 | 313 | ### Credits 314 | - wallacebrf for extensive beta testing of syno_app_mover v3. 315 | - ctrlaltdelete for the code to export Container Manager/Docker container's settings. 316 | -------------------------------------------------------------------------------- /images/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app.png -------------------------------------------------------------------------------- /images/app2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app2.png -------------------------------------------------------------------------------- /images/app3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app3.png -------------------------------------------------------------------------------- /images/app4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app4.png -------------------------------------------------------------------------------- /images/app5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app5.png -------------------------------------------------------------------------------- /images/app6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/app6.png -------------------------------------------------------------------------------- /images/auto_option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/auto_option.png -------------------------------------------------------------------------------- /images/backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/backup.png -------------------------------------------------------------------------------- /images/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/docker.png -------------------------------------------------------------------------------- /images/help_option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/help_option.png -------------------------------------------------------------------------------- /images/how_to_download_generic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/how_to_download_generic.png -------------------------------------------------------------------------------- /images/icons/-Copyright_info.txt: -------------------------------------------------------------------------------- 1 | The icons in this folder are either Copyright © Synology Inc. or Copyright © the 3rd party package developer. 2 | https://kb.synology.com/en-br/DSM/help/DSM/Home/about?version=7 3 | -------------------------------------------------------------------------------- /images/icons/ActiveBackup-GSuite_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ActiveBackup-GSuite_64.png -------------------------------------------------------------------------------- /images/icons/ActiveBackup-Office365_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ActiveBackup-Office365_64.png -------------------------------------------------------------------------------- /images/icons/ActiveBackup_business_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ActiveBackup_business_64.png -------------------------------------------------------------------------------- /images/icons/ActiveInsight_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ActiveInsight_64.png -------------------------------------------------------------------------------- /images/icons/AntiVirus-McAfee_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/AntiVirus-McAfee_64.png -------------------------------------------------------------------------------- /images/icons/ArchiwareP5_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ArchiwareP5_64.png -------------------------------------------------------------------------------- /images/icons/AudioStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/AudioStation_64.png -------------------------------------------------------------------------------- /images/icons/Authenticator_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Authenticator_64.png -------------------------------------------------------------------------------- /images/icons/AvrCenter_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/AvrCenter_64.png -------------------------------------------------------------------------------- /images/icons/AvrLogger_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/AvrLogger_64.png -------------------------------------------------------------------------------- /images/icons/BitDefenderForMailPlus_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/BitDefenderForMailPlus_64.png -------------------------------------------------------------------------------- /images/icons/C2IdentityLDAPAgent_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/C2IdentityLDAPAgent_64.png -------------------------------------------------------------------------------- /images/icons/CMS_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/CMS_64.png -------------------------------------------------------------------------------- /images/icons/Calendar_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Calendar_64.png -------------------------------------------------------------------------------- /images/icons/ChannelsDVR_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ChannelsDVR_64.png -------------------------------------------------------------------------------- /images/icons/Chat_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Chat_64.png -------------------------------------------------------------------------------- /images/icons/CloudSync_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/CloudSync_64.png -------------------------------------------------------------------------------- /images/icons/CodecPack_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/CodecPack_64.png -------------------------------------------------------------------------------- /images/icons/Contacts_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Contacts_64.png -------------------------------------------------------------------------------- /images/icons/ContainerManager_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ContainerManager_64.png -------------------------------------------------------------------------------- /images/icons/DNSServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/DNSServer_64.png -------------------------------------------------------------------------------- /images/icons/DdbBackup_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/DdbBackup_64.png -------------------------------------------------------------------------------- /images/icons/DirectoryServerForWindowsDomain_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/DirectoryServerForWindowsDomain_64.png -------------------------------------------------------------------------------- /images/icons/DirectoryServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/DirectoryServer_64.png -------------------------------------------------------------------------------- /images/icons/DocumentViewer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/DocumentViewer_64.png -------------------------------------------------------------------------------- /images/icons/EmbyServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/EmbyServer_64.png -------------------------------------------------------------------------------- /images/icons/FileStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/FileStation_64.png -------------------------------------------------------------------------------- /images/icons/Git_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Git_64.png -------------------------------------------------------------------------------- /images/icons/GlacierBackup_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/GlacierBackup_64.png -------------------------------------------------------------------------------- /images/icons/GoodSync_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/GoodSync_64.png -------------------------------------------------------------------------------- /images/icons/HybridShare_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/HybridShare_64.png -------------------------------------------------------------------------------- /images/icons/HyperBackupVault_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/HyperBackupVault_64.png -------------------------------------------------------------------------------- /images/icons/HyperBackup_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/HyperBackup_64.png -------------------------------------------------------------------------------- /images/icons/Joomla_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Joomla_64.png -------------------------------------------------------------------------------- /images/icons/KodExplorer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/KodExplorer_64.png -------------------------------------------------------------------------------- /images/icons/LogAnalysis_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/LogAnalysis_64.png -------------------------------------------------------------------------------- /images/icons/MEGAcmd_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MEGAcmd_64.png -------------------------------------------------------------------------------- /images/icons/MailClient_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MailClient_64.png -------------------------------------------------------------------------------- /images/icons/MailPlus-Server_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MailPlus-Server_64.png -------------------------------------------------------------------------------- /images/icons/MailServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MailServer_64.png -------------------------------------------------------------------------------- /images/icons/MailStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MailStation_64.png -------------------------------------------------------------------------------- /images/icons/MariaDB10_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MariaDB10_64.png -------------------------------------------------------------------------------- /images/icons/MediaServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MediaServer_64.png -------------------------------------------------------------------------------- /images/icons/MediaWiki_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MediaWiki_72.png -------------------------------------------------------------------------------- /images/icons/MinimServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/MinimServer_64.png -------------------------------------------------------------------------------- /images/icons/Mosquitto_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Mosquitto_64.png -------------------------------------------------------------------------------- /images/icons/NBR-Transporter_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/NBR-Transporter_64.png -------------------------------------------------------------------------------- /images/icons/NBR_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/NBR_64.png -------------------------------------------------------------------------------- /images/icons/Node.js_cropped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Node.js_cropped.png -------------------------------------------------------------------------------- /images/icons/NoteStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/NoteStation_64.png -------------------------------------------------------------------------------- /images/icons/PACS_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/PACS_64.png -------------------------------------------------------------------------------- /images/icons/PDFViewer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/PDFViewer_64.png -------------------------------------------------------------------------------- /images/icons/PHP_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/PHP_64.png -------------------------------------------------------------------------------- /images/icons/Perl_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Perl_64.png -------------------------------------------------------------------------------- /images/icons/PhotoStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/PhotoStation_64.png -------------------------------------------------------------------------------- /images/icons/PrestoServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/PrestoServer_64.png -------------------------------------------------------------------------------- /images/icons/ProxyServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ProxyServer_64.png -------------------------------------------------------------------------------- /images/icons/Python_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Python_64.png -------------------------------------------------------------------------------- /images/icons/RadiusServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/RadiusServer_64.png -------------------------------------------------------------------------------- /images/icons/RagicBuilder_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/RagicBuilder_64.png -------------------------------------------------------------------------------- /images/icons/SANManager_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SANManager_64.png -------------------------------------------------------------------------------- /images/icons/SSOServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SSOServer_64.png -------------------------------------------------------------------------------- /images/icons/SnapshotReplication_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SnapshotReplication_64.png -------------------------------------------------------------------------------- /images/icons/Sonarr_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Sonarr_64.png -------------------------------------------------------------------------------- /images/icons/Sony_BraviaSignage_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Sony_BraviaSignage_64.png -------------------------------------------------------------------------------- /images/icons/Spreadsheet_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Spreadsheet_64.png -------------------------------------------------------------------------------- /images/icons/StorageAnalyzer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/StorageAnalyzer_64.png -------------------------------------------------------------------------------- /images/icons/SurveillanceStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SurveillanceStation_64.png -------------------------------------------------------------------------------- /images/icons/SynoFinder_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SynoFinder_64.png -------------------------------------------------------------------------------- /images/icons/SynoSmisProvider_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SynoSmisProvider_64.png -------------------------------------------------------------------------------- /images/icons/SynologyApplicationService_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SynologyApplicationService_64.png -------------------------------------------------------------------------------- /images/icons/SynologyDrive_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/SynologyDrive_64.png -------------------------------------------------------------------------------- /images/icons/Tailscale_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Tailscale_64.png -------------------------------------------------------------------------------- /images/icons/TeamViewer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/TeamViewer_64.png -------------------------------------------------------------------------------- /images/icons/TextEditor_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/TextEditor_64.png -------------------------------------------------------------------------------- /images/icons/USBCopy_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/USBCopy_64.png -------------------------------------------------------------------------------- /images/icons/UniversalSearch_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/UniversalSearch_64.png -------------------------------------------------------------------------------- /images/icons/UniversalViewer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/UniversalViewer_64.png -------------------------------------------------------------------------------- /images/icons/VPNCenter_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/VPNCenter_64.png -------------------------------------------------------------------------------- /images/icons/VideoStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/VideoStation_64.png -------------------------------------------------------------------------------- /images/icons/VirtualHere_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/VirtualHere_64.png -------------------------------------------------------------------------------- /images/icons/VirtualManagement_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/VirtualManagement_64.png -------------------------------------------------------------------------------- /images/icons/WebDAVServer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/WebDAVServer_64.png -------------------------------------------------------------------------------- /images/icons/WebStation_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/WebStation_64.png -------------------------------------------------------------------------------- /images/icons/WebTools-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/WebTools-48.png -------------------------------------------------------------------------------- /images/icons/Wordpress_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/Wordpress_64.png -------------------------------------------------------------------------------- /images/icons/anti_virus_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/anti_virus_64.png -------------------------------------------------------------------------------- /images/icons/apache_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/apache_64.png -------------------------------------------------------------------------------- /images/icons/bb-qq_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/bb-qq_64.png -------------------------------------------------------------------------------- /images/icons/diagnosis_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/diagnosis_64.png -------------------------------------------------------------------------------- /images/icons/docker_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/docker_64.png -------------------------------------------------------------------------------- /images/icons/domotz_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/domotz_64.png -------------------------------------------------------------------------------- /images/icons/download_station_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/download_station_64.png -------------------------------------------------------------------------------- /images/icons/elephantdrive_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/elephantdrive_64.png -------------------------------------------------------------------------------- /images/icons/exFAT-Free_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/exFAT-Free_72.png -------------------------------------------------------------------------------- /images/icons/ffmpeg_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/ffmpeg_72.png -------------------------------------------------------------------------------- /images/icons/gateone-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/gateone-64.png -------------------------------------------------------------------------------- /images/icons/iDrive_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/iDrive_72.png -------------------------------------------------------------------------------- /images/icons/jackett-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/jackett-64.png -------------------------------------------------------------------------------- /images/icons/jellyfin-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/jellyfin-64.png -------------------------------------------------------------------------------- /images/icons/log_center_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/log_center_64.png -------------------------------------------------------------------------------- /images/icons/mediainfo-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/mediainfo-64.png -------------------------------------------------------------------------------- /images/icons/medusa-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/medusa-64.png -------------------------------------------------------------------------------- /images/icons/mono_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/mono_64.png -------------------------------------------------------------------------------- /images/icons/photos_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/photos_64.png -------------------------------------------------------------------------------- /images/icons/phpMyAdmin_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/phpMyAdmin_72.png -------------------------------------------------------------------------------- /images/icons/plexmediaserver_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/plexmediaserver_48.png -------------------------------------------------------------------------------- /images/icons/radarr-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/radarr-64.png -------------------------------------------------------------------------------- /images/icons/resiliosync-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/resiliosync-48.png -------------------------------------------------------------------------------- /images/icons/shellinabox-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/shellinabox-48.png -------------------------------------------------------------------------------- /images/icons/storage_manager_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/storage_manager_64.png -------------------------------------------------------------------------------- /images/icons/syncthing-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/syncthing-64.png -------------------------------------------------------------------------------- /images/icons/synocli_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/synocli_72.png -------------------------------------------------------------------------------- /images/icons/transmission-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/transmission-64.png -------------------------------------------------------------------------------- /images/icons/tvheadend-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/tvheadend-64.png -------------------------------------------------------------------------------- /images/icons/vtigerCRM_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/icons/vtigerCRM_64.png -------------------------------------------------------------------------------- /images/list_option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/list_option.png -------------------------------------------------------------------------------- /images/move_shared_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/move_shared_folder.png -------------------------------------------------------------------------------- /images/pkg_center_64_blurr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/pkg_center_64_blurr.png -------------------------------------------------------------------------------- /images/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/thumbnail.png -------------------------------------------------------------------------------- /images/updated_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/007revad/Synology_app_mover/1cc9995a9f145c74325095eaadcf4bf54acbb5c2/images/updated_list.png -------------------------------------------------------------------------------- /moving_extras.md: -------------------------------------------------------------------------------- 1 | Some packages that are installed in the DSM system partition store the user's settings on a volume. 2 | 3 | Below are instructions on how to move those packages' settings to another volume. 4 | 5 | ### USB Copy 6 | 7 | To move the USB Copy's database to another volume: 8 | 1. Open USB Copy. 9 | 2. Click the gear icon to open settings. 10 | 3. Change Database location to other volume. 11 | 4. Click OK. 12 | -------------------------------------------------------------------------------- /my-other-scripts.md: -------------------------------------------------------------------------------- 1 | ## All my scripts 2 | 3 | #### Contents 4 | - [Plex](#plex) 5 | - [Synology docker](#synology-docker) 6 | - [Synology recovery](#synology-recovery) 7 | - [Other Synology scripts](#other-synology-scripts) 8 | - [Synology hardware restrictions](#synology-hardware-restrictions) 9 | - [How To Guides](#how-to-guides) 10 | - [Synology dev](#synology-dev) 11 | ## 12 | 13 | ### Plex 14 | 15 | - **Synology_Plex_Backup** 16 | - A script to backup Plex to a tgz file foror DSM 7 and DSM 6. 17 | - Works for Plex Synology package and Plex in docker. 18 | 19 | - **Asustor_Plex_Backup** 20 | - Backup your Asustor's Plex Media Server settings and database. 21 | 22 | - **Linux_Plex_Backup** 23 | - Backup your Linux Plex Media Server's settings and database. 24 | 25 | - **Plex_Server_Sync** 26 | - Sync your main Plex server database & metadata to a backup Plex server. 27 | - Works for Synology, Asustor, Linux and supports Plex package or Plex in docker. 28 | 29 |               [Back to Contents](#contents) 30 | 31 | ### Synology docker 32 | 33 | - **Synology_Docker_export** 34 | - Export all Synology Container Manager or Docker containers' settings as json files to your docker shared folder. 35 | 36 | - **Synology_ContainerManager_IPv6** 37 | - Enable IPv6 for Container Manager's bridge network. 38 | 39 | - **ContainerManager_for_all_armv8** 40 | - Script to install Container Manager on a RS819, DS119j, DS418, DS418j, DS218, DS218play or DS118. 41 | 42 | - **Docker_Autocompose** 43 | - Create .yml files from your docker existing containers. 44 | 45 | - **Synology_docker_cleanup** 46 | - Remove orphan docker btrfs subvolumes and images in Synology DSM 7 and DSM 6. 47 | 48 |               [Back to Contents](#contents) 49 | 50 | ### Synology recovery 51 | 52 | - **Synology_DSM_reinstall** 53 | - Easily re-install the same DSM version without losing any data or settings. 54 | 55 | - **Synology_Recover_Data** 56 | - A script to make it easy to recover your data from your Synology's drives using a computer. 57 | 58 | - **Synology clear drive error** 59 | - Clear drive critical errors so DSM will let you use the drive. 60 | 61 | - **Synology_DSM_Telnet_Password** 62 | - Synology DSM Recovery Telnet Password of the Day generator. 63 | 64 | - **Syno_DSM_Extractor_GUI** 65 | - Windows GUI for extracting Synology DSM 7 pat files and spk package files. 66 | 67 |               [Back to Contents](#contents) 68 | 69 | ### Other Synology scripts 70 | 71 | - **Synology_app_mover** 72 | - Easily move Synology packages from one volume to another volume. 73 | 74 | - **Video_Station_for_DSM_722** 75 | - Script to install Video Station in DSM 7.2.2 76 | 77 | - **SS_Motion_Detection** 78 | - Installs previous Surveillance Station and Advanced Media Extensions versions so motion detection and HEVC are supported. 79 | 80 | - **Synology_Config_Backup** 81 | - Backup and export your Synology DSM configuration. 82 | 83 | - **Synology_CPU_temperature** 84 | - Get and log Synology NAS CPU temperature via SSH. 85 | 86 | - **Synology_SMART_info** 87 | - Show Synology smart test progress or smart health and attributes. 88 | 89 | - **Synology_Cleanup_Coredumps** 90 | - Cleanup memory core dumps from crashed processes. 91 | 92 | - **Synology_toggle_reset_button** 93 | - Script to disable or enable the reset button and show current setting. 94 | 95 | - **Synology_Download_Station_Chrome_Extension** 96 | - Download Station Chrome Extension. 97 | 98 | - **Seagate_lowCurrentSpinup** 99 | - This script avoids the need to buy and install a higher wattage power supply when using multiple large Seagate SATA HDDs. 100 | 101 |               [Back to Contents](#contents) 102 | 103 | ### Synology hardware restrictions 104 | 105 | - **Synology_HDD_db** 106 | - 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. 107 | 108 | - **Synology_enable_M2_volume** 109 | - Enable creating volumes with non-Synology M.2 drives. 110 | - Enable Health Info for non-Synology NVMe drives (not in DSM 7.2.1 or later). 111 | 112 | - **Synology_M2_volume** 113 | - Easily create an M.2 volume on Synology NAS. 114 | 115 | - **Synology_enable_M2_card** 116 | - Enable Synology M.2 PCIe cards in Synology NAS that don't officially support them. 117 | 118 | - **Synology_enable_eunit** 119 | - Enable an unsupported Synology eSATA Expansion Unit models. 120 | 121 | - **Synology_enable_Deduplication** 122 | - Enable deduplication with non-Synology SSDs and unsupported NAS models. 123 | 124 | - **Synology_SHR_switch** 125 | - Easily switch between SHR and RAID Groups, or enable RAID F1. 126 | 127 | - **Synology_enable_sequential_IO** 128 | - Enables sequential I/O for your SSD caches, like DSM 6 had. 129 | 130 | - **Synology_Information_Wiki** 131 | - Information about Synology hardware. 132 | 133 |               [Back to Contents](#contents) 134 | 135 | ### How To Guides 136 | 137 | - **Synology_SSH_key_setup** 138 | - How to setup SSH key authentication for your Synology. 139 | 140 |               [Back to Contents](#contents) 141 | 142 | ### Synology dev 143 | 144 | - **Download_Synology_Archive** 145 | - Download all or part of the Synology archive. 146 | 147 | - **Syno_DSM_Extractor_GUI** 148 | - Windows GUI for extracting Synology DSM 7 pat files and spk package files. 149 | 150 | - **ScriptNotify** 151 | - DSM 7 package to allow your scripts to send DSM notifications. 152 | 153 | - **DTC_GUI_for_Windows** 154 | - GUI for DTC.exe for Windows. 155 | 156 |               [Back to Contents](#contents) 157 | -------------------------------------------------------------------------------- /syno_app_mover.conf: -------------------------------------------------------------------------------- 1 | # buffer is used when checking if target volume has enough space 2 | # Add 50 GB buffer so we don't fill the target volume 3 | 4 | buffer=50 5 | 6 | 7 | # The backuppath is only used by Backup and Restore modes 8 | # backuppath should be in the format of /volume/sharename/folder 9 | # For example: 10 | # backuppath="/volume1/backups" 11 | # 12 | # Note: The script will create a syno_app_mover folder in backuppath 13 | 14 | backuppath="/volume1/backups" 15 | 16 | 17 | # Skip backup if previous backup was done less than x minutes ago 18 | # Set to "0" to always backup 19 | # skip_minutes is in minutes 20 | 21 | skip_minutes=360 22 | 23 | 24 | # exclude setting for use when auto="all" option is used to skip specified apps 25 | # For example: 26 | # exclude="ContainerManager" 27 | # exclude="DownloadStation,ContainerManager,HyperBackup" 28 | # 29 | # Note: You need to use the app's system name 30 | # Run syno_app_mover.sh with the --list option to see your app's system names 31 | 32 | exclude= 33 | 34 | 35 | # For Docker or Container Manager's container settings json exports 36 | # Set delete_older to age in days before old exports are deleted 37 | # Set ignored_containers to a list of containers to not export settings 38 | # For example: 39 | # delete_older=7 40 | # ignored_containers="libraspeed-1,netdata" 41 | # 42 | # Note you need use the container's docker name. To see their names via SSH use: 43 | # sudo docker ps -a --format "{{.Names}}" 44 | 45 | delete_older=30 46 | ignored_containers= 47 | 48 | -------------------------------------------------------------------------------- /syno_app_mover.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # shellcheck disable=SC2076,SC2207,SC2238,SC2129 3 | #------------------------------------------------------------------------------ 4 | # Easily move Synology packages from one volume to another volume. 5 | # Also can backup and restore packages. 6 | # 7 | # Github: https://github.com/007revad/Synology_app_mover 8 | # Script verified at https://www.shellcheck.net/ 9 | # 10 | # To run in a shell (replace /volume1/scripts/ with path to script): 11 | # sudo -s /volume1/scripts/syno_app_mover.sh 12 | #------------------------------------------------------------------------------ 13 | # TODO 14 | # Instead of moving large extra folders copy them to the target volume. 15 | # Then rename the source volume's @downloads to @downloads_backup. 16 | # 17 | # Add ability to move all apps 18 | # https://www.reddit.com/r/synology/comments/1eybzc1/comment/ljcj8re/ 19 | # 20 | # Maybe add backing up "/volume#/@iSCSI/VDISK_BLUN" (VMM VMs) 21 | # https://www.synology-forum.de/threads/backup-der-vms.135462/post-1194705 22 | # https://www.synology-forum.de/threads/virtual-machine-manager-vms-sichern.91952/post-944113 23 | # 24 | #------------------------------------------------------------------------------ 25 | # DONE Add `@database` as an app that can be moved. 26 | # DONE Added logging 27 | # DONE Added USB Copy to show how to move USB Copy database (move mode only) 28 | #------------------------------------------------------------------------------ 29 | 30 | scriptver="v4.2.89" 31 | script=Synology_app_mover 32 | repo="007revad/Synology_app_mover" 33 | scriptname=syno_app_mover 34 | logpath="$(dirname "$(realpath "$0")")" 35 | logfile="$logpath/${scriptname}_$(date +%Y-%m-%d_%H-%M).log" 36 | 37 | # Prevent Entware or user edited PATH causing issues 38 | # shellcheck disable=SC2155 # Declare and assign separately to avoid masking return values 39 | export PATH=$(echo "$PATH" | sed -e 's/\/opt\/bin:\/opt\/sbin://') 40 | 41 | ding(){ 42 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" 43 | printf \\a 44 | } 45 | 46 | # Save options used 47 | args=("$@") 48 | 49 | 50 | if [[ $1 == "--debug" ]] || [[ $1 == "-d" ]]; then 51 | set -x 52 | export PS4='`[[ $? == 0 ]] || echo "\e[1;31;40m($?)\e[m\n "`LINE $LINENO ' 53 | fi 54 | 55 | if [[ $1 == "--trace" ]] || [[ $1 == "-t" ]]; then 56 | trace="yes" 57 | fi 58 | 59 | if [[ ${1,,} == "--fix" ]]; then 60 | # Bypass exit if dependent package failed to stop 61 | # For restoring broken package to original volume 62 | fix="yes" 63 | fi 64 | 65 | # Check script is running as root 66 | if [[ $( whoami ) != "root" ]]; then 67 | ding 68 | echo -e "${Error}ERROR${Off} This script must be run as sudo or root!" 69 | exit 1 # Not running as root 70 | fi 71 | 72 | # Check script is running on a Synology NAS 73 | if ! /usr/bin/uname -a | grep -i synology >/dev/null; then 74 | echo "This script is NOT running on a Synology NAS!" 75 | echo "Copy the script to a folder on the Synology" 76 | echo "and run it from there." 77 | exit 1 # Not a Synology NAS 78 | fi 79 | 80 | # Get NAS model 81 | model=$(cat /proc/sys/kernel/syno_hw_version) 82 | #modelname="$model" 83 | 84 | # Check for dodgy characters after model number 85 | if [[ $model =~ 'pv10-j'$ ]]; then # GitHub syno_hdd_db issue #10 86 | model=${model%??????}+ # replace last 6 chars with + 87 | elif [[ $model =~ '-j'$ ]]; then # GitHub syno_hdd_db issue #2 88 | model=${model%??} # remove last 2 chars 89 | fi 90 | 91 | # Show script version 92 | #echo -e "$script $scriptver\ngithub.com/$repo\n" 93 | echo "$script $scriptver" 94 | 95 | # Get DSM full version 96 | productversion=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION productversion) 97 | buildphase=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION buildphase) 98 | buildnumber=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION buildnumber) 99 | smallfixnumber=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION smallfixnumber) 100 | majorversion=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION majorversion) 101 | #minorversion=$(/usr/syno/bin/synogetkeyvalue /etc.defaults/VERSION minorversion) 102 | 103 | # Show DSM full version and model 104 | if [[ $buildphase == GM ]]; then buildphase=""; fi 105 | if [[ $smallfixnumber -gt "0" ]]; then smallfix="-$smallfixnumber"; fi 106 | echo -e "$model DSM $productversion-$buildnumber$smallfix $buildphase\n" 107 | 108 | 109 | usage(){ 110 | cat </dev/null 2>&1 && pwd ) 342 | source=$(readlink "$source") 343 | # If $source was a relative symlink, we need to resolve it 344 | # relative to the path where the symlink file was located 345 | [[ $source != /* ]] && source=$scriptpath/$source 346 | done 347 | scriptpath=$( cd -P "$( dirname "$source" )" >/dev/null 2>&1 && pwd ) 348 | scriptfile=$( basename -- "$source" ) 349 | echo "Running from: ${scriptpath}/$scriptfile" 350 | 351 | #echo "Script location: $scriptpath" # debug 352 | #echo "Source: $source" # debug 353 | #echo "Script filename: $scriptfile" # debug 354 | 355 | #echo "tag: $tag" # debug 356 | #echo "scriptver: $scriptver" # debug 357 | 358 | 359 | cleanup_tmp(){ 360 | # Delete downloaded .tar.gz file 361 | if [[ -f "/tmp/$script-$shorttag.tar.gz" ]]; then 362 | if ! rm "/tmp/$script-$shorttag.tar.gz"; then 363 | echo -e "${Error}ERROR${Off} Failed to delete"\ 364 | "downloaded /tmp/$script-$shorttag.tar.gz!" >&2 365 | fi 366 | fi 367 | 368 | # Delete extracted tmp files 369 | if [[ -d "/tmp/$script-$shorttag" ]]; then 370 | if ! rm -r "/tmp/$script-$shorttag"; then 371 | echo -e "${Error}ERROR${Off} Failed to delete"\ 372 | "downloaded /tmp/$script-$shorttag!" >&2 373 | fi 374 | fi 375 | } 376 | 377 | 378 | if ! printf "%s\n%s\n" "$tag" "$scriptver" | 379 | sort --check=quiet --version-sort >/dev/null ; then 380 | echo -e "\n${Cyan}There is a newer version of this script available.${Off}" 381 | echo -e "Current version: ${scriptver}\nLatest version: $tag" 382 | scriptdl="$scriptpath/$script-$shorttag" 383 | if [[ -f ${scriptdl}.tar.gz ]] || [[ -f ${scriptdl}.zip ]]; then 384 | # They have the latest version tar.gz downloaded but are using older version 385 | echo "You have the latest version downloaded but are using an older version" 386 | sleep 10 387 | elif [[ -d $scriptdl ]]; then 388 | # They have the latest version extracted but are using older version 389 | echo "You have the latest version extracted but are using an older version" 390 | sleep 10 391 | else 392 | if [[ $autoupdate == "yes" ]]; then 393 | if [[ $age -gt "$delay" ]] || [[ $age -eq "$delay" ]]; then 394 | echo "Downloading $tag" 395 | reply=y 396 | else 397 | echo "Skipping as $tag is less than $delay days old." 398 | fi 399 | else 400 | echo -e "${Cyan}Do you want to download $tag now?${Off} [y/n]" 401 | read -r -t 30 reply 402 | fi 403 | 404 | if [[ ${reply,,} == "y" ]]; then 405 | # Delete previously downloaded .tar.gz file and extracted tmp files 406 | cleanup_tmp 407 | 408 | if cd /tmp; then 409 | url="https://github.com/$repo/archive/refs/tags/$tag.tar.gz" 410 | if ! curl -JLO -m 30 --connect-timeout 5 "$url"; then 411 | echo -e "${Error}ERROR${Off} Failed to download"\ 412 | "$script-$shorttag.tar.gz!" 413 | else 414 | if [[ -f /tmp/$script-$shorttag.tar.gz ]]; then 415 | # Extract tar file to /tmp/ 416 | if ! tar -xf "/tmp/$script-$shorttag.tar.gz" -C "/tmp"; then 417 | echo -e "${Error}ERROR${Off} Failed to"\ 418 | "extract $script-$shorttag.tar.gz!" 419 | else 420 | # Set script sh files as executable 421 | if ! chmod a+x "/tmp/$script-$shorttag/"*.sh ; then 422 | permerr=1 423 | echo -e "${Error}ERROR${Off} Failed to set executable permissions" 424 | fi 425 | 426 | # Copy new script sh file to script location 427 | if ! cp -p "/tmp/$script-$shorttag/${scriptname}.sh" "${scriptpath}/${scriptfile}"; 428 | then 429 | copyerr=1 430 | echo -e "${Error}ERROR${Off} Failed to copy"\ 431 | "$script-$shorttag sh file(s) to:\n $scriptpath/${scriptfile}" 432 | fi 433 | 434 | # Copy script's conf file to script location if missing 435 | if [[ ! -f "$scriptpath/${scriptname}.conf" ]]; then 436 | # Set permission on config file 437 | if ! chmod 664 "/tmp/$script-$shorttag/${scriptname}.conf"; then 438 | permerr=1 439 | echo -e "${Error}ERROR${Off} Failed to set read/write permissions on:" 440 | echo "$scriptpath/${scriptname}.conf" 441 | fi 442 | 443 | # Copy existing conf file settings to new conf file 444 | while read -r LINE; do 445 | if [[ ${LINE:0:1} != "#" ]]; then 446 | if [[ $LINE =~ ^[a-z_]+=.* ]]; then 447 | oldfile="${scriptpath}/${scriptname}.conf" 448 | newfile="/tmp/$script-$shorttag/${scriptname}.conf" 449 | key="${LINE%=*}" 450 | oldvalue="$(synogetkeyvalue "$oldfile" "$key")" 451 | newvalue="$(synogetkeyvalue "$newfile" "$key")" 452 | if [[ $oldvalue != "$newvalue" ]]; then 453 | synosetkeyvalue "$newfile" "$key" "$oldvalue" 454 | fi 455 | fi 456 | fi 457 | done < "${scriptpath}/${scriptname}.conf" 458 | 459 | # Copy conf file to script location 460 | if ! cp -p "/tmp/$script-$shorttag/${scriptname}.conf"\ 461 | "${scriptpath}/${scriptname}.conf"; then 462 | copyerr=1 463 | echo -e "${Error}ERROR${Off} Failed to copy"\ 464 | "$script-$shorttag conf file to:\n $scriptpath/${scriptname}.conf" 465 | else 466 | conftxt=", ${scriptname}.conf" 467 | fi 468 | fi 469 | 470 | # Copy new CHANGES.txt file to script location (if script on a volume) 471 | if [[ $scriptpath =~ /volume* ]]; then 472 | # Set permissions on CHANGES.txt 473 | if ! chmod 664 "/tmp/$script-$shorttag/CHANGES.txt"; then 474 | permerr=1 475 | echo -e "${Error}ERROR${Off} Failed to set read/write permissions on:" 476 | echo "$scriptpath/CHANGES.txt" 477 | fi 478 | 479 | # Copy new CHANGES.txt file to script location 480 | if ! cp -p "/tmp/$script-$shorttag/CHANGES.txt"\ 481 | "${scriptpath}/${scriptname}_CHANGES.txt"; then 482 | echo -e "${Error}ERROR${Off} Failed to copy"\ 483 | "$script-$shorttag/CHANGES.txt to:\n $scriptpath" 484 | else 485 | changestxt=" and changes.txt" 486 | fi 487 | fi 488 | 489 | # Delete downloaded tmp files 490 | cleanup_tmp 491 | 492 | # Notify of success (if there were no errors) 493 | if [[ $copyerr != 1 ]] && [[ $permerr != 1 ]]; then 494 | echo -e "\n$tag ${scriptfile}$conftxt$changestxt downloaded to: ${scriptpath}\n" 495 | 496 | # Reload script 497 | printf -- '-%.0s' {1..79}; echo # print 79 - 498 | exec "${scriptpath}/$scriptfile" "${args[@]}" 499 | fi 500 | fi 501 | else 502 | echo -e "${Error}ERROR${Off}"\ 503 | "/tmp/$script-$shorttag.tar.gz not found!" 504 | #ls /tmp | grep "$script" # debug 505 | fi 506 | fi 507 | cd "$scriptpath" || echo -e "${Error}ERROR${Off} Failed to cd to script location!" 508 | else 509 | echo -e "${Error}ERROR${Off} Failed to cd to /tmp!" 510 | fi 511 | fi 512 | fi 513 | fi 514 | 515 | conffile="${scriptpath}/${scriptname}.conf" 516 | # Fix line endings 517 | # grep can't detect Windows or Mac line endings 518 | # but can detect if there's no Linux endings. 519 | if grep -rIl -m 1 $'\r' "$conffile" >/dev/null; then 520 | # Does not contain Linux line endings 521 | sed -i 's/\r\n/\n/g' "$conffile" # Fix Windows line endings 522 | sed -i 's/\r/\n/g' "$conffile" # Fix Mac line endings 523 | fi 524 | 525 | # Add log header 526 | echo "$script $scriptver" > "$logfile" 527 | echo -e "$model DSM $productversion-$buildnumber$smallfix $buildphase\n" >> "$logfile" 528 | echo "Running from: ${scriptpath}/$scriptfile" >> "$logfile" 529 | 530 | 531 | #------------------------------------------------------------------------------ 532 | # Functions 533 | 534 | # shellcheck disable=SC2317,SC2329 # Don't warn about unreachable commands in this function 535 | pause(){ 536 | # When debugging insert pause command where needed 537 | read -s -r -n 1 -p "Press any key to continue..." 538 | read -r -t 0.1 -s -e -- # Silently consume all input 539 | stty echo echok # Ensure read didn't disable echoing user input 540 | echo -e "\n" |& tee -a "$logfile" 541 | } 542 | 543 | # shellcheck disable=SC2317,SC2329 # Don't warn about unreachable commands in this function 544 | debug(){ 545 | if [[ $1 == "on" ]]; then 546 | set -x 547 | export PS4='`[[ $? == 0 ]] || echo "\e[1;31;40m($?)\e[m\n "`LINE $LINENO ' 548 | elif [[ $1 == "off" ]]; then 549 | set +x 550 | fi 551 | } 552 | 553 | progbar(){ 554 | # $1 is pid of process 555 | # $2 is string to echo 556 | string="$2" 557 | local dots 558 | local progress 559 | dots="" 560 | while [[ -d /proc/$1 ]]; do 561 | dots="${dots}." 562 | progress="$dots" 563 | if [[ ${#dots} -gt "10" ]]; then 564 | dots="" 565 | progress=" " 566 | fi 567 | echo -ne " ${2}$progress\r"; /usr/bin/sleep 0.3 568 | done 569 | } 570 | 571 | progstatus(){ 572 | # $1 is return status of process 573 | # $2 is string to echo 574 | # $3 line number function was called from 575 | local tracestring 576 | local pad 577 | tracestring="${FUNCNAME[0]} called from ${FUNCNAME[1]} $3" 578 | pad=$(printf -- ' %.0s' {1..80}) 579 | [ "$trace" == "yes" ] && printf '%.*s' 80 "${tracestring}${pad}" && echo "" 580 | if [[ $1 == "0" ]]; then 581 | echo -e "$2 " 582 | else 583 | ding 584 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} $2 failed!" |& tee -a "$logfile" 585 | echo "$tracestring ($scriptver)" |& tee -a "$logfile" 586 | if [[ $exitonerror != "no" ]]; then 587 | exit 1 # Skip exit if exitonerror != no 588 | fi 589 | fi 590 | exitonerror="" 591 | #echo "return: $1" # debug 592 | } 593 | 594 | package_status(){ 595 | # $1 is package name 596 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 597 | # local code 598 | /usr/syno/bin/synopkg status "${1}" >/dev/null 599 | code="$?" 600 | # DSM 7.2 0 = started, 17 = stopped, 255 = not_installed, 150 = broken 601 | # DSM 6 to 7.1 0 = started, 3 = stopped, 4 = not_installed, 150 = broken 602 | if [[ $code == "0" ]]; then 603 | #echo "$1 is started" # debug 604 | return 0 605 | elif [[ $code == "17" ]] || [[ $code == "3" ]]; then 606 | #echo "$1 is stopped" # debug 607 | return 1 608 | elif [[ $code == "255" ]] || [[ $code == "4" ]]; then 609 | #echo "$1 is not installed" # debug 610 | return 255 611 | elif [[ $code == "150" ]]; then 612 | #echo "$1 is broken" # debug 613 | return 150 614 | else 615 | return "$code" 616 | fi 617 | } 618 | 619 | package_is_running(){ 620 | # $1 is package name 621 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 622 | /usr/syno/bin/synopkg is_onoff "${1}" >/dev/null 623 | code="$?" 624 | return "$code" 625 | } 626 | 627 | wait_status(){ 628 | # Wait for package to finish stopping or starting 629 | # $1 is package 630 | # $2 is start or stop 631 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 632 | local num 633 | if [[ $2 == "start" ]]; then 634 | state="0" 635 | elif [[ $2 == "stop" ]]; then 636 | state="1" 637 | fi 638 | if [[ $state == "0" ]] || [[ $state == "1" ]]; then 639 | num="0" 640 | package_status "$1" 641 | while [[ $? != "$state" ]]; do 642 | sleep 1 643 | num=$((num +1)) 644 | if [[ $num -gt "20" ]]; then 645 | break 646 | fi 647 | package_status "$1" 648 | done 649 | fi 650 | } 651 | 652 | package_stop(){ 653 | # $1 is package name 654 | # $2 is package display name 655 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 656 | if [[ ${#pkgs_sorted[@]} -gt "1" ]]; then 657 | /usr/syno/bin/synopkg stop "$1" >/dev/null & 658 | else 659 | # Only timeout if there are other packages to process 660 | #timeout 5.0m /usr/syno/bin/synopkg stop "$1" >/dev/null & 661 | # Docker can take 12 minutes to stop 70 containers 662 | timeout 30.0m /usr/syno/bin/synopkg stop "$1" >/dev/null & 663 | fi 664 | pid=$! 665 | string="Stopping ${Cyan}${2}${Off}" 666 | echo "Stopping $2" >> "$logfile" 667 | progbar "$pid" "$string" 668 | wait "$pid" 669 | progstatus "$?" "$string" "line ${LINENO}" 670 | 671 | # Allow package processes to finish stopping 672 | #wait_status "$1" stop 673 | wait_status "$1" stop & 674 | pid=$! 675 | string="Waiting for ${Cyan}${2}${Off} to stop" 676 | echo "Waiting for $2 to stop" >> "$logfile" 677 | progbar "$pid" "$string" 678 | wait "$pid" 679 | progstatus "$?" "$string" "line ${LINENO}" 680 | } 681 | 682 | package_start(){ 683 | # $1 is package name 684 | # $2 is package display name 685 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 686 | if [[ ${#pkgs_sorted[@]} -gt "1" ]]; then 687 | /usr/syno/bin/synopkg start "$1" >/dev/null & 688 | else 689 | # Only timeout if there are other packages to process 690 | #timeout 5.0m /usr/syno/bin/synopkg start "$1" >/dev/null & 691 | # Docker can take 15 minutes to start 70 containers 692 | timeout 30.0m /usr/syno/bin/synopkg start "$1" >/dev/null & 693 | fi 694 | pid=$! 695 | string="Starting ${Cyan}${2}${Off}" 696 | echo "Starting $2" >> "$logfile" 697 | progbar "$pid" "$string" 698 | wait "$pid" 699 | progstatus "$?" "$string" "line ${LINENO}" 700 | 701 | # Allow package processes to finish starting 702 | #wait_status "$1" start 703 | wait_status "$1" start & 704 | pid=$! 705 | string="Waiting for ${Cyan}${2}${Off} to start" 706 | echo "Waiting for $2 to start" >> "$logfile" 707 | progbar "$pid" "$string" 708 | wait "$pid" 709 | progstatus "$?" "$string" "line ${LINENO}" 710 | } 711 | 712 | # shellcheck disable=SC2317 # Don't warn about unreachable commands in this function 713 | package_uninstall(){ 714 | # $1 is package name 715 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 716 | /usr/syno/bin/synopkg uninstall "$1" >/dev/null & 717 | pid=$! 718 | string="Uninstalling ${Cyan}${1}${Off}" 719 | echo "Ininstalling $1" >> "$logfile" 720 | progbar "$pid" "$string" 721 | wait "$pid" 722 | progstatus "$?" "$string" "line ${LINENO}" 723 | } 724 | 725 | # shellcheck disable=SC2317 # Don't warn about unreachable commands in this function 726 | package_install(){ 727 | # $1 is package name 728 | # $2 is /volume2 etc 729 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 730 | /usr/syno/bin/synopkg install_from_server "$1" "$2" >/dev/null & 731 | pid=$! 732 | string="Installing ${Cyan}${1}${Off} on ${Cyan}$2${Off}" 733 | echo "Installing $1 on $2" >> "$logfile" 734 | progbar "$pid" "$string" 735 | wait "$pid" 736 | progstatus "$?" "$string" "line ${LINENO}" 737 | } 738 | 739 | is_empty(){ 740 | # $1 is /path/folder 741 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 742 | if [[ -d $1 ]]; then 743 | local contents 744 | contents=$(find "$1" -maxdepth 1 -printf '.') 745 | if [[ ${#contents} -gt 1 ]]; then 746 | return 1 # Not empty 747 | fi 748 | fi 749 | } 750 | 751 | backup_dir(){ 752 | # $1 is folder to backup (@docker etc) 753 | # $2 is volume (/volume1 etc) 754 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 755 | local perms 756 | if [[ -d "$2/$1" ]]; then 757 | 758 | # Make backup folder on $2 759 | if [[ ! -d "${2}/${1}_backup" ]]; then 760 | # Set same permissions as original folder 761 | perms=$(stat -c %a "${2:?}/${1:?}") 762 | if ! mkdir -m "$perms" "${2:?}/${1:?}_backup"; then 763 | ding 764 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to create directory!" 765 | echo -e "Line ${LINENO}: ERROR Failed to create directory!" >> "$logfile" 766 | process_error="yes" 767 | if [[ $all != "yes" ]] || [[ $fix != "yes" ]]; then 768 | exit 1 # Skip exit if mode != all and fix != yes 769 | fi 770 | return 1 771 | fi 772 | fi 773 | 774 | # Backup $1 775 | if ! is_empty "${2:?}/${1:?}_backup"; then 776 | # @docker_backup folder exists and is not empty 777 | echo -e "There is already a backup of $1" |& tee -a "$logfile" 778 | echo -e "Do you want to overwrite it? [y/n]" |& tee -a "$logfile" 779 | read -r answer 780 | echo "$answer" >> "$logfile" 781 | echo "" |& tee -a "$logfile" 782 | if [[ ${answer,,} != "y" ]]; then 783 | return 784 | fi 785 | fi 786 | 787 | cp -prf "${2:?}/${1:?}/." "${2:?}/${1:?}_backup" |& tee -a "$logfile" & 788 | pid=$! 789 | # If string is too long progbar repeats string for each dot 790 | string="Backing up $1 to ${Cyan}${1}_backup${Off}" 791 | echo "Backing up $1 to ${1}_backup" >> "$logfile" 792 | progbar "$pid" "$string" 793 | wait "$pid" 794 | progstatus "$?" "$string" "line ${LINENO}" 795 | fi 796 | } 797 | 798 | cdir(){ 799 | # $1 is path to cd to 800 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 801 | if ! cd "$1"; then 802 | ding 803 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} cd to $1 failed!" 804 | echo -e "Line ${LINENO}: ERROR cd to $1 failed!" >> "$logfile" 805 | process_error="yes" 806 | if [[ $all != "yes" ]] || [[ $fix != "yes" ]]; then 807 | exit 1 # Skip exit if mode != all and fix != yes 808 | fi 809 | return 1 810 | fi 811 | } 812 | 813 | create_dir(){ 814 | # $1 is source /path/folder 815 | # $2 is target /path/folder 816 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 817 | 818 | # Create target folder with source folder's permissions 819 | if [[ ! -d "$2" ]]; then 820 | # Set same permissions as original folder 821 | perms=$(stat -c %a "${1:?}") 822 | if ! mkdir -m "$perms" "${2:?}"; then 823 | ding 824 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to create directory!" 825 | echo -e "Line ${LINENO}: ERROR Failed to create directory!" >> "$logfile" 826 | process_error="yes" 827 | if [[ $all != "yes" ]] || [[ $fix != "yes" ]]; then 828 | exit 1 # Skip exit if mode != all and fix != yes 829 | fi 830 | return 1 831 | fi 832 | fi 833 | } 834 | 835 | move_pkg_do(){ 836 | # $1 is package name 837 | # $2 is destination volume or path 838 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 839 | 840 | # Move package's @app directories 841 | if [[ ${mode,,} == "move" ]]; then 842 | #mv -f "${source:?}" "${2:?}/${appdir:?}" |& tee -a "$logfile" & 843 | #pid=$! 844 | #string="${action} $source to ${Cyan}$2${Off}" 845 | #echo "${action} $source to $2" >> "$logfile" 846 | #progbar "$pid" "$string" 847 | #wait "$pid" 848 | #progstatus "$?" "$string" 849 | 850 | if [[ ! -d "${2:?}/${appdir:?}/${1:?}" ]] ||\ 851 | is_empty "${2:?}/${appdir:?}/${1:?}"; then 852 | 853 | # Move source folder to target folder 854 | if [[ -w "/$sourcevol" ]]; then 855 | mv -f "${source:?}" "${2:?}/${appdir:?}" |& tee -a "$logfile" & 856 | else 857 | # Source volume is read only 858 | cp -prf "${source:?}" "${2:?}/${appdir:?}" |& tee -a "$logfile" & 859 | fi 860 | pid=$! 861 | string="${action} $source to ${Cyan}$2${Off}" 862 | echo "${action} $source to $2" >> "$logfile" 863 | progbar "$pid" "$string" 864 | wait "$pid" 865 | progstatus "$?" "$string" "line ${LINENO}" 866 | else 867 | 868 | # Copy source contents if target folder exists 869 | cp -prf "${source:?}" "${2:?}/${appdir:?}" |& tee -a "$logfile" & 870 | pid=$! 871 | string="Copying $source to ${Cyan}$2${Off}" 872 | echo "Copying $source to $2" >> "$logfile" 873 | progbar "$pid" "$string" 874 | wait "$pid" 875 | progstatus "$?" "$string" "line ${LINENO}" 876 | 877 | #rm -rf "${source:?}" |& tee -a "$logfile" & 878 | rm -r --preserve-root "${source:?}" |& tee -a "$logfile" & 879 | pid=$! 880 | exitonerror="no" 881 | string="Removing $source" 882 | echo "$string" >> "$logfile" 883 | progbar "$pid" "$string" 884 | wait "$pid" 885 | progstatus "$?" "$string" "line ${LINENO}" 886 | fi 887 | else 888 | # if ! is_empty "${destination:?}/${appdir:?}/${1:?}"; then 889 | # echo "Skipping ${action,,} ${appdir}/$1 as target is not empty:" |& tee -a "$logfile" 890 | # echo " ${destination}/${appdir}/$1" |& tee -a "$logfile" 891 | # else 892 | #mv -f "${source:?}" "${2:?}/${appdir:?}" |& tee -a "$logfile" & 893 | #pid=$! 894 | #string="${action} $source to ${Cyan}$2${Off}" 895 | #echo "${action} $source to $2" >> "$logfile" 896 | #progbar "$pid" "$string" 897 | #wait "$pid" 898 | #progstatus "$?" "$string" 899 | exitonerror="no" && move_dir "$appdir" 900 | # fi 901 | fi 902 | } 903 | 904 | edit_symlinks(){ 905 | # $1 is package name 906 | # $2 is destination volume 907 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 908 | 909 | # Edit /var/packages symlinks 910 | case "$appdir" in 911 | @appconf) # etc --> @appconf 912 | rm "/var/packages/${1:?}/etc" |& tee -a "$logfile" 913 | ln -s "${2:?}/@appconf/${1:?}" "/var/packages/${1:?}/etc" |& tee -a "$logfile" 914 | 915 | # /usr/syno/etc/packages/$1 916 | # /volume1/@appconf/$1 917 | if [[ -L "/usr/syno/etc/packages/${1:?}" ]]; then 918 | rm "/usr/syno/etc/packages/${1:?}" |& tee -a "$logfile" 919 | ln -s "${2:?}/@appconf/${1:?}" "/usr/syno/etc/packages/${1:?}" |& tee -a "$logfile" 920 | fi 921 | ;; 922 | @apphome) # home --> @apphome 923 | rm "/var/packages/${1:?}/home" |& tee -a "$logfile" 924 | ln -s "${2:?}/@apphome/${1:?}" "/var/packages/${1:?}/home" |& tee -a "$logfile" 925 | ;; 926 | @appshare) # share --> @appshare 927 | rm "/var/packages/${1:?}/share" |& tee -a "$logfile" 928 | ln -s "${2:?}/@appshare/${1:?}" "/var/packages/${1:?}/share" |& tee -a "$logfile" 929 | ;; 930 | @appstore) # target --> @appstore 931 | rm "/var/packages/${1:?}/target" |& tee -a "$logfile" 932 | ln -s "${2:?}/@appstore/${1:?}" "/var/packages/${1:?}/target" |& tee -a "$logfile" 933 | 934 | # DSM 6 - Some packages have var symlink 935 | if [[ $majorversion -lt 7 ]]; then 936 | if [[ -L "/var/packages/${1:?}/var" ]]; then 937 | rm "/var/packages/${1:?}/var" |& tee -a "$logfile" 938 | ln -s "${2:?}/@appstore/${1:?}/var" "/var/packages/${1:?}/var" |& tee -a "$logfile" 939 | fi 940 | fi 941 | ;; 942 | @apptemp) # tmp --> @apptemp 943 | rm "/var/packages/${1:?}/tmp" |& tee -a "$logfile" 944 | ln -s "${2:?}/@apptemp/${1:?}" "/var/packages/${1:?}/tmp" |& tee -a "$logfile" 945 | ;; 946 | @appdata) # var --> @appdata 947 | rm "/var/packages/${1:?}/var" |& tee -a "$logfile" 948 | ln -s "${2:?}/@appdata/${1:?}" "/var/packages/${1:?}/var" |& tee -a "$logfile" 949 | ;; 950 | *) 951 | echo -e "${Red}Oops!${Off} appdir: ${appdir}\n" 952 | echo -e "Oops! appdir: ${appdir}\n" >> "$logfile" 953 | return 954 | ;; 955 | esac 956 | } 957 | 958 | move_pkg(){ 959 | # $1 is package name 960 | # $2 is destination volume 961 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 962 | local appdir 963 | local perms 964 | local destination 965 | local appdirs_tmp 966 | local app_paths_tmp 967 | if [[ ${mode,,} == "backup" ]]; then 968 | destination="$bkpath" 969 | elif [[ ${mode,,} == "restore" ]]; then 970 | destination="$2" 971 | else 972 | destination="$2" 973 | fi 974 | if [[ $majorversion -gt 6 ]]; then 975 | applist=( "@appconf" "@appdata" "@apphome" "@appshare" "@appstore" "@apptemp" ) 976 | else 977 | applist=( "@appstore" ) 978 | fi 979 | if [[ ${mode,,} == "restore" ]]; then 980 | if ! cdir "$bkpath"; then 981 | process_error="yes" 982 | return 1 983 | fi 984 | sourcevol=$(echo "$bkpath" | cut -d "/" -f2) # var is used later in script 985 | # shellcheck disable=SC1083 986 | while IFS= read -r appdir; do 987 | if [[ "${applist[*]}" =~ "$appdir" ]]; then 988 | appdirs_tmp+=("$appdir") 989 | fi 990 | done < <(find . -name "@app*" -exec basename \{} \;) 991 | 992 | # Sort array 993 | IFS=$'\n' appdirs=($(sort <<<"${appdirs_tmp[*]}")); unset IFS 994 | 995 | if [[ ${#appdirs[@]} -gt 0 ]]; then 996 | for appdir in "${appdirs[@]}"; do 997 | create_dir "/${sourcevol:?}/${appdir:?}" "${destination:?}/${appdir:?}" 998 | move_pkg_do "$1" "$destination" 999 | done 1000 | fi 1001 | else 1002 | if ! cdir /var/packages; then 1003 | process_error="yes" 1004 | return 1 1005 | fi 1006 | # shellcheck disable=SC2162 # `read` without `-r` will mangle backslashes 1007 | while read -r link source; do 1008 | app_paths_tmp+=("$source") 1009 | done < <(find . -maxdepth 2 -type l -ls | grep '/'"${1// /\\\\ }"'$' | cut -d'.' -f2- | sed 's/ ->//') 1010 | 1011 | # Sort array 1012 | IFS=$'\n' app_paths=($(sort <<<"${app_paths_tmp[*]}")); unset IFS 1013 | 1014 | if [[ ${#app_paths[@]} -gt 0 ]]; then 1015 | for source in "${app_paths[@]}"; do 1016 | appdir=$(echo "$source" | cut -d "/" -f3) 1017 | sourcevol=$(echo "$source" | cut -d "/" -f2) # var is used later in script 1018 | if [[ "${applist[*]}" =~ "$appdir" ]]; then 1019 | create_dir "/${sourcevol:?}/${appdir:?}" "${destination:?}/${appdir:?}" 1020 | move_pkg_do "$1" "$2" 1021 | if [[ ${mode,,} == "move" ]]; then 1022 | edit_symlinks "$pkg" "$destination" 1023 | fi 1024 | fi 1025 | done 1026 | fi 1027 | fi 1028 | 1029 | # Backup or restore DSM 6 /usr/syno/etc/packages/$pkg/ 1030 | if [[ $majorversion -lt "7" ]]; then 1031 | copy_dir_dsm6 "$1" "$2" 1032 | fi 1033 | } 1034 | 1035 | set_buffer(){ 1036 | # Set buffer GBs so we don't fill volume 1037 | bufferGB=$(/usr/syno/bin/synogetkeyvalue "$conffile" buffer) 1038 | if [[ $bufferGB -gt "0" ]]; then 1039 | buffer=$((bufferGB *1048576)) 1040 | else 1041 | buffer=0 1042 | fi 1043 | } 1044 | 1045 | folder_size(){ 1046 | # $1 is folder to check size of 1047 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1048 | need="" # var is used later in script 1049 | needed="" # var is used later in script 1050 | if [[ -d "$1" ]]; then 1051 | # Get size of $1 folder 1052 | need=$(/usr/bin/du -s "$1" | awk '{print $1}') 1053 | if [[ ! $need =~ ^[0-9]+$ ]]; then 1054 | echo -e "${Yellow}WARNING${Off} Failed to get size of $1" 1055 | echo -e "WARNING Failed to get size of $1" >> "$logfile" 1056 | need=0 1057 | fi 1058 | # Add buffer GBs so we don't fill volume 1059 | set_buffer 1060 | needed=$((need +buffer)) 1061 | fi 1062 | } 1063 | 1064 | vol_free_space(){ 1065 | # $1 is volume to check free space 1066 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1067 | free="" # var is used later in script 1068 | if [[ -d "$1" ]]; then 1069 | # Get amount of free space on $1 volume 1070 | if [[ $1 =~ ^"/volumeUSB" ]]; then # Issue #63 and #138 1071 | tmp_usb="/$(echo "$1" | cut -d"/" -f2)/usbshare" 1072 | free=$(df --output=avail "$tmp_usb" | grep -A1 Avail | grep -v Avail) 1073 | else 1074 | free=$(df --output=avail "$1" | grep -A1 Avail | grep -v Avail) 1075 | fi 1076 | fi 1077 | } 1078 | 1079 | need_show(){ 1080 | if [[ $need -gt "999999" ]]; then 1081 | size_show="$((need /1048576)) GB" 1082 | elif [[ $need -gt "999" ]]; then 1083 | size_show="$((need /1048)) MB" 1084 | else 1085 | size_show="$need KB" 1086 | fi 1087 | } 1088 | 1089 | check_space(){ 1090 | # $1 is /path/folder 1091 | # $2 is source volume or target volume 1092 | # $3 is 'extra' or null 1093 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1094 | 1095 | # Skip USBCopy and @database 1096 | if [[ $pkg == USBCopy ]] || [[ $pkg == "@database" ]]; then 1097 | return 0 1098 | fi 1099 | 1100 | if [[ $3 == "extra" ]]; then 1101 | # Get size of extra @ folder 1102 | folder_size "$1" 1103 | else 1104 | # Total size of pkg or all pkgs 1105 | need="$all_pkg_size" 1106 | # Add buffer GBs so we don't fill volume 1107 | set_buffer 1108 | needed=$((need +buffer)) 1109 | fi 1110 | 1111 | # Get amount of free space on target volume 1112 | vol_free_space "$2" 1113 | 1114 | # Check we have enough space 1115 | if [[ ! $free -gt $needed ]]; then 1116 | if [[ $all == "yes" ]] && [[ $3 != "extra" ]]; then 1117 | echo -e "${Yellow}WARNING${Off} Not enough space to ${mode,,}"\ 1118 | "${Cyan}All apps${Off} to $targetvol" 1119 | echo -e "WARNING Not enough space to ${mode,,}"\ 1120 | "All apps to $targetvol" >> "$logfile" 1121 | else 1122 | echo -e "${Yellow}WARNING${Off} Not enough space to ${mode,,}"\ 1123 | "/${sourcevol}/${Cyan}$(basename -- "$1")${Off} to $targetvol" 1124 | echo -e "WARNING Not enough space to ${mode,,}"\ 1125 | "/${sourcevol}/$(basename -- "$1") to $targetvol" >> "$logfile" 1126 | fi 1127 | need_show 1128 | echo -en "Free: $((free /1048576)) GB Needed: $size_show" |& tee -a "$logfile" 1129 | if [[ $buffer -gt "0" ]]; then 1130 | echo -e " (plus $bufferGB GB buffer)\n" |& tee -a "$logfile" 1131 | else 1132 | echo -e "\n" |& tee -a "$logfile" 1133 | fi 1134 | return 1 1135 | else 1136 | return 0 1137 | fi 1138 | } 1139 | 1140 | show_move_share(){ 1141 | # $1 is package name 1142 | # $2 is share name 1143 | # $3 is stopped or running 1144 | # $4 is more or null 1145 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1146 | echo -e "\nIf you want to move your $2 shared folder to $targetvol" |& tee -a "$logfile" 1147 | echo -e " While ${Cyan}$1${Off} is ${Cyan}$3${Off}:" 1148 | echo -e " While $1 is $3:" >> "$logfile" 1149 | echo " 1. Go to 'Control Panel > Shared Folders'." |& tee -a "$logfile" 1150 | echo " 2. Select your $2 shared folder and click Edit." |& tee -a "$logfile" 1151 | echo " 3. Change Location to $targetvol" |& tee -a "$logfile" 1152 | echo " 4. Click on Advanced and check that 'Enable data checksums' is selected." |& tee -a "$logfile" 1153 | echo " - 'Enable data checksums' is only available if moving to a Btrfs volume." |& tee -a "$logfile" 1154 | echo " 5. Click Save." |& tee -a "$logfile" 1155 | if [[ $4 == "more" ]]; then 1156 | echo " - If $1 has more shared folders repeat steps 2 to 5." |& tee -a "$logfile" 1157 | fi 1158 | if [[ $3 == "stopped" ]]; then 1159 | echo -e " 6. After step 5 has finished start $1 \n" |& tee -a "$logfile" 1160 | fi 1161 | } 1162 | 1163 | copy_dir_dsm6(){ 1164 | # Backup or restore DSM 6 /usr/syno/etc/packages/$pkg/ 1165 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1166 | # $1 is package name 1167 | # $2 is destination volume 1168 | local pack 1169 | local packshow 1170 | local extras 1171 | pack="/${pkg:?}" 1172 | packshow="${pkg:?}" 1173 | if [[ ${mode,,} == "backup" ]]; then 1174 | if [[ ! -d "${bkpath:?}/etc" ]]; then 1175 | mkdir -m 700 "${bkpath:?}/etc" 1176 | fi 1177 | 1178 | #if ! is_empty "/usr/syno/etc/packages/${1:?}"; then 1179 | # If string is too long progbar gets messed up 1180 | cp -prf "/usr/syno/etc/packages/${1:?}" "${bkpath:?}/etc" |& tee -a "$logfile" & 1181 | pid=$! 1182 | string="${action} /usr/syno/etc/packages/${Cyan}${1}${Off}" 1183 | echo "${action} /usr/syno/etc/packages/${1}" >> "$logfile" 1184 | progbar "$pid" "$string" 1185 | wait "$pid" 1186 | progstatus "$?" "$string" "line ${LINENO}" 1187 | #fi 1188 | elif [[ ${mode,,} == "restore" ]]; then 1189 | #if [[ -d "${bkpath}/$1" ]]; then 1190 | # If string is too long progbar gets messed up 1191 | cp -prf "${bkpath:?}/etc/${1:?}" "/usr/syno/etc/packages" |& tee -a "$logfile" & 1192 | pid=$! 1193 | string="${action} $1 to /usr/syno/etc/packages" 1194 | echo "$string" >> "$logfile" 1195 | progbar "$pid" "$string" 1196 | wait "$pid" 1197 | progstatus "$?" "$string" "line ${LINENO}" 1198 | #fi 1199 | fi 1200 | } 1201 | 1202 | copy_dir(){ 1203 | # Used by package backup and restore 1204 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1205 | # $1 is folder (@surveillance etc) 1206 | # $2 is "extras" or null 1207 | local pack 1208 | local packshow 1209 | local extras 1210 | if [[ $2 == "extras" ]]; then 1211 | #pack="" 1212 | extras="/extras" 1213 | else 1214 | pack="/${pkg:?}" 1215 | packshow="${pkg:?}" 1216 | #extras="" 1217 | fi 1218 | 1219 | if [[ ${mode,,} == "backup" ]]; then 1220 | if [[ $2 == "extras" ]] && [[ ! -d "${bkpath:?}/extras" ]]; then 1221 | mkdir -m 700 "${bkpath:?}/extras" 1222 | fi 1223 | create_dir "/${sourcevol:?}/${1:?}$pack" "${bkpath:?}${extras}/${1:?}" 1224 | #if ! is_empty "/${sourcevol:?}/${1:?}$pack"; then 1225 | if [[ $2 == "extras" ]]; then 1226 | # If string is too long progbar gets messed up 1227 | #cp -prf "/${sourcevol:?}/${1:?}$pack" "${bkpath:?}${extras}" |& tee -a "$logfile" & 1228 | if [[ $1 == "@docker" ]]; then 1229 | excludeargs=( 1230 | "--exclude=subvolumes/*/tmp/" # btfs Issue #120 1231 | "--exclude=subvolumes/*/run/" # btfs Issue #120 1232 | "--exclude=aufs/diff/*/run/" # aufs (ext4) Issue #117 1233 | "--exclude=subvolumes/*/syslog-ng.ctl" # 0 byte file Issue #186 1234 | ) 1235 | rsync -q -aHX --delete --compress-level=0 "${excludeargs[@]}" "/${sourcevol:?}/${1:?}$pack"/ "${bkpath:?}${extras}/${1:?}" |& tee -a "$logfile" & 1236 | else 1237 | rsync -q -aHX --delete --compress-level=0 "/${sourcevol:?}/${1:?}$pack"/ "${bkpath:?}${extras}/${1:?}" |& tee -a "$logfile" & 1238 | fi 1239 | pid=$! 1240 | string="${action} /${sourcevol}/${1}" 1241 | echo "$string" >> "$logfile" 1242 | progbar "$pid" "$string" 1243 | wait "$pid" 1244 | progstatus "$?" "$string" "line ${LINENO}" 1245 | else 1246 | # If string is too long progbar gets messed up 1247 | #cp -prf "/${sourcevol:?}/${1:?}$pack" "${bkpath:?}${extras}/${1:?}" |& tee -a "$logfile" & 1248 | rsync -q -aHX --delete --compress-level=0 "/${sourcevol:?}/${1:?}$pack"/ "${bkpath:?}${extras}/${1:?}" |& tee -a "$logfile" & 1249 | pid=$! 1250 | string="${action} /${sourcevol}/${1}/${Cyan}$pkg${Off}" 1251 | echo "${action} /${sourcevol}/${1}/$pkg" >> "$logfile" 1252 | progbar "$pid" "$string" 1253 | wait "$pid" 1254 | progstatus "$?" "$string" "line ${LINENO}" 1255 | fi 1256 | #fi 1257 | elif [[ ${mode,,} == "restore" ]]; then 1258 | #if [[ -d "${bkpath}/$1" ]]; then 1259 | # If string is too long progbar gets messed up 1260 | cp -prf "${bkpath:?}${extras}/${1:?}" "${targetvol:?}" |& tee -a "$logfile" & 1261 | pid=$! 1262 | if [[ -n "$extras" ]]; then 1263 | string="${action} $1 to $targetvol" 1264 | echo "$string" >> "$logfile" 1265 | else 1266 | string="${action} ${1}/${Cyan}$packshow${Off} to $targetvol" 1267 | echo "${action} ${1}/$packshow to $targetvol" >> "$logfile" 1268 | fi 1269 | progbar "$pid" "$string" 1270 | wait "$pid" 1271 | progstatus "$?" "$string" "line ${LINENO}" 1272 | #fi 1273 | fi 1274 | } 1275 | 1276 | move_dir(){ 1277 | # $1 is folder (@surveillance etc) 1278 | # $2 is "extras" or null 1279 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1280 | 1281 | # Delete @eaDir to prevent errors 1282 | # e.g. "mv: cannot remove '/volume1/@': Operation not permitted" 1283 | if [[ -d "/${sourcevol:?}/${1:?}/@eaDir" ]]; then 1284 | rm -rf "/${sourcevol:?}/${1:?}/@eaDir" |& tee -a "$logfile" 1285 | fi 1286 | 1287 | # Warn if folder is larger than 1GB 1288 | if [[ ! "${applist[*]}" =~ $1 ]]; then 1289 | folder_size "/${sourcevol:?}/$1" 1290 | if [[ $need -gt "1048576" ]]; then 1291 | echo -e "${Red}WARNING $action $1 could take a long time${Off}" 1292 | echo -e "WARNING $action $1 could take a long time" >> "$logfile" 1293 | fi 1294 | fi 1295 | 1296 | if [[ -d "/${sourcevol:?}/${1:?}" ]]; then 1297 | if [[ ${mode,,} == "move" ]]; then 1298 | if [[ ! -d "/${targetvol:?}/${1:?}" ]]; then 1299 | if [[ $1 == "@docker" ]] || [[ $1 == "@img_bkp_cache" ]]; then 1300 | # Create @docker folder on target volume 1301 | create_dir "/${sourcevol:?}/${1:?}" "${targetvol:?}/${1:?}" 1302 | # Move contents of @docker to @docker on target volume 1303 | if [[ -w "/$sourcevol" ]]; then 1304 | mv -f "/${sourcevol:?}/${1:?}"/* "${targetvol:?}/${1:?}" |& tee -a "$logfile" & 1305 | else 1306 | # Source volume is read only 1307 | cp -prf "/${sourcevol:?}/${1:?}"/* "${targetvol:?}/${1:?}" |& tee -a "$logfile" & 1308 | fi 1309 | else 1310 | if [[ -w "/$sourcevol" ]]; then 1311 | mv -f "/${sourcevol:?}/${1:?}" "${targetvol:?}/${1:?}" |& tee -a "$logfile" & 1312 | else 1313 | # Source volume is read only 1314 | cp -prf "/${sourcevol:?}/${1:?}" "${targetvol:?}/${1:?}" |& tee -a "$logfile" & 1315 | fi 1316 | fi 1317 | pid=$! 1318 | string="${action} /${sourcevol}/$1 to ${Cyan}$targetvol${Off}" 1319 | echo "$string" >> "$logfile" 1320 | progbar "$pid" "$string" 1321 | wait "$pid" 1322 | progstatus "$?" "$string" "line ${LINENO}" 1323 | elif ! is_empty "/${sourcevol:?}/${1:?}"; then 1324 | 1325 | # Copy source contents if target folder exists 1326 | cp -prf "/${sourcevol:?}/${1:?}" "${targetvol:?}" |& tee -a "$logfile" & 1327 | pid=$! 1328 | string="Copying /${sourcevol}/$1 to ${Cyan}$targetvol${Off}" 1329 | echo "$string" >> "$logfile" 1330 | progbar "$pid" "$string" 1331 | wait "$pid" 1332 | progstatus "$?" "$string" "line ${LINENO}" 1333 | 1334 | # Delete source folder if empty 1335 | # if [[ $1 != "@docker" ]]; then 1336 | if is_empty "/${sourcevol:?}/${1:?}"; then 1337 | rm -rf --preserve-root "/${sourcevol:?}/${1:?}" |& tee -a "$logfile" & 1338 | pid=$! 1339 | exitonerror="no" 1340 | string="Removing /${sourcevol}/$1" 1341 | echo "$string" >> "$logfile" 1342 | progbar "$pid" "$string" 1343 | wait "$pid" 1344 | progstatus "$?" "$string" "line ${LINENO}" 1345 | fi 1346 | fi 1347 | # fi 1348 | else 1349 | copy_dir "$1" "$2" 1350 | fi 1351 | elif [[ ${mode,,} == "restore" ]]; then 1352 | # Restore from USB backup 1353 | if [[ -d "/${bkpath:?}/${1:?}" ]]; then 1354 | copy_dir "$1" "$2" 1355 | fi 1356 | else 1357 | if [[ ${mode,,} != "restore" ]]; then 1358 | echo -e "No /${sourcevol}/$1 to ${mode,,}" |& tee -a "$logfile" 1359 | else 1360 | echo -e "No ${bkpath}/$1 to ${mode,,}" |& tee -a "$logfile" 1361 | fi 1362 | fi 1363 | } 1364 | 1365 | move_extras(){ 1366 | # $1 is package name 1367 | # $2 is destination /volume 1368 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1369 | local file 1370 | local value 1371 | # Change /volume1 to /volume2 etc 1372 | case "$1" in 1373 | ActiveBackup) 1374 | exitonerror="no" && move_dir "@ActiveBackup" extras 1375 | # /var/packages/ActiveBackup/target/log/ 1376 | if [[ ${mode,,} != "backup" ]]; then 1377 | if ! readlink /var/packages/ActiveBackup/target/log | grep "${2:?}" >/dev/null; then 1378 | rm /var/packages/ActiveBackup/target/log |& tee -a "$logfile" 1379 | ln -s "${2:?}/@ActiveBackup/log" /var/packages/ActiveBackup/target/log |& tee -a "$logfile" 1380 | fi 1381 | file=/var/packages/ActiveBackup/target/etc/setting.conf 1382 | if [[ -f "$file" ]]; then 1383 | echo "{\"conf_repo_volume_path\":\"$2\"}" > "$file" 1384 | fi 1385 | fi 1386 | ;; 1387 | ActiveBackup-GSuite) 1388 | exitonerror="no" && move_dir "@ActiveBackup-GSuite" extras 1389 | ;; 1390 | ActiveBackup-Office365) 1391 | exitonerror="no" && move_dir "@ActiveBackup-Office365" extras 1392 | ;; 1393 | AntiVirus) 1394 | exitonerror="no" && move_dir "@quarantine" extras 1395 | if [[ -d "$sourcevol/.quarantine" ]]; then 1396 | exitonerror="no" && move_dir ".quarantine" extras 1397 | fi 1398 | ;; 1399 | Chat) 1400 | if [[ ${mode,,} == "move" ]]; then 1401 | echo -e "Are you going to move the ${Cyan}chat${Off} shared folder to ${Cyan}${targetvol}${Off}? [y/n]" 1402 | echo -e "Are you going to move the chat shared folder to ${targetvol}? [y/n]" >> "$logfile" 1403 | read -r answer 1404 | echo "$answer" >> "$logfile" 1405 | echo "" |& tee -a "$logfile" 1406 | if [[ ${answer,,} == y ]]; then 1407 | # /var/packages/Chat/shares/chat --> /volume1/chat 1408 | rm "/var/packages/${1:?}/shares/chat" |& tee -a "$logfile" 1409 | ln -s "${2:?}/chat" "/var/packages/${1:?}shares/chat" |& tee -a "$logfile" 1410 | # /var/packages/Chat/target/synochat --> /volume1/chat/@ChatWorking 1411 | rm "/var/packages/${1:?}/target/synochat" |& tee -a "$logfile" 1412 | ln -s "${2:?}/chat/@ChatWorking" "/var/packages/${1:?}target/synochat" |& tee -a "$logfile" 1413 | fi 1414 | fi 1415 | ;; 1416 | Calendar) 1417 | exitonerror="no" && move_dir "@calendar" extras 1418 | if [[ -d "/@synocalendar" ]]; then 1419 | exitonerror="no" && move_dir "$sourcevol/@synocalendar" extras 1420 | fi 1421 | file="/var/packages/Calendar/etc/share_link.json" 1422 | if [[ -f "$file" ]]; then 1423 | if grep "$sourcevol/@calendar/attach" "$file" >/dev/null; then 1424 | instring="/$sourcevol/@calendar/attach" 1425 | repstring="$2/@calendar/attach" 1426 | sed -i 's|'"$instring"'|'"$repstring"'|g' "$file" |& tee -a "$logfile" 1427 | chmod 600 "$file" |& tee -a "$logfile" 1428 | fi 1429 | fi 1430 | ;; 1431 | ContainerManager|Docker) 1432 | 1433 | # /var/services/web_packages/docker ??? 1434 | 1435 | # Edit symlink before moving @docker 1436 | # If edit after it does not get edited if move @docker errors 1437 | if [[ ${mode,,} != "backup" ]]; then 1438 | if [[ $majorversion -gt "6" ]]; then 1439 | # /var/packages/ContainerManager/var/docker/ --> /volume1/@docker 1440 | # /var/packages/Docker/var/docker/ --> /volume1/@docker 1441 | if [[ -L "/var/packages/${pkg:?}/var/docker" ]]; then 1442 | rm "/var/packages/${pkg:?}/var/docker" |& tee -a "$logfile" 1443 | fi 1444 | ln -s "${2:?}/@docker" "/var/packages/${pkg:?}/var/docker" |& tee -a "$logfile" 1445 | else 1446 | # /var/packages/Docker/target/docker/ --> /volume1/@docker 1447 | if [[ -L "/var/packages/${pkg:?}/target/docker" ]]; then 1448 | rm "/var/packages/${pkg:?}/target/docker" |& tee -a "$logfile" 1449 | fi 1450 | ln -s "${2:?}/@docker" "/var/packages/${pkg:?}/target/docker" |& tee -a "$logfile" 1451 | fi 1452 | fi 1453 | exitonerror="no" && move_dir "@docker" extras 1454 | ;; 1455 | DownloadStation) 1456 | exitonerror="no" && move_dir "@download" extras 1457 | ;; 1458 | GlacierBackup) 1459 | exitonerror="no" && move_dir "@GlacierBackup" extras 1460 | if [[ ${mode,,} != "backup" ]]; then 1461 | file=/var/packages/GlacierBackup/etc/common.conf 1462 | if [[ -f "$file" ]]; then 1463 | echo "cache_volume=$2" > "$file" 1464 | fi 1465 | fi 1466 | ;; 1467 | HyperBackup) 1468 | # Most of this section is not needed for moving HyperBackup. 1469 | # I left it here in case I can use it for some other package in future. 1470 | 1471 | # Moving "@img_bkp_cache" and editing synobackup.conf 1472 | # to point the repos to the new location causes backup tasks 1473 | # to show as offline with no way to fix them or delete them! 1474 | # 1475 | # Thankfully HyperBackup recreates the data in @img_bkp_cache 1476 | # when the backup task is run, or a resync is done. 1477 | 1478 | # file=/var/packages/HyperBackup/etc/synobackup.conf 1479 | # [repo_1] 1480 | # client_cache="/volume1/@img_bkp_cache/ClientCache_image_image_local.oJCDvd" 1481 | # if [[ -f "$file" ]]; then 1482 | 1483 | # Get list of [repo_#] in $file 1484 | # readarray -t contents < "$file" 1485 | # for r in "${contents[@]}"; do 1486 | # l=$(echo "$r" | grep -E "repo_[0-9]+") 1487 | # if [[ -n "$l" ]]; then 1488 | # l="${l/]/}" && l="${l/[/}" 1489 | # repos+=("$l") 1490 | # fi 1491 | # done 1492 | 1493 | # Edit values with sourcevol to targetvol 1494 | # for section in "${repos[@]}"; do 1495 | # value="$(/usr/syno/bin/get_section_key_value "$file" "$section" client_cache)" 1496 | # #echo "$value" # debug 1497 | # if echo "$value" | grep "$sourcevol" >/dev/null; then 1498 | # newvalue="${value/$sourcevol/$targetvol}" 1499 | #echo "$newvalue" # debug 1500 | #echo "" # debug 1501 | # /usr/syno/bin/set_section_key_value "$file" "$section" client_cache "$newvalue" 1502 | #echo "set_section_key_value $file $section client_cache $newvalue" # debug 1503 | #echo "" # debug 1504 | #echo "" # debug 1505 | # fi 1506 | # done 1507 | # fi 1508 | 1509 | # Move @img_bkp folders 1510 | #if [[ -d "/${sourcevol}/@img_bkp_cache" ]] ||\ 1511 | # [[ -d "/${sourcevol}/@img_bkp_mount" ]]; then 1512 | # backup_dir "@img_bkp_cache" "$sourcevol" 1513 | # backup_dir "@img_bkp_mount" "$sourcevol" 1514 | 1515 | # exitonerror="no" && move_dir "@img_bkp_cache" 1516 | # exitonerror="no" && move_dir "@img_bkp_mount" 1517 | #fi 1518 | if [[ -d "/${sourcevol}/@img_bkp_cache" ]]; then 1519 | #backup_dir "@img_bkp_cache" "$sourcevol" 1520 | exitonerror="no" && move_dir "@img_bkp_cache" extras 1521 | fi 1522 | ;; 1523 | 1524 | jellyfin) 1525 | if [[ ${mode,,} != "backup" ]]; then 1526 | file=/var/packages/jellyfin/var/config/system.xml # Issue #171 1527 | if [[ -f "$file" ]]; then 1528 | sed -i 's|'"/$sourcevol/@appdata"'|'"${2:?}/@appdata"'|g' "$file" 1529 | fi 1530 | fi 1531 | ;; 1532 | 1533 | MailPlus-Server) 1534 | # Moving MailPlus-Server does not update 1535 | # /var/packages/MailPlus-Server/etc/synopkg_conf/reg_volume 1536 | # I'm not sure if it matters? 1537 | 1538 | if [[ ${mode,,} != "backup" ]]; then 1539 | # Edit symlink /var/spool/@MailPlus-Server -> /volume1/@MailPlus-Server 1540 | if ! readlink /var/spool/@MailPlus-Server | grep "${2:?}" >/dev/null; then 1541 | rm /var/spool/@MailPlus-Server |& tee -a "$logfile" 1542 | ln -s "${2:?}/@MailPlus-Server" /var/spool/@MailPlus-Server |& tee -a "$logfile" 1543 | chown -h MailPlus-Server:MailPlus-Server /var/spool/@MailPlus-Server |& tee -a "$logfile" 1544 | fi 1545 | # Edit logfile /volume1/@maillog/rspamd_redis.log 1546 | # in /volume2/@MailPlus-Server/rspamd/redis/redis.conf 1547 | file="/$sourcevol/@MailPlus-Server/rspamd/redis/redis.conf" 1548 | if [[ -f "$file" ]]; then 1549 | if grep "$sourcevol" "$file" >/dev/null; then 1550 | sed -i 's|'"logfile /$sourcevol"'|'"logfile ${2:?}"'|g' "$file" |& tee -a "$logfile" 1551 | chmod 600 "$file" |& tee -a "$logfile" 1552 | fi 1553 | fi 1554 | fi 1555 | exitonerror="no" && move_dir "@maillog" extras 1556 | exitonerror="no" && move_dir "@MailPlus-Server" extras 1557 | ;; 1558 | MailServer) 1559 | exitonerror="no" && move_dir "@maillog" extras 1560 | exitonerror="no" && move_dir "@MailScanner" extras 1561 | exitonerror="no" && move_dir "@clamav" extras 1562 | ;; 1563 | Node.js_v*) 1564 | if [[ ${mode,,} != "backup" ]]; then 1565 | if readlink /usr/local/bin/node | grep "${1:?}" >/dev/null; then 1566 | rm /usr/local/bin/node |& tee -a "$logfile" 1567 | ln -s "${2:?}/@appstore/${1:?}/usr/local/bin/node" /usr/local/bin/node |& tee -a "$logfile" 1568 | fi 1569 | for n in /usr/local/node/nvm/versions/* ; do 1570 | if readlink "${n:?}/bin/node" | grep "${1:?}" >/dev/null; then 1571 | rm "${n:?}/bin/node" |& tee -a "$logfile" 1572 | ln -s "${2:?}/@appstore/${1:?}/usr/local/bin/node" "${n:?}/bin/node" |& tee -a "$logfile" 1573 | fi 1574 | done 1575 | fi 1576 | ;; 1577 | PrestoServer) 1578 | exitonerror="no" && move_dir "@presto" extras 1579 | if [[ ${mode,,} != "backup" ]]; then 1580 | file=/var/packages/PrestoServer/etc/db-path.conf 1581 | if [[ -f "$file" ]]; then 1582 | echo "db-vol=${2:?}" > "$file" 1583 | fi 1584 | fi 1585 | ;; 1586 | SurveillanceStation) 1587 | exitonerror="no" && move_dir "@ssbackup" extras 1588 | exitonerror="no" && move_dir "@surveillance" extras 1589 | if [[ ${mode,,} != "backup" ]]; then 1590 | file=/var/packages/SurveillanceStation/etc/settings.conf 1591 | if [[ -f "$file" ]]; then 1592 | /usr/syno/bin/synosetkeyvalue "$file" active_volume "${2:?}" |& tee -a "$logfile" 1593 | file=/var/packages/SurveillanceStation/target/@surveillance 1594 | rm "$file" |& tee -a "$logfile" 1595 | ln -s "${2:?}/@surveillance" /var/packages/SurveillanceStation/target |& tee -a "$logfile" 1596 | chown -h SurveillanceStation:SurveillanceStation "$file" |& tee -a "$logfile" 1597 | fi 1598 | fi 1599 | ;; 1600 | synocli*) 1601 | #exitonerror="no" && move_dir "@$1" 1602 | ;; 1603 | SynologyApplicationService) 1604 | exitonerror="no" && move_dir "@SynologyApplicationService" extras 1605 | if [[ ${mode,,} != "backup" ]]; then 1606 | file=/var/packages/SynologyApplicationService/etc/settings.conf 1607 | if [[ -f "$file" ]]; then 1608 | /usr/syno/bin/synosetkeyvalue "$file" volume "${2:?}/@SynologyApplicationService" |& tee -a "$logfile" 1609 | fi 1610 | fi 1611 | ;; 1612 | SynologyDrive) 1613 | # Synology Drive database 1614 | # Moving the database in Synology Drive Admin moves @synologydrive 1615 | #exitonerror="no" && move_dir "@synologydrive" extras 1616 | 1617 | # Synology Drive ShareSync Folder 1618 | exitonerror="no" && move_dir "@SynologyDriveShareSync" extras 1619 | if [[ ${mode,,} != "backup" ]]; then 1620 | file=/var/packages/SynologyDrive/etc/sharesync/daemon.conf 1621 | if [[ -f "$file" ]]; then 1622 | sed -i 's|'/"$sourcevol"'|'"${2:?}"'|g' "$file" |& tee -a "$logfile" 1623 | chmod 644 "$file" |& tee -a "$logfile" 1624 | fi 1625 | 1626 | file=/var/packages/SynologyDrive/etc/sharesync/monitor.conf 1627 | if [[ -f "$file" ]]; then 1628 | value="$(synogetkeyvalue "$file" system_db_path)" 1629 | if [[ -n $value ]]; then 1630 | /usr/syno/bin/synosetkeyvalue "$file" system_db_path "${value/${sourcevol}/$(basename "${2:?}")}" |& tee -a "$logfile" 1631 | fi 1632 | fi 1633 | 1634 | file=/var/packages/SynologyDrive/etc/sharesync/service.conf 1635 | if [[ -f "$file" ]]; then 1636 | /usr/syno/bin/synosetkeyvalue "$file" volume "${2:?}" |& tee -a "$logfile" 1637 | fi 1638 | 1639 | # Moving the database in Synology Drive Admin changes 1640 | # the repo symlink and the db-vol setting 1641 | # in /var/packages/SynologyDrive/etc/db-path.conf 1642 | #if ! readlink /var/packages/SynologyDrive/etc/repo | grep "${2:?}" >/dev/null; then 1643 | # rm /var/packages/SynologyDrive/etc/repo |& tee -a "$logfile" 1644 | # ln -s "${2:?}/@synologydrive/@sync" /var/packages/SynologyDrive/etc/repo |& tee -a "$logfile" 1645 | #fi 1646 | fi 1647 | ;; 1648 | WebDAVServer) 1649 | exitonerror="no" && move_dir "@webdav" extras 1650 | ;; 1651 | Virtualization) 1652 | exitonerror="no" && move_dir "@GuestImage" extras 1653 | exitonerror="no" && move_dir "@Repository" extras 1654 | 1655 | # Move Virtual Machines - target must be btrfs 1656 | #exitonerror="no" && move_dir "@iSCSI" extras 1657 | 1658 | # VMM creates /volume#/vdsm_repo.conf so no need to move it 1659 | ;; 1660 | *) 1661 | return 1662 | ;; 1663 | esac 1664 | } 1665 | 1666 | web_packages(){ 1667 | # $1 is pkg in lower case 1668 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1669 | if [[ $buildnumber -gt "64570" ]]; then 1670 | # DSM 7.2.1 and later 1671 | # synoshare --get-real-path is case insensitive 1672 | web_pkg_path=$(/usr/syno/sbin/synoshare --get-real-path web_packages) 1673 | else 1674 | # DSM 7.2 and earlier 1675 | # synoshare --getmap is case insensitive 1676 | web_pkg_path=$(/usr/syno/sbin/synoshare --getmap web_packages | grep volume | cut -d"[" -f2 | cut -d"]" -f1) 1677 | # I could also have used: 1678 | # web_pkg_path=$(/usr/syno/sbin/synoshare --get web_packages | tr '[]' '\n' | sed -n "9p") 1679 | fi 1680 | if [[ -d "$web_pkg_path" ]]; then 1681 | if [[ -n "${pkg:?}" ]] && [[ -d "$web_pkg_path/${pkg,,}" ]]; then 1682 | if [[ ${mode,,} == "backup" ]]; then 1683 | if [[ ! -d "${bkpath}/web_packages" ]]; then 1684 | mkdir -m 755 "${bkpath:?}/web_packages" 1685 | fi 1686 | if [[ -d "${bkpath}/web_packages" ]]; then 1687 | # If string is too long progbar gets messed up 1688 | cp -prf "${web_pkg_path:?}/${1:?}" "${bkpath:?}/web_packages" |& tee -a "$logfile" & 1689 | pid=$! 1690 | string="${action} $web_pkg_path/${pkg,,}" 1691 | echo "$string" >> "$logfile" 1692 | progbar "$pid" "$string" 1693 | wait "$pid" 1694 | progstatus "$?" "$string" "line ${LINENO}" 1695 | else 1696 | ding 1697 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to create directory!" 1698 | echo -e "Line ${LINENO}: ERROR Failed to create directory!" >> "$logfile" 1699 | echo -e " ${bkpath:?}/web_packages\n" |& tee -a "$logfile" 1700 | fi 1701 | elif [[ ${mode,,} == "restore" ]]; then 1702 | if [[ -d "${bkpath}/web_packages/${1}" ]]; then 1703 | # If string is too long progbar gets messed up 1704 | cp -prf "${bkpath:?}/web_packages/${1:?}" "${web_pkg_path:?}" |& tee -a "$logfile" & 1705 | pid=$! 1706 | string="${action} $web_pkg_path/${pkg,,}" 1707 | echo "$string" >> "$logfile" 1708 | progbar "$pid" "$string" 1709 | wait "$pid" 1710 | progstatus "$?" "$string" "line ${LINENO}" 1711 | fi 1712 | fi 1713 | fi 1714 | fi 1715 | } 1716 | 1717 | check_pkg_installed(){ 1718 | # Check if package is installed 1719 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1720 | 1721 | # $1 is package 1722 | # $2 is package name 1723 | /usr/syno/bin/synopkg status "${1:?}" >/dev/null 1724 | code="$?" 1725 | if [[ $code == "255" ]] || [[ $code == "4" ]]; then 1726 | ding 1727 | echo -e "${Error}ERROR${Off} ${Cyan}${2}${Off} is not installed!" 1728 | echo -e "ERROR ${2} is not installed!" >> "$logfile" 1729 | echo -e "Install ${Cyan}${2}${Off} then try Restore again" 1730 | echo -e "Install ${2} then try Restore again" >> "$logfile" 1731 | process_error="yes" 1732 | if [[ $all != "yes" ]]; then 1733 | exit 1 # Skip exit if mode is All 1734 | fi 1735 | return 1 1736 | else 1737 | return 0 1738 | fi 1739 | } 1740 | 1741 | check_pkg_versions_match(){ 1742 | # $1 is installed package version 1743 | # $2 is backed up package version 1744 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1745 | if [[ $1 != "$2" ]]; then 1746 | ding 1747 | echo -e "${Yellow}Backup and installed package versions don't match!${Off}" 1748 | echo -e "Backup and installed package versions don't match!" >> "$logfile" 1749 | echo " Backed up version: $2" |& tee -a "$logfile" 1750 | echo " Installed version: $1" |& tee -a "$logfile" 1751 | echo "Do you want to continue restoring ${pkg_name}? [y/n]" |& tee -a "$logfile" 1752 | read -r reply 1753 | if [[ ${reply,,} != "y" ]]; then 1754 | exit # Answered no 1755 | else 1756 | echo "" |& tee -a "$logfile" 1757 | fi 1758 | fi 1759 | } 1760 | 1761 | skip_dev_tools(){ 1762 | # $1 is $pkg 1763 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1764 | local skip1 1765 | local skip2 1766 | if [[ ${mode,,} == "backup" ]]; then 1767 | skip1="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" startable)" 1768 | skip2="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" ctl_stop)" 1769 | elif [[ ${mode,,} == "restore" ]]; then 1770 | skip1="$(/usr/syno/bin/synogetkeyvalue "${backuppath}/syno_app_mover/${package}/INFO" startable)" 1771 | skip2="$(/usr/syno/bin/synogetkeyvalue "${backuppath}/syno_app_mover/${package}/INFO" ctl_stop)" 1772 | fi 1773 | if [[ $skip1 == "no" ]] || [[ $skip2 == "no" ]]; then 1774 | return 0 1775 | else 1776 | return 1 1777 | fi 1778 | } 1779 | 1780 | prune_dangling(){ 1781 | if [[ $pkg == "ContainerManager" ]] || [[ $pkg == "Docker" ]]; then 1782 | if [[ -w "/$sourcevol" ]]; then 1783 | # Start package if needed so we can prune images 1784 | if ! package_is_running "$pkg"; then 1785 | package_start "$pkg" "$pkg_name" 1786 | fi 1787 | 1788 | if [[ ${mode,,} == "restore" ]]; then 1789 | # Remove dangling and unused images 1790 | echo "Removing dangling and unused docker images" |& tee -a "$logfile" 1791 | docker image prune --all --force >/dev/null 1792 | else 1793 | # Remove dangling images 1794 | echo "Removing dangling docker images" |& tee -a "$logfile" 1795 | docker image prune --force >/dev/null 1796 | fi 1797 | else 1798 | # Skip read only source volume 1799 | echo "/$sourcevol is read only. Skipping:" |& tee -a "$logfile" 1800 | echo " - Removing dangling and unused docker images" |& tee -a "$logfile" 1801 | fi 1802 | fi 1803 | } 1804 | 1805 | check_pkg_size(){ 1806 | # $1 is package name 1807 | # $2 is package source volume 1808 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 1809 | if [[ $pkg == "@database" ]]; then 1810 | size=$(/usr/bin/du -s /var/services/pgsql/ | awk '{print $1}') 1811 | else 1812 | #size=$(/usr/bin/du -sL /var/packages/"$1"/target | awk '{print $1}') 1813 | size=$(/usr/bin/du -s /var/packages/"$1"/target/ | awk '{print $1}') 1814 | case "$1" in 1815 | ActiveBackup) 1816 | if [[ -d "/$sourcevol/@ActiveBackup" ]]; then 1817 | size2=$(/usr/bin/du -s /"$sourcevol"/@ActiveBackup | awk '{print $1}') 1818 | size=$((size +"$size2")) 1819 | fi 1820 | ;; 1821 | ActiveBackup-GSuite) 1822 | if [[ -d "/$sourcevol/@ActiveBackup-GSuite" ]]; then 1823 | size2=$(/usr/bin/du -s /"$sourcevol"/@ActiveBackup-GSuite | awk '{print $1}') 1824 | size=$((size +"$size2")) 1825 | fi 1826 | ;; 1827 | ActiveBackup-Office365) 1828 | if [[ -d "/$sourcevol/@ActiveBackup-Office365" ]]; then 1829 | size2=$(/usr/bin/du -s /"$sourcevol"/@ActiveBackup-Office365 | awk '{print $1}') 1830 | size=$((size +"$size2")) 1831 | fi 1832 | ;; 1833 | Calendar) 1834 | if [[ -d "/$sourcevol/@calendar" ]]; then 1835 | size2=$(/usr/bin/du -s /"$sourcevol"/@calendar | awk '{print $1}') 1836 | size=$((size +"$size2")) 1837 | fi 1838 | ;; 1839 | ContainerManager|Docker) 1840 | prune_dangling # Prune dangling docker images 1841 | if [[ -d "/$sourcevol/@docker" ]]; then 1842 | size2=$(/usr/bin/du -s /"$sourcevol"/@docker | awk '{print $1}') 1843 | size=$((size +"$size2")) 1844 | fi 1845 | ;; 1846 | DownloadStation) 1847 | if [[ -d "/$sourcevol/@download" ]]; then 1848 | size2=$(/usr/bin/du -s /"$sourcevol"/@download | awk '{print $1}') 1849 | size=$((size +"$size2")) 1850 | fi 1851 | ;; 1852 | GlacierBackup) 1853 | if [[ -d "/$sourcevol/@GlacierBackup" ]]; then 1854 | size2=$(/usr/bin/du -s /"$sourcevol"/@GlacierBackup | awk '{print $1}') 1855 | size=$((size +"$size2")) 1856 | fi 1857 | ;; 1858 | HyperBackup) 1859 | if [[ -d "/$sourcevol/@img_bkp_cache" ]]; then 1860 | size2=$(/usr/bin/du -s /"$sourcevol"/@img_bkp_cache | awk '{print $1}') 1861 | size=$((size +"$size2")) 1862 | fi 1863 | ;; 1864 | MailPlus-Server) 1865 | if [[ -d "/$sourcevol/@maillog" ]]; then 1866 | size2=$(/usr/bin/du -s /"$sourcevol"/@maillog | awk '{print $1}') 1867 | size=$((size +"$size2")) 1868 | fi 1869 | if [[ -d "/$sourcevol/@MailPlus-Server" ]]; then 1870 | size2=$(/usr/bin/du -s /"$sourcevol"/@MailPlus-Server | awk '{print $1}') 1871 | size=$((size +"$size2")) 1872 | fi 1873 | ;; 1874 | MailServer) 1875 | if [[ -d "/$sourcevol/@maillog" ]]; then 1876 | size2=$(/usr/bin/du -s /"$sourcevol"/@maillog | awk '{print $1}') 1877 | size=$((size +"$size2")) 1878 | fi 1879 | if [[ -d "/$sourcevol/@MailScanner" ]]; then 1880 | size2=$(/usr/bin/du -s /"$sourcevol"/@MailScanner | awk '{print $1}') 1881 | size=$((size +"$size2")) 1882 | fi 1883 | if [[ -d "/$sourcevol/@clamav" ]]; then 1884 | size2=$(/usr/bin/du -s /"$sourcevol"/@clamav | awk '{print $1}') 1885 | size=$((size +"$size2")) 1886 | fi 1887 | ;; 1888 | PrestoServer) 1889 | if [[ -d "/$sourcevol/@presto" ]]; then 1890 | size2=$(/usr/bin/du -s /"$sourcevol"/@presto | awk '{print $1}') 1891 | size=$((size +"$size2")) 1892 | fi 1893 | ;; 1894 | SurveillanceStation) 1895 | if [[ -d "/$sourcevol/@ssbackup" ]]; then 1896 | size2=$(/usr/bin/du -s /"$sourcevol"/@ssbackup | awk '{print $1}') 1897 | size=$((size +"$size2")) 1898 | fi 1899 | if [[ -d "/$sourcevol/@surveillance" ]]; then 1900 | size2=$(/usr/bin/du -s /"$sourcevol"/@surveillance | awk '{print $1}') 1901 | size=$((size +"$size2")) 1902 | fi 1903 | ;; 1904 | SynologyApplicationService) 1905 | if [[ -d "/$sourcevol/@SynologyApplicationService" ]]; then 1906 | size2=$(/usr/bin/du -s /"$sourcevol"/@SynologyApplicationService | awk '{print $1}') 1907 | size=$((size +"$size2")) 1908 | fi 1909 | ;; 1910 | SynologyDrive) 1911 | # Moving the database in Synology Drive Admin moves @synologydrive 1912 | #if [[ -d "/$sourcevol/@synologydrive" ]]; then 1913 | # size2=$(/usr/bin/du -s /"$sourcevol"/@synologydrive | awk '{print $1}') 1914 | # size=$((size +"$size2")) 1915 | #fi 1916 | if [[ -d "/$sourcevol/@SynologyDriveShareSync" ]]; then 1917 | size2=$(/usr/bin/du -s /"$sourcevol"/@SynologyDriveShareSync | awk '{print $1}') 1918 | size=$((size +"$size2")) 1919 | fi 1920 | ;; 1921 | WebDAVServer) 1922 | if [[ -d "/$sourcevol/@webdav" ]]; then 1923 | size2=$(/usr/bin/du -s /"$sourcevol"/@webdav | awk '{print $1}') 1924 | size=$((size +"$size2")) 1925 | fi 1926 | ;; 1927 | Virtualization) 1928 | if [[ -d "/$sourcevol/@GuestImage" ]]; then 1929 | size2=$(/usr/bin/du -s /"$sourcevol"/@GuestImage | awk '{print $1}') 1930 | size=$((size +"$size2")) 1931 | fi 1932 | if [[ -d "/$sourcevol/@Repository" ]]; then 1933 | size2=$(/usr/bin/du -s /"$sourcevol"/@Repository | awk '{print $1}') 1934 | size=$((size +"$size2")) 1935 | fi 1936 | ;; 1937 | *) 1938 | total_size="$size" 1939 | return 1940 | ;; 1941 | esac 1942 | fi 1943 | total_size="$size" 1944 | } 1945 | 1946 | source_fs(){ 1947 | # $1 is $sourcevol 1948 | sourcefs="$(df --print-type "/${1:?}" | tail -n +2 | awk '{print $2}')" 1949 | } 1950 | 1951 | target_fs(){ 1952 | # $1 is $targetvol 1953 | targetfs="$(df --print-type "/${1:?}" | tail -n +2 | awk '{print $2}')" 1954 | } 1955 | 1956 | 1957 | #------------------------------------------------------------------------------ 1958 | # Select mode 1959 | 1960 | echo "" |& tee -a "$logfile" 1961 | if [[ $auto == "yes" ]]; then 1962 | echo -e "Using auto ${Cyan}${mode}${Off} mode\n" 1963 | echo -e "Using auto $mode mode\n" >> tee -a "$logfile" 1964 | else 1965 | modes=( "Move" "Backup" "Restore" ) 1966 | x="1" 1967 | for m in "${modes[@]}"; do 1968 | echo "$x) $m" >> "$logfile" 1969 | x=$((x +1)) 1970 | done 1971 | 1972 | echo "Select the mode " >> "$logfile" 1973 | PS3="Select the mode: " 1974 | select m in "${modes[@]}"; do 1975 | case "$m" in 1976 | Move) 1977 | mode="Move" 1978 | action="Moving" 1979 | break 1980 | ;; 1981 | Backup) 1982 | mode="Backup" 1983 | action="Backing up" 1984 | break 1985 | ;; 1986 | Restore) 1987 | mode="Restore" 1988 | action="Restoring" 1989 | break 1990 | ;; 1991 | *) 1992 | echo "Invalid choice!" |& tee -a "$logfile" 1993 | ;; 1994 | esac 1995 | done 1996 | echo -e "You selected ${Cyan}${mode}${Off}\n" 1997 | echo -e "You selected ${mode}\n" >> "$logfile" 1998 | fi 1999 | 2000 | 2001 | # Check backup path if mode is backup or restore 2002 | if [[ ${mode,,} != "move" ]]; then 2003 | if [[ ! -f "$conffile" ]]; then 2004 | ding 2005 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} $conffile not found!" 2006 | echo -e "Line ${LINENO}: ERROR $conffile not found!" >> "$logfile" 2007 | exit 1 # Conf file not found 2008 | fi 2009 | if [[ ! -r "$conffile" ]]; then 2010 | ding 2011 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} $conffile not readable!" 2012 | echo -e "Line ${LINENO}: ERROR $conffile not readable!" >> "$logfile" 2013 | exit 1 # Conf file not readable 2014 | fi 2015 | 2016 | # Get and validate backup path 2017 | backuppath="$(/usr/syno/bin/synogetkeyvalue "$conffile" backuppath)" 2018 | if [[ -z "$backuppath" ]]; then 2019 | ding 2020 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} backuppath missing from ${conffile}!" 2021 | echo -e "Line ${LINENO}: ERROR backuppath missing from ${conffile}!" >> "$logfile" 2022 | exit 1 # Backup path missing in conf file 2023 | elif [[ ! -d "$backuppath" ]]; then 2024 | ding 2025 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Backup folder ${Cyan}$backuppath${Off} not found!" 2026 | echo -e "Line ${LINENO}: ERROR Backup folder $backuppath not found!" >> "$logfile" 2027 | exit 1 # Backup folder not found 2028 | fi 2029 | 2030 | # Get list of excluded packages 2031 | exclude="$(/usr/syno/bin/synogetkeyvalue "$conffile" exclude)" 2032 | if [[ $exclude ]]; then 2033 | IFS=',' read -r -a excludes <<< "$exclude"; unset IFS 2034 | # Trim leading and trailing spaces 2035 | for i in "${excludes[@]}"; do 2036 | excludelist+=($(echo -n "$i" | xargs)) 2037 | done 2038 | fi 2039 | 2040 | # Get age of container settings exports to delete 2041 | delete_older="$(/usr/syno/bin/synogetkeyvalue "$conffile" delete_older)" 2042 | 2043 | # Get list of ignored containers 2044 | ignored_containers="$(/usr/syno/bin/synogetkeyvalue "$conffile" ignored_containers)" 2045 | if [[ $ignored_containers ]]; then 2046 | IFS=',' read -r -a ignoreds <<< "$ignored_containers"; unset IFS 2047 | # Trim leading and trailing spaces 2048 | for i in "${ignoreds[@]}"; do 2049 | ignored_containers_list+=($(echo -n "$i" | xargs)) 2050 | done 2051 | fi 2052 | fi 2053 | if [[ ${mode,,} == "backup" ]]; then 2054 | echo -e "Backup path is: ${Cyan}${backuppath}${Off}\n" 2055 | echo -e "Backup path is: ${backuppath}\n" >> "$logfile" 2056 | elif [[ ${mode,,} == "restore" ]]; then 2057 | echo -e "Restore from path is: ${Cyan}${backuppath}${Off}\n" 2058 | echo -e "Restore from path is: ${backuppath}\n" >> "$logfile" 2059 | fi 2060 | 2061 | # Check USB backup path file system is ext3, ext4 or btrfs if mode is backup 2062 | backupvol="$(echo "$backuppath" | cut -d"/" -f2)" 2063 | if [[ $backupvol =~ volumeUSB[1-9] ]]; then 2064 | filesys="$(mount | grep "/${backupvol:?}/usbshare " | awk '{print $5}')" 2065 | if [[ ! $filesys =~ ^ext[3-4]$ ]] && [[ ! $filesys =~ ^btrfs$ ]]; then 2066 | ding 2067 | echo -e "${Yellow}WARNING${Off} Only backup to ext3, ext4 or btrfs USB partition!" 2068 | echo -e "WARNING Only backup to ext3, ext4 or btrfs USB partition!" >> "$logfile" 2069 | exit 1 # USB volume is not ext3, ext4 of btrfs 2070 | fi 2071 | fi 2072 | 2073 | 2074 | #------------------------------------------------------------------------------ 2075 | # Select package 2076 | 2077 | declare -A package_names 2078 | declare -A package_names_rev 2079 | package_infos=( ) 2080 | if [[ ${mode,,} != "restore" ]]; then 2081 | 2082 | if [[ $auto == "yes" ]]; then 2083 | # Add auto packages to array 2084 | for package in "${autolist[@]}"; do 2085 | package_name="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" displayname)" 2086 | if [[ -z "$package_name" ]]; then 2087 | package_name="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" package)" 2088 | fi 2089 | 2090 | # Skip packages that are dev tools with no data 2091 | if ! skip_dev_tools "$package"; then 2092 | #package_infos+=("${package_name}") 2093 | package_names["${package_name}"]="${package}" 2094 | package_names_rev["${package}"]="${package_name}" 2095 | else 2096 | echo -e "Skipping non-stoppable app: $package_name" |& tee -a "$logfile" 2097 | skip_echo="yes" 2098 | fi 2099 | done 2100 | 2101 | # Show skipped system apps 2102 | if [[ ${#skipped[*]} -gt "0" ]]; then 2103 | echo -e "Skipping system app(s): ${skipped[*]}" |& tee -a "$logfile" 2104 | skip_echo="yes" 2105 | fi 2106 | if [[ $skip_echo == "yes" ]]; then 2107 | echo "" |& tee -a "$logfile" 2108 | fi 2109 | else 2110 | # Add non-system packages to array 2111 | cdir /var/packages || exit 2112 | while IFS= read -r -d '' link && IFS= read -r -d '' target; do 2113 | if [[ ${link##*/} == "target" ]] && echo "$target" | grep -q 'volume'; then 2114 | # Check symlink target exists 2115 | if [[ -a "/var/packages${link#.}" ]] ; then 2116 | 2117 | # Skip broken packages with no INFO file 2118 | package="$(printf %s "$link" | cut -d'/' -f2 )" 2119 | if [[ -f "/var/packages/${package}/INFO" ]]; then 2120 | package_volume="$(printf %s "$target" | cut -d'/' -f1,2 )" 2121 | package_name="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" displayname)" 2122 | if [[ -z "$package_name" ]]; then 2123 | package_name="$(/usr/syno/bin/synogetkeyvalue "/var/packages/${package}/INFO" package)" 2124 | fi 2125 | 2126 | # Skip packages that are dev tools with no data 2127 | if ! skip_dev_tools "$package"; then 2128 | package_infos+=("${package_volume}|${package_name}") 2129 | package_names["${package_name}"]="${package}" 2130 | package_names_rev["${package}"]="${package_name}" 2131 | fi 2132 | fi 2133 | fi 2134 | fi 2135 | done < <(find . -maxdepth 2 -type l -printf '%p\0%l\0') 2136 | fi 2137 | elif [[ ${mode,,} == "restore" ]]; then 2138 | 2139 | # Add list of backed up packages to array 2140 | cdir "${backuppath}/syno_app_mover" || exit 2141 | for package in *; do 2142 | if [[ -d "$package" ]] && [[ $package != "@eaDir" ]]; then 2143 | if [[ ${package:0:1} != "-" ]]; then 2144 | package_name="$(/usr/syno/bin/synogetkeyvalue "${backuppath}/syno_app_mover/${package}/INFO" displayname)" 2145 | if [[ -z "$package_name" ]]; then 2146 | package_name="$(/usr/syno/bin/synogetkeyvalue "${backuppath}/syno_app_mover/${package}/INFO" package)" 2147 | fi 2148 | 2149 | # Skip packages that are dev tools with no data 2150 | if ! skip_dev_tools "$package"; then 2151 | package_infos+=("${package_name}") 2152 | package_names["${package_name}"]="${package}" 2153 | package_names_rev["${package}"]="${package_name}" 2154 | fi 2155 | fi 2156 | fi 2157 | done < <(find . -maxdepth 2 -type d) 2158 | fi 2159 | 2160 | # Add USB Copy if installed (so we can show how to move USB Copy's database) 2161 | if [[ ${mode,,} == "move" ]]; then 2162 | package_status USBCopy >/dev/null 2163 | code="$?" 2164 | if [[ $code -lt "2" ]]; then 2165 | package_names["USB Copy"]="USBCopy" 2166 | package_names_rev["USBCopy"]="USB Copy" 2167 | 2168 | file="/var/packages/USBCopy/etc/setting.conf" 2169 | package_volume=$(synogetkeyvalue "$file" repo_vol_path) 2170 | usbcopy_vol="$package_volume" 2171 | 2172 | if [[ ${mode,,} != "restore" ]]; then 2173 | package_infos+=("${package_volume}|USB Copy") 2174 | elif [[ ${mode,,} == "restore" ]]; then 2175 | package_infos+=("USB Copy") 2176 | fi 2177 | fi 2178 | fi 2179 | 2180 | # Add @database if Move selected 2181 | if [[ ${mode,,} == "move" ]]; then 2182 | package_names["@database"]="@database" 2183 | package_names_rev["@database"]="@database" 2184 | 2185 | package_volume="/$(readlink "/var/services/pgsql" | cut -d"/" -f2)" 2186 | database_vol="$package_volume" 2187 | 2188 | if [[ ${mode,,} != "restore" ]]; then 2189 | package_infos+=("${package_volume}|@database") 2190 | elif [[ ${mode,,} == "restore" ]]; then 2191 | package_infos+=("@database") 2192 | fi 2193 | fi 2194 | 2195 | # Sort array 2196 | IFS=$'\n' package_infos_sorted=($(sort <<<"${package_infos[*]}")); unset IFS 2197 | 2198 | if [[ $auto != "yes" ]]; then 2199 | # Offer to backup or restore all packages 2200 | if [[ ${mode,,} == "backup" ]]; then 2201 | echo -e "Do you want to backup ${Cyan}All${Off} packages? [y/n]" 2202 | echo -e "Do you want to backup All packages? [y/n]" >> "$logfile" 2203 | read -r answer 2204 | echo "$answer" >> "$logfile" 2205 | #echo "" |& tee -a "$logfile" 2206 | if [[ ${answer,,} == "y" ]]; then 2207 | all="yes" 2208 | echo -e "You selected ${Cyan}All${Off}\n" 2209 | echo -e "You selected All\n" >> "$logfile" 2210 | fi 2211 | elif [[ ${mode,,} == "restore" ]]; then 2212 | echo -e "Do you want to restore ${Cyan}All${Off} backed up packages? [y/n]" 2213 | echo -e "Do you want to restore All backed up packages? [y/n]" >> "$logfile" 2214 | read -r answer 2215 | #echo "" |& tee -a "$logfile" 2216 | if [[ ${answer,,} == "y" ]]; then 2217 | all="yes" 2218 | echo -e "You selected ${Cyan}All${Off}\n" 2219 | echo -e "You selected All\n" >> "$logfile" 2220 | fi 2221 | fi 2222 | 2223 | if [[ $all != "yes" ]]; then 2224 | if [[ ${mode,,} != "restore" ]]; then 2225 | # Select package to move or backup 2226 | 2227 | if [[ ${#package_infos_sorted[@]} -gt 0 ]]; then 2228 | echo -e "[Installed package list]" |& tee -a "$logfile" 2229 | for ((i=1; i<=${#package_infos_sorted[@]}; i++)); do 2230 | info="${package_infos_sorted[i-1]}" 2231 | before_pipe="${info%%|*}" 2232 | after_pipe="${info#*|}" 2233 | package_infos_show+=("$before_pipe $after_pipe") 2234 | done 2235 | fi 2236 | 2237 | if [[ ${#package_infos_show[@]} -gt 0 ]]; then 2238 | x="1" 2239 | for m in "${package_infos_show[@]}"; do 2240 | echo "$x) $m" >> "$logfile" 2241 | x=$((x +1)) 2242 | done 2243 | echo "Select the package to ${mode,,} " >> "$logfile" 2244 | PS3="Select the package to ${mode,,}: " 2245 | select m in "${package_infos_show[@]}"; do 2246 | case "$m" in 2247 | /volume*) 2248 | # Parse selected element of array 2249 | package_volume="$(echo "$m" | awk '{print $1}')" 2250 | pkg_name=${m#"$package_volume "} 2251 | pkg="${package_names[${pkg_name}]}" 2252 | break 2253 | ;; 2254 | *) 2255 | echo "Invalid choice! $m" |& tee -a "$logfile" 2256 | ;; 2257 | esac 2258 | done 2259 | else 2260 | echo "No movable packages found!" |& tee -a "$logfile" 2261 | exit 1 2262 | fi 2263 | 2264 | echo -e "You selected ${Cyan}${pkg_name}${Off} in ${Cyan}${package_volume}${Off}\n" 2265 | echo -e "You selected ${pkg_name} in ${package_volume}\n" >> "$logfile" 2266 | 2267 | if [[ ${pkg_name} == "USB Copy" ]]; then 2268 | linktargetvol="$usbcopy_vol" 2269 | elif [[ ${pkg_name} == "@database" ]]; then 2270 | linktargetvol="$database_vol" 2271 | else 2272 | target=$(readlink "/var/packages/${pkg}/target") 2273 | linktargetvol="/$(printf %s "${target:?}" | cut -d'/' -f2 )" 2274 | fi 2275 | 2276 | elif [[ ${mode,,} == "restore" ]]; then 2277 | # Select package to backup 2278 | 2279 | # Select package to restore 2280 | if [[ ${#package_infos_sorted[@]} -gt 0 ]]; then 2281 | echo -e "[Restorable package list]" |& tee -a "$logfile" 2282 | x="1" 2283 | for p in "${package_infos_sorted[@]}"; do 2284 | echo "$x) $p" >> "$logfile" 2285 | x=$((x +1)) 2286 | done 2287 | 2288 | echo "Select the package to restore " >> "$logfile" 2289 | PS3="Select the package to restore: " 2290 | select pkg_name in "${package_infos_sorted[@]}"; do 2291 | if [[ $pkg_name ]]; then 2292 | pkg="${package_names[${pkg_name}]}" 2293 | if [[ -d $pkg ]]; then 2294 | echo -e "You selected ${Cyan}${pkg_name}${Off}\n" 2295 | echo -e "You selected ${pkg_name}\n" >> "$logfile" 2296 | break 2297 | else 2298 | ding 2299 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} $pkg_name not found!" 2300 | echo -e "Line ${LINENO}: ERROR $pkg_name not found!" >> "$logfile" 2301 | exit 1 # Selected package not found 2302 | fi 2303 | else 2304 | echo "Invalid choice!" |& tee -a "$logfile" 2305 | fi 2306 | done 2307 | 2308 | # Check if package is installed 2309 | check_pkg_installed "$pkg" "$pkg_name" 2310 | else 2311 | ding 2312 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} No package backups found!" 2313 | echo -e "Line ${LINENO}: ERROR No package backups found!" >> "$logfile" 2314 | exit 1 # No package backups found 2315 | fi 2316 | fi 2317 | fi 2318 | fi 2319 | 2320 | # Assign just the selected package to array 2321 | if [[ $all != "yes" ]] && [[ $auto != "yes" ]]; then 2322 | unset package_names 2323 | declare -A package_names 2324 | package_names["${pkg_name:?}"]="${pkg:?}" 2325 | 2326 | unset package_names_rev 2327 | declare -A package_names_rev 2328 | package_names_rev["${pkg:?}"]="${pkg_name:?}" 2329 | fi 2330 | 2331 | 2332 | #------------------------------------------------------------------------------ 2333 | # Select volume 2334 | 2335 | # Get list of available volumes 2336 | volumes=( ) 2337 | for volume in /volume*; do 2338 | # Ignore /volumeUSB# and /volume0 2339 | if [[ $volume =~ /volume[1-9][0-9]?$ ]]; then 2340 | # Skip volume package is currently installed on 2341 | if [[ $volume != "$linktargetvol" ]]; then 2342 | # Ignore unmounted volumes 2343 | if df -h | grep "$volume" >/dev/null ; then 2344 | volumes+=("$volume") 2345 | fi 2346 | fi 2347 | fi 2348 | done 2349 | 2350 | # Select destination volume 2351 | if [[ ${mode,,} == "move" ]]; then 2352 | if [[ ${#volumes[@]} -gt 1 ]]; then 2353 | x="1" 2354 | for v in "${volumes[@]}"; do 2355 | echo "$x) $v" >> "$logfile" 2356 | x=$((x +1)) 2357 | done 2358 | echo "Select the destination volume " >> "$logfile" 2359 | PS3="Select the destination volume: " 2360 | select targetvol in "${volumes[@]}"; do 2361 | if [[ $targetvol ]]; then 2362 | if [[ -d $targetvol ]]; then 2363 | echo -e "You selected ${Cyan}${targetvol}${Off}\n" 2364 | echo -e "You selected ${targetvol}\n" >> "$logfile" 2365 | break 2366 | else 2367 | ding 2368 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} $targetvol not found!" 2369 | echo -e "Line ${LINENO}: ERROR $targetvol not found!" >> "$logfile" 2370 | exit 1 # Target volume not found 2371 | fi 2372 | else 2373 | echo "Invalid choice!" |& tee -a "$logfile" 2374 | fi 2375 | done 2376 | elif [[ ${#volumes[@]} -eq 1 ]]; then 2377 | targetvol="${volumes[0]}" 2378 | echo -e "Destination volume is ${Cyan}${targetvol}${Off}\n" 2379 | echo -e "Destination volume is ${targetvol}\n" >> "$logfile" 2380 | else 2381 | ding 2382 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Only 1 volume found!" 2383 | echo -e "Line ${LINENO}: ERROR Only 1 volume found!" >> "$logfile" 2384 | exit 1 # Only 1 volume 2385 | fi 2386 | elif [[ ${mode,,} == "backup" ]]; then 2387 | targetvol="/$(echo "${backuppath:?}" | cut -d"/" -f2)" 2388 | if [[ $all != "yes" ]]; then 2389 | echo -e "Destination volume is ${Cyan}${targetvol}${Off}\n" 2390 | echo -e "Destination volume is ${targetvol}\n" >> "$logfile" 2391 | fi 2392 | elif [[ ${mode,,} == "restore" ]]; then 2393 | if [[ $all != "yes" ]]; then 2394 | targetvol="/$(readlink "/var/packages/${pkg:?}/target" | cut -d"/" -f2)" 2395 | echo -e "Destination volume is ${Cyan}${targetvol}${Off}\n" 2396 | echo -e "Destination volume is ${targetvol}\n" >> "$logfile" 2397 | fi 2398 | fi 2399 | 2400 | warn_docker(){ 2401 | ding 2402 | echo -en "${Yellow}WARNING${Off} $action $pkg_name containers from " 2403 | echo -e "${Cyan}$sourcefs${Off} volume to ${Cyan}$targetfs${Off} volume" 2404 | echo -e "results in needing to migrate the containers. Some may fail to migrate.\n" 2405 | 2406 | echo -n "WARNING $action docker containers from " >> "$logfile" 2407 | echo "$sourcefs volume to $targetfs volume" >> "$logfile" 2408 | echo -e "results in needing to migrate the containers. Some may fail to migrate.\n" >> "$logfile" 2409 | sleep 2 2410 | } 2411 | 2412 | # Check source and target filesystem if Docker or Container Manager selected 2413 | if [[ ${package_names[*]} =~ "ContainerManager" ]] || [[ ${package_names[*]} =~ "Docker" ]]; then 2414 | if [[ $mode == "restore" ]]; then 2415 | sourcevol=$(echo "$bkpath" | cut -d "/" -f2) 2416 | else 2417 | if [[ ${package_names[*]} =~ "ContainerManager" ]]; then 2418 | pkg="ContainerManager" 2419 | pkg_name="Container Manager" 2420 | elif [[ ${package_names[*]} =~ "Docker" ]]; then 2421 | pkg="Docker" 2422 | pkg_name="Docker" 2423 | fi 2424 | target=$(readlink "/var/packages/${pkg}/target") 2425 | sourcevol="$(printf %s "${target:?}" | cut -d'/' -f2 )" 2426 | fi 2427 | source_fs "$sourcevol" 2428 | target_fs "$targetvol" 2429 | if [[ $targetfs != "$sourcefs" ]]; then 2430 | # Warn about different filesystems 2431 | warn_docker 2432 | docker_migrate="yes" 2433 | fi 2434 | fi 2435 | 2436 | # Check selected pkgs will fit on target volume 2437 | # Should add a progress bar? 2438 | if [[ "${#package_names[@]}" -gt "1" ]]; then 2439 | echo -e "Checking size of selected apps" |& tee -a "$logfile" 2440 | else 2441 | echo -e "Checking size of ${package_names_rev[*]}" |& tee -a "$logfile" 2442 | fi 2443 | for pkg in "${package_names[@]}"; do 2444 | # Get volume package is installed on 2445 | sourcevol="$(readlink "/var/packages/$pkg/target" | cut -d'/' -f2)" 2446 | 2447 | # Get pkg total size 2448 | check_pkg_size "$pkg" "/$sourcevol" 2449 | all_pkg_size=$((all_pkg_size +total_size)) 2450 | done 2451 | 2452 | # Abort if not enough space on target volume 2453 | if ! check_space "$pkg" "${targetvol:?}" "$all_pkg_size"; then 2454 | ding 2455 | exit 1 # Not enough space 2456 | fi 2457 | 2458 | # Show size of selected packages 2459 | if [[ $all_pkg_size -gt "999999" ]]; then 2460 | echo -e "Size of selected app(s) is $((all_pkg_size /1048576)) GB\n" |& tee -a "$logfile" 2461 | elif [[ $all_pkg_size -gt "999" ]]; then 2462 | echo -e "Size of selected app(s) is $((all_pkg_size /1048)) MB\n" |& tee -a "$logfile" 2463 | else 2464 | echo -e "Size of selected app(s) is $all_pkg_size KB\n" |& tee -a "$logfile" 2465 | fi 2466 | 2467 | # Check user is ready 2468 | if [[ $auto != "yes" ]]; then 2469 | if [[ $all == "yes" ]]; then 2470 | if [[ ${mode,,} == "backup" ]]; then 2471 | echo -e "Ready to ${Yellow}${mode}${Off} ${Cyan}All${Off} packages to ${Cyan}${backuppath}${Off}? [y/n]" 2472 | echo -e "Ready to $mode All packages to ${backuppath}? [y/n]" >> "$logfile" 2473 | else 2474 | echo -e "Ready to ${Yellow}${mode}${Off} ${Cyan}All${Off} backed up packages? [y/n]" 2475 | echo -e "Ready to $mode All backed up packages? [y/n]" >> "$logfile" 2476 | fi 2477 | elif [[ ${mode,,} == "backup" ]]; then 2478 | echo -e "Ready to ${Yellow}${mode}${Off} ${Cyan}${pkg_name}${Off} to ${Cyan}${backuppath}${Off}? [y/n]" 2479 | echo -e "Ready to $mode ${Cyan}${pkg_name} to ${backuppath}? [y/n]" >> "$logfile" 2480 | else 2481 | echo -e "Ready to ${Yellow}${mode}${Off} ${Cyan}${pkg_name}${Off} to ${Cyan}${targetvol}${Off}? [y/n]" 2482 | echo -e "Ready to $mode ${pkg_name} to ${targetvol}? [y/n]" >> "$logfile" 2483 | fi 2484 | read -r answer 2485 | echo "$answer" >> "$logfile" 2486 | echo "" |& tee -a "$logfile" 2487 | if [[ ${answer,,} != y ]]; then 2488 | exit # Answered no 2489 | fi 2490 | fi 2491 | 2492 | # Reset shell's SECONDS var to later show how long the script took 2493 | SECONDS=0 2494 | 2495 | 2496 | #------------------------------------------------------------------------------ 2497 | # Get list of packages sorted by with dependents, with dependencies then others 2498 | 2499 | # Loop through package_names associative array 2500 | for pkg_name in "${!package_names[@]}"; do 2501 | pkg="${package_names["$pkg_name"]}" 2502 | 2503 | # Get list of packages with dependents 2504 | has_dependtents=() 2505 | has_dependtents+=($(/usr/syno/bin/synopkg list --name --depend-on "$pkg")) 2506 | if [[ ${#has_dependtents[@]} -gt "0" ]]; then 2507 | # Add to list of running packages with dependents 2508 | pkgs_with_deps+=("$pkg") 2509 | else 2510 | 2511 | # Get list of packages with dependencies 2512 | has_deps="" 2513 | info="/var/packages/${pkg}/INFO" 2514 | has_deps=$(/usr/syno/bin/synogetkeyvalue "$info" install_dep_packages) 2515 | if [[ -n "$has_deps" ]]; then 2516 | # Add to list of packages with dependencies 2517 | dep_pkgs+=("$pkg") 2518 | else 2519 | 2520 | # Add to list of other packages 2521 | pkgs_no_dep+=("$pkg") 2522 | fi 2523 | fi 2524 | done 2525 | 2526 | # Sort array 2527 | IFS=$'\n' pkgs_with_deps_sorted=($(sort -u <<<"${pkgs_with_deps[*]}")); unset IFS 2528 | 2529 | # Sort array 2530 | IFS=$'\n' dep_pkgs_sorted=($(sort -u <<<"${dep_pkgs[*]}")); unset IFS 2531 | 2532 | # Sort array 2533 | IFS=$'\n' pkgs_no_dep_sorted=($(sort -u <<<"${pkgs_no_dep[*]}")); unset IFS 2534 | 2535 | 2536 | # Add packages with dependents to pkgs_sorted 2537 | for v in "${!pkgs_with_deps_sorted[@]}"; do 2538 | pkgs_sorted+=("${pkgs_with_deps_sorted["$v"]}") 2539 | done 2540 | 2541 | # Append packages with dependencies to pkgs_sorted 2542 | for v in "${!dep_pkgs_sorted[@]}"; do 2543 | pkgs_sorted+=("${dep_pkgs_sorted["$v"]}") 2544 | done 2545 | 2546 | # Append other packages to pkgs_sorted 2547 | for v in "${!pkgs_no_dep_sorted[@]}"; do 2548 | pkgs_sorted+=("${pkgs_no_dep_sorted["$v"]}") 2549 | done 2550 | 2551 | # Free some memory 2552 | unset pkgs_with_deps 2553 | unset dep_pkgs 2554 | unset pkgs_no_dep 2555 | unset pkgs_with_deps_sorted 2556 | unset dep_pkgs_sorted 2557 | unset pkgs_no_dep_sorted 2558 | 2559 | 2560 | # Get list of running packages from array sorted by 2561 | # with dependents, with dependencies then others 2562 | for pkg in "${pkgs_sorted[@]}"; do 2563 | if [[ -f "/var/packages/${pkg}/enabled" ]]; then 2564 | running_pkgs_sorted+=("$pkg") 2565 | fi 2566 | done 2567 | 2568 | 2569 | # Get list of running packages dependent on pgsql service 2570 | if [[ ${pkgs_sorted[*]} =~ "@database" ]]; then 2571 | # Add running packages that use pgsql that need starting to array 2572 | if cd "/var/packages"; then 2573 | for package in *; do 2574 | if [[ -d "$package" ]]; then 2575 | depservice="$(synogetkeyvalue "/var/packages/${package}/INFO" start_dep_services)" 2576 | #long_name="$(synogetkeyvalue "/var/packages/${package}/INFO" displayname)" 2577 | if echo "$depservice" | grep -q 'pgsql'; then 2578 | if package_is_running "$package"; then 2579 | running_pkgs_dep_pgsql+=("$package") 2580 | fi 2581 | fi 2582 | fi 2583 | done < <(find . -maxdepth 2 -type d) 2584 | fi 2585 | fi 2586 | 2587 | 2588 | #------------------------------------------------------------------------------ 2589 | # Stop the package or packages 2590 | 2591 | stop_packages(){ 2592 | # Check package is running 2593 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 2594 | if package_is_running "$pkg"; then 2595 | 2596 | # Stop package 2597 | package_stop "$pkg" "$pkg_name" 2598 | 2599 | # Check package stopped 2600 | if package_is_running "$pkg"; then 2601 | stop_pkg_fail="yes" 2602 | ding 2603 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to stop ${pkg_name}!" |& tee -a "$logfile" 2604 | # echo "${pkg_name} status $code" |& tee -a "$logfile" 2605 | process_error="yes" 2606 | if [[ $all != "yes" ]] || [[ $fix != "yes" ]]; then 2607 | exit 1 # Skip exit if mode != all and fix != yes 2608 | fi 2609 | return 1 2610 | else 2611 | stop_pkg_fail="" 2612 | fi 2613 | 2614 | if [[ $pkg == "ContainerManager" ]] || [[ $pkg == "Docker" ]]; then 2615 | # Stop containerd-shim 2616 | killall containerd-shim >/dev/null 2>&1 2617 | fi 2618 | # else 2619 | # skip_start="yes" 2620 | fi 2621 | } 2622 | 2623 | 2624 | #------------------------------------------------------------------------------ 2625 | # Backup extra @folders 2626 | 2627 | backup_extras(){ 2628 | # $1 is @folder (@docker or @downloads etc) 2629 | local extrabakvol 2630 | local answer 2631 | # Skip if source volume is read only 2632 | if [[ -w "/$sourcevol" ]]; then 2633 | if [[ ${mode,,} != "backup" ]]; then 2634 | if [[ ${mode,,} == "move" ]]; then 2635 | extrabakvol="/$sourcevol" 2636 | elif [[ ${mode,,} == "restore" ]]; then 2637 | extrabakvol="$targetvol" 2638 | fi 2639 | echo -e "NOTE: A backup of ${Cyan}$1${Off} is required"\ 2640 | "for recovery if the ${mode,,} fails." 2641 | echo -e "NOTE: A backup of $1 is required"\ 2642 | "for recovery if the ${mode,,} fails." >> "$logfile" 2643 | echo -e "Do you want to ${Yellow}backup${Off} the"\ 2644 | "${Cyan}$1${Off} folder on $extrabakvol? [y/n]" 2645 | echo -e "Do you want to backup the"\ 2646 | "$1 folder on $extrabakvol? [y/n]" >> "$logfile" 2647 | read -r answer 2648 | echo "$answer" >> "$logfile" 2649 | if [[ ${answer,,} == "y" ]]; then 2650 | # Check we have enough space 2651 | if ! check_space "/${sourcevol}/$1" "/${sourcevol}" extra; then 2652 | ding 2653 | echo -e "${Error}ERROR${Off} Not enough space on $extrabakvol to backup ${Cyan}$1${Off}!" 2654 | echo -e "ERROR Not enough space on $extrabakvol to backup $1!" >> "$logfile" 2655 | echo "Do you want to continue ${action,,} ${1}? [y/n]" |& tee -a "$logfile" 2656 | read -r answer 2657 | echo "$answer" >> "$logfile" 2658 | if [[ ${answer,,} != "y" ]]; then 2659 | exit # Answered no 2660 | fi 2661 | else 2662 | echo -e "${Red}WARNING Backing up $1 could take a long time${Off}" 2663 | echo -e "WARNING Backing up $1 could take a long time" >> "$logfile" 2664 | backup_dir "$1" "$extrabakvol" 2665 | fi 2666 | fi 2667 | fi 2668 | fi 2669 | } 2670 | 2671 | 2672 | #------------------------------------------------------------------------------ 2673 | # Move the package or packages 2674 | 2675 | prepare_backup_restore(){ 2676 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 2677 | 2678 | # Set bkpath variable 2679 | if [[ ${mode,,} != "move" ]]; then 2680 | bkpath="${backuppath}/syno_app_mover/$pkg" 2681 | fi 2682 | 2683 | # Set targetvol variable 2684 | if [[ ${mode,,} == "restore" ]] && [[ $all == "yes" ]]; then 2685 | targetvol="/$(readlink "/var/packages/${pkg:?}/target" | cut -d"/" -f2)" 2686 | fi 2687 | 2688 | # Check installed package version and backup version 2689 | # Get package version 2690 | if [[ ${mode,,} != "move" ]]; then 2691 | pkgversion=$(/usr/syno/bin/synogetkeyvalue "/var/packages/$pkg/INFO" version) 2692 | fi 2693 | 2694 | # Get backup package version 2695 | if [[ ${mode,,} == "restore" ]]; then 2696 | pkgbackupversion=$(/usr/syno/bin/synogetkeyvalue "$bkpath/INFO" version) 2697 | if [[ $pkgversion ]] && [[ $pkgbackupversion ]]; then 2698 | check_pkg_versions_match "$pkgversion" "$pkgbackupversion" 2699 | fi 2700 | fi 2701 | 2702 | # Create package folder if mode is backup 2703 | if [[ ${mode,,} == "backup" ]]; then 2704 | if [[ ! -d "$bkpath" ]]; then 2705 | if ! mkdir -p "${bkpath:?}"; then 2706 | ding 2707 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to create directory!" 2708 | echo -e "Line ${LINENO}: ERROR Failed to create directory!" >> "$logfile" 2709 | process_error="yes" 2710 | if [[ $all != "yes" ]]; then 2711 | exit 1 # Skip exit if mode is All 2712 | fi 2713 | return 1 2714 | fi 2715 | fi 2716 | 2717 | # Backup package's INFO file 2718 | cp -p "/var/packages/$pkg/INFO" "$bkpath/INFO" |& tee -a "$logfile" 2719 | fi 2720 | } 2721 | 2722 | process_packages(){ 2723 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 2724 | target=$(readlink "/var/packages/${pkg}/target") 2725 | #sourcevol="/$(printf %s "${target:?}" | cut -d'/' -f2 )" 2726 | sourcevol="$(printf %s "${target:?}" | cut -d'/' -f2 )" 2727 | 2728 | # Move package 2729 | if [[ $pkg == "ContainerManager" ]] || [[ $pkg == "Docker" ]]; then 2730 | # Move @docker if package is ContainerManager or Docker 2731 | 2732 | # Check if @docker is on same volume as Docker package 2733 | if [[ -d "/${sourcevol}/@docker" ]]; then 2734 | # Check we have enough space 2735 | if ! check_space "/${sourcevol}/@docker" "${targetvol}" extra; then 2736 | ding 2737 | echo -e "${Error}ERROR${Off} Not enough space on $targetvol to ${mode,,} ${Cyan}@docker${Off}!" 2738 | echo -e "ERROR Not enough space on $targetvol to ${mode,,} @docker!" >> "$logfile" 2739 | process_error="yes" 2740 | if [[ $all != "yes" ]]; then 2741 | exit 1 # Skip exit if mode is All 2742 | fi 2743 | return 1 2744 | fi 2745 | fi 2746 | 2747 | # Backup @docker 2748 | backup_extras "@docker" 2749 | 2750 | # Move package and edit symlinks 2751 | move_pkg "$pkg" "$targetvol" 2752 | 2753 | elif [[ $pkg == "DownloadStation" ]]; then 2754 | # Move @download if package is DownloadStation 2755 | 2756 | # Check if @download is on same volume as DownloadStation package 2757 | if [[ -d "/${sourcevol}/@download" ]]; then 2758 | # Check we have enough space 2759 | if ! check_space "/${sourcevol}/@download" "${targetvol}" extra; then 2760 | ding 2761 | echo -e "${Error}ERROR${Off} Not enough space on $targetvol to ${mode,,} ${Cyan}@download${Off}!" 2762 | echo -e "ERROR Not enough space on $targetvol to ${mode,,} @download!" >> "$logfile" 2763 | process_error="yes" 2764 | if [[ $all != "yes" ]]; then 2765 | exit 1 # Skip exit if mode is All 2766 | fi 2767 | return 1 2768 | fi 2769 | fi 2770 | 2771 | # Backup @download 2772 | backup_extras "@download" 2773 | 2774 | # Move package and edit symlinks 2775 | move_pkg "$pkg" "$targetvol" 2776 | else 2777 | # Move package and edit symlinks 2778 | move_pkg "$pkg" "$targetvol" 2779 | fi 2780 | 2781 | # Move package's other folders 2782 | move_extras "$pkg" "$targetvol" 2783 | 2784 | # Backup or restore package's web_packages folder 2785 | if [[ ${mode,,} != "move" ]]; then 2786 | web_packages "${pkg,,}" 2787 | fi 2788 | } 2789 | 2790 | start_packages(){ 2791 | [ "$trace" == "yes" ] && echo "${FUNCNAME[0]} called from ${FUNCNAME[1]}" |& tee -a "$logfile" 2792 | # if [[ $skip_start != "yes" ]]; then 2793 | if [[ $pkg != "@database" ]]; then 2794 | # Only start package if not already running 2795 | if ! package_is_running "$pkg"; then 2796 | 2797 | if [[ ${mode,,} == "backup" ]]; then 2798 | answer="y" 2799 | elif [[ $all == "yes" ]]; then 2800 | answer="y" 2801 | else 2802 | echo -e "\nDo you want to start ${Cyan}$pkg_name${Off} now? [y/n]" 2803 | echo -e "\nDo you want to start $pkg_name now? [y/n]" >> "$logfile" 2804 | read -r answer 2805 | echo "$answer" >> "$logfile" 2806 | fi 2807 | 2808 | if [[ ${answer,,} == "y" ]]; then 2809 | # Start package 2810 | package_start "$pkg" "$pkg_name" 2811 | 2812 | # Check package started 2813 | if ! package_is_running "$pkg"; then 2814 | ding 2815 | echo -e "Line ${LINENO}: ${Error}ERROR${Off} Failed to start ${pkg_name}!" 2816 | echo -e "Line ${LINENO}: ERROR Failed to start ${pkg_name}!" >> "$logfile" 2817 | # echo "${pkg_name} status $code" |& tee -a "$logfile" 2818 | process_error="yes" 2819 | if [[ $all != "yes" ]]; then 2820 | exit 1 # Skip exit if mode is All 2821 | fi 2822 | else 2823 | did_start_pkg="yes" 2824 | fi 2825 | else 2826 | no_start_pkg="yes" 2827 | fi 2828 | fi 2829 | fi 2830 | # fi 2831 | } 2832 | 2833 | check_last_process_time(){ 2834 | # $1 is pkg 2835 | if [[ ${mode,,} != "move" ]]; then 2836 | #now=$(date +%s) 2837 | if [[ -f "${backuppath}/syno_app_mover/$1/last${mode,,}" ]]; then 2838 | last_process_time=$(cat "${backuppath}/syno_app_mover/$1/last${mode,,}") 2839 | skip_minutes=$(/usr/syno/bin/synogetkeyvalue "$conffile" skip_minutes) 2840 | if [[ $skip_minutes -gt "0" ]]; then 2841 | skip_secs=$((skip_minutes *60)) 2842 | #if $(($(date +%s) +skip_secs)) -gt 2843 | if [[ $((last_process_time +skip_secs)) -gt $(date +%s) ]]; then 2844 | return 1 2845 | fi 2846 | fi 2847 | fi 2848 | fi 2849 | } 2850 | 2851 | docker_export(){ 2852 | local docker_share 2853 | local export_dir 2854 | local container 2855 | local export_file 2856 | export_date="$(date +%Y%m%d_%H%M)" 2857 | 2858 | # Get docker share location 2859 | if [[ $buildnumber -gt "64570" ]]; then 2860 | # DSM 7.2.1 and later 2861 | # synoshare --get-real-path is case insensitive (docker or Docker both work) 2862 | docker_share=$(/usr/syno/sbin/synoshare --get-real-path docker) 2863 | else 2864 | # DSM 7.2 and earlier 2865 | # synoshare --getmap is case insensitive (docker or Docker both work) 2866 | docker_share=$(/usr/syno/sbin/synoshare --getmap docker | grep volume | cut -d"[" -f2 | cut -d"]" -f1) 2867 | # I could also have used: 2868 | # docker_share=$(/usr/syno/sbin/synoshare --get docker | tr '[]' '\n' | sed -n "9p") 2869 | fi 2870 | 2871 | if [[ ! -d "$docker_share" ]]; then 2872 | echo "${Error}WARNING${Off} docker shared folder not found!" 2873 | echo "WARNING docker shared folder not found!" >> "$logfile" 2874 | return 2875 | else 2876 | export_dir="${docker_share}/app_mover_exports" 2877 | fi 2878 | 2879 | if [[ ! -d "$export_dir" ]]; then 2880 | if ! mkdir "$export_dir"; then 2881 | echo "${Error}WARNING${Off} Failed to create docker export folder!" 2882 | echo "WARNING Failed to create docker export folder!" >> "$logfile" 2883 | return 2884 | else 2885 | chmod 755 "$export_dir" |& tee -a "$logfile" 2886 | fi 2887 | fi 2888 | 2889 | echo "Exporting container settings to ${export_dir}" |& tee -a "$logfile" 2890 | # Get list of all containers (running and stopped) 2891 | for container in $(docker ps --all --format "{{ .Names }}"); do 2892 | if grep -q "$container" <<< "${ignored_containers_list[@]}" ; then 2893 | echo "Skipping ${container} on ignore list." |& tee -a "$logfile" 2894 | continue 2895 | else 2896 | export_file="${export_dir:?}/${container}_${export_date}.json" 2897 | echo "Exporting $container json" |& tee -a "$logfile" 2898 | # synowebapi -s or --silent does not work 2899 | /usr/syno/bin/synowebapi --exec api=SYNO.Docker.Container.Profile method=export version=1 outfile="$export_file" name="$container" &>/dev/null 2900 | 2901 | # Check export was successful 2902 | if [[ ! -f "$export_file" ]] || [[ $(stat -c %s "$export_file") -eq "0" ]]; then 2903 | # No file or 0 bytes 2904 | echo "${Error}WARNING${Off} Failed to export $container settings!" 2905 | echo "WARNING Failed to export $container settings!" >> "$logfile" 2906 | return 2907 | else 2908 | chmod 660 "${export_dir:?}/${container}_${export_date}.json" |& tee -a "$logfile" 2909 | fi 2910 | 2911 | # Delete settings exports older than $delete_older days 2912 | if [[ $delete_older =~ ^[2-9][0-9]?$ ]]; then 2913 | find "$export_dir" -name "${container,,}_*.json" -mtime +"$delete_older" -exec rm {} \; 2914 | fi 2915 | fi 2916 | done 2917 | } 2918 | 2919 | move_database(){ 2920 | # Get volume where @database currently is 2921 | target=$(readlink "/var/services/pgsql") 2922 | #sourcevol="/$(printf %s "${target:?}" | cut -d'/' -f2 )" 2923 | sourcevol="$(printf %s "${target:?}" | cut -d'/' -f2 )" 2924 | 2925 | if [[ $majorversion -gt 6 ]]; then 2926 | # Stop the pgsql service - Also stops dependant apps 2927 | systemctl stop pgsql-adapter.service & 2928 | else 2929 | # DSM 6 2930 | synoservicectl --stop pgsql-adapter & 2931 | fi 2932 | pid=$! 2933 | string="Stopping pgsql service and dependent apps" 2934 | echo "Stopping pgsql service and dependent apps" >> "$logfile" 2935 | progbar "$pid" "$string" 2936 | wait "$pid" 2937 | progstatus "$?" "$string" "line ${LINENO}" 2938 | 2939 | # Check pgsql service has stopped 2940 | if [[ $majorversion -gt 6 ]]; then 2941 | # DSM 7, running = 0 stopped = 3 2942 | if systemctl status pgsql-adapter.service >/dev/null; then 2943 | ding 2944 | echo "ERROR Failed to stop pgsql service!" |& tee -a "$logfile" 2945 | return 1 2946 | #else 2947 | # echo "Stopped pgsql service" |& tee -a "$logfile" 2948 | fi 2949 | else 2950 | # DSM 6, running = 0 stopped = 1 2951 | if synoservicectl --status pgsql-adapter >/dev/null; then 2952 | ding 2953 | echo "ERROR Failed to stop pgsql service!" |& tee -a "$logfile" 2954 | return 1 2955 | #else 2956 | # echo "Stopped pgsql service" |& tee -a "$logfile" 2957 | fi 2958 | fi 2959 | 2960 | # Create @database folder if needed 2961 | if [[ ! -d "${targetvol:?}/@database" ]]; then 2962 | mkdir -m755 "${targetvol:?}/@database" 2963 | fi 2964 | 2965 | # Copy pgsql folder 2966 | cp -pr "/${sourcevol:?}/@database/pgsql" "${targetvol:?}/@database/pgsql" & 2967 | pid=$! 2968 | string="Copying pgsql database to $targetvol/@database" 2969 | echo "Copying pgsql database to $targetvol/@database" >> "$logfile" 2970 | progbar "$pid" "$string" 2971 | wait "$pid" 2972 | progstatus "$?" "$string" "line ${LINENO}" 2973 | 2974 | # Copy other folders 2975 | if [[ -d "/${sourcevol:?}/@database/autoupdate" ]]; then 2976 | cp -pr "/${sourcevol:?}/@database/autoupdate" "${targetvol:?}/@database/autoupdate" 2977 | fi 2978 | if [[ -d "/${sourcevol:?}/@database/synolog" ]]; then 2979 | cp -pr "/${sourcevol:?}/@database/synolog" "${targetvol:?}/@database/synolog" 2980 | fi 2981 | if [[ -d "/${sourcevol:?}/@database/synologan" ]]; then 2982 | cp -pr "/${sourcevol:?}/@database/synologan" "${targetvol:?}/@database/synologan" 2983 | fi 2984 | 2985 | # Edit pgsql symlink 2986 | rm /var/services/pgsql 2987 | ln -s "${targetvol:?}/@database/pgsql" /var/services/pgsql 2988 | 2989 | # Start the pgsql service 2990 | echo "Starting pgsql service" |& tee -a "$logfile" 2991 | if [[ $majorversion -gt 6 ]]; then 2992 | # Stop the pgsql service - Also stops dependant apps 2993 | systemctl start pgsql-adapter.service 2994 | else 2995 | # DSM 6 2996 | synoservicectl --stop pgsql-adapter 2997 | fi 2998 | 2999 | 3000 | # Check pgsql service is ok 3001 | if [[ $majorversion -gt 6 ]]; then 3002 | # DSM 7, running = 0 stopped = 3 3003 | if ! systemctl status pgsql-adapter.service >/dev/null; then 3004 | ding 3005 | echo "ERROR Failed to start pgsql service!" |& tee -a "$logfile" 3006 | return 1 3007 | #else 3008 | # echo "Started pgsql service" |& tee -a "$logfile" 3009 | fi 3010 | else 3011 | # DSM 6, running = 0 stopped = 1 3012 | if ! synoservicectl --status pgsql-adapter >/dev/null; then 3013 | ding 3014 | echo "ERROR Failed to start pgsql service!" |& tee -a "$logfile" 3015 | return 1 3016 | #else 3017 | # echo "Started pgsql service" |& tee -a "$logfile" 3018 | fi 3019 | fi 3020 | return 0 3021 | } 3022 | 3023 | 3024 | # Loop through pkgs_sorted array and process package 3025 | for pkg in "${pkgs_sorted[@]}"; do 3026 | pkg_name="${package_names_rev["$pkg"]}" 3027 | process_error="" 3028 | 3029 | # Skip backup or restore for excluded apps 3030 | if [[ $all == "yes" ]] && [[ "${excludelist[*]}" =~ $pkg ]] &&\ 3031 | [[ $mode != "move" ]]; then 3032 | echo -e "Excluding $pkg\n" |& tee -a "$logfile" 3033 | continue 3034 | fi 3035 | 3036 | #if [[ $pkg == USBCopy ]] && [[ ${mode,,} == "move" ]]; then 3037 | if [[ $pkg == USBCopy ]]; then 3038 | # USBCopy only needs database location changed in USB Copy ui 3039 | continue 3040 | fi 3041 | 3042 | #if [[ $pkg == "@database" ]] && [[ ${mode,,} == "move" ]]; then 3043 | if [[ $pkg == "@database" ]]; then 3044 | move_database 3045 | continue 3046 | fi 3047 | 3048 | if [[ $pkg == "ContainerManager" ]] || [[ $pkg == "Docker" ]]; then 3049 | if [[ -w "/$sourcevol" ]]; then 3050 | # Start package if needed so we can prune images 3051 | # and export container configurations 3052 | if ! package_is_running "$pkg"; then 3053 | package_start "$pkg" "$pkg_name" 3054 | fi 3055 | 3056 | if [[ ${mode,,} != "restore" ]]; then 3057 | # Export container settings to json files 3058 | docker_export 3059 | fi 3060 | 3061 | #if [[ ${mode,,} == "restore" ]]; then 3062 | # # Remove dangling and unused images 3063 | # echo "Removing dangling and unused docker images" |& tee -a "$logfile" 3064 | # docker image prune --all --force >/dev/null 3065 | #else 3066 | # # Remove dangling images 3067 | # echo "Removing dangling docker images" |& tee -a "$logfile" 3068 | # docker image prune --force >/dev/null 3069 | #fi 3070 | else 3071 | # Skip read only source volume 3072 | echo "/$sourcevol is read only. Skipping:" |& tee -a "$logfile" 3073 | echo " - Exporting container settings" |& tee -a "$logfile" 3074 | #echo " - Removing dangling and unused docker images" |& tee -a "$logfile" 3075 | fi 3076 | fi 3077 | 3078 | if ! check_last_process_time "$pkg" && [[ $all == "yes" ]]; then 3079 | echo "Skipping $pkg_name as a ${mode,,} was done less than $skip_minutes minutes ago" |& tee -a "$logfile" 3080 | else 3081 | if [[ ${mode,,} != "move" ]]; then 3082 | prepare_backup_restore 3083 | fi 3084 | stop_packages 3085 | 3086 | if [[ ${1,,} == "--test" ]] || [[ ${1,,} == "test" ]]; then 3087 | echo "process_packages" 3088 | else 3089 | if [[ $stop_pkg_fail != "yes" ]]; then 3090 | process_packages 3091 | if [[ ${mode,,} != "move" ]] && [[ $process_error != "yes" ]]; then 3092 | # Save last backup time 3093 | echo -n "$(date +%s)" > "${backuppath}/syno_app_mover/$pkg/last${mode,,}" 3094 | chmod 755 "${backuppath}/syno_app_mover/$pkg/last${mode,,}" |& tee -a "$logfile" 3095 | fi 3096 | fi 3097 | fi 3098 | 3099 | # shellcheck disable=SC2143 # Use grep -q 3100 | if [[ $(echo "${running_pkgs_sorted[@]}" | grep -w "$pkg") ]]; then 3101 | start_packages 3102 | fi 3103 | fi 3104 | echo "" |& tee -a "$logfile" 3105 | done 3106 | 3107 | 3108 | #------------------------------------------------------------------------------ 3109 | # Show how to move related shared folder(s) 3110 | 3111 | docker_volume_edit(){ 3112 | # Remind user to edit container's volume setting 3113 | echo "If you moved shared folders that your $pkg_name containers use" |& tee -a "$logfile" 3114 | echo "as volumes you will need to edit your docker compose or .env files," |& tee -a "$logfile" 3115 | echo -e "or the container's settings, to point to the changed volume number.\n" |& tee -a "$logfile" 3116 | } 3117 | 3118 | suggest_move_share(){ 3119 | # show_move_share 3120 | if [[ ${mode,,} == "move" ]]; then 3121 | case "$pkg" in 3122 | ActiveBackup) 3123 | show_move_share "Active Backup for Business" ActiveBackupforBusiness stopped 3124 | ;; 3125 | AudioStation) 3126 | share_link=$(readlink /var/packages/AudioStation/shares/music) 3127 | if [[ $share_link == "/${sourcevol}/music" ]]; then 3128 | show_move_share "Audio Station" music stopped more 3129 | fi 3130 | ;; 3131 | Chat) 3132 | show_move_share "Chat Server" chat stopped 3133 | ;; 3134 | CloudSync) 3135 | show_move_share "Cloud Sync" CloudSync stopped 3136 | ;; 3137 | ContainerManager) 3138 | show_move_share "Container Manager" docker stopped 3139 | docker_volume_edit 3140 | ;; 3141 | Docker) 3142 | show_move_share "Docker" docker stopped 3143 | docker_volume_edit 3144 | ;; 3145 | MailPlus-Server) 3146 | show_move_share "MailPlus Server" MailPlus running 3147 | ;; 3148 | MinimServer) 3149 | show_move_share "Minim Server" MinimServer stopped 3150 | ;; 3151 | Plex*Media*Server) 3152 | if [[ $majorversion -gt "6" ]]; then 3153 | show_move_share "Plex Media Server" PlexMediaServer stopped 3154 | else 3155 | show_move_share "Plex Media Server" Plex stopped 3156 | fi 3157 | ;; 3158 | SurveillanceStation) 3159 | show_move_share "Surveillance Station" surveillance stopped 3160 | ;; 3161 | SynologyPhotos) 3162 | share_link=$(readlink /var/services/photo) 3163 | if [[ -d "$share_link" ]]; then 3164 | if [[ $share_link == "/${sourcevol}/photo" ]]; then 3165 | show_move_share "Synology Photos" photo stopped 3166 | fi 3167 | fi 3168 | ;; 3169 | VideoStation) 3170 | share_link=$(readlink /var/packages/VideoStation/shares/video) 3171 | if [[ $share_link == "/${sourcevol}/video" ]]; then 3172 | show_move_share "Video Station" video stopped more 3173 | fi 3174 | ;; 3175 | *) 3176 | ;; 3177 | esac 3178 | fi 3179 | } 3180 | 3181 | if [[ ${mode,,} == "move" ]]; then 3182 | if [[ $all == "yes" ]]; then 3183 | # Loop through pkgs_sorted array and process package 3184 | for pkg in "${pkgs_sorted[@]}"; do 3185 | pkg_name="${package_names_rev["$pkg"]}" 3186 | suggest_move_share 3187 | done 3188 | else 3189 | suggest_move_share 3190 | fi 3191 | fi 3192 | 3193 | 3194 | #------------------------------------------------------------------------------ 3195 | # Start package and dependent packages that aren't running 3196 | 3197 | # Loop through running_pkgs_sorted array 3198 | if [[ $no_start_pkg != "yes" ]]; then 3199 | did_start_pkg="" 3200 | for pkg in "${running_pkgs_sorted[@]}"; do 3201 | pkg_name="${package_names_rev["$pkg"]}" 3202 | start_packages 3203 | done 3204 | if [[ $did_start_pkg == "yes" ]]; then 3205 | echo "" |& tee -a "$logfile" 3206 | fi 3207 | fi 3208 | 3209 | # Start pqsql dependent pkgs that were running but aren't now 3210 | # Loop through running_pkgs_dep_pgsql array 3211 | if [[ $no_start_pkg != "yes" ]]; then 3212 | did_start_pkg="" 3213 | for pgsql_pkg in "${running_pkgs_dep_pgsql[@]}"; do 3214 | if ! package_is_running "$pgsql_pkg"; then 3215 | pgsql_pkg_name="$(synogetkeyvalue "/var/packages/${pgsql_pkg}/INFO" displayname)" 3216 | package_start "$pgsql_pkg" "$pgsql_pkg_name" 3217 | fi 3218 | done 3219 | if [[ $did_start_pkg == "yes" ]]; then 3220 | echo "" |& tee -a "$logfile" 3221 | fi 3222 | fi 3223 | 3224 | if [[ $all == "yes" ]]; then 3225 | echo -e "Finished ${action,,} all packages\n" |& tee -a "$logfile" 3226 | elif [[ $auto == "yes" ]]; then 3227 | echo -e "Finished ${action,,} ${pkgs_sorted[*]}\n" |& tee -a "$logfile" 3228 | else 3229 | echo -e "Finished ${action,,} $pkg_name\n" |& tee -a "$logfile" 3230 | fi 3231 | 3232 | # Show how long the script took 3233 | end="$SECONDS" 3234 | if [[ $end -ge 3600 ]]; then 3235 | printf 'Duration: %dh %dm\n\n' $((end/3600)) $((end%3600/60)) |& tee -a "$logfile" 3236 | elif [[ $end -ge 60 ]]; then 3237 | echo -e "Duration: $((end/60))m $((end%60))s\n" |& tee -a "$logfile" 3238 | else 3239 | echo -e "Duration: ${end} seconds\n" |& tee -a "$logfile" 3240 | fi 3241 | 3242 | 3243 | #------------------------------------------------------------------------------ 3244 | # Show how to export and import package's database if dependent on MariaDB10 3245 | 3246 | # Loop through package_names associative array 3247 | for pkg_name in "${!package_names[@]}"; do 3248 | pkg="${package_names[$pkg_name]}" 3249 | if [[ ${mode,,} != "move" ]]; then 3250 | info="/var/packages/${pkg}/INFO" 3251 | if /usr/syno/bin/synogetkeyvalue "$info" install_dep_packages | grep 'MariaDB' >/dev/null 3252 | then 3253 | mariadb_list+=("${pkg_name}") 3254 | mariadb_show="yes" 3255 | fi 3256 | fi 3257 | done 3258 | 3259 | if [[ $mariadb_show == "yes" ]]; then 3260 | if [[ ${mode,,} == "backup" ]]; then 3261 | # Show how to export package's database 3262 | echo -e "If you want to ${Yellow}backup${Off} the database of"\ 3263 | "${Cyan}${mariadb_list[*]}${Off} do the following:" 3264 | echo -e "If you want to backup the database of"\ 3265 | "${mariadb_list[*]} do the following:" >> "$logfile" 3266 | echo " If you don't have phpMyAdmin installed:" |& tee -a "$logfile" 3267 | echo " 1. Install phpMyAdmin." |& tee -a "$logfile" 3268 | echo " 2. Open phpMyAdmin" |& tee -a "$logfile" 3269 | echo " 3. Log in with user root and your MariaDB password." |& tee -a "$logfile" 3270 | echo " Once you are logged in to phpMyAdmin:" |& tee -a "$logfile" 3271 | echo " 1. Click on the package name on the left." |& tee -a "$logfile" 3272 | echo " 2. Click on the Export tab at the top." |& tee -a "$logfile" 3273 | echo " 3. Click on the Export button." |& tee -a "$logfile" 3274 | echo -e " 4. Save the export to a safe location.\n" |& tee -a "$logfile" 3275 | elif [[ ${mode,,} == "restore" ]]; then 3276 | # Show how to import package's exported database 3277 | echo -e "If you want to ${Yellow}restore${Off} the database of"\ 3278 | "${Cyan}${mariadb_list[*]}${Off} do the following:" 3279 | echo -e "If you want to restore the database of"\ 3280 | "${mariadb_list[*]} do the following:" >> "$logfile" 3281 | echo " If you don't have phpMyAdmin installed:" |& tee -a "$logfile" 3282 | echo " 1. Install phpMyAdmin." |& tee -a "$logfile" 3283 | echo " 2. Open phpMyAdmin" |& tee -a "$logfile" 3284 | echo " 3. Log in with user root and your MariaDB password." |& tee -a "$logfile" 3285 | echo " Once you are logged in to phpMyAdmin:" |& tee -a "$logfile" 3286 | echo " 1. Click on the package name on the left." |& tee -a "$logfile" 3287 | echo " 2. Click on the Import tab at the top." |& tee -a "$logfile" 3288 | echo " 3. Click on the 'Choose file' button." |& tee -a "$logfile" 3289 | echo -e " 4. Browse to your exported .sql file and import it.\n" |& tee -a "$logfile" 3290 | fi 3291 | fi 3292 | 3293 | 3294 | #------------------------------------------------------------------------------ 3295 | # Show how to migrate docker containers if different file system 3296 | 3297 | if [[ $docker_migrate == "yes" ]]; then 3298 | echo -e "You will need to migrate your containers" |& tee -a "$logfile" 3299 | echo " 1. Open Container Manager." |& tee -a "$logfile" 3300 | echo " 2. Click the Manage link." |& tee -a "$logfile" 3301 | echo " 3. Select the container you want to migrate." |& tee -a "$logfile" 3302 | echo " 4. Click Migrate." |& tee -a "$logfile" 3303 | echo -e " 5. Click Continue.\n" |& tee -a "$logfile" 3304 | fi 3305 | 3306 | 3307 | #------------------------------------------------------------------------------ 3308 | # Suggest change location of shared folder(s) if package moved 3309 | 3310 | suggest_change_location(){ 3311 | # Suggest moving CloudSync database if package is CloudSync 3312 | if [[ $pkg == CloudSync ]]; then 3313 | # Show how to move CloudSync database 3314 | echo -e "If you want to move the CloudSync database to $targetvol" |& tee -a "$logfile" 3315 | echo " 1. Open Cloud Sync." |& tee -a "$logfile" 3316 | echo " 2. Click Settings." |& tee -a "$logfile" 3317 | echo " 3. Change 'Database Location Settings' to $targetvol" |& tee -a "$logfile" 3318 | echo -e " 4. Click Save.\n" |& tee -a "$logfile" 3319 | fi 3320 | 3321 | # Suggest moving @download if package is DownloadStation 3322 | if [[ $pkg == DownloadStation ]]; then 3323 | # Show how to move DownloadStation database and temp files 3324 | #file="/var/packages/DownloadStation/etc/db-path.conf" 3325 | #value="$(/usr/syno/bin/synogetkeyvalue "$file" db-vol)" 3326 | #if [[ $value != "$targetvol" ]]; then 3327 | echo -e "If you want to move the DownloadStation database & temp files to $targetvol" |& tee -a "$logfile" 3328 | echo " 1. Open Download Station." |& tee -a "$logfile" 3329 | echo " 2. Click Settings." |& tee -a "$logfile" 3330 | echo " 3. Click General." |& tee -a "$logfile" 3331 | echo " 4. Change 'Temporary location' to $targetvol" |& tee -a "$logfile" 3332 | echo -e " 5. Click OK.\n" |& tee -a "$logfile" 3333 | #fi 3334 | fi 3335 | 3336 | # Suggest moving Note Station database if package is NoteStation 3337 | if [[ $pkg == NoteStation ]]; then 3338 | # Show how to move Note Station database 3339 | echo -e "If you want to move the Note Station database to $targetvol" |& tee -a "$logfile" 3340 | echo " 1. Open Note Station." |& tee -a "$logfile" 3341 | echo " 2. Click Settings." |& tee -a "$logfile" 3342 | echo " 3. Click Administration." |& tee -a "$logfile" 3343 | echo " 4. Change Volume to $targetvol" |& tee -a "$logfile" 3344 | echo -e " 5. Click OK.\n" |& tee -a "$logfile" 3345 | fi 3346 | 3347 | # Suggest moving Synology Drive database if package is SynologyDrive 3348 | if [[ $pkg == SynologyDrive ]]; then 3349 | # Show how to move Drive database 3350 | file="/var/packages/SynologyDrive/etc/db-path.conf" 3351 | value="$(/usr/syno/bin/synogetkeyvalue "$file" db-vol)" 3352 | if [[ $value != "$targetvol" ]]; then 3353 | echo -e "If you want to move the Synology Drive database to $targetvol" |& tee -a "$logfile" 3354 | echo " 1. Open Synology Drive Admin Console." |& tee -a "$logfile" 3355 | echo " 2. Click Settings." |& tee -a "$logfile" 3356 | echo " 3. Change Location to $targetvol" |& tee -a "$logfile" 3357 | echo -e " 4. Click Apply.\n" |& tee -a "$logfile" 3358 | fi 3359 | fi 3360 | 3361 | # Suggest moving database if package is USBCopy 3362 | if [[ $pkg == USBCopy ]]; then 3363 | # Show how to move USB Copy database 3364 | echo -e "To move the USB Copy database to $targetvol" 3365 | echo " 1. Open 'USB Copy'." 3366 | echo " 2. Click the gear icon to open settings." 3367 | echo " 3. Change Database location to $targetvol" 3368 | echo -e " 4. Click OK.\n" 3369 | fi 3370 | 3371 | # Suggest moving VMs if package is Virtualization 3372 | if [[ $pkg == Virtualization ]]; then 3373 | # Show how to move VMs 3374 | echo -e "If you want to move your VMs to $targetvol\n" |& tee -a "$logfile" 3375 | echo "1. Add $targetvol as Storage in Virtual Machine Manager" |& tee -a "$logfile" 3376 | echo " 1. Open Virtual Machine Manager." |& tee -a "$logfile" 3377 | echo " 2. Click Storage and Click Add." |& tee -a "$logfile" 3378 | echo " 3. Complete the steps to add $targetvol" |& tee -a "$logfile" 3379 | echo -e "\n2. Move the VM to $targetvol" |& tee -a "$logfile" 3380 | echo " 1. Click on Virtual Machine." |& tee -a "$logfile" 3381 | echo " 2. Click on the VM to move." |& tee -a "$logfile" 3382 | echo " 3. Shut Down the VM." |& tee -a "$logfile" 3383 | echo " 4. Click Action then click Migrate." |& tee -a "$logfile" 3384 | echo " 5. Make sure Change Storage is selected." |& tee -a "$logfile" 3385 | echo " 6. Click Next." |& tee -a "$logfile" 3386 | echo -e " 7. Complete the steps to migrate the VM.\n" |& tee -a "$logfile" 3387 | fi 3388 | } 3389 | 3390 | if [[ ${mode,,} == "move" ]]; then 3391 | if [[ $all == "yes" ]]; then 3392 | # Loop through pkgs_sorted array and process package 3393 | for pkg in "${pkgs_sorted[@]}"; do 3394 | pkg_name="${package_names_rev["$pkg"]}" 3395 | suggest_change_location 3396 | done 3397 | else 3398 | suggest_change_location 3399 | fi 3400 | fi 3401 | 3402 | exit 3403 | 3404 | --------------------------------------------------------------------------------