├── .gitignore ├── BSD-LICENSE.txt ├── COPYING.txt ├── HISTORY.txt ├── INSTALL.txt ├── README.txt ├── demo.mlbackupconf.sample ├── fix-postfix-queue.sh ├── globalexclusions ├── install.sh └── mlbackup /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore vim backup files. 2 | *~ 3 | versionnumber 4 | .mlbackup.swp 5 | -------------------------------------------------------------------------------- /BSD-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Pepi Zawodsky 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | MacLemon Backup - COPYING 2 | 3 | # Author: Pepi Zawodsky 4 | # Authors eMail: mlbackup@maclemon.at 5 | # Website: https://github.com/MacLemon/mlbackup 6 | # License: Modified BSD License (also known as "3-clause BSD license") 7 | 8 | You should have received a copy of the "Modified BSD License" with this software. BSD-LICENSE.txt 9 | 10 | If you create derivative works of or improve this software, we love to hear about them. We are interested in incorporating your changes into the main project as well. If you have questions, suggestions, bug-reports or feature-requests please contact the author! Pull requests on Github are welcome as well! -------------------------------------------------------------------------------- /HISTORY.txt: -------------------------------------------------------------------------------- 1 | # What's new? 2 | ------------------------------------------------------------ 3 | 4 | ## mlbackup 194 5 | Fixes issue #6: A bug in installer.sh and the installer package that broke online versioncheck. 6 | https://github.com/MacLemon/mlbackup/issues/6 7 | 8 | ## mlbackup 193 9 | ### New features in mlbackup 10 | - An alias named "Latest" is now created after each successful backup pointing to the latest finished backup. 11 | - Added a new config option $MLcustomRsyncOptions that allows custom and per configuration rsync options to be used. This option is passed after all mlbackup native options and may be suitable to override these. 12 | 13 | #### new features in the admin email message 14 | - The admin email now contains a link to my flattr button https://flattr.com/thing/141895/mlbackup and encourages users to make a donation to support further development. 15 | - The admin email message will now report the start and end timestamps of each backup. 16 | - The amount of free space on the MLdestPath is now reported in the admin email message. 17 | - Configfile, backup source and destination are now reported in the admin email message. 18 | - When reporting that there are ERROR backups the destination path is now added to the Admin Email. 19 | - Report Emails now will include a human readable error message for fatal and non-fatal errors. 20 | 21 | #### globalexclusions 22 | - global exclusions: Added exclusion of TimeMachine local snapshots used in 10.7 and higher 23 | 24 | 25 | ### Improvements 26 | #### Admin email message 27 | - improved wording for debug messages and admin email. 28 | 29 | #### globalexclusions 30 | - global exclusions is now sorted in: system and global/usual things, Apple things, files created by GUI applications., Resorted Apple OS's, Fixed two typos in globalexclusions - Thanks to @zettt for the patch! 31 | 32 | ### Bugfixes 33 | - Fixed the way the install.sh script handles detection of systems that need the postfix fix. 34 | - Corrected a bug that would try to fix postfix on 10.7 and fail. This part is now only run on 10.[456]. Also fixes a bug with the installer package that would report failure where it actually did install just fine. 35 | - Fixed a minor typo in handling of the comment added to a backup if setfcomment is installed by fink. 36 | - Corrected a typo in case rsync reported an error to include a human readable error message in the admin email. 37 | - Corrected a bug that would prevent the addition of a human readable error message when there were warnings or errors during the backup. 38 | 39 | ### mlbackup 40 | - Added error message 127 "Rsync not found on remote machine, probably mlbackup not installed." - Thanks to Yene for the patch! 41 | - Corrected a typo in the README. 42 | - Updated MLinfoURL to point users to github for updates instead of maclemon.at 43 | - Improved stability: Quoted a few file variables. These are extremley unlikely (if possible at all) to contain spaces but for safety reasons they were quoted. 44 | - More robust detection of concurrent invocation of mlbackup with the same config file. 45 | - More robust detection of the most recent backup to refer to for hard links. 46 | - Improved handling and cleanup of OLD, ERROR and crashed backups that leave a .pid tag and .noindex folder. 47 | - More robust detection of which backups to rotate. 48 | 49 | ## License changed to "Modified BSD license" 50 | - We're no longer using the GPL license, but from mlbackup-190 on we're using the more permissive Modified BSD license (also known as "3-clause BSD license") A copy of the license is included with mlbackup. 51 | 52 | 53 | ## rsync 3.0.9 54 | - Updated bundled rsync 3 to 3.0.9 55 | - For detailed information what is new in rsync 3.0.9 see rsync-3.0.9-NEWS.txt 56 | 57 | ------------------------------------------------------------ 58 | 59 | ## mlbackup 160 60 | - Fixes issue 1, a bug that would try to send mail even if MLAdminEmail was empty. 61 | - Growl notifications are now less verbose in the logs if Growl somehow misbehaves. 62 | 63 | ## rsync 3.0.8 64 | - Updated bundled rsync 3 to 3.0.8 65 | - Fixes a bug with rsync and libiconv that could occur on 32-bit PPC systems under 10.4. 66 | - For detailed information what is new in rsync 3.0.8 see rsync-3.0.8-NEWS.txt 67 | 68 | ------------------------------------------------------------ 69 | 70 | ## mlbackup 157 71 | - First new release of mlbackup that is now hosted on [GitHub](https://github.com/MacLemon/mlbackup) 72 | - mlbackup now requires the bundled rsync 3.0.7, be sure to update all your Macs to the new release. 73 | - Rotating Backups should now be slightly faster. 74 | 75 | ### rsync 3.0.7 76 | - Updated bundled rsync 3 to 3.0.7 77 | - Bundled rsync 3 now comes optimized for PowerPC G3, PowerPC G4, PowerPC G5, intel 32bit and intel 64bit processors. 78 | - Bundled rsync 3 passes all backup bouncer tests and also Mike Bombich's extended backup bouncer tests. 79 | -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | MacLemon Backup - INSTALL 2 | 3 | There are two ways to install mlbackup on your Mac. 4 | 5 | The recommended way: 6 | Use the Installer package to install mlbackup and the required rsync 3 on your Mac. This is the recommended way and can be used with the graphical Installer.app, /usr/sbin/installer on the command line, or even Apple Remote Desktop. 7 | 8 | 9 | The not-recommended way: 10 | Use the included install.sh script to copy all the mlbackup files to your Mac. This DOES NOT install the REQUIRED rsync 3 automatically. Basically this method is only suitable if you want to install mlbackup only for testing your own patches. 11 | 12 | You can build rsync 3 from the included sources which you can also obtain from http://rsync.samba.org/ 13 | It is likely that you need to edit the rsync path in /usr/local/bin/mlbackup manually when building your own rsync or pass --prefix=/usr/local/maclemon to ./configure. 14 | 15 | For the email notification to work make sure that /usr/bin/mail correctly works on your system. 16 | 17 | 18 | 19 | The following files will be placed on your system: 20 | 21 | /etc/maclemon/backup/demo.mlbackupconf.sample 22 | A sample configuration file which you are encouraged to duplicate, rename and put your configuration option into. Do not directly edit this file as it will be overwritten by newer installations of the mlback install.sh script. 23 | 24 | 25 | /etc/maclemon/backup/globalexclusions 26 | A file containing files and folders which should not be backed up on Mac OS X or which are just plain nonsense to backup (like caches). Do not edit this file directly, use a per configuration exclusion file for your needs instead to override the settings in here. 27 | 28 | 29 | /usr/local/bin/mlbackup 30 | The main mlbackup script that does most of the magic. 31 | 32 | 33 | /usr/local/maclemon/bin/rsync 34 | /usr/local/maclemon/share/man/man1/rsync.1 35 | /usr/local/maclemon/share/man/man5/rsyncd.conf.5 36 | The great rsync 3 and man pages that empower mlbackup and do the rest of the magic. 37 | 38 | 39 | UPGRADES from prior versions of mlbackup: 40 | You can simply use the .mpkg to update mlbackup and rsync. There is no NEED to change your configuration files. You are ENCOURAGED to compare your currently used config files to the updated demo.mlbackupconf.sample to find out about new options that might be of interest to you. 41 | 42 | # EOF 43 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | mlbackup - README 2 | 3 | If you like mlbackup and use it to safeguard your data, please consider supporting it's further development through flattr! Thanks! 4 | https://flattr.com/thing/141895/mlbackup 5 | 6 | This software is provided as-is. mlbackup has proven to work fine on my servers and many other's, but please do not solely rely on the backups made with mlbackup. As usual, always have at least a second backup for vital data. Please use the wiki at the [mlbackup](https://github.com/MacLemon/mlbackup) github page to post your tips and tricks and how you use mlbackup! 7 | 8 | 9 | 10 | Target Audience: 11 | ------------------------------------------------------------------------------- 12 | Mac OS X Admins and Geek Users who like a nice intelligent and incremental backup through the shell. Can be run from launchd (or cron) if you like. This is NOT INTENDED for casual users. mlbackup is explicitly targeted at the Mac OS X (10.4 Tiger, 10.5 Leopard, 10.6 Snow Leopard and respective Server Versions) platform. It has not been tested on other software platforms! mlbackup requires at least Mac OS X 10.4.11 and has been successfully tested up to 10.7.3 with backup bouncer. 13 | 14 | mlbackup is not yet tested on the Mac OS X 10.8 Mountain Lion Developer Preview, but will support 10.8 in the future. If you did test mlbackup on Mountain Lion I welcome your feedback! 15 | 16 | 17 | 18 | Download & Versioncheck: 19 | ------------------------------------------------------------------------------- 20 | The recommended way is to use the full packages from the [mlbackup downloads](https://github.com/MacLemon/mlbackup/downloads) on Github! 21 | You can always get the latest version of mlbackup at the [mlbackup](https://github.com/MacLemon/mlbackup) GitHub page. 22 | If you invoke mlbackup without a config file parameter it will check online for an updated version. It tries to connect to http://versioncheck.maclemon.at/mlbackup.txt to find out if there is a newer version available. At no point is ANY information sent to our servers to respect your privacy. 23 | 24 | 25 | 26 | Installation: 27 | ------------------------------------------------------------------------------- 28 | Just use install the installer package available on the [mlbackup downloads](https://github.com/MacLemon/mlbackup/downloads) page on Github. 29 | See the INSTALL.txt file for not recommended other ways. (Those are mainly for people who want to contribute to the development of mlbackup.) 30 | 31 | 32 | 33 | How to use mlbackup: 34 | ------------------------------------------------------------------------------- 35 | Duplicate the provided sample configuration file found in /etc/maclemon/backup/demo.mlbackupconf.sample after installation. (Do NOT edit and use this file as your working configuration as it will be overwritten with a newer versions if you update mlbackup.) 36 | The sample config is well documented and should be easy for an admin to fill out all the necessary variables to get a working configuration for your purpose. If you find any parameters complex or unintuitive to use send us feedback on how we can improve this! 37 | 38 | To invoke mlbackup use a command like this: 39 | mlbackup path/to/your/configuration-file.mlbackupconf 40 | 41 | I recommend to use the following paths to store your config files: 42 | - For system wide configurations: /etc/maclemon/backup/ or /etc/mlbackup 43 | - For personal backups: ~/.mlbackup/ 44 | 45 | 46 | 47 | Additions: 48 | ------------------------------------------------------------------------------- 49 | None of these are mandatory, but they provide some comfort and help to beautify your backups. 50 | 51 | Growl: 52 | If you have growl and growlnotify installed, mlbackup will try to make use of it. For more info on growl see http://growl.info/ 53 | 54 | 55 | 56 | Known Issues: 57 | ------------------------------------------------------------------------------- 58 | Still no manpage for mlbackup yet. (There still is hope and you should be able to get mlbackup up and running easily anyway.) 59 | 60 | The backup set name may NOT include german umlaut characters and spaces. (I am still investigating why this is the case. If you have any information on how to make this work, please contact me!) This issue ONLY affects the naming of the backup sets. The files you intend to backup are not affected and will be backupped just fine! 61 | 62 | If you are using Kerio mailserver be sure to check with the Kerio documentation on how to use the sendmail replacement wrapper for Kerio on your system. Otherwise mlbackup may not be able to send email. If you're using the Mac OS X postfix mailserver everything should just work. If you don't want to or cannot send email, just leave the $MLadminEmail="" 63 | 64 | Versioncheck will not work if you need to connect to the web using a proxy server. This will hopefully be improved in a future version. (Patches welcome!) 65 | 66 | If mlbackup cannot check for updates it will present you an Exit Code that it got from curl(1) but will not give you a helpful human readable error message. At the moment you need to look up the error in man curl. 67 | 68 | 69 | 70 | Feedback: 71 | ------------------------------------------------------------------------------- 72 | You can direct feedback to me in several ways: 73 | - My GitHub Profile: https://github.com/MacLemon 74 | - Twitter: https://twitter.com/mlbackup 75 | - eMail: mlbackup@maclemon.at 76 | 77 | 78 | 79 | Bug Reports: 80 | ------------------------------------------------------------------------------- 81 | If you find a bug in mlbackup please open an issue at the [mlbackup issues](https://github.com/MacLemon/mlbackup/issues) page on Github! 82 | 83 | 84 | When reporting a bug, please tell us how we can reproduce the bug. Please also include the configuration file you use when the bug occurs. Also include rsync.log and error.log of the backup where the bug showed up. To provide Debug output, please add MLdebug=1 to your config. This will spit out vast amounts of debugging information that will help track down the problem. Don't forget to remove that line again or set MLdebug=0 if you don't need it anymore. It will speed up your backups considerably. 85 | 86 | 87 | Enjoy using mlbackup! 88 | 89 | Best Regards 90 | Pepi Zawodsky 91 | -------------------------------------------------------------------------------- /demo.mlbackupconf.sample: -------------------------------------------------------------------------------- 1 | # BackLemon Demo Configuration file 2 | 3 | # To use this config file invoke mlbackup like this: 4 | # mlbackup path/to/your.mlbackupconf 5 | 6 | 7 | # NOTE on Naming Backups: 8 | # Known issue: Spaces and german Umlauts in the backup name do cause problems, so just don't use them. 9 | # If you know how to make this work, please contact me! 10 | 11 | # What is the name of this backup set? 12 | MLbackupName="MacLemon-Sample" 13 | 14 | 15 | # How many Backup Sets to keep? (Integer > 0) 16 | # Default: 5 17 | MLbackupCount=5 18 | 19 | 20 | # Configuring the SOURCE that will be backed up: 21 | 22 | # What file or directory to Backup. (No trailing Slash for directories) 23 | # Default: $HOME 24 | MLsourcePath="$HOME" 25 | 26 | 27 | # Configuring the Destination we will save the Backup to. 28 | 29 | # Where shall the Backups be stored (local path on the destination machine) 30 | # Default: /Volumes/Backup 31 | MLdestPath="/Volumes/Backup" 32 | 33 | 34 | # Where to send the eMail notification about the backup to? 35 | # If you need multiple recipients separate them with commas. 36 | # Example: "admin@example.com,user@example.com" 37 | 38 | # If you don't have a working mailserver (postfix) setup on your Mac, like this might be on a Client Mac, you can just leave MLadminEmail="" and mlbackup will do it's backups as good as always, but without trying to send mail. The message will still be saved with the backup so you can have a look at it. Of course you may also choose to just not receive email about backups. 39 | # Default: $USER 40 | MLadminEmail="$USER" 41 | 42 | 43 | # If you don't want to exclude certain files that we deem unnecessary for a backup, set this parameter to 0. 44 | # To see what we exclude by default see /etc/maclemon/backup/globalexclusions 45 | # The default is to respect globalexclusions and not backup what is mentioned there. 46 | # Default: MLuseGlobalExclusions=1 47 | MLuseGlobalExclusions=1 48 | 49 | 50 | # You can specify an additional file with objects that you want to exclude from your backups. 51 | # You can leave that parameter empty "" if you don't want to use this. 52 | # You may use both MLconfigExcludeFrom and MLuseGlobalExclusions in combination. 53 | # Default: MLconfigExcludeFrom="" 54 | MLconfigExcludeFrom="" 55 | 56 | # You can specify custom rsync options per config here: 57 | MLcustomRsyncOptions="" 58 | # Example: You can set --bwlimit=3072 to limit rsync I/O throughput to 3MB per second. bwlimit is passed in KB/s 59 | # See man rsync for other options you may want to use. 60 | # Hint: Turning on debugging with MLdebug=1 in this config file to see the final resulting rsync command in the log. 61 | #EOF 62 | -------------------------------------------------------------------------------- /fix-postfix-queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # fixes the postfix queue on Mac OS X Client 3 | # Never touches postfix on Mac OS X Server. 4 | 5 | if [ ! $(sw_vers | grep -q "Server") ] 6 | then 7 | if [ $(sw_vers | grep -q "10.[456]") ] 8 | then 9 | echo 10 | echo Fixing the postifx queue system on Mac OS X client 11 | /etc/postfix/post-install create-missing 12 | fi 13 | else 14 | echo 15 | echo This is Mac OS X Server, not touching the postfix system. 16 | fi 17 | #EOF 18 | -------------------------------------------------------------------------------- /globalexclusions: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Excludes File for rsync Backups 3 | # by Pepi 2005-2009 4 | # eMail: mlbackup@maclemon.at 5 | # 6 | # For mlbackup __VVAALLIIDD__RREEVVIISSIIOONNSS__ 7 | # 8 | # This is the global exclusions file for backlemon. Files and folders mentioned 9 | # in this file will be EXCLUDED from your backup! 10 | # 11 | # To have one of these still backed up, use your personal inclusions an 12 | # exclusions file for a backup. See man rsync for more info on how to write 13 | # these or learn from the comments in this file. 14 | # 15 | # Please send ANY suggestions, corrections or other files/folders that should 16 | # be included in this file to pepi@maclemon.at (In english or german language) 17 | # If you are the author of a software that keeps cache data in uncommon places 18 | # that may safely be left out from a backup, please contact me with the details 19 | # so that I can add these locations to this exclusions file. 20 | # 21 | # Things we consider for future exclusion are at the end of the file. Any info 22 | # regarding these files is welcome. 23 | # 24 | # To learn more about rsync include/exclude patterns see the rsync manpage! 25 | # 26 | ############################################################################### 27 | # TODO: 28 | # Globally SORT all this stuff. How? Suggestions are welcome. 29 | # 30 | ############################################################################### 31 | # 32 | # 2012/02/17 Added TimeMachine local Snapshots used in 10.7 or higher 33 | # 34 | # 2012/02/15 Changed: Made a first attempt at reorganizing this file 35 | # 36 | # 2009/02/04: Added: Different stuff related to temp directories 37 | # fifos and sockets 38 | # 2008/11/20: Added: 39 | # iSlayer iStat Menus Cache 40 | # Acrobat 8 Cache 41 | # Miro Icon Cache and Partial Files 42 | # Leopard preloaded Updates 43 | # 44 | # 2008/08/02: Added several Leopard only Exclusions 45 | # 46 | # 2007.05.29: Added System Kernel Extensions Cache File 47 | # Removed Testing Excludes in favor of per config exclusions 48 | # 49 | # 2007.05.27: Added .part Mozilla Firefox 2.0.0.3 Downlaod partial files 50 | # Added Adobe PCD Cache Exclusion 51 | # 52 | # 2006.10.11: Added Exclusion patterns to speed up testing. (will be removed) 53 | # 2006.08.30: Corrected some directory exclusions 54 | # 2006.08.22: Added Cache files for Adobe Bridge (Creative Suite 2) 55 | # 2006.08.22: Added tmp/ and temp/ directory global exclusion 56 | # 57 | # Version 8 2006.06.16: Improved explanation for Apple Backup 3 excludes. 58 | # File is now under SubVersion Control. 59 | # 60 | # Version 7 2006.03.26 Cleaned up and added some more explanations 61 | # Additions: .TemporaryItems/ 62 | # 63 | # Version 6 2006.03.17 Added Notes about NetNewsWire Cache Files 64 | # 65 | # Version 5 2006.03.13 Added .cache Fileextension to excludes 66 | # 67 | # Version 4 2006.03.12 Added .iChatTransfer Fileextension to excludes 68 | # 69 | # Version 3 2006.03.06 Added some more files and folder types specific to OSX 70 | # Especially Objects that might reside in a user's 71 | # Library folder. 72 | # 73 | # New Exclusions Added: 74 | # AppleWorks Filter and Assistant Cache files (german) 75 | # (other language's localized filenames requested) 76 | # Freespace 2 Game Cache file 77 | # Webkit Favicon Cache (regexp should be improved!) 78 | # User's Logs (default keep) 79 | # ACE2Cache (unknown app, currently keeping) 80 | # Safari Favicon Cache 81 | # BBEdit Cache and Backup Files 82 | # Shiira Browser Favicons Cache 83 | # BZFlag (Game) Cache Files 84 | # Camino (Webbrowser) Cache Files 85 | # TVtoday Fernsehen Widget Cache 86 | # FlickrExport Resize Cache 87 | # Google Earth MyPlaces Application Backup file 88 | # Apple Backup Failed Backups 89 | # Java Applet Cache 90 | # Improved Exclusions: 91 | # mlMac Folders 92 | # NetNewsWire Backup and Favicon Cache Folders 93 | # 94 | # Version 2 2005.07.25. Added a few files and folder types, specific to 95 | # Mac OS X 10.4 (Tiger), cleared up the wording of some 96 | # warnings to make it easier to understand. 97 | # 98 | # Version 1 2005.03.23. initial concept of exclude files for 99 | # a backup of your $HOME. 100 | # 101 | ############################################################################### 102 | 103 | # Ususal extensions to local backup and temporary files 104 | - *~ 105 | - *.bak 106 | - *.backup 107 | - *.tmp 108 | - *.temp 109 | - /private/tmp/* 110 | - /tmp/* 111 | - /private/var/vm/* 112 | - /var/vm/* 113 | - *.sock 114 | - *.fifo 115 | 116 | # Java Applet Cache 117 | - .jpi_cache/ 118 | 119 | # Temporary Items folders created by Mac OS and other Apps 120 | - .TemporaryItems/ 121 | - temp/ 122 | - tmp/** 123 | 124 | # We won't backup stuff, that is already in the Trash. 125 | - .Trash/ 126 | - .Trashes 127 | - Network Trash Folder/ 128 | - ._Network Trash Folder 129 | 130 | # Common Cache Files for many apps 131 | - *.cache 132 | 133 | # Apple stuff 134 | ############################################################################### 135 | 136 | # Classic Finder Desktop Database files, only used by Mac OS 9/Classic 137 | # Will be useless in case of restore 138 | - Desktop DB 139 | - Desktop DF 140 | 141 | # 10.3+ Adaptive hotfile Clustering Info will be useless in case of restore. 142 | - .hotfiles.btree 143 | 144 | # 10.4+ Spotlight indeces will be useless in case of restore. 145 | - .Spotlight-V100/ 146 | # Special note, I guess the V100 MAY change in future releases of Spotlight. 147 | # So we better be aware of this. May be changed to a wildcard in the future. 148 | 149 | # 10.5 additions 150 | - /.fseventsd 151 | # TimeMachine tagging of Volume 152 | - .com.apple.timemachine.supported 153 | # Leopard Special Folders 154 | - /net 155 | - /home 156 | - /Network 157 | - /automount 158 | - /dev/* 159 | - /Volumes/* 160 | - /.com.apple.NetBootX 161 | - /OpenFolderListDF 162 | - /VM Storage 163 | - /Shutdown Check 164 | - /Cleanup At Startup 165 | - /Auth.bak 166 | - /.vol/* 167 | - /Library/Updates/* 168 | 169 | # Mac OS X 10.7 and higher 170 | # Local TimeMachine Snapshots 171 | - /.MobileBackups 172 | 173 | # Find By Content Lock Folder, used by Sherlock 174 | - .FBCLockFolder/ 175 | 176 | # Finder Desktop File information files 177 | # - .DS_Store 178 | # Excluding these files will speed up the backup noticably, but also at the cost of loosing your view selections, custom Icons and Spotlight/finder comments set on objects. Depending on your source files you may or may not want to skip these files. 179 | 180 | # The Volume Settings Folder by Mac OS 181 | - TheVolumeSettingsFolder/ 182 | - ._TheVolumeSettingsFolder 183 | 184 | # The FindByContentFolder from Mac OS 9 (Sherlock) 185 | - /TheFindByContentFolder 186 | - .FBCindex 187 | - Library/Indexes/FindByContent/00001/ 188 | - Library/Indexes/FindByContent/00002/ 189 | - Library/Indexes/FindByContent/FBCPrivateIndexDB.plist 190 | 191 | # Mac OS X System Kernel Extensions Cache File 192 | - Library/Extensions.kextcache 193 | 194 | # User's Caches, global Library Caches and even System Caches 195 | - Library/Caches/ 196 | 197 | # Aliases to the recently used apps/docs in the Apple Menu 198 | - Library/Recent Applications/ 199 | - Library/Recent Documents/ 200 | 201 | # Bookmarks to recently connected servers (AFP, SMB, FTP, etc.) 202 | # Accessible from the Finders "Go" Menu 203 | # We do not exclude these by default, as they're like bookmarks. 204 | # - Library/Recent Servers/ 205 | 206 | # Users Logs and global Library Logs (for all users) 207 | # You might be interested in keeping those logs, so the default is to backup them 208 | # - Library/Logs/ 209 | # Or skip only the CrashReporter Logs and keep the rest? 210 | # - Library/Logs/CrashReporter/*.log 211 | 212 | # Apple iSync Backup Data 213 | # Currently we keep this, as I've seen to many people empty their phone and 214 | # AddressBook/Calendar by dumb use of iSync 215 | # If you don't want to keep this, uncomment the following line (remove # ) 216 | # - Library/SyncService/Backup Data/ 217 | 218 | # Flickr Export Resize Cache 219 | # Info: http://flickr.com/ 220 | - Library/Application Support/FlickrExport/ResizeCache/ 221 | 222 | # User's and System Keychains 223 | ############################################################################### 224 | 225 | ############################################################################### 226 | ############################ SECURITY WARNING ################################# 227 | ############################################################################### 228 | # If you don't know about the safety of your data on the 229 | # location you save your backup to, you may want to SKIP these as your 230 | # keychains may contain vital and private login data as well as your encryption 231 | # private keys and certificates! 232 | # 233 | # Keychain files are protected by a password (usually your login password) 234 | # so make sure at least that password is really good. 235 | # 236 | # In that case you should backup your keychains to ANOTHER location that you 237 | # know your files are safe on! 238 | # (Like your private iPod, USB Stick, external Drive, etc.) 239 | # 240 | # If the line below this block begins with a comment "#" or ";" then your 241 | # keychain files will be backuped! 242 | ############################################################################### 243 | # - Library/Keychains/ 244 | 245 | # User's Fonts 246 | # CAUTION: If you're doing a lot of font management (activating/deactivatig) 247 | # fonts, you may want to SKIP this folder, as font's might be copied to and 248 | # deleted from this folder by your font management software. 249 | # eg: Extensis Suitcase, FontDoctor, FontExplorer, etc. 250 | # - Library/Fonts/ 251 | 252 | ############################################################################### 253 | # Things we are considering for exclusion, but are not yet sure if this is ok. 254 | # If you have insight about one of these items please contact me! 255 | ############################################################################### 256 | # 257 | # Distributed Compiler, /usr/bin/distcc 258 | # ~/.distcc/ 259 | # ~/.distcc/state/ 260 | 261 | 262 | # Apps 263 | ############################################################################### 264 | 265 | # Miro 266 | - Library/Application Support/Miro/icon-cache/ 267 | - Movies/Miro/Incomplete Downloads 268 | 269 | # Google Earth - MyPlaces Application Backup File & temp file 270 | # Info: http://earth.google.com 271 | - Library/Application Support/Google Earth/myplaces.backup.kml 272 | - Library/Application Support/Google Earth/myplaces.kml.tmp 273 | 274 | # iSerial Reader 275 | # - Library/Application Support/iSerial Reader/Cache/ 276 | 277 | # iSlayer iStatPro Widget 278 | - Library/Application Support/iSlayer/ProcessesIconCache/ 279 | - Library/Application Support/iSlayer/Processes/IconsCache 280 | 281 | # Wired.app 282 | ############################################################################### 283 | # This ONLY applies to wired versions BELOW 1.3. Since 1.3 passwords are stored 284 | # in the keychain where they belong. 285 | # 286 | # SECURITY WARNING: This file contains login data to your wired bookmarks in 287 | # PLAIN TEXT! If you're not sure your backup location is safe from prying eyes 288 | # you may want to skip this file and backup to another location. 289 | # 290 | # Since Mac OS 10.4 .plist files are usually stored as binary XML files. 291 | # This takes about 15 seconds more to get to the plain text passwords. 292 | # Conclusion, it's just as unsave as before! Take care! 293 | # 294 | # If the line below this block begins with a comment "#" or ";" then your 295 | # Wired Preferences will be backuped! 296 | ############################################################################### 297 | # - Library/Preferences/com.zanka.WiredClient.plist 298 | 299 | # BZflag (Game) Cache files 300 | # Info: http://sourceforge.net/projects/bzflag/ 301 | - Library/Application Support/BZFlag/cache/ 302 | 303 | 304 | # Camino (Mozilla Engine based Cocoa webbrowser) Cache Files 305 | # Info: http://www.caminobrowser.org/ 306 | - Library/Application Support/Camino/Cache/ 307 | 308 | 309 | # TVtoday Fernsehen Widget (TV Program Guide) Cache Files 310 | # Info: http://www.sebastian-krauss.de/software/ 311 | - Library/Application Support/Fernsehen/Cache/ 312 | 313 | # Adobe Acrobat Distiller FontCache Files 314 | # Info: http://www.adobe.com/ 315 | 316 | # For Adobe Acrobat Distiller 6 317 | - Library/Application Support/Adobe/Acrobat/Distiller 6/FontCache/PSHFList 318 | 319 | # For Adobe Acrobat Distiller 7 320 | - Library/Application Support/Adobe/Acrobat/Distiller 7/FontCache/PSHFList 321 | 322 | # For Adobe Acrobat 8 323 | - Library/Acrobat User Data/Preflight Acrobat 8/Preferences/Cache/* 324 | - Library/Application Support/Adobe/Acrobat/Distiller 8/FontCache/PSHFList 325 | 326 | # Module Caches for german Adobe Creative Suite 327 | - Library/Preferences/Adobe Photoshop 7.0 Settings/Zusatzmodul-Cache.psp 328 | - Library/Preferences/Adobe Photoshop CS Einstellungen/Zusatzmodul-Cache.psp 329 | - Library/Preferences/Adobe InDesign/Version 3.0/InDesign ClipboradScrap 330 | - Library/Preferences/Adobe InDesign/Version 3.0/InDesign OSXServicesScrap 331 | - Library/Preferences/Adobe Illustrator 10/Zusatzmodul-Cache.psp 332 | 333 | # This Cache file belongs to Adobe Creative Suite 334 | # Info: http://www.adobe.com/support/techdocs/330060.html 335 | - Library/Preferences/ACE2Cache 336 | - Library/Application Support/Adobe/Adobe PCD/cache/ 337 | 338 | # Adobe Creative Suite 2 - Adobe Bridge Cache files 339 | - Adobe Bridge Cache.bc 340 | - Adobe Bridge Cache.bct 341 | 342 | # AppleWorks Assistent and Filter Caches 343 | # These filenames are localized, what are they called in other languages 344 | # that are missing here? Please submit this info! 345 | 346 | # German 347 | - Library/Preferences/AppleWorks/AppleWorks 6 Assistenten Cache 348 | - Library/Preferences/AppleWorks/AppleWorks 6 Filter Cache 349 | - Dokumente/AppleWorks Benutzerdaten/Ausgangspunkt/Cache 350 | 351 | # BBedit Prefs Data Backup Files 352 | # Info: http://www.barebones.com/ 353 | - Library/Preferences/BBEdit Preferences/BBEdit Prefs Data (Backup) 354 | 355 | # Containing your preferred and recent files 356 | # For BBEdit below 8.0 357 | # - /Library/Preferences/BBEdit Preferences/Recent Files & Favorites 358 | # For BBEdit 8 (and possibly above) 359 | # - /Library/Preferences/com.barebones.bbedit.PreferenceData/Recent Files & Favorites 360 | 361 | # Containing your preferred and recent folders 362 | # For BBEdit below 8.0 363 | # - Library/Preferences/BBEdit Preferences/Recent Folders & Favorites 364 | # For BBEdit 8 (and possibly above) 365 | # - Library/Preferences/com.barebones.bbedit.PreferenceData/Recent Folders & Favorites 366 | 367 | # can we savely leave out this file? 368 | # - Library/Preferences/BBEdit Preferences/Clipboards 369 | 370 | # Shiira (Webkit Browser) Favicons Cache (00-15/00-15/*.cache improve regexp) 371 | # and Temporary Feed (RSS) Files 372 | # Info: http://hmdt-web.net/shiira/en 373 | - Library/Shiira/IconDatabase/ 374 | - Library/Shiira/Feeds/tmp/*.xml 375 | 376 | # Freespace 2 (Game) Cache files *.ibx 377 | # Info: http://freespace2.com/ 378 | - Library/FS2_Open/data/cache/ 379 | 380 | # Apple Calculator Currency Exchange Rates 381 | # When restoring a backup exchange rates will be outdated and should be 382 | # updated anyway, no need to backup them. 383 | - Library/Application Support/Calculator/FinancialRates.plist 384 | 385 | # OpenUp Archive decompressed files 386 | # Info about OpenUp: http://www.stepwise.com/Software/OpenUp/ 387 | # Download: http://homepage.mac.com/sanguish/OpenUp/ 388 | - Library/OpenUp/ 389 | 390 | # Recent Items used by Allume Stuffit Deluxe (former Aladdin Systems) 391 | # Info: http://www.allume.com/ or http://www.stuffit.com/ 392 | - Library/Preferences/Allume/StuffIt Deluxe Recent Items/ 393 | 394 | # Microsoft Internet Explorer Cache Files for Downloads 395 | # We don't link to Microsoft! 396 | - Library/Preferences/Explorer/Download Cache/ 397 | 398 | # Microsoft Internet Explorer temporary files 399 | - Library/Preferences/Explorer/Temporary Files/ 400 | 401 | # Microsoft Office 2004 (11) Font Cache Files 402 | - Documents/Microsoft-Benutzerdaten/Entourage Temp 403 | - Documents/Microsoft-Benutzerdaten/Office X-Identitäten/Hauptidentität/Datenbank Cache 404 | - Library/Preferences/Microsoft/Office Font Cache (10) 405 | - Library/Preferences/Microsoft/Office Font Cache (11) 406 | - Library/Preferences/Microsoft/Office Registration Cache X 407 | - Library/Preferences/Microsoft/Office Registration Cache 11 408 | - Library/Preferences/MS Internet Cache 409 | 410 | # Connectix Virtual PC 6.x, Printer Spooler files 411 | # Info: http://www.connectix.com/ 412 | # Virtual PC has since been bought by Microsoft :-( 413 | - Library/Preferences/Virtaul PC 6.0 Preferences/Virtual PC Print Spool/ 414 | 415 | # iCab WebBrowser temporary and cache folder 416 | # http://www.icab.de/ 417 | - Library/Preferences/iCab Preferences/iCab Cache/ 418 | 419 | # iSerial Reader Cache Files 420 | - Library/Application Support/iSerial Reader/Cache 421 | 422 | # RagTime Cache Files 423 | # http://www.ragtime.de/ 424 | - Library/Preferences/RagTime/RagTime Privat Cache_de 425 | - Library/Preferences/RagTime/RagTime Solo Cache_en 426 | 427 | # VLC (Video Lan Client) Cache 428 | # Info: http://www.videolan.org/ 429 | - Library/Preferences/VLC/cache/ 430 | 431 | # mlMac partial and fully downloaded Files (This applies to the default 432 | # location, if you have moved your incoming and temp directories you 433 | # may want to change the path below as well! 434 | # Info: http://mlmac.org/ 435 | # If YOU know what should be added here, contact me please! (see top of file!) 436 | - Library/Application Support/mlMac/incoming/ 437 | - Library/Application Support/mlMac/temp/ 438 | - Library/Application Support/mlMac/torrents/ 439 | - Library/Application Support/mlMac/*.old 440 | 441 | # Mac The Ripper Temp Files 442 | - .dvdcss 443 | 444 | # NetNewsWire and NetNewsWire Lite Caches: 445 | # Info & Download: http://ranchero.com/netnewswire/ 446 | # Only applies to NNW before 2.1b16, the caches have been moved to 447 | # Library/Caches/ since which we are excluding by default. 448 | - Library/Application Support/NetNewsWire/Cache/ 449 | - Library/Application Support/NetNewsWire/Backups/ 450 | - Library/Application Support/NetNewsWire/Favicons/ 451 | 452 | # NewsFire RSS Reader Cache 453 | # Info & Download: http://www.newsfirerss.com/ 454 | - Library/Application Support/NewsFire/Cache/ 455 | 456 | # PopCap Game: Zuma 457 | # - Library/Application Support/PopCap/Zuma/levels/cached_thumbnails/* 458 | 459 | # Quark XPress 6 Aliases, for recently used files 460 | - Library/Preferences/Quark/QuarkXPress 6.0/MRU/*.qxp 461 | 462 | # DiscTop Artwork - will be refetched if missing, not vital to a backup 463 | # If you desperately want to keep the comment out the line accordingly. 464 | # Info: http://www.mekentosj.com/disctop/ 465 | - Library/Application Support/DiscTop/Artwork/ 466 | 467 | # Mozilla FireFox WebCache (all Profiles) 468 | # http://www.mozilla.com/ 469 | # ------------------------------------------ These rules should be improved! 470 | - Library/Application Support/FireFox/Profiles/**Cache/ 471 | - Library/Application Support/FireFox/Profiles/**/Cache.Trash/ 472 | 473 | # LaunchBar 3 SetupCache (Does not apply to LaunchBar 4) 474 | # Info: http://obdev.at/products/launchbar/ 475 | - Library/Application Support/LaunchBar/SetupCache.plist 476 | 477 | # Synergy Temporary Album Cover 478 | # Info: http://wincent.com/a/products/synergy-classic/ 479 | - Library/Application Support/Synergy/Temporary Album Covers/ 480 | 481 | # Pulp Fiction RSS Cache 482 | # Info: http://freshsqueeze.com/products/pulpfiction/ 483 | # Thanks to Brad Miller from Freshly Squeezed Software for your support. 484 | - Library/Application Support/PulpFiction/Cache/ 485 | # Library/Caches is generally excluded by default, no need to specify again. 486 | # - Libraray/Caches/PulpFiction/ 487 | 488 | # Wired partially transferred files 489 | # Info and Download: http://www.zankasoftware.com/wired/ 490 | - *.WiredTransfer 491 | 492 | # Heidrun Partial download files 493 | # Info: http://www.macupdate.com/info.php/id/11881 494 | # Info 2: http://www.versiontracker.com/dyn/moreinfo/macosx/16296 495 | - *.HeidrunDownload 496 | 497 | # Audiobook Builder Temporary Files 498 | # More Info: http://www.splasm.com/audiobookbuilder/ 499 | - Library/Application Support/Audiobook Builder/Temp/* 500 | 501 | # BluePhoneElite 1.x 502 | # To be checked 503 | # - Library/Application Support/BluePhoneElite/Archive_Old 504 | # - Library/Application Support/BluePhonElite/SMS Archive_1.0.8.780 505 | # und andere Versions und builds Nummern RegExp? 506 | 507 | # Apple Safari (and Webkit?) partial downloads 508 | # Info: http://www.apple.com/safari/ 509 | - *.download 510 | # Safari Favicons Cache (00-15/00-15/*.cache please help to improve this regexp) 511 | - Library/Safari/Icons/ 512 | # Webkit Favicon Cache files (Subfolder 00-15/00-15, should improve regexp here) 513 | # to exactly and only match these folders 00-15/00-15/*.cache 514 | - Library/Icons/ 515 | 516 | # Mozilla Firefox Partial downloads 517 | - *.part 518 | 519 | # iChat Partial Transfers 520 | - *.iChatTransfer 521 | 522 | # Apple Addressbook Backup. Actually, these are packages (which are actually folders in the filesystem) simply containing the normal files used by Address Book in the Library 523 | - *.abbu/ 524 | 525 | # Apple iCal Backup. Actually, these are packages simply containing the normal files used by iCal in the Library 526 | - *.icbu/ 527 | 528 | # Apple Backup 3.0 incompleted Backup Set (due to error during Backup or because the Backup is currently running) 529 | # Does it make sense to keep a FAILED backup of another Backup application? 530 | - *.backXX/ 531 | # other filetypes used by Apple Backup 3.0 are 532 | # FullBackups and Incremental Backups 533 | # - *.FullBackup/ 534 | # - *.IncrementalBackup/ 535 | 536 | # iSync - SyncService "Revert to last Sync" files 537 | # Though not vital for a backup, possibly useful if your iSync goes belly up 538 | # and you end up with an empty Addressbook and empty cell phone/iPod/PDA/.Mac 539 | # Info: http://www.apple.com/isync/ 540 | # NOT excluded by default. 541 | # - Library/SyncService/ 542 | 543 | #EOF 544 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # Name: install.sh, an installer script for mlbackup 4 | # Author: Pepi Zawodsky 5 | # Authors eMail: mlbackup@maclemon.at 6 | # Website: http://maclemon.at/mlbackup 7 | # License: GNU general public license (GPL) http://www.gnu.org/licenses/gpl.html 8 | ############################################################################### 9 | # install.sh, an installer script for mlbackup 10 | # Copyright (C) 2005-2008 Pepi Zawodsky 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | # 25 | ############################################################################### 26 | 27 | MLbackupInstallerVersion="0.0.2" 28 | # MLbackupBuild=__CCUURREENNTT__RREEVVIISSIIOONN__ 29 | MLbackupBuild=$(git log --pretty=format:'' | wc -l | sed "s/[ \t]//g") 30 | 31 | ############################################################################### 32 | # Must be run as root 33 | 34 | MLbinDir=/usr/local/bin 35 | MLconfigDir=/etc/maclemon/backup 36 | MLcpFlags="-vp" 37 | MLlnFlags="-vi" 38 | MLsed=/usr/bin/sed 39 | 40 | 41 | MLrootUID=0 42 | if [ "$UID" -ne "$MLrootUID" ] 43 | then # We are not root 44 | echo Sorry, $(basename $0) must be run as root. 45 | 46 | # install.sh should check if the user is able to provide a password that can be used. 47 | # Member of group admin or wheel on Mac OS X should be enough, maybe check the sudoers file as well. 48 | exit 1 49 | else # Yes, we are root. 50 | echo 51 | echo Creating directories 52 | # Creating the directory to keep the scripts 53 | mkdir -p $MLbinDir 54 | 55 | # Creating the directory to keep the sample config and globalexclusions 56 | mkdir -p $MLconfigDir 57 | 58 | echo 59 | echo copying files 60 | # copying the files 61 | cp $MLcpFlags mlbackup $MLbinDir 62 | $MLsed -i "" "s/__CCUURREENNTT__RREEVVIISSIIOONN__/$MLbackupBuild/g" "$MLbinDir/mlbackup" 63 | 64 | cp $MLcpFlags globalexclusions $MLconfigDir/ 65 | cp $MLcpFlags demo.mlbackupconf.sample $MLconfigDir/ 66 | 67 | 68 | # Setting correct Ownership of files 69 | 70 | chown root:wheel $MLbinDir/mlbackup $MLconfigDir/globalexclusions $MLconfigDir 71 | 72 | echo 73 | echo Setting correct privileges and file modes 74 | # Setting correct file modes 75 | chmod 755 $MLbinDir/mlbackup $MLconfigDir 76 | chmod 644 $MLconfigDir/globalexclusions $MLconfigDir/demo.mlbackupconf.sample 77 | 78 | if [ ! $(sw_vers | grep -q "Server") ] 79 | then 80 | if [ $(sw_vers | grep -q "10.[456]") ] 81 | then 82 | echo 83 | echo Fixing the postifx queue system on Mac OS X client 84 | /etc/postfix/post-install create-missing 85 | fi 86 | else 87 | echo 88 | echo This is Mac OS X Server, not touching the postfix system. 89 | fi 90 | echo Done installing the MacLemon backup scripts. See the README for more info 91 | fi 92 | #EOF 93 | -------------------------------------------------------------------------------- /mlbackup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # Name: mlbackup, a backup system with autorotation for Mac OS X (Server) 4 | # Author: Pepi Zawodsky 5 | # Authors eMail: mlbackup@maclemon.at 6 | # Website: http://maclemon.at/mlbackup 7 | # License: GNU general public license (GPL) http://www.gnu.org/licenses/gpl.html 8 | ############################################################################### 9 | # mlbackup, a backup system with autorotation for Mac OS X (Server) 10 | # Copyright (C) 2005-2011 Pepi Zawodsky 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | # 25 | ############################################################################### 26 | # first thing we do is check the time to later see how long things took 27 | MLtimeScriptStart=$(date +%s) 28 | ############################################################################### 29 | # Debug Mode. Set to 1 to get some debug messages set to 0 to skip them. 30 | # Can be set in the config file as well and will override this setting here! 31 | MLdebug=0 32 | ############################################################################### 33 | # determining a few standard variables for comfortable use later 34 | MLfullCommand=$0 35 | MLbaseCommand=$(basename $0) 36 | MLhostname=$(hostname) 37 | MLversion=1.5.3 38 | MLrevision=__CCUURREENNTT__RREEVVIISSIIOONN__ 39 | MLlatestBackupTitle="Latest" 40 | MLflattrURL="https://flattr.com/thing/141895/mlbackup" 41 | # For development and testing only: 42 | # MLrevision=$(svn info svn+maclemon:///Backup/trunk | grep "Revision:" | awk {'print $2'}) 43 | # echo "MLrevision: $MLrevision" 44 | ############################################################################### 45 | # Error and exit codes used 46 | # Everything Ok returns 0 47 | # Any rsync error returns the return value of rsync 48 | # Known rsync error codes are 1-30 49 | # Any other error returns one of these (128-254): 50 | MLE_RemoteSourceNotFound=242 51 | MLE_ConcurrentInstanceRunningWithSameConfig=243 52 | MLE_SourceNotFound=244 53 | MLE_NoConfigFileParameterAndStableUpdateAvailable=245 54 | MLE_NoConfigFileParameterAndCouldNotVersioncheck=246 55 | MLE_ConfigExclusionsFileNotReadable=247 56 | MLE_ConfigExclusionsFileDoesNotExist=248 57 | MLE_DestinationNotFound=249 58 | MLE_DestinationNotWriteable=250 59 | MLE_NoConfigFileParameter=251 60 | MLE_DestinationIsNoDirectory=252 61 | MLE_ConfigFileNotReadable=253 62 | MLE_ConfigFileNotFound=254 63 | ############################################################################### 64 | # Check if we run as root and set MLweAreRoot accordingly. 65 | # Other parts of the script can rely on this variable to be set correctly. 66 | # Like future preflight and postflight scripts. 67 | MLrootUID=0 68 | if [ "$UID" -ne "$MLrootUID" ] 69 | then # I am not root 70 | MLweAreRoot=0 71 | 72 | else # Bow before me, for I am root! 73 | MLweAreRoot=1 74 | fi 75 | ############################################################################### 76 | # defining our own functions: 77 | 78 | function appendToFile (){ 79 | # Appends a given text at the end of a given file 80 | # usage: appendToFile "path/to/filename" "Message to append" 81 | 82 | # Checking if the target file exists and is writable 83 | if [ -w "$1" ] # Is the file to append to existent AND writable 84 | then # Yes, file does exist AND is writable 85 | echo "$2" >> "$1" 86 | else # The file is not writable, need to further investigate 87 | 88 | if [ -e "$1" ] # Does the file at least exist? 89 | then # Yes, it does exist 90 | # but it is not writable 91 | echo "The file $1 is not writable for $USER. Logging message to console." 92 | echo "$2" 93 | else # File does not exist 94 | if [ -w "$(dirname $1)" ] # Is the directory where the file should result in writable? 95 | then # Yes, the directory does exist AND is writable 96 | # Then we can just create the file and be happy. 97 | echo "$2" >> "$1" 98 | else # No, the directory is NOT writable OR may not even exist 99 | if [ -d "$(dirname $1)" ] # Does the directory exist at all? 100 | then # Yes, it does exist, but is not writable. 101 | echo "The File $1 does not exist and the directory $(dirname $1) is not writable so we cannot create the file either. Please fix the permissions for $USER. Logging message to console." 102 | echo "$2" 103 | else # No, the directory does not even exist. User needs to create it. 104 | echo "Cannot create file $1 as user $USER because $(dirname $1) does not exist. You need to create it manually and make it writable for $USER. Logging message to console." 105 | echo "$2" 106 | fi 107 | fi 108 | fi 109 | fi 110 | } 111 | 112 | #------------------------------------------------------------------------------ 113 | # function prependToFile (){ 114 | # Prepends a given Text at the beginning of a given file 115 | # usage: prependToFile "path/to/filename" "Message to prepend" 116 | # caveat: No error checking yet 117 | 118 | # Pushed back a moment, current found solutions are not elegant and require at least 119 | # one additional temporary file. 120 | 121 | # } 122 | 123 | #------------------------------------------------------------------------------ 124 | function debug (){ 125 | # outputs a debugging message to console if the MLdebug Flag is set to 1 126 | # usage: debug "Your debugging Message" 127 | if [ $MLdebug -eq 1 ] # Is the debug flag set? 128 | then # Output everything that is passed to stdout: 129 | # Should Debugging Messages be output to stderr instead? Please give feedback! 130 | MLtheDebugMessage="$(date) $MLbaseCommand[$$] DEBUG: $@" 131 | echo $MLtheDebugMessage 132 | 133 | # same message passed to the admin eMail Message 134 | appendToFile "$MLadminEmailMessage" "$MLtheDebugMessage" 135 | fi 136 | } 137 | #------------------------------------------------------------------------------ 138 | function cleanup (){ 139 | # removes all our temporary files so we leave a clean and pithy system when we exit 140 | 141 | # Removing already created temp files. 142 | debug "Removing temp MLrsyncLogFile in $MLrsyncLogFile" 143 | $MLrm "$MLrsyncLogFile" 144 | 145 | debug "Removing temp MLrsyncErrFile in $MLrsyncErrFile" 146 | $MLrm "$MLrsyncErrFile" 147 | 148 | debug "Removing my .pid file in $MLmyPidFile." 149 | $MLrm "$MLmyPidFile" 150 | } 151 | 152 | #------------------------------------------------------------------------------ 153 | function seconds2dhms (){ 154 | # Takes the number of seconds as integer and returns a string with human 155 | # readable output in the form of 11d 22h 33m 44s to make durations 156 | # in the form of seconds easier to read for humans. 157 | # Usage: humanReadableDuration=seconds2dhms $NumberOfSeconds 158 | seconds2dhms_seconds=$1 159 | 160 | seconds2dhms_days=$(( seconds2dhms_seconds / 86400 )); # One day equals 86400 seconds 161 | seconds2dhms_seconds=$(( seconds2dhms_seconds % 86400 )) 162 | 163 | seconds2dhms_hours=$(( seconds2dhms_seconds / 3600 )); # One hour equals 3600 seconds 164 | seconds2dhms_seconds=$(( seconds2dhms_seconds % 3600 )) 165 | 166 | seconds2dhms_minutes=$(( seconds2dhms_seconds / 60 )) 167 | seconds2dhms_seconds=$(( seconds2dhms_seconds % 60 )) 168 | 169 | #days 170 | case $seconds2dhms_days in 171 | 0) seconds2dhms_daytext="";; 172 | 1) seconds2dhms_daytext="$seconds2dhms_days day";; 173 | *) seconds2dhms_daytext="$seconds2dhms_days days";; 174 | esac 175 | 176 | #hours 177 | case $seconds2dhms_hours in 178 | 0) seconds2dhms_hourtext="";; 179 | 1) seconds2dhms_hourtext="$seconds2dhms_hours hour";; 180 | *) seconds2dhms_hourtext="$seconds2dhms_hours hours";; 181 | esac 182 | 183 | #minutes 184 | case $seconds2dhms_minutes in 185 | 0) seconds2dhms_minutetext="";; 186 | 1) seconds2dhms_minutetext="$seconds2dhms_minutes minute";; 187 | *) seconds2dhms_minutetext="$seconds2dhms_minutes minutes";; 188 | esac 189 | 190 | #seconds 191 | case $seconds2dhms_seconds in 192 | 0) seconds2dhms_secondtext="";; 193 | 1) seconds2dhms_secondtext="$seconds2dhms_seconds second";; 194 | *) seconds2dhms_secondtext="$seconds2dhms_seconds seconds";; 195 | esac 196 | 197 | echo "$seconds2dhms_daytext $seconds2dhms_hourtext $seconds2dhms_minutetext $seconds2dhms_secondtext" 198 | } 199 | ############################################################################### 200 | # Creating a few temporary files we need 201 | 202 | MLadminEmailMessage=$(mktemp -t MLadminEmailMessage.XXXXXXXXXX) # Email composition for Backup Admin 203 | debug "MLadminEmailMessage = $MLadminEmailMessage" 204 | 205 | # If the backup only takes place on localhost we should probably directly 206 | # create the logfiles in the backup destination (which we would need to create 207 | # ourselves instead of letting rsync do the job.) 208 | MLrsyncLogFile=$(mktemp -t MLrsyncLogFile.XXXXXXXXXX) # Logfile for rsync LOG 209 | debug "MLrsyncLogFile = $MLrsyncLogFile" 210 | 211 | MLrsyncErrFile=$(mktemp -t MLrsyncErrFile.XXXXXXXXXX) # Logfile for rsync ERR 212 | debug "MLrsyncErrFile = $MLrsyncErrFile" 213 | ############################################################################### 214 | # Version Checking info 215 | MLversioncheckBaseURL="http://versioncheck.maclemon.at/" 216 | MLversioncheckURL="$MLversioncheckBaseURL$MLbaseCommand.txt" 217 | MLinfoURL="https://github.com/MacLemon.at/mlbackup" 218 | debug "MLversioncheckURL: $MLversioncheckURL" 219 | ############################################################################### 220 | # Check if we'are running in an interactive shell, and control output accordingly. 221 | # Would print out "not a tty" if non-interactive and a tty device if interactive 222 | # I know that tty -s is deprecated according to man tty, but test -s 0 223 | # seems to be broken and does not give reliable results. test -t 0 is unusable. 224 | 225 | # Would return "not a tty" if non-interactive and a tty device if interactive 226 | 227 | debug "Checking for interactive TTY" 228 | /usr/bin/tty -s 229 | MLttyReturned=$? 230 | 231 | # echo MLttyReturned = $MLttyReturned 232 | 233 | if [ $MLttyReturned -eq 1 ] 234 | then # tty returns 1 on nonInteractive 235 | MLisInteractive=0 236 | debug "Running in a non-interactive environment. tty returned $MLttyReturned, MLisInteractive set to $MLisInteractive." 237 | else # tty returns 0 on interactive (tty present) 238 | MLisInteractive=1 239 | debug "Running in an interactive environment. tty returned $MLttyReturned, MLisInteractive set to $MLisInteractive." 240 | fi 241 | ############################################################################### 242 | # Setting our own internal variables. 243 | # To be improved. Some of these may be moved to the config file later. 244 | 245 | # Path to rsync 246 | # MLrsync="/usr/bin/rsync" # For Mac OS X Tiger (10.4 and up) Apple rsync 247 | MLrsync="/usr/local/maclemon/bin/rsync" # Since r76, we use our own rsync 3 248 | # MLrsync="/usr/local/maclemon-beta/bin/rsync" # For our trial and error experimentation 249 | MLsourceRsync="$MLrsync" 250 | MLdestRsync="--rsync-path=$MLrsync" 251 | 252 | # Dry run, for debugging Rsync, does NOT alter any files, only pretends to. 253 | # This option is ONLY to be used for debugging mlbackup. 254 | # MLdryRun=-n 255 | 256 | # The options to invoke rsync with. 257 | MLrsyncOptions="-apogtxl --hard-links --fuzzy --fileflags --protect-args --protect-decmpfs --force-change --crtimes --devices --specials" 258 | 259 | # When running interactively we're showing some progress and stats for the user 260 | if [ $MLisInteractive ] 261 | then # we show a progress for the user, else we do not, since in a non-interactive session there is noone to watch this. 262 | MLshowRsyncProgress="--progress --stats" 263 | fi 264 | 265 | #Rsync should use compression for non-local-only backup transport (SSH) 266 | MLrsyncNetworkOptions="--compress --compress-level=9" 267 | 268 | 269 | # Rsync should be verbose 270 | # Rsync verbosity beyond -vv does NOT seem to work on Mac OS X, I am afraid this is an rsync bug 271 | MLbeVerbose="-v" 272 | 273 | # Delete trashed files from the backup so our backups don't grow infinitely 274 | MLdelete="--delete" 275 | 276 | # Exclude Paths and Filenames mentioned in this file. 277 | # Per Default we respect the global Exclusions file to speed up backups 278 | MLuseGlobalExclusions=1 279 | MLglobalExclusionsFile=/etc/maclemon/backup/globalexclusions 280 | MLglobalExcludeFrom="--exclude-from=/etc/maclemon/backup/globalexclusions" 281 | 282 | # If there is a path in MLconfigExcludeFrom then we will import that one. 283 | # If it is empty, there is nothing to import. 284 | MLconfigExcludeFrom="" 285 | 286 | # For deleting stuff we use 287 | MLrm="rm" 288 | 289 | # Writing Script starting time to the Admin email: 290 | appendToFile "$MLadminEmailMessage" "Backup started: $(date -r $MLtimeScriptStart)" 291 | ############################################################################### 292 | # Getting the configuration file 293 | # Handling of the config file should be a little more elegant. 294 | # Known Issue: Versioncheck does not yet respect Mac OS X Proxy settings. 295 | 296 | # Did we get a parameter to use as a config file? 297 | if [ -z "$1" ] 298 | then # There was no config filename passed 299 | # Outputting Usage information as needed for POSIX 300 | echo "Usage: $MLbaseCommand path/to/configfile" 301 | 302 | # Checking for current stable version 303 | MLcheckedVersion=$(curl -sL --connect-timeout 30 $MLversioncheckURL | grep -w "^mlbackup.stable" | awk '{printf $3}') 304 | MLcurlReturned=$? 305 | if [ $MLcurlReturned -eq 0 ] # Could we successfully check our version? 306 | then # Yes we could successfully versioncheck 307 | if [[ $MLcheckedVersion -gt $MLrevision ]] # Is there a newer version available? 308 | then # Yes, there is a newer version available 309 | echo The current revision of $MLbaseCommand is $MLcheckedVersion, you are running $MLrevision. 310 | echo Visit $MLinfoURL to get an update. 311 | exit $MLE_NoConfigFileParameterAndStableUpdateAvailable 312 | 313 | else # No Update available, running current 314 | exit $MLE_NoConfigFileParameter 315 | 316 | fi 317 | else # No, we could not successfully versioncheck. 318 | # Known Issue: curl(1) error codes are not yet displayed as human readable text. 319 | echo Could not check for update. curl\(1\) Exit Code $MLcurlReturned. 320 | exit $MLE_NoConfigFileParameterAndCouldNotVersioncheck 321 | fi 322 | 323 | else # We were passed a config file 324 | MLconfigFile="$1" 325 | debug "Config file to use is: $MLconfigFile" 326 | 327 | # Now let's check that parameter 328 | # Does this file exist? 329 | if [ -e "$MLconfigFile" ] 330 | then # The file does exist 331 | debug "Config file $MLconfigFile exists." 332 | 333 | # Is the config file readable by the user invoking the script? 334 | if [ -r "$MLconfigFile" ] 335 | then # The config file can be read by the user invoking this script 336 | 337 | # Load in the config (DIRTY *yuck*) Better use the defaults system 338 | appendToFile "$MLadminEmailMessage" "Using config file in $MLconfigFile" 339 | debug "Loading the config file $MLconfigFile" 340 | . "$MLconfigFile" 341 | else # The user does not have read permission for the config file 342 | echo $MLbaseCommand[$$]:FATAL The config file $MLconfigFile seems to exist but is not readable by $USER. Please change the mode or owner of the configuration file or use a different user to run $MLbaseCommand! 343 | exit $MLE_ConfigFileNotReadable # config file not readable 344 | # We might do further testing of this file to give a better error 345 | fi 346 | else # The config file doesn't exist, FATAL 347 | echo $MLbaseCommand[$$]:FATAL The config file $MLconfigFile could not be found. Please check the path! 348 | exit $MLE_ConfigFileNotFound # Config file not found 349 | fi # [ -e $MLconfigFile ] 350 | fi # [ -z "$1" ] 351 | ############################################################################### 352 | #------------------------------------------------------------------------------ 353 | # Cannot define function earlier since we need parameters from the config file. 354 | # Depending if Growl is installed 355 | # We define the notifyGrowl function differently to preserve performance 356 | 357 | MLgrowlnotify=/usr/local/bin/growlnotify 358 | 359 | if [ -e "$MLgrowlnotify" ] 360 | then 361 | MLgrowlStandardPriority="Normal" 362 | 363 | # creating a pseudorandom ID for growl coalescing. Should be sufficently unique for our purpose. 364 | let "MLgrowlID = $MLtimeScriptStart + $RANDOM" 365 | debug "MLgrowlID = $MLgrowlID" 366 | 367 | function notifyGrowl () { 368 | # Usage: notifyGrowl "text of message" ["text of title" "other growlnotify options"] 369 | # We use the icon of the source as notification Icon 370 | # Automatically handles registration with growl as mlbackup, ID, coalescing 371 | # other growlnotify options could be "--sticky" for example 372 | # Could we really use SIPS to badge this mit an mlbackup icon? Esoteric? 373 | MLgrowlIconpath="$MLsourcePath" # For use with --iconpath/-I (capital i) 374 | 375 | if [ ! -z "$2" ] 376 | then 377 | MLgrowlTitle="$2" 378 | else 379 | MLgrowlTitle="$MLbackupName" 380 | fi 381 | 382 | MLgrowlTitle="$MLbackupName" 383 | $MLgrowlnotify --priority "$MLgrowlStandardPriority" --identifier "$MLgrowlID" --iconpath "$MLgrowlIconpath" --name "$MLbaseCommand" $3 -m "$1" -t "$MLgrowlTitle" >/dev/null 2>&1 384 | } 385 | else 386 | debug "Could not find /usr/local/bin/growlnotify, Growl notifications are disabled." 387 | function notifyGrowl () { 388 | debug "$MLgrowlnotify is not installed. Cannot growl message parameters $@." 389 | # Doing nothing, since growl is not installed. 390 | } 391 | fi 392 | ############################################################################### 393 | # Post processing of new parameters loaded from the config file. 394 | 395 | # Increasing overall verbosity if we're in DEBUG mode. 396 | if [ $MLdebug -eq 1 ] # Is the debug flag set? 397 | then # Yes, Increase verbosity 398 | MLbeVerbose="-vvv" # For rsync 399 | MLrm="rm -v" # for rm, actually -v is a NON POSIX standard option in rm on Mac OS X. 400 | fi 401 | ############################################################################### 402 | # Procesing global and per config exclusion files 403 | 404 | debug "MLconfigExcludeFrom: $MLconfigExcludeFrom" 405 | if [ -z "$MLconfigExcludeFrom" ] 406 | then # There has no per config exclusion file been set 407 | debug "No per-config exclusions file has been set." 408 | debug "MLuseGlobalExclusions: $MLuseGlobalExclusions" 409 | if [ $MLuseGlobalExclusions -eq 1 ] 410 | then # We shall only use the global exclusions 411 | debug "We are using the globalexclusions." 412 | MLexcludeFrom="--exclude-from=/etc/maclemon/backup/globalexclusions" 413 | else # We shall NOT use the global exclusions, nothing left to consider for exclusion 414 | debug "We shall not use globalexclusions. Nothing will be excluded from the backup." 415 | MLexcludeFrom="" 416 | fi 417 | debug "MLexcludeFrom: $MLexcludeFrom" 418 | else # We shall respect a per config exclusions file. 419 | debug "A per-config exclusions file has been set." 420 | if [ -e $MLconfigExcludeFrom ] 421 | then # The file does exist 422 | debug "This exclusions file does exist." 423 | if [ -r $MLconfigExcludeFrom ] 424 | then # The per-config exclusions file can be read by the user invoking this script 425 | debug "This exclusions file is readable by $USER." 426 | if [ $MLuseGlobalExclusions -eq 1 ] 427 | then # We shall also use the global exclusions, so we need to combine the files 428 | debug "Globalexclusions shall also be respected." 429 | MLcombinedExclusions=$(mktemp -t MLcombinedExclusions.XXXXXXXXXX) # Temporary File for exclusions 430 | debug "MLcombinedExclusions = $MLcombinedExclusions" 431 | debug "Combining globalexclusions and per-config exclusions." 432 | grep -h -v -e "^#" -v -e "^$" -v -e "^;" "$MLglobalExclusionsFile" "$MLconfigExcludeFrom" | sort | uniq > $MLcombinedExclusions 433 | MLexcludeFrom="--exclude-from=$MLcombinedExclusions" 434 | else # We shall not use the globalexclusion, so we only use the per-config exclusions 435 | debug "Globalexclusions shall not be used, only using per-config exclusions." 436 | MLexcludeFrom="--exclude-from=$MLconfigExcludeFrom" 437 | fi 438 | else # The user does not have read permission for the per-config exclusions file 439 | echo $MLbaseCommand[$$]:FATAL The config file $MLconfigExcludeFrom seems to exist but is not readable by $USER. Please change the mode or owner of the configuration file or use a different user to run $MLbaseCommand! 440 | exit $MLE_ConfigExclusionsFileNotReadable # per-config exclusions file not readable. Exiting 441 | fi 442 | else # The per-config exclusions file does not exist, FATAL. 443 | echo $MLbaseCommand[$$]:FATAL The config file $MLconfigExcludeFrom could not be found. Please check the path! 444 | exit $MLE_ConfigExclusionsFileDoesNotExist # Per Config Exclusions file does not exist. Exiting. 445 | fi 446 | fi 447 | ############################################################################### 448 | # Writing a .pid file to /tmp 449 | MLmyPidFile="/tmp/$MLbaseCommand-$MLbackupName.pid" 450 | echo $$ > "$MLmyPidFile" 451 | debug "PID File written to $MLmyPidFile" 452 | # This .pid file is removed at the end of the script 453 | ############################################################################### 454 | # Sanitizing of Input to variables. 455 | # 456 | # error handling of config file, setting defaults for missing parameters 457 | ############################################################################### 458 | # FUTURE: Preflight scripts will be called from here. 459 | # Possibly exchanged for a Plug-In like system. Not yet decided. 460 | ############################################################################### 461 | 462 | # For rsync 3 the options are a LOT different: 463 | MLextendedAttributes="--hard-links --perms --executability --acls --xattrs --owner --group --times" 464 | 465 | debug "Using custom rsync options from config file: $MLcustomRsyncOptions" 466 | 467 | 468 | 469 | # checking target 470 | # target is always local at the moment 471 | 472 | if [ -e "$MLdestPath" ] # Does our target exist? 473 | then # Yes, it does exist, 474 | if [ -d "$MLdestPath" ] # Is it a directory as well? 475 | then # Yes, it IS a directory. 476 | # check if it is writeable! 477 | # if yes ok, else fail 478 | if [[ -r "$MLdestPath" && -w "$MLdestPath" && -x "$MLdestPath" ]] # Can we rwx the destination? We need it. 479 | then # Great, everything we need! 480 | debug "The destination $MLdestPath offers all privs we need." 481 | else 482 | echo "The destination $MLdestPath need read, write and execute privs for the user $USER invoking this script to be able to backup your data." 483 | exit $MLE_DestinationNotWriteable 484 | fi 485 | else 486 | echo "$MLbaseCommand: The destination $MLdestPath is not a directory. We can not save backups in anything but a directory (like a file or block device)" 487 | exit $MLE_DestinationIsNoDirectory 488 | fi 489 | appendToFile "$MLadminEmailMessage" "Backup destination: $MLdestPath" 490 | else # No, the target does not exist 491 | debug "FATAL: The target $MLdestPath could not be found." 492 | debug "If your target is on an external volume, make sure it is mounted!" 493 | 494 | MLtargetNotFoundNotification="The target $MLdestPath could not be found! If your target is on an external volume, make sure it is mounted!" 495 | 496 | # sending the admin eMail Notification, only if we have an address 497 | if [ $MLadminEmail ] # Is the AdminEMail Address set? 498 | then # Yes, there is an address! 499 | debug "Sending the Admin eMail to $MLadminEmail" 500 | echo "$MLtargetNotFoundNotification" | /usr/bin/mail -s "$MLbaseCommand $MLhostname $MLbackupName: Target missing" $MLadminEmail 501 | else # No address set 502 | debug "No MLadminEmail Address set, cannot send eMail!" 503 | logger "$MLbaseCommand: $MLtargetNotFoundNotification" 504 | fi # [ $MLadminEmail -ne "" ] 505 | 506 | notifyGrowl "ERROR: Destination could not be found." "" "--sticky" 507 | cleanup 508 | exit $MLE_DestinationNotFound 509 | fi 510 | 511 | 512 | # Checking the source 513 | # Source could be local, could be remote via SSH as well, we need to accomodate that, but expect a local source in favor of a remote source. 514 | MLfatalError=1 515 | 516 | debug "Testing for local source in: $MLsourcePath" 517 | if [ -r "$MLsourcePath" -o -d "$MLsourcePath" ] # If the source exists (be it a local file or folder) 518 | then # Yes, the source folder can be found locally, using that one. 519 | MLrsyncNetworkOptions="" 520 | 521 | debug "The Source $MLsourcePath does exist locally." 522 | MLfatalError=0 523 | MLsourceIsRemote=0 524 | else # No, the source could not be found locally, could still be remotely located. 525 | debug "Local source could not be found." 526 | debug "Testing for a remote source with $MLsourcePath" 527 | # testing if a remote source does exist. 528 | 529 | $MLsourceRsync $MLdestRsync $MLrsyncNetworkOptions -n "$MLsourcePath" > /dev/null 2>&1 530 | MLrsyncRemoteTest=$? 531 | 532 | case $MLrsyncRemoteTest in 533 | 0) # The last backup went ok 534 | MLeRsyncErrorMessage="" 535 | MLfatalError=0 536 | MLsourceIsRemote=1 ;; 537 | # Error Codes we know from the rsync man page 538 | 1) MLeRsyncErrorMessage="Syntax or usage error";; 539 | 2) MLeRsyncErrorMessage="Protocol incompatibility";; 540 | 3) MLeRsyncErrorMessage="Errors selecting input/output files, dirs";; 541 | 4) MLeRsyncErrorMessage="Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server.";; 542 | 5) MLeRsyncErrorMessage="Error starting client-server protocol";; 543 | 6) MLeRsyncErrorMessage="Daemon unable to append to log-file";; 544 | 10) MLeRsyncErrorMessage="Error in socket I/O";; 545 | 11) MLeRsyncErrorMessage="Error in file I/O";; 546 | 12) MLeRsyncErrorMessage="Error in rsync protocol data stream";; 547 | 13) MLeRsyncErrorMessage="Errors with program diagnostics";; 548 | 14) MLeRsyncErrorMessage="Error in IPC code";; 549 | 20) MLeRsyncErrorMessage="Received SIGUSR1 or SIGINT";; 550 | 21) MLeRsyncErrorMessage="Some error returned by waitpid()";; 551 | 22) MLeRsyncErrorMessage="Error allocating core memory buffers";; 552 | 23) MLeRsyncErrorMessage="Partial transfer due to error";; 553 | 24) MLeRsyncErrorMessage="Partial transfer due to vanished source files";; 554 | 25) MLeRsyncErrorMessage="The --max-delete limit stopped deletions";; 555 | 30) MLeRsyncErrorMessage="Timeout in data send/receive";; 556 | 127) MLeRsyncErrorMessage="Rsync not found on remote machine, probably mlbackup not installed.";; 557 | 255) MLeRsyncErrorMessage="ssh could not connect, probably unknown hostname." 558 | # Any other error that might have occured that is unspecified 559 | ;; 560 | *) MLeRsyncErrorMessage="$0: Rsync returned Error Code $MLbackupStatus: Sorry, we do not know what this error code means. You may want to check your logfiles or the man page for rsync on your system." 561 | ;; 562 | esac 563 | debug "Remote Source test returned Code $MLrsyncRemoteTest" 564 | debug "$MLeRsyncErrorMessage" 565 | 566 | 567 | if [ $MLfatalError -eq 1 ] 568 | then 569 | # The Source does not exist, bailing out. 570 | debug "The Source $MLsourcePath could not be found. Cleaning up, exiting." 571 | 572 | appendToFile "$MLdestPath/$MLbackupName.log" "Testing for remote Source returned: $MLeRsyncErrorMessage" 573 | appendToFile "$MLdestPath/$MLbackupName.log" "$(date) [$$] Source $MLsourcePath does not exist." 574 | 575 | cleanup 576 | exit $MLE_SourceNotFound 577 | fi 578 | fi 579 | appendToFile "$MLadminEmailMessage" "Backup source: $MLsourcePath" 580 | # Checking for concurrent mlbackup running with the same configuration 581 | if [ -r "$MLdestPath/$MLbackupName.pid" ] # Is there already a tag .pid in the destination? 582 | then # Yes, there is a tag 583 | MLprobablyConcurrentPid=$(cat "$MLdestPath/$MLbackupName.pid") 584 | 585 | # Checking if this tag is old or if it really is a running mlbackup instance 586 | # The pid from the tag does have "mlbackup" and the same config file in use 587 | 588 | MLprobablyConcurrentProcess=$(/bin/ps -ax | grep "^$MLprobablyConcurrentPid" | grep "$MLfullCommand" | grep -e "$MLconfigFile") 589 | MLprobablyConcurrentProcessReturned=$? 590 | debug "Checking for concurrent proess returned $MLprobablyConcurrentProcessReturned" 591 | debug "MLprobablyConcurrentProcess = $MLprobablyConcurrentProcess" 592 | 593 | if [ "$MLprobablyConcurrentProcessReturned" -eq 0 ] 594 | then 595 | # we found another instance of mlbackup running with the same config. 596 | # Refusing to run two instances simultanously to preserve backup integrity 597 | debug "Found another instance of mlbackup with PID $MLprobablyConcurrentPid. Refusing simultaneous invocations. Exiting." 598 | 599 | notifyGrowl "Simultaneous invocation detected. Aborting." 600 | 601 | cleanup 602 | exit $MLE_ConcurrentInstanceRunningWithSameConfig 603 | else 604 | # The Tag seems to be leftover or the concurrent instance has finished by now. 605 | debug "Found tag $MLdestPath/$MLbackupName.pid with PID $MLprobablyConcurrentPid which does not seem to be a running instance of $MLbaseCommand with config $MLconfigFile. Continuing." 606 | fi 607 | else 608 | debug "Could not detect another concurrent running instance of mlbackup with config $MLconfigFile" 609 | fi 610 | 611 | debug "Writing my own tag to $MLdestPath/$MLbackupName.pid" 612 | echo $$ > "$MLdestPath/$MLbackupName.pid" 613 | 614 | # We need to find the most recent Backup as our Target for the link-dest 615 | MLmostRecentSet=$(ls -1tw "$MLdestPath/" | grep -E "^$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" | head -1) 616 | debug "The most Recent Set to refer to is: $MLmostRecentSet" 617 | 618 | #Fetching the current date and time 619 | MLbackupDate=$(date "+%Y.%m.%d-%H.%M.%S") 620 | 621 | # Creating the Final Destination directory: 622 | # the .noindex trick surely keeps Spotlight from indexing while we backup 623 | # No matter if Spotlight indexin is enabled for the volume or not. 624 | MLfinalTarget="$MLdestPath/$MLbackupName-$MLbackupDate.noindex" 625 | debug "MLfinalTarget = $MLfinalTarget" 626 | mkdir "$MLfinalTarget" 627 | 628 | notifyGrowl "Backup running" 629 | debug "Rsync starting now." 630 | MLtimeRsyncStart=$(date +%s) 631 | # backing up 632 | 633 | # building the final command to run the backup 634 | 635 | debug $MLsourceRsync $MLbeVerbose "$MLdestRsync" $MLrsyncOptions $MLshowRsyncProgress $MLrsyncNetworkOptions $MLdryRun $MLextendedAttributes $MLdelete $MLexcludeFrom $MLcustomRsyncOptions --log-file="$MLrsyncLogFile" --link-dest="$MLdestPath/$MLmostRecentSet/" "$MLsourcePath" "$MLfinalTarget/" 2>"$MLrsyncErrFile" 636 | 637 | $MLsourceRsync $MLbeVerbose "$MLdestRsync" $MLrsyncOptions $MLshowRsyncProgress $MLrsyncNetworkOptions $MLdryRun $MLextendedAttributes $MLdelete $MLexcludeFrom $MLcustomRsyncOptions --log-file="$MLrsyncLogFile" --link-dest="$MLdestPath/$MLmostRecentSet/" "$MLsourcePath" "$MLfinalTarget/" 2>"$MLrsyncErrFile" 638 | MLbackupStatus=$? # Fetching the return code from our rsync command 639 | MLtimeRsyncEnd=$(date +%s) # Fetching a timestamp after rsync for timing stats 640 | 641 | 642 | let "MLtimeRsyncDuration = $MLtimeRsyncEnd - $MLtimeRsyncStart" 643 | if [ $MLtimeRsyncDuration -eq 1 ] # Just to care for proper language 644 | then # It was only one second 645 | debug "rsync took $MLtimeRsyncDuration second." 646 | else # zero, two or more seconds 647 | debug "rsync took $MLtimeRsyncDuration seconds. $( 648 | if [ $MLtimeRsyncDuration -gt 60 ] # more than 60 seconds 649 | then # makes sense to output in human readable format 650 | seconds2dhms $MLtimeRsyncDuration 651 | fi)" 652 | fi 653 | ############################################################################### 654 | # Post processing the recorded rsync logfiles and temporary files: 655 | # We move and compress the logfiles to the backup destination. (currently only on localhost) 656 | debug "Compressing the logfiles and moving them to the backup destination." 657 | 658 | debug "--- Post processing the error.log" 659 | if [ -s $MLrsyncErrFile ] # Non zero byte error.log? Only in case of errors 660 | then # Yes, there were errors recorded. 661 | debug "Compressing $MLrsyncErrFile to $MLfinalTarget/error.log.gz." 662 | gzip -9 --no-name --to-stdout "$MLrsyncErrFile" > "$MLfinalTarget/error.log.gz" 663 | /bin/chmod 644 "$MLfinalTarget/error.log.gz" 664 | else 665 | debug "The error.log $MLrsyncErrFile was empty, looks good." 666 | fi # [ -s $MLrsyncErrFile ] 667 | 668 | # removing the error.log tempfile, should it not have been done by gzip already 669 | if [ -e "$MLrsyncErrFile" ] # Does our "$MLrsyncErrFile" still exist? 670 | then # Yes, it does exist, let us remove it. 671 | debug "The temp MLrsyncErrFile $MLrsyncErrFile still exists, removing it." 672 | $MLrm "$MLrsyncErrFile" 673 | else 674 | debug "The temp MLrsyncErrFile $MLrsyncErrFile did not exist aynmore, no need to delete it." 675 | fi 676 | 677 | debug "--- Post processing the rsync.log" 678 | if [ -s "$MLrsyncLogFile" ] # Non zero bytes rsync.log? (Expected) 679 | then # Yes, of course, compress and move to the backup folder 680 | debug "Compressing $MLrsyncLogFile to $MLfinalTarget/rsync.log.gz." 681 | gzip -9 --no-name --to-stdout "$MLrsyncLogFile" > "$MLfinalTarget/rsync.log.gz" 682 | 683 | # make sure, the user can read that file! 684 | /bin/chmod 644 "$MLfinalTarget/rsync.log.gz" 685 | else 686 | debug "The rsync.log $MLrsyncLogFile was empty, this is extremely unlikely!" 687 | fi # [ -s $MLrsyncLogFile ] 688 | 689 | # Removing the rsync.log tempfile, should it not have been done by gzip already 690 | if [ -e "$MLrsyncLogFile" ] # Does our "$MLrsyncLogFile" still exist? Either was zero bytes, ot somethow not removed by gzip. 691 | then # Yes, it does exist, let us remove it. 692 | debug "The temp MLrsyncLogFile $MLrsyncLogFile still exists, removing it." 693 | $MLrm "$MLrsyncLogFile" 694 | else 695 | debug "The temp MLrsyncLogFile $MLrsyncLogFile did not exist aynmore, no need to delete it." 696 | fi 697 | 698 | # Cleaning up MLcombinedExclusions 699 | if [ $MLcombinedExclusions ] 700 | then # Yes, we have a temporary MLcombinedExclusions file, let us remove it. 701 | debug "Removing MLcombinedExclusions: $MLcombinedExclusions" 702 | $MLrm "$MLcombinedExclusions" 703 | fi 704 | ############################################################################### 705 | # Post processing of the backup: 706 | debug "--- Backup postprocessing" 707 | 708 | # Beeing pessimistic we expect the backup to have failed, and change that if it hasn't. 709 | MLfatalError=1 710 | 711 | case $MLbackupStatus in 712 | 0) # The last backup went ok 713 | # If there is setlabel installed, we color it green (green is good) 714 | MLeRsyncErrorMessage="" 715 | MLfatalError=0 ;; 716 | # Error Codes we know from the rsync man page 717 | 1) MLeRsyncErrorMessage="Syntax or usage error";; 718 | 2) MLeRsyncErrorMessage="Protocol incompatibility";; 719 | 3) MLeRsyncErrorMessage="Errors selecting input/output files, dirs";; 720 | 4) MLeRsyncErrorMessage="Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server.";; 721 | 5) MLeRsyncErrorMessage="Error starting client-server protocol";; 722 | 6) MLeRsyncErrorMessage="Daemon unable to append to log-file" 723 | MLfatalError=2 ;; 724 | 10) MLeRsyncErrorMessage="Error in socket I/O";; 725 | 11) MLeRsyncErrorMessage="Error in file I/O";; 726 | 12) MLeRsyncErrorMessage="Error in rsync protocol data stream";; 727 | 13) MLeRsyncErrorMessage="Errors with program diagnostics";; 728 | 14) MLeRsyncErrorMessage="Error in IPC code";; 729 | 20) MLeRsyncErrorMessage="Received SIGUSR1 or SIGINT" 730 | # The backup has been aborted by the user or some other interrupt. 731 | # We should definitely clean up our mess before exiting. 732 | # To be implemented 733 | ;; 734 | 21) MLeRsyncErrorMessage="Some error returned by waitpid()";; 735 | 22) MLeRsyncErrorMessage="Error allocating core memory buffers";; 736 | 23) MLeRsyncErrorMessage="Partial transfer due to error" 737 | MLfatalError=2 ;; 738 | 24) MLeRsyncErrorMessage="Partial transfer due to vanished source files";; 739 | 25) MLeRsyncErrorMessage="The --max-delete limit stopped deletions";; 740 | 30) MLeRsyncErrorMessage="Timeout in data send/receive";; 741 | 742 | # Any other error that might have occured that is unspecified 743 | *) MLeRsyncErrorMessage="$0: Rsync returned Error Code $MLbackupStatus: Sorry, we do not know what this error code means. You may want to check your logfiles or the man page for rsync on your system." 744 | ;; 745 | esac 746 | 747 | case $MLfatalError in 748 | 1) # Some fatal error occured during the backup 749 | debug "Rsync returned $MLbackupStatus: $MLeRsyncErrorMessage" 750 | appendToFile "$MLadminEmailMessage" "Rsync returned $MLbackupStatus $MLeRsyncErrorMessage" 751 | 752 | debug "--- Post Processing backup errors" 753 | if [ $MLbackupStatus -ne 0 ] # Something went wrong during the backup 754 | then 755 | # Telling that something went wrong 756 | debug "Rsync returned $MLbackupStatus: $MLeRsyncErrorMessage" 757 | 758 | # If there is setlabel installed, we color it red (red like a warning) 759 | MLsetlabelPath=/sw/bin/setlabel 760 | if [ -e $MLsetlabelPath ] # only makes it red if setlabel command is installed 761 | then 762 | debug "Setting a red label for ERROR $MLfinalTarget" 763 | $MLsetlabelPath Red "$MLfinalTarget" 764 | fi # [ -e $MLsetlabelPath ] 765 | 766 | # If we have setfcomment installed, we add a nice comment to the folder 767 | MLsetfcommentPath=/sw/bin/setfcomment 768 | if [ -e $MLsetfcommentPath ] # Is setfcomment intalled? 769 | then 770 | debug "Setting Backup ERROR comment" 771 | /sw/bin/setfcomment -c "Unfinished backup! Rsync returned $MLbackupStatus: $MLeRsyncErrorMessage Created by $MLbaseCommand $MLbacklemonVersion($MLbacklemonBuild). Invoked by $USER on $MLbackupDate from Source: $MLsourcePath" "$MLfinalTarget/" 772 | fi # [ -e $MLsetfcommentPath ] 773 | 774 | # renaming the unfinished backup, so it will not be used for the next delta backup! 775 | MLfinalNewTarget="$MLdestPath/ERROR-$MLbackupName-$MLbackupDate" 776 | mv "$MLfinalTarget" "$MLfinalNewTarget" 777 | MLfinalTarget="$MLfinalNewTarget" 778 | fi #[ $MLbackupStatus -ne 0 ] 779 | ;; 780 | *) # The backup went OK, or had some other non fatal error (warning) 781 | appendToFile "$MLadminEmailMessage" "The Backup $MLbackupName went OK!" 782 | 783 | if [ $MLbackupStatus -gt 0 ] 784 | then 785 | appendToFile "$MLadminEmailMessage" "$MLeRsyncErrorMessage." 786 | fi #[ $MLbackupStatus -ne "" ] 787 | 788 | MLsetlabelPath=/sw/bin/setlabel 789 | if [ -e $MLsetlabelPath ] # only makes it green if setlabel command is installed 790 | then 791 | $MLsetlabelPath Green "$MLfinalTarget/" 792 | fi 793 | 794 | # If we have setfcomment installed, we add a nice comment to the folder 795 | MLsetfcommentPath=/sw/bin/setfcomment 796 | if [ -e $MLsetfcommentPath ] # Is setfcomment intalled? 797 | then 798 | /sw/bin/setfcomment -c "Created by $MLbaseCommand $MLversion. Invoked by $USER on $MLbackupDate from Source: $MLsourcePath" "$MLfinalTarget/" 799 | fi 800 | 801 | # checking if we need to remove some old ones 802 | MLoldBackupCount=$(ls -1w "$MLdestPath/" | grep -Ec "^$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" ) 803 | let "MLoldBackupCountDifference = $MLoldBackupCount - $MLbackupCount" 804 | debug "MLoldBackupCountDifference = " $MLoldBackupCountDifference 805 | 806 | if [ "$MLoldBackupCount" -gt "$MLbackupCount" ] # There are surplus Backups, so we remove them 807 | then 808 | 809 | MLoldBackupList=$(ls -1w "$MLdestPath/" | grep -E "^$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" | head -$MLoldBackupCountDifference) 810 | debug "Old Backup Count: $MLoldBackupCount, $MLoldBackupCountDifference to be removed." 811 | debug "Old Backup List: $MLoldBackupList" 812 | 813 | if [ $MLoldBackupCountDifference -eq 1 ] # just one old backup 814 | then # Yes, just a single old backup. 815 | debug "There is $MLoldBackupCountDifference surplus old backup, starting to remove it." 816 | else # no, several old backups to be removed 817 | debug "There are $MLoldBackupCountDifference surplus old backups, starting to remove them." 818 | fi 819 | 820 | for MLoldBackupTobeRemoved in $MLoldBackupList 821 | do 822 | 823 | debug "Removing the Set in: $MLdestPath/$MLoldBackupTobeRemoved" 824 | $MLrm -Rf "$MLdestPath/$MLoldBackupTobeRemoved" 825 | MLrmReturnCode=$? 826 | debug "rm returned $MLrmReturnCode" 827 | 828 | if [ $MLrmReturnCode -ne 0 ] # did rm NOT return 0? 829 | then # no it did not return 0, meaning an error occured 830 | # So we try to unlock files and delete the remaining ones again 831 | debug "Trying to unlock files that could not be deleted" 832 | /usr/bin/chflags -R nouchg "$MLdestPath/$MLoldBackupTobeRemoved" # unlocking files 833 | debug "Deleting the remaining files again." 834 | $MLrm -Rf "$MLdestPath/$MLoldBackupTobeRemoved" # And delete the rest again 835 | MLrmReturnCode=$? 836 | debug "rm returned $MLrmReturnCode" 837 | fi 838 | 839 | if [ $MLrmReturnCode -ne 0 ] # did rm still NOT return 0? 840 | then # no it did not return 0, meaning an error occured 841 | # Could not delete the old backup 842 | # try to label it gray 843 | if [ -e $MLsetlabelPath ] # only makes it gray if setlabel command is installed 844 | then 845 | $MLsetlabelPath Gray "$MLdestPath/$MLoldBackupTobeRemoved" 846 | fi # [ -e $MLsetlabelPath ] 847 | # and rename it 848 | mv "$MLdestPath/$MLoldBackupTobeRemoved" "$MLdestPath/OLD-$MLoldBackupTobeRemoved" 849 | appendToFile "$MLadminEmailMessage" "The Backup $MLdestPath/$MLoldBackupTobeRemoved could not be deleted because rm(1) returned $MLrmReturnCode. It has been renamed to $MLdestPath/OLD-$MLoldBackupTobeRemoved. Please investigate why this backup could not be deleted automatically. Remove this old backup manually!" 850 | 851 | fi # [ $MLrmReturnCode -ne 0 ] 852 | done 853 | fi 854 | 855 | # Ranaming the Backup so it will be reused as link-target for the next run 856 | mv "$MLfinalTarget" "$MLdestPath/$MLbackupName-$MLbackupDate" 857 | MLfinalTarget="$MLdestPath/$MLbackupName-$MLbackupDate" 858 | ln -shf "$MLfinalTarget" "$MLdestPath/$MLlatestBackupTitle" 859 | debug "mlbackup was successful!" 860 | ;; 861 | esac 862 | 863 | # Backup is completed by now. We can savely remove our tag.pid 864 | # Antother instance launched now can not affect backup integrity anymore. 865 | debug "Removing tag.pid in $MLdestPath/$MLbackupName.pid" 866 | $MLrm "$MLdestPath/$MLbackupName.pid" 867 | 868 | debug "--- Handling OLD backups" 869 | # Reporting of surplus OLD and ERROR backups that need to be taken care of 870 | # OLD backups that should have been removed during rotation 871 | # but somehow could not be deleted (protected files, etc.) 872 | MLreallyOldBackupCount=$(ls -1w "$MLdestPath/" | grep -Ec "^OLD-$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" ) 873 | 874 | if [ $MLreallyOldBackupCount -ne 0 ] # any ERROR backups left 875 | then # Yes, at least one OLD backup still left. 876 | MLreallyOldBackupList=$(ls -1w "$MLdestPath/" | grep -E "^OLD-$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" ) 877 | case $MLreallyOldBackupCount in 878 | 1) 879 | appendToFile "$MLadminEmailMessage" " 880 | There is $MLreallyOldBackupCount old backup set that could not be removed automatically. Please remove it manually. 881 | ${MLreallyOldBackupList} 882 | " 883 | ;; 884 | *) 885 | appendToFile "$MLadminEmailMessage" " 886 | There are $MLreallyOldBackupCount old backup sets that could not be removed automatically. Please remove them manually. 887 | ${MLreallyOldBackupList} 888 | " 889 | ;; 890 | esac 891 | fi # [ $MLreallyOldBackupCount -ne 0 ] 892 | 893 | debug "--- Handling ERROR backups" 894 | # ERROR backups that did not finish or had problems 895 | MLreallyErrorBackupCount=$(ls -1w "$MLdestPath/" | grep -Ec "^ERROR-$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" ) 896 | 897 | if [ $MLreallyErrorBackupCount -ne 0 ] # any ERROR backups left 898 | then # Yes, at least one ERROR backup still left. 899 | MLreallyErrorBackupList=$(ls -1w "$MLdestPath/" | grep -E "^ERROR-$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]$" ) 900 | 901 | case $MLreallyErrorBackupCount in 902 | 1) 903 | appendToFile "$MLadminEmailMessage" " 904 | There is $MLreallyErrorBackupCount failed backup set left in $MLdestPath. Please remove it manually. 905 | ${MLreallyErrorBackupList} 906 | " 907 | ;; 908 | *) 909 | appendToFile "$MLadminEmailMessage" " 910 | There are $MLreallyErrorBackupCount failed backup sets left in $MLdestPath. Please remove them manually. 911 | ${MLreallyErrorBackupList} 912 | " 913 | ;; 914 | esac 915 | fi # [ $MLreallyErrorBackupCount -ne 0 ] 916 | 917 | debug "--- Handling ABORTED and .noindex backups" 918 | # ERROR backups that did not finish or had problems 919 | MLabortedBackupCount=$(ls -1w "$MLdestPath/" | grep -Ec "$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]\.noindex$" ) 920 | 921 | if [ $MLabortedBackupCount -ne 0 ] # any ERROR backups left 922 | then # Yes, at least one ERROR backup still left. 923 | MLabortedBackupList=$(ls -1w "$MLdestPath/" | grep -E "$MLbackupName-(19|20)[0-9][0-9]\.(0[1-9]|1[012])\.(0[1-9]|[12][0-9]|3[01])-([01][0-9]|2[0-3])\.[0-5][0-9]\.[0-5][0-9]\.noindex$" ) 924 | case $MLabortedBackupCount in 925 | 1) 926 | appendToFile "$MLadminEmailMessage" " 927 | There is $MLabortedBackupCount aborted backup set left in $MLdestPath. Please investigate the cause of abortion by checking the logs and remove it manually. 928 | ${MLabortedBackupList} 929 | " 930 | ;; 931 | *) 932 | appendToFile "$MLadminEmailMessage" " 933 | There are $MLabortedBackupCount aborted backup sets left in $MLdestPath. Please investigate the cause of abortion by checking the logs and remove them manually. 934 | ${MLabortedBackupList} 935 | " 936 | ;; 937 | esac 938 | 939 | fi # [ $MLabortedBackupCount -ne 0 ] 940 | 941 | debug "--- Moving the Admin eMail Message to the Backup." 942 | # I should REALLY improve on Backup error postprocessing. *embarrassing* 943 | if [ -s $MLadminEmailMessage ] # admin eMail message greater than 0 bytes? 944 | then # Yes, something is in the Message file 945 | # So we move it to the Backup Directory and rename it accordingly 946 | mv "$MLadminEmailMessage" "$MLfinalTarget/AdminEMail.txt" 947 | # Updating the variable, so some very late messages are still appended 948 | MLadminEmailMessage=$MLfinalTarget/AdminEMail.txt 949 | 950 | /bin/chmod 644 "$MLadminEmailMessage" 951 | 952 | else # No, the message is empty, very unlikely 953 | # nothing to shout about, so we silently remove the temporary file 954 | # We can NEVER get here in debug mode thats why we use echo here! 955 | echo "MLadminEmailMessage was empty, we just remove the temporary file." 956 | $MLrm "$MLadminEmailMessage" 957 | unset $MLadminEmailMessage 958 | fi 959 | 960 | # FUTURE: Postflight script 961 | ############################################################################### 962 | # Almost last thing is to determine how long the backup took. 963 | 964 | # Report free space on the destination volume. 965 | appendToFile "$MLadminEmailMessage" "Free space on $MLdestPath: $(df -h "$MLdestPath" | tail -1 | sed "s/^ *//;s/ *$//;s/ \{1,\}/ /g" | cut -d " " -f 4) ($(df "$MLdestPath" | tail -1 | sed "s/^ *//;s/ *$//;s/ \{1,\}/ /g" | cut -d " " -f 4) $(df "$MLdestPath" | head -1 | sed "s/^ *//;s/ *$//;s/ \{1,\}/ /g" | cut -d " " -f 2))" 966 | 967 | MLtimeScriptEnd=$(date +%s) 968 | #Calculating the time difference between start and end giving us the duration 969 | let "MLtimeScriptDurationTotal = $MLtimeScriptEnd - $MLtimeScriptStart" 970 | 971 | if [ $MLtimeScriptDurationTotal -eq 1 ] # Just to care for proper language 972 | then # It was only one second 973 | debug "Backup took $MLtimeScriptDurationTotal second." 974 | else # zero, two or more seconds 975 | if [ $MLtimeScriptDurationTotal -gt 60 ] # Backup tool longer than 60 seconds, which equals 1 minute? 976 | then # Yes, took longer than 60 seconds. 977 | appendToFile "$MLadminEmailMessage" "Backup took $(seconds2dhms $MLtimeScriptDurationTotal). ($MLtimeScriptDurationTotal seconds)" 978 | else 979 | appendToFile "$MLadminEmailMessage" "Backup took $MLtimeScriptDurationTotal seconds." 980 | fi 981 | fi 982 | 983 | # Timestamping the admin message with the end of the backup 984 | appendToFile "$MLadminEmailMessage" "Backup ended: $(date -r $MLtimeScriptEnd)" 985 | 986 | 987 | # Encouraging users to support the development of mlbackup by adding a flattr link ot the email. 988 | appendToFile "$MLadminEmailMessage" " 989 | 990 | You're using mlbackup to safeguard your data. Please consider making a donation to support further development or click our flattr button once in a while. 991 | https://flattr.com/thing/141895/mlbackup 992 | 993 | Thanks! 994 | 995 | " 996 | 997 | debug "--- Sending the AdminEmail Message per mail." 998 | # sending the admin eMail Notification, only if we have an address 999 | if [ $MLadminEmail ] # Is the AdminEMail Address set? 1000 | then # Yes, there is an address! 1001 | debug "Sending the Admin eMail to $MLadminEmail" 1002 | cat "$MLadminEmailMessage" | mail -s "$MLbaseCommand $MLhostname $MLbackupName Report $MLbackupStatus" $MLadminEmail 1003 | else # No address set 1004 | debug "No MLadminEmail Address set, cannot send eMail!" 1005 | appendToFile "$MLadminEmailMessage" "No MLadminEmail Address set. You will not receive backup notifications via eMail." 1006 | fi # [ $MLadminEmail -ne "" ] 1007 | 1008 | notifyGrowl "Finished backup" 1009 | 1010 | debug "--- Removing .pid file in $MLmyPidFile" 1011 | $MLrm "$MLmyPidFile" 1012 | 1013 | debug "BackLemon END" 1014 | ############################################################################### 1015 | # EOF 1016 | --------------------------------------------------------------------------------