Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit a2fb14e9fdb6ad61176230f590f7863616bacfb8 @jrust committed Jan 11, 2012
Showing with 1,990 additions and 0 deletions.
  1. +57 −0 CHANGES
  2. +340 −0 LICENSE
  3. +126 −0 README
  4. +871 −0 ribs
  5. +414 −0 ribs.log
  6. +2 −0 test dir/.svn/README.txt
  7. 0 test dir/.svn/empty-file
  8. +47 −0 test dir/.svn/entries
  9. +1 −0 test dir/.svn/format
  10. +1 −0 test dir/.svn/prop-base/README.svn-base
  11. +1 −0 test dir/.svn/prop-base/junk.svn-base
  12. +1 −0 test dir/.svn/props/README.svn-work
  13. +1 −0 test dir/.svn/props/junk.svn-work
  14. +1 −0 test dir/.svn/text-base/README.svn-base
  15. +1 −0 test dir/.svn/text-base/include.mp3.svn-base
  16. +1 −0 test dir/.svn/text-base/junk.svn-base
  17. +1 −0 test dir/README
  18. +2 −0 test dir/docs/.svn/README.txt
  19. 0 test dir/docs/.svn/empty-file
  20. +28 −0 test dir/docs/.svn/entries
  21. +1 −0 test dir/docs/.svn/format
  22. +1 −0 test dir/docs/.svn/prop-base/stuff.txt.svn-base
  23. +1 −0 test dir/docs/.svn/props/stuff.txt.svn-work
  24. +1 −0 test dir/docs/.svn/text-base/stuff.txt.svn-base
  25. +2 −0 test dir/docs/junk/.svn/README.txt
  26. 0 test dir/docs/junk/.svn/empty-file
  27. +22 −0 test dir/docs/junk/.svn/entries
  28. +1 −0 test dir/docs/junk/.svn/format
  29. +1 −0 test dir/docs/junk/.svn/prop-base/junk.txt.svn-base
  30. +1 −0 test dir/docs/junk/.svn/props/junk.txt.svn-work
  31. +1 −0 test dir/docs/junk/.svn/text-base/junk.txt.svn-base
  32. +1 −0 test dir/docs/junk/junk.txt
  33. +2 −0 test dir/docs/mp3/.svn/README.txt
  34. 0 test dir/docs/mp3/.svn/empty-file
  35. +22 −0 test dir/docs/mp3/.svn/entries
  36. +1 −0 test dir/docs/mp3/.svn/format
  37. +1 −0 test dir/docs/mp3/.svn/prop-base/booroo.mp3.svn-base
  38. +1 −0 test dir/docs/mp3/.svn/props/booroo.mp3.svn-work
  39. +1 −0 test dir/docs/mp3/.svn/text-base/booroo.mp3.svn-base
  40. +1 −0 test dir/docs/mp3/booroo.mp3
  41. +1 −0 test dir/docs/stuff.txt
  42. +1 −0 test dir/include.mp3
  43. +1 −0 test dir/junk
  44. +2 −0 test dir/my mp3/.svn/README.txt
  45. 0 test dir/my mp3/.svn/empty-file
  46. +22 −0 test dir/my mp3/.svn/entries
  47. +1 −0 test dir/my mp3/.svn/format
  48. +1 −0 test dir/my mp3/.svn/prop-base/test.mp3.svn-base
  49. +1 −0 test dir/my mp3/.svn/props/test.mp3.svn-work
  50. +1 −0 test dir/my mp3/.svn/text-base/test.mp3.svn-base
  51. +1 −0 test dir/my mp3/test.mp3
57 CHANGES
@@ -0,0 +1,57 @@
+2.3
+===
+* The example tar script now does not throw an error the first time the script runs.
+* Now works correctly when only backing directories up once a day (limit => 1).
+* Backup directories and exclude directories can now contain spaces.
+
+2.2
+===
+* A per-host shell command can now be run for both a successful and
+ unsuccessful backup (Nathan).
+* A different style of incremental backups is now available for each
+ the hard link method is not used and only changed files are put into
+ the backup directories. Useful for backup setups with lots of files
+ (Nathan).
+* The ssh port is now configurable (Phil Schultz <phil@alcsoftware.com>)
+* Include patterns are now supported (Dan Allen <dan@mojavelinux.com>)
+* If ribs is backing up its host machine as the current user ssh is not used
+ and no password is needed (Dan Allen <dan@mojavelinux.com>)
+
+2.1
+===
+* Added example test configuration and directory for easy testing of RIBS.
+* Made default config options more sensible.
+* Fixed bug where logfile wasn't created if it wasn't already present.
+* Code cleanup.
+* Moved reinit to its own function and made it possible to reinit
+ configurations that aren't turned on (Phil Schultz phil@alcsoftware.com).
+* Backups will try and finish all specified backups even if an error
+ is hit during one of them (Phil Schultz phil@alcsoftware.com).
+
+2.0.1
+=====
+* Fixed Console_Getopt bugs. Must be using version 1.0 of that library now.
+* Cleaned up the README
+
+2.0
+===
+* Added --test option which performs a dry run.
+* Added --reinit option which reinitializes the backup from scratch.
+* Added --debug option which outputs debug information.
+* Improved error handling so that hitting CTRL-C during execution
+ shouldn't cause program to hang.
+* Fixed bug where multiple excludes weren't working (Thanks to Brian
+ Johnson blj AT thermoanalytics DOT com).
+* Added examples in the README on how to use the excludes feature
+* Added example in the README on how to extract an incremental backup.
+* Code cleanup.
+
+1.1
+===
+* Now using PEAR's Getopt utility to make the obtaining of command line
+ args work with different versions of PHP
+* Fixed up some the documentation to be more accurate.
+
+1.0
+===
+* Initial release
340 LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
126 README
@@ -0,0 +1,126 @@
+RIBS (Rsync Incremental Backup System) by Jason Rust <jrust@rustyparts.com>
+You can find the latest version of this script over at:
+http://www.ribs-backup.org/
+
+Description:
+RIBS is an incremental backup system written in PHP which utilizes some
+common *nix programs (specifically rsync, ssh and cp). Incremental
+backups mean frequent backups can be done (i.e. hourly) with only around
+2x the space of the full backup. Using rsync means that RIBS can act as
+both a backup script on a local machine, or as a script to backup
+several network hosts. It is designed to be highly configurable and
+highly informative to the system administrator. There is a high amount
+of error checking, and logging/email capabilities.
+
+Requirements:
+* rsync - http://samba.anu.edu.au/rsync/
+* cp & rm - http://www.gnu.org/software/fileutils/fileutils.html
+* PHP - http://www.php.net/
+* basic PEAR libraries (as of version 1.1) - http://pear.php.net/
+* PEAR's Console_Getopt-1.0 package. This comes with PEAR,
+ but many people have version 0.11 which won't work. Get it at:
+ http://pear.php.net/package-info.php?pacid=67
+
+Quick Usage Explanation:
+For those in a hurry or just wanting to test out the script, the below
+commands should get you up and going:
+* Download the latest version of RIBS
+* tar -xzvf ribs-x.x.tar.gz
+* cd ribs-x.x
+* ./ribs.php example hourly
+
+After that the test example backup should be run using the test directory
+that comes with RIBS. From there you can customize the options and start
+running backups on real data.
+
+Detailed Usage Explanation:
+Install rsync. Set it up to run over ssh (you will need to install ssh
+keys on the servers you will be backing up (man ssh-keygen). If you set
+this up right you should be able to ssh from the backup machine to the
+remote host as the backup user without it asking you for a password
+Next, go through the user settings of this script to set up the hosts
+you want to backup and the different configuration options (such as
+email and logging settings). Last you need to set the script up to run
+in crontab for your different hosts.
+
+An example crontab entry might look something like the following:
+0 0-23/3 * * * /usr/local/bin/ribs my_host hourly # run my_host every three hours
+59 1 * * * /usr/local/bin/ribs my_host,big_host daily # run these two hosts daily
+58 1 * * 0 /usr/local/bin/ribs small_host weekly # run small_host once a week
+57 1 1 * * /usr/local/bin/ribs ALL monthly # use the keyword ALL to run all hosts monthly
+
+Notice that we schedule the daily, weekly, and monthly to occur at a
+different hour than the hourly ones.
+
+You can run this script from the command line and may want to do so a
+few times before installing it in crontab to make sure you have worked
+out the kinks. Also it is important to schedule the cron jobs such that
+they will not overlap with each other. In other words, if the daily
+backup runs at the same time as the hourly backup you will have
+problems. Generally, scheduling the backups 15 minutes apart will work.
+
+Exclude Patterns:
+Much of the following explanation of exclude patterns comes from the
+rsync man page. The patterns can take several forms. The rules are:
+
+* If the pattern starts with a / then it is matched against the start of the
+ filename, otherwise it is matched against the end of the filename. Thus
+ "/foo" would match a file called "foo" at the base of the tree. On the
+ other hand, "foo" would match any file called "foo" anywhere in the tree
+ because the algorithm is applied recursively from top down; it behaves as
+ if each path component gets a turn at being the end of the file name.
+
+* If the pattern ends with a / then it will only match a directory, not a file,
+ link or device.
+
+* If the pattern contains a wildcard character from the set *?[ then expression
+ matching is applied using the shell filename matching rules. Otherwise a simple
+ string match is used.
+
+* If the pattern includes a double asterisk "**" then all wildcards in the
+ pattern will match slashes, otherwise they will stop at slashes.
+
+* If the pattern begins with a + then the file will be included. However, the
+ include rule must come before the exclude rule in order to override it.
+
+* Examples:
+ 'directories' => '/etc/rc.d'
+ 'excludes' => '/init.d' // exclude the top level init.d directory in rd.d/
+ 'excludes' => '*.sh' // exclude all shell files
+ 'excludes' => '+foo.sh *.sh rc*.d/' // exclude all shell files, except foo.sh, and all rcX.d directories
+
+Backup Types:
+The default backup type is incremental using hard links. This means
+that every directory will look like a full backup, but it will only take
+the space of the backup plus the changed files. However, for backups
+with lots of files (>1000) this can become slow. Thus, the other option
+is to use set the 'use_hard_links' option to false for the backup
+configuration. This will keep a full backup in the most recent
+directory, but only archive changed files in the other directories.
+So, roughly the same amount of space will be used, but not every
+directory will look like a full backup, and it will be faster for
+backups with lots of files.
+
+Extracting Incremental Backups From a hard linked backup:
+If an hourly backup is done and you would like to extract all changed files
+from that backup the following command will achieve that:
+find /backups/backup_name/hourly.0 -type f -links 1 | sed 's, ,\\,g' | xargs tar -czf /tmp/foo.tar.gz
+
+Note on ssh and port forwarding:
+If port forwarding with ssh means nothing to you, then you can ignore below.
+
+When connecting to the same 'host' twice, but the second connection is to a port
+forward to another host (i.e. behind a firewall), StrictHostKeyChecking (in the
+ssh config file on the host running ribs) will need to be disabled because the
+host key of the first port will conflict with the host key of the second port.
+
+An example: Machine A is x.x.x.x Machine B is y.y.y.y Machine A has ssh
+running on port 22. Machine B also has ssh listening on port 22, but Machine B
+is not accessible from the outside. So a port forward is setup on Machine A to
+get traffic to Machine B (e.g x.x.x.x:999 -> y.y.y.y:22)
+
+Credits:
+Thanks to Mike Rubel for his excellent paper and sample code...
+http://www.mikerubel.org/computers/rsync_snapshots/
+Thanks to Greg Lawler (http://zinkwazi.com) for the first BASH version
+Thanks to Shai (http://shaibn.com/) for maintaining ribs-backup.org
871 ribs
@@ -0,0 +1,871 @@
+#!/usr/bin/php -q
+<?php
+/** $Id: ribs 1625 2004-11-24 20:55:48Z jrust $ */
+// {{{ version
+
+define('RIBS_VERSION', '2.3');
+
+// }}}
+// {{{ description
+
+/**
+ * RIBS (Rsync Incremental Backup System) by Jason Rust <jrust@rustyaprts.com>
+ * Copyright (c) 2002-2003 Jason Rust <jrust@rustyparts.com>
+ * The latest version of this program can be found at
+ * http://rustyparts.com/scripts.php
+ *
+ * License:
+ *
+ * This source file is subject to the GNU Public License (GPL),
+ * that is bundled with this package in the file LICENSE, and is
+ * available at through the world-wide-web at
+ * http://www.fsf.org/copyleft/lesser.html
+ * If you did not receive a copy of the LGPL and are unable to
+ * obtain it through the world-wide-web, you can get it by writing the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See http://www.gnu.org/copyleft/gpl.html for a copy of the license.
+ *
+ * Description:
+ *
+ * RIBS is an incremental backup system written in PHP which utilizes
+ * some common *nix programs (specifically rsync, ssh and cp).
+ *
+ * Requirements:
+ *
+ * rsync - http://samba.anu.edu.au/rsync/
+ * cp & rm - http://www.gnu.org/software/fileutils/fileutils.html
+ * PHP - http://www.php.net/
+ * basic PEAR libraries (as of version 1.1) - http://pear.php.net/
+ *
+ * Use:
+ *
+ * See the README that comes with this package.
+ */
+
+// }}}
+// {{{ user settings
+
+/****** Configuration Section ******/
+
+/**
+ * This is the place on the server where the backups will end up WITH trailing slash
+ * @type string
+ */
+$s_destinationDir = dirname(__FILE__) . '/backups/';
+
+/**
+ * An array of the different servers to back up, and what directories on them to back up
+ * The structure is as follows:
+ * 'backup_name' => array(
+ * 'enabled' => 'this config enabled? true or false',
+ * 'ip' => 'server ip address/FQDN',
+ * 'ssh_user' => 'the ssh user to use for rsync',
+ * 'ssh_port' => 'the ssh port (optional, defaults to 22)',
+ * 'directories' => 'backup directories separated by a space WITHOUT a trailing slash (i.e. /home /root)',
+ * If a directory has a space in it, escape it with a \
+ * 'excludes' => 'the directories to exclude separated by a space.
+ * See the README for more information on exclude patterns.'
+ * 'limits' => 'an array of directory limits that will allow you to override the limits you set in
+ * $a_backupTypeSettings. Completely optional. e.g. array('hourly' => 2) if you back up
+ * hourly twice a day.'
+ * 'use_hard_links'=> 'Whether to do incremental backups using hard links or real files.
+ * Default option is true. See "Backup Types" in the README for more info.'
+ * 'post_command' => 'A shell command to run after a successful backup. Replaces %fullPath%
+ * and %backupType% with the real values.'
+ * 'post_error_command' => 'Same as post_command, but run when an error occurs.'
+ * ),
+ * @type array
+ */
+$a_backupHosts = array(
+ 'my_host' => array(
+ 'enabled' => false,
+ 'ip' => 'my_host.example.com',
+ 'ssh_user' => 'backup',
+ 'directories' => '/etc /var/lib/mysql /home',
+ 'excludes' => '',
+ 'limits' => array('hourly' => 24), // because this is backed up every hour
+ ),
+ 'small_host' => array(
+ 'enabled' => false,
+ 'ip' => 'small_host.example.com',
+ 'ssh_user' => 'backup',
+ 'ssh_port' => '9999',
+ 'directories' => '/etc',
+ 'excludes' => '',
+ ),
+ 'big_host' => array(
+ 'enabled' => false,
+ 'ip' => '10.52.1.1',
+ 'ssh_user' => 'root',
+ 'directories' => '/var',
+ 'excludes' => 'mp3/', // exclude any mp3 directories
+ ),
+ // A test example configuration that can be used with the test
+ // directory that comes with RIBS.
+ 'example' => array(
+ 'enabled' => true,
+ 'ip' => 'localhost',
+ 'ssh_user' => get_current_user(),
+ 'directories' => dirname(__FILE__) . '/test\ dir',
+ 'use_hard_links'=> true,
+ // An example of a post_command which will tar up each backup.
+ // NOTE: this is only useful if use_hard_links is false
+ // 'post_command' => 'if [ -d %fullPath%%backupType%.1 ]; then tar czv -C %fullPath%%backupType%.1 -f backup.tar.gz .; rm -rf %fullPath%%backupType%.1; mkdir %fullPath%%backupType%.1; mv backup.tar.gz %fullPath%%backupType%.1/; fi',
+ 'excludes' => '/test\ dir/my\ mp3 +/test\ dir/include.mp3 *.mp3 *.svn/ junk/',
+ // exclude the root mp3 directory,
+ // any mp3 files anywhere else (except for include.mp3),
+ // and any .svn/ and junk/ directories
+ ),
+);
+
+/**
+ * Some settings for the four different backup types. For each type you must specify
+ * 'limit' => of directories to keep. So, if you run every two hours, make hourly 12,
+ * if every hour then 24, etc. Try to span the entire day. The below setting runs 8
+ * times a day (every three hours), keeps 7 days, 4 weeks, and 12 months of backups.
+ * 'email' => whether to send email or not after completion
+ * 'log' => whether to log after completion
+ * @type array
+ */
+$a_backupTypeSettings = array(
+ 'hourly' => array('limit' => 8, 'email' => true, 'log' => true),
+ 'daily' => array('limit' => 7, 'email' => true, 'log' => true),
+ 'weekly' => array('limit' => 4, 'email' => true, 'log' => true),
+ 'monthly' => array('limit' => 12, 'email' => true, 'log' => true),
+);
+
+/**
+ * The email address to send reports to (you can comma separate multiple addresses)
+ * @type string
+ */
+$s_email = '';
+
+/**
+ * The log file.
+ * @type string
+ */
+$s_logFile = dirname(__FILE__) . '/ribs.log';
+
+/**
+ * When to start the log over. Note, this does not mean we rotate the log
+ * it is just to keep the log file from getting too big. Can be hourly, daily,
+ * weekly, or monthly
+ * @type string
+ */
+$s_restartBackupLog = 'weekly';
+
+/**
+ * When to do an actual rsync. Otherwise, we just copy the oldest directory
+ * of the type below to the current type. Example: if doing a monthly backup
+ * and $s_rsyncType is not 'monthly' then the oldest weekly directory will be
+ * copied to monthly.0. This keeps down the amount of disk space needed. Usually you
+ * will want this to be 'hourly'
+ * @type string
+ */
+$s_rsyncType = 'hourly';
+
+/**
+ * Always email if there's an error? This overrides the specific backup setting
+ * to ensure you will get an email if there is a problem.
+ * @type bool
+ */
+$b_emailOnError = true;
+
+/**
+ * Die quietly? If so, then on error we just shut up, email (see above), and quit,
+ * otherwise we throw the error.
+ * @type bool
+ */
+$b_silentOnError = false;
+
+/**
+ * Default permissions for when we have to create a new directory
+ * @type int
+ */
+$s_defaultDirPerms = 0750;
+
+/**
+ * Additional comands to be run at the end of each backup (useful for giving
+ * additional info about file sizes, directories, etc.). Leave empty for nothing.
+ * %fullPath% is a placeholder that will be filled in with the full path to the current backup.
+ * @type string
+ */
+$s_extraCommands = "ls -l %fullPath%; df -h";
+
+/**
+ * The extra rsync commands to use
+ * @type string
+ */
+$s_rsyncArgs = '-arztplv --delete --delete-excluded --stats --timeout=180';
+
+/**
+ * The path to the rsync command
+ * @type string
+ */
+$s_rsync = '/usr/bin/rsync';
+
+/**
+ * The path to rm
+ * @var string
+ */
+$s_rm = '/bin/rm';
+
+/**
+ * The path to cp
+ * @type string
+ */
+$s_cp = '/bin/cp';
+
+/****** End Config. No need to edit anything else! ******/
+
+// }}}
+// {{{ readline()
+
+/**
+ * Reads a line from standard input. Have to put it up here so php loads it in.
+ *
+ * @access public
+ * @return string The string from input
+ */
+if (!function_exists('readline')) {
+ function readline () {
+ $fp = fopen('php://stdin', 'r');
+ $in = fgets($fp, 4094); // Maximum windows buffer size
+ fclose ($fp);
+ return $in;
+ }
+}
+
+// }}}
+// {{{ requires
+
+require_once 'Console/Getopt.php';
+
+// }}}
+// {{{ grab command line vars
+
+// don't run out of time
+set_time_limit(0);
+
+// we want all errors
+error_reporting(E_ALL);
+
+$args = Console_Getopt::readPHPArgv();
+if (PEAR::isError($args)) {
+ die('Fatal Error: ' . $args->getMessage() . "\n");
+}
+
+$options = Console_Getopt::getopt($args, 'dhtr', array('debug', 'help', 'test', 'reinit'));
+if (PEAR::isError($options)) {
+ die($options->getMessage() . "\n");
+}
+
+$b_debug = false;
+$b_dryRun = false;
+$b_cleanupDryRun = false;
+$b_reinit = false;
+$s_log = '';
+$b_error = false;
+
+foreach ($options[0] as $option) {
+ switch ($option[0]) {
+ case 'h':
+ case '--help':
+ showUsage($args[0]);
+ exit;
+ break;
+ case 'd':
+ case '--debug':
+ $b_debug = true;
+ break;
+ case 't':
+ case '--test':
+ $b_dryRun = true;
+ break;
+ case 'r':
+ case '--reinit':
+ $b_reinit = true;
+ break;
+ }
+}
+
+if (empty($options[1][0])) {
+ writeln('Error: Configuation not specified' . "\n");
+ showUsage($args[0]);
+ exit;
+}
+
+// grab the config names from the command line
+$a_configNames = explode(',', $options[1][0]);
+
+// ALL is a special keyword to run all backups
+if ($a_configNames[0] == 'ALL') {
+ $a_configNames = array_keys($a_backupHosts);
+}
+
+if ($b_reinit) {
+ reInitBackups();
+ exit;
+}
+
+if (empty($options[1][1])) {
+ writeln('Error: Backup type not specified' . "\n");
+ showUsage($args[0]);
+ exit;
+}
+
+// grab the backup type from the command line
+$s_backupType = $options[1][1];
+
+if ($b_debug) {
+ array_shift($args);
+ writeln('Debug mode is ON.');
+ writeln('Arguments received: ' . implode(' ', $args));
+ writeln('Configuration names: ' . implode(',', $a_configNames));
+ writeln('Backup type: ' . $s_backupType);
+}
+
+if ($b_dryRun) {
+ writeln('Dry run mode is ON.');
+}
+
+// }}}
+// {{{ set up vars and dirs
+
+// start log
+$s_log .= date('F j, Y, g:i a') . ": $s_backupType backups for " . implode(',', $a_configNames) . "\n";
+
+// make sure it's a valid type
+if ($s_backupType != 'hourly' &&
+ $s_backupType != 'daily' &&
+ $s_backupType != 'weekly' &&
+ $s_backupType != 'monthly') {
+ writeln("ERROR: The backup type: '$s_backupType' is not valid (valid types are hourly, daily, weekly, and monthly).");
+ exit;
+}
+
+// check binaries
+if (!is_executable($s_rsync)) {
+ writeln("WARNING: The rsync program: '$s_rsync' is not valid.");
+ exit;
+}
+
+if (!is_executable($s_rm)) {
+ writeln("WARNING: The rm program: '$s_rm' is not valid.");
+ exit;
+}
+
+if (!is_executable($s_cp)) {
+ writeln("WARNING: The cp program: '$s_cp' is not valid.");
+ exit;
+}
+
+if (!is_dir($s_destinationDir)) {
+ mkdir($s_destinationDir, $s_defaultDirPerms);
+ $s_log .= writeln("Created destination directory: $s_destinationDir", true);
+}
+
+// determine the type below the current type
+if ($s_backupType == 'daily') {
+ $s_typeBelow = 'hourly';
+}
+elseif ($s_backupType == 'weekly') {
+ $s_typeBelow = 'daily';
+}
+elseif ($s_backupType == 'monthly') {
+ $s_typeBelow = 'weekly';
+}
+else {
+ $s_typeBelow = 'monthly';
+}
+
+// }}}
+// {{{ loop through backup configurations
+
+foreach ($a_configNames as $s_configName) {
+ // make sure that we are using a valid configuration
+ if (!isset($a_backupHosts[$s_configName])) {
+ $tmp_msg = writeln("WARNING: The configuation: '$s_configName' is not valid.\n", true, true);
+ $s_log .= $tmp_msg;
+ $b_error = true;
+ continue;
+ }
+ else {
+ $s_log .= writeln("-= Beginning backups for $s_configName\n", true, true);
+ }
+
+ // make sure it's enabled
+ if (!$a_backupHosts[$s_configName]['enabled']) {
+ $s_log .= writeln("$s_configName is disabled. Skipping backup.", true);
+ continue;
+ }
+
+ $s_fullPath = $s_destinationDir . $s_configName . '/';
+
+ if (!is_dir($s_fullPath)) {
+ mkdir($s_fullPath, $s_defaultDirPerms);
+ $s_log .= writeln("Created directory for $s_configName: $s_fullPath", true);
+ }
+
+ // {{{ rotate the current list of backups if we can
+
+ if ($tmp_handle = opendir($s_fullPath)) {
+ $a_dirList = array();
+ $a_dirListTypeBelow = array();
+ while (false !== ($tmp_file = readdir($tmp_handle))) {
+ if (is_dir($s_fullPath . $tmp_file)) {
+ if (preg_match(":$s_backupType\.\d+$:", $tmp_file)) {
+ $a_dirList[] = $tmp_file;
+ }
+
+ // for later we need the directories of the type below
+ if (preg_match(":$s_typeBelow\.\d+$:", $tmp_file)) {
+ $a_dirListTypeBelow[] = $tmp_file;
+ }
+ }
+ }
+
+ closedir($tmp_handle);
+
+ // determine maximum number of directories allowed for this backup
+ if (isset($a_backupHosts[$s_configName]['limits']) &&
+ isset($a_backupHosts[$s_configName]['limits'][$s_backupType])) {
+ $tmp_max = $a_backupHosts[$s_configName]['limits'][$s_backupType];
+ }
+ else {
+ $tmp_max = $a_backupTypeSettings[$s_backupType]['limit'];
+ }
+
+ // If the max is 1 (backing up only once a day) then don't rotate anything
+ if ($tmp_max > 1) {
+ // go through directories in reverse order and rotate them
+ natsort($a_dirList);
+ $a_dirList = array_reverse($a_dirList);
+ foreach ($a_dirList as $tmp_dir) {
+ $tmp_key = preg_replace(':.*\.(\d+)$:', '\\1', $tmp_dir);
+ // rotate off any of the old backups
+ if (($tmp_key + 1) >= $tmp_max) {
+ if ($b_debug || $b_dryRun) {
+ $tmp_msg = 'Rotating off old backup: ' . $s_fullPath . $tmp_dir;
+ if ($b_dryRun) {
+ $tmp_msg = str_replace('Rotating', 'Would rotate', $tmp_msg);
+ }
+
+ writeln($tmp_msg);
+ }
+
+ if (!$b_dryRun) {
+ // :NOTE: can use System::rm when it supports symlinks in directories
+ exec("$s_rm -rf $s_fullPath$tmp_dir");
+ }
+ }
+ // otherwise rotate the directory up
+ else {
+ $tmp_key++;
+ $tmp_newDir = preg_replace(':\.\d+$:', ".$tmp_key", $tmp_dir);
+ if ($b_debug || $b_dryRun) {
+ $tmp_msg = "Rotating backup directory from $s_fullPath$tmp_dir to $s_fullPath$tmp_newDir";
+ if ($b_dryRun) {
+ $tmp_msg = str_replace('Rotating', 'Would rotate', $tmp_msg);
+ }
+
+ writeln($tmp_msg);
+ }
+
+ if (!$b_dryRun) {
+ rename($s_fullPath . $tmp_dir, $s_fullPath . $tmp_newDir);
+ }
+ }
+ }
+ }
+ }
+
+ // }}}
+ // {{{ perform rsync
+
+ // this dir shouldn't be here, but check anyhow to make sure we
+ // don't get recursive directories
+ if (!$b_dryRun && $tmp_max > 1 && is_dir("$s_fullPath$s_backupType.0") && !$b_dryRun) {
+ exec("$s_rm -rf $s_fullPath$s_backupType.0");
+ }
+
+ // we only rsync if the type is hourly or on the type is the one they want rsynced
+ if ($s_backupType == 'hourly' || $s_backupType == $s_rsyncType) {
+ // make hard-link-only copy of latest directory
+ if (is_dir("$s_fullPath$s_backupType.1") && !$b_dryRun) {
+ if (!isset($a_backupHosts[$s_configName]['use_hard_links']) ||
+ $a_backupHosts[$s_configName]['use_hard_links']) {
+ exec("$s_cp -al $s_fullPath$s_backupType.1 $s_fullPath$s_backupType.0");
+ } else {
+ // When not using the hard-link method of backups we
+ // want the full backup to be in .0 and any files that have
+ // been changed to be placed in .1
+ rename("$s_fullPath$s_backupType.1", "$s_fullPath$s_backupType.0");
+ mkdir("$s_fullPath$s_backupType.1", $s_defaultDirPerms);
+ }
+ }
+
+ // directory needs to exist for dry run
+ if ($b_dryRun && !is_dir("$s_fullPath$s_backupType.0")) {
+ $b_cleanupDryRun = true;
+ mkdir("$s_fullPath$s_backupType.0");
+ }
+
+ $tmp_excludes = preg_split('/([^\\\\])\s/', $a_backupHosts[$s_configName]['excludes'], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+ $exclude_args = '';
+ for ($i = 0; $i < count($tmp_excludes); $i++) {
+ $s_exclude = str_replace('\\', '', $tmp_excludes[$i]);
+ if (isset($tmp_excludes[$i + 1]) && strlen($tmp_excludes[$i + 1]) == 1) {
+ $s_exclude .= $tmp_excludes[++$i];
+ }
+
+ // check if we want to include rather than exclude
+ if (substr($s_exclude, 0, 1) == '+') {
+ $s_exclude = '+ ' . substr($s_exclude, 1);
+ }
+ // in this case we want a literal '+'
+ elseif (substr($s_exclude, 0, 2) == '\+') {
+ $s_exclude = '+' . substr($s_exclude, 2);
+ }
+
+ $exclude_args = $exclude_args . " --exclude=\"$s_exclude\"";
+ }
+
+ $tmp_rsyncArgs = $s_rsyncArgs;
+ if ($b_dryRun) {
+ $tmp_rsyncArgs .= ' -n';
+ }
+
+ // See if ribs is running on the localhost as the current user,
+ // in which case we don't use ssh, making it possible to run ribs
+ // without a password.
+ if ($a_backupHosts[$s_configName]['ip'] == 'localhost' &&
+ $a_backupHosts[$s_configName]['ssh_user'] == get_current_user()) {
+ $tmp_rsyncArgs .= ' ' . $a_backupHosts[$s_configName]['directories'];
+ }
+ else {
+ $tmp_dirs = preg_replace('/\\\\\s/', '\\\\\\\\ ', $a_backupHosts[$s_configName]['directories']);
+ $s_port = isset($a_backupHosts[$s_configName]['ssh_port']) ?
+ $a_backupHosts[$s_configName]['ssh_port'] : 22;
+ $tmp_rsyncArgs .= " -e \"ssh -p $s_port\" ";
+ $tmp_rsyncArgs .= "\"{$a_backupHosts[$s_configName]['ssh_user']}@";
+ $tmp_rsyncArgs .= "{$a_backupHosts[$s_configName]['ip']}:";
+ $tmp_rsyncArgs .= $tmp_dirs . '"';
+ }
+
+ if (isset($a_backupHosts[$s_configName]['use_hard_links']) &&
+ !$a_backupHosts[$s_configName]['use_hard_links']) {
+ $tmp_rsyncArgs .= " --backup --backup-dir=\"$s_fullPath$s_backupType.1\"";
+ }
+
+ // now we do the actual rsync from the system into the latest snapshot (notice that
+ // rsync behaves like cp --remove-destination by default, so the destination
+ // is unlinked first. If it were not so, this would copy over the other snapshot(s) too!
+ $s_args = "$exclude_args $tmp_rsyncArgs " .
+ "$s_fullPath$s_backupType.0 2>&1";
+ $s_cmd = $s_rsync . ' ' . $s_args;
+ if ($b_debug) {
+ writeln('Executing rsync command: ' . $s_cmd);
+ }
+
+ $s_log .= `$s_cmd`;
+
+ if ($b_cleanupDryRun) {
+ rmdir("$s_fullPath$s_backupType.0");
+ }
+ }
+ // else we just rotate the most recent directory of the type below up to the current
+ // type. This saves space so that there is only one "real" directory with files. The
+ // other directories are hardlinked directories.
+ else {
+ natsort($a_dirListTypeBelow);
+ $tmp_lastDir = end($a_dirListTypeBelow);
+ if ($tmp_lastDir != '' && is_dir($s_fullPath . $tmp_lastDir)) {
+ if ($b_debug || $b_dryRun) {
+ $tmp_msg = "Performing backup by copying $s_fullPath$tmp_lastDir to $s_fullPath$s_backupType.0";
+ if ($b_dryRun) {
+ $tmp_msg = str_replace('Performing', 'Would perform', $tmp_msg);
+ }
+
+ writeln($tmp_msg);
+ }
+ if (!$b_dryRun) {
+ exec("$s_cp -al $s_fullPath$tmp_lastDir $s_fullPath$s_backupType.0");
+ }
+
+ $s_log .= writeln("Performed $s_backupType backup by copying the last $s_typeBelow up to $s_backupType", true);
+ }
+ else {
+ $tmp_msg = writeln("WARNING: Could not perform $s_backupType backup because the $s_typeBelow type does not exist.", true, true);
+ $tmp_msg .= writeln("You must run the $s_typeBelow backup first or change what type of backup performs the actual");
+ $tmp_msg .= writeln("rsync (\$s_rsyncType is the config variable to check).", true);
+ $s_log .= $tmp_msg;
+ $b_error = true;
+ continue;
+ }
+ }
+
+ // }}}
+ // {{{ check for rsync problems
+
+ // see if there was an error
+ if (stristr($s_log, 'rsync error')) {
+ $tmp_msg = writeln("WARNING: there seems to have been an rsync error.\nCheck the logs for more information.", true, true);
+ $s_log .= $tmp_msg;
+ $b_error = true;
+ if (isset($a_backupHosts[$s_configName]['post_error_command'])) {
+ $s_cmd = replaceVars($a_backupHosts[$s_configName]['post_error_command']);
+ $s_log .= "\nPost error command: $s_cmd\n";
+ $s_log .= `($s_cmd) 2>&1`;
+ }
+ }
+ // let the snapshot reflect the current date
+ elseif (is_dir("$s_fullPath$s_backupType.0") && !$b_dryRun) {
+ touch("$s_fullPath$s_backupType.0");
+ if (($s_backupType == 'hourly' || $s_backupType == $s_rsyncType) &&
+ !is_link($s_fullPath . 'current')) {
+ symlink("$s_fullPath$s_backupType.0", $s_fullPath . 'current');
+ }
+
+ if (isset($a_backupHosts[$s_configName]['post_command'])) {
+ $s_cmd = replaceVars($a_backupHosts[$s_configName]['post_command']);
+ $s_log .= "\nPost command: $s_cmd\n";
+ $s_log .= `($s_cmd) 2>&1`;
+ }
+
+ // give some extra helpful info
+ if ($s_extraCommands != '') {
+ $s_log .= "\nAdditional information:\n";
+ $s_cmd = replaceVars($s_extraCommands);
+ $s_log .= `($s_cmd) 2>&1`;
+ }
+ }
+ elseif (!$b_dryRun) {
+ $tmp_msg = writeln("WARNING: it looks like the backup for config '$s_configName' was not successful.", true, true);
+ $tmp_msg .= writeln("The snapshot directory that is supposed to be created was not created:", true);
+ $tmp_msg .= writeln("$s_fullPath$s_backupType.0", true);
+ $tmp_msg .= writeln("Check the logs for more information.", true);
+ $s_log .= $tmp_msg;
+ $b_error = true;
+ }
+
+ // }}}
+}
+
+// send off the logs
+if ($b_error) {
+ mailAndLog($s_log);
+}
+else {
+ mailAndLog();
+}
+
+exit;
+
+// }}}
+// {{{ mailAndLog()
+
+/**
+ * Performs the necessary mailing and logging and exiting of the program
+ *
+ * @param string $in_errorMessage (optional) The error message
+ *
+ * @return void
+ */
+function mailAndLog($in_errorMessage = false)
+{
+ global $a_backupHosts, $a_backupTypeSettings, $a_configNames,
+ $s_backupType, $s_log, $s_email, $s_logFile, $s_restartBackupLog,
+ $b_silentOnError, $b_emailOnError, $b_debug, $b_dryRun;
+
+ $s_log = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n$s_log";
+ $s_log .= "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n";
+ // log the message to file
+ if ($a_backupTypeSettings[$s_backupType]['log'] && $s_logFile != '') {
+ // determine file mode
+ $tmp_fileMode = $s_backupType == $s_restartBackupLog ? 'w' : 'a';
+ $fp = @fopen($s_logFile, $tmp_fileMode);
+ if ($fp) {
+ fwrite($fp, $s_log);
+ fclose($fp);
+ if ($b_debug) {
+ writeln('Successfully wrote to logfile: ' . $s_logFile);
+ }
+ }
+ else {
+ $in_errorMessage .= writeln("WARNING: Could not write to log file: $s_logFile", true, true);
+ $s_log .= $in_errorMessage;
+ }
+ }
+
+ // e-mail the log if they want it or it's an error
+ if (isset($a_backupTypeSettings[$s_backupType]) &&
+ ($a_backupTypeSettings[$s_backupType]['email'] ||
+ ($b_emailOnError && $in_errorMessage !== false)) &&
+ $s_email != '') {
+ $tmp_error = $in_errorMessage !== false ? ' (WARNING) ' : '';
+ $s_subject = "[ RIBS $tmp_error $s_backupType backups for " . implode(',', $a_configNames) . " ]";
+ if ($b_debug) {
+ writeln('Emailing backup log to: ' . $s_email);
+ }
+
+ mail($s_email, $s_subject, $s_log);
+ }
+
+ if ($in_errorMessage !== false && (!$b_silentOnError || $b_debug)) {
+ echo $in_errorMessage;
+ }
+
+ if ($b_debug || $b_dryRun) {
+ $tmp_msg = 'Dumping log for this backup:';
+ if ($b_dryRun) {
+ $tmp_msg = str_replace('Dumping log', 'What the log would be', $tmp_msg);
+ }
+
+ writeln($tmp_msg);
+ writeln($s_log);
+ }
+}
+
+// }}}
+// {{{ reInitBackups()
+
+/**
+ * Re-initialize a backup by removing the directory associated with it.
+ *
+ * @access public
+ * @return void
+ */
+function reInitBackups()
+{
+ global $a_backupHosts, $a_configNames, $s_log, $s_destinationDir, $s_rm;
+
+ writeln('Beginning Re-initialization.');
+ foreach ($a_configNames as $s_configName) {
+ // make sure that we are using a valid configuration
+ if (!isset($a_backupHosts[$s_configName])) {
+ writeln("WARNING: The configuation: '$s_configName' is not valid, skipping it.\n", false, true);
+ continue;
+ }
+
+ $answer = '';
+ $s_fullPath = $s_destinationDir . $s_configName . '/';
+ writeln ("Are you sure you want to re-initialize $s_configName?", false, true);
+ echo 'This will completely remove it\'s backup directory and start from scratch. [y/n]: ';
+ $answer = trim(readline());
+ if ($answer == 'y' || $answer == 'Y') {
+ exec("$s_rm -rf $s_fullPath");
+ writeln('Successfully re-initialized ' . $s_configName . '.');
+ continue;
+ }
+ elseif ($answer == 'n' || $answer == 'N') {
+ writeln('Skipping re-initialization of ' . $s_configName . '.');
+ continue;
+ }
+ else {
+ writeln('Aborting re-initialization.');
+ exit;
+ }
+ }
+
+ writeln('Re-initialization complete.');
+}
+
+
+// }}}
+// {{{ showUsage()
+
+/**
+ * Shows the usage message
+ *
+ * @param string $in_file The currently running file name
+ *
+ * @access public
+ * @return void
+ */
+function showUsage($in_file)
+{
+ $s_usage =
+'RIBS version ' . RIBS_VERSION . '
+Copyright (c) 2002-2003 Jason Rust <jrust@rustyparts.com>
+
+RIBS (Rsync Incremental Backup System) is a command line PHP script
+which will perform incremental backups to a variable number of hosts
+(and directories on those hosts).
+
+Usage: ' . $in_file . ' [options] CONFIG_NAME BACKUP_TYPE
+
+Variables:
+ CONFIG_NAME A comma separated list of configurations to run
+ or ALL if you want to run all configurations
+ BACKUP_TYPE The type of backup to run. Can be hourly, daily,
+ weekly, or monthly
+
+Options:
+ -h, --help Show this help message
+ -d, --debug Show debug information
+ -t, --test Do a dry run. Does not transfer any files or move
+ any directories, just shows what would happen.
+ -r, --reinit Re-initialize the backup. Removes any existing
+ backups for the specified CONFIG_NAME so that the
+ backups are started from scratch. WARNING: Any
+ existing data will be erased.
+
+Report any bugs to: jrust@rustyparts.com';
+ writeln($s_usage);
+}
+
+// }}}
+// {{{ writeln()
+
+/**
+ * Writes a line to standard output
+ *
+ * @param string $in_message The message to write.
+ * @param bool $in_return (optional) Return the message instead of echoing it?
+ * @param bool $in_pre (optional) Prepend a newline to the string?
+ *
+ * @access public
+ * @return void
+ */
+function writeln($in_message, $in_return = false, $in_pre = false)
+{
+ if ($in_pre) {
+ $in_message = "\n" . $in_message;
+ }
+
+ $in_message = $in_message . "\n";
+ if ($in_return) {
+ return $in_message;
+ }
+ else {
+ echo $in_message;
+ }
+}
+
+// }}}
+// {{{ replaceVars()
+
+/**
+ * Replaces the placeholders %fullPath% and %backupType% with the actual
+ * value.
+ *
+ * @var string $in_cmd The command that has the placeholders
+ *
+ * @return string The command with placeholders replaced
+ */
+function replaceVars($in_cmd)
+{
+ $in_cmd = str_replace('%fullPath%', $GLOBALS['s_fullPath'], $in_cmd);
+ $in_cmd = str_replace('%backupType%', $GLOBALS['s_backupType'], $in_cmd);
+ return $in_cmd;
+}
+
+// }}}
+?>
414 ribs.log
@@ -0,0 +1,414 @@
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+May 27, 2004, 12:03 pm: weekly backups for example
+
+-= Beginning backups for example
+
+Performed weekly backup by copying the last daily up to weekly
+
+Additional information:
+total 12
+lrwxrwxrwx 1 jrust jrust 49 May 27 12:01 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:02 daily.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:02 hourly.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:03 weekly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 323M 139M 70% /
+/dev/hda1 198M 16M 172M 9% /boot
+/dev/hda8 29G 26G 2.2G 93% /home
+none 506M 0 506M 0% /dev/shm
+/dev/hda6 487M 9.0M 453M 2% /tmp
+/dev/hda2 4.9G 4.2G 385M 92% /usr
+/dev/hda3 981M 668M 264M 72% /var
+//retal/jrust$ 31G 29G 2.6G 92% /mnt/smb/p
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+May 27, 2004, 12:03 pm: hourly backups for example
+
+-= Beginning backups for example
+
+building file list ... done
+test dir/
+test dir/README
+rsync[1952] (server receiver) heap statistics:
+ arena: 122880 (bytes from sbrk)
+ ordblks: 5 (chunks not in use)
+ smblks: 2
+ hblks: 0 (chunks from mmap)
+ hblkhd: 0 (bytes from mmap)
+ usmblks: 0
+ fsmblks: 80
+ uordblks: 108792 (bytes used)
+ fordblks: 14088 (bytes free)
+ keepcost: 1000 (bytes in releasable chunk)
+rsync[1950] (sender) heap statistics:
+ arena: 344064 (bytes from sbrk)
+ ordblks: 4 (chunks not in use)
+ smblks: 3
+ hblks: 0 (chunks from mmap)
+ hblkhd: 0 (bytes from mmap)
+ usmblks: 0
+ fsmblks: 152
+ uordblks: 328064 (bytes used)
+ fordblks: 16000 (bytes free)
+ keepcost: 3696 (bytes in releasable chunk)
+
+Number of files: 7
+Number of files transferred: 1
+Total file size: 131 bytes
+Total transferred file size: 67 bytes
+Literal data: 67 bytes
+Matched data: 0 bytes
+File list size: 164
+Total bytes written: 275
+Total bytes read: 36
+
+wrote 275 bytes read 36 bytes 622.00 bytes/sec
+total size is 131 speedup is 0.42
+
+Additional information:
+total 12
+lrwxrwxrwx 1 jrust jrust 49 May 27 12:01 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:02 daily.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:03 hourly.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:03 weekly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 323M 139M 70% /
+/dev/hda1 198M 16M 172M 9% /boot
+/dev/hda8 29G 26G 2.2G 93% /home
+none 506M 0 506M 0% /dev/shm
+/dev/hda6 487M 9.0M 453M 2% /tmp
+/dev/hda2 4.9G 4.2G 385M 92% /usr
+/dev/hda3 981M 668M 264M 72% /var
+//retal/jrust$ 31G 29G 2.6G 92% /mnt/smb/p
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+May 27, 2004, 12:03 pm: daily backups for example
+
+-= Beginning backups for example
+
+Performed daily backup by copying the last hourly up to daily
+
+Additional information:
+total 12
+lrwxrwxrwx 1 jrust jrust 49 May 27 12:01 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwx--- 4 jrust jrust 4096 May 27 12:03 daily.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:03 hourly.0
+drwxrwx--- 3 jrust jrust 4096 May 27 12:03 weekly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 323M 139M 70% /
+/dev/hda1 198M 16M 172M 9% /boot
+/dev/hda8 29G 26G 2.2G 93% /home
+none 506M 0 506M 0% /dev/shm
+/dev/hda6 487M 9.0M 453M 2% /tmp
+/dev/hda2 4.9G 4.2G 385M 92% /usr
+/dev/hda3 981M 668M 264M 72% /var
+//retal/jrust$ 31G 29G 2.6G 92% /mnt/smb/p
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:29 pm: hourly backups for example
+Created destination directory: /home/jrust/testing/ribs/backups/
+
+-= Beginning backups for example
+
+Created directory for example: /home/jrust/testing/ribs/backups/example/
+building file list ... done
+created directory /home/jrust/testing/ribs/backups/example/hourly.0
+foo/
+foo/test
+test dir/
+test dir/README
+test dir/docs/
+test dir/docs/mp3/
+test dir/docs/stuff.txt
+test dir/include.mp3
+test dir/junk
+
+Number of files: 9
+Number of files transferred: 5
+Total file size: 130 bytes
+Total transferred file size: 130 bytes
+Literal data: 130 bytes
+Matched data: 0 bytes
+File list size: 197
+Total bytes written: 534
+Total bytes read: 120
+
+wrote 534 bytes read 120 bytes 1308.00 bytes/sec
+total size is 130 speedup is 0.20
+
+Additional information:
+total 4
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:29 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 4 jrust jrust 4096 Nov 24 12:29 hourly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:31 pm: hourly backups for example
+Created destination directory: /home/jrust/testing/ribs/backups/
+
+-= Beginning backups for example
+
+Created directory for example: /home/jrust/testing/ribs/backups/example/
+building file list ... done
+created directory /home/jrust/testing/ribs/backups/example/hourly.0
+foo/
+foo/test
+test dir/
+test dir/README
+test dir/docs/
+test dir/docs/mp3/
+test dir/docs/stuff.txt
+test dir/include.mp3
+test dir/junk
+
+Number of files: 9
+Number of files transferred: 5
+Total file size: 130 bytes
+Total transferred file size: 130 bytes
+Literal data: 130 bytes
+Matched data: 0 bytes
+File list size: 197
+Total bytes written: 534
+Total bytes read: 120
+
+wrote 534 bytes read 120 bytes 436.00 bytes/sec
+total size is 130 speedup is 0.20
+
+Post command: if tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; then rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+tar: /home/jrust/testing/ribs/backups/example/hourly.1: Cannot chdir: No such file or directory
+tar: Error is not recoverable: exiting now
+
+Additional information:
+total 4
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:31 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 4 jrust jrust 4096 Nov 24 12:31 hourly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:31 pm: hourly backups for example
+
+-= Beginning backups for example
+
+building file list ... done
+
+Number of files: 9
+Number of files transferred: 0
+Total file size: 130 bytes
+Total transferred file size: 0 bytes
+Literal data: 0 bytes
+Matched data: 0 bytes
+File list size: 197
+Total bytes written: 209
+Total bytes read: 20
+
+wrote 209 bytes read 20 bytes 458.00 bytes/sec
+total size is 130 speedup is 0.57
+
+Post command: if tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; then rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+tar: /home/jrust/testing/ribs/backups/example/hourly.1: Cannot chdir: No such file or directory
+tar: Error is not recoverable: exiting now
+
+Additional information:
+total 4
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:31 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 4 jrust jrust 4096 Nov 24 12:31 hourly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:31 pm: hourly backups for example
+
+-= Beginning backups for example
+
+building file list ... done
+
+Number of files: 9
+Number of files transferred: 0
+Total file size: 130 bytes
+Total transferred file size: 0 bytes
+Literal data: 0 bytes
+Matched data: 0 bytes
+File list size: 197
+Total bytes written: 209
+Total bytes read: 20
+
+wrote 209 bytes read 20 bytes 458.00 bytes/sec
+total size is 130 speedup is 0.57
+
+Post command: if tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; then rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+./
+
+Additional information:
+total 8
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:31 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 4 jrust jrust 4096 Nov 24 12:31 hourly.0
+drwxrwxr-x 2 jrust jrust 4096 Nov 24 12:31 hourly.1
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:32 pm: hourly backups for example
+
+-= Beginning backups for example
+
+building file list ... done
+foo/
+foo/test
+
+Number of files: 9
+Number of files transferred: 1
+Total file size: 135 bytes
+Total transferred file size: 5 bytes
+Literal data: 5 bytes
+Matched data: 0 bytes
+File list size: 197
+Total bytes written: 255
+Total bytes read: 40
+
+wrote 255 bytes read 40 bytes 196.67 bytes/sec
+total size is 135 speedup is 0.46
+
+Post command: if tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; then rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+./
+./foo/
+./foo/test
+
+Additional information:
+total 12
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:31 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 4 jrust jrust 4096 Nov 24 12:32 hourly.0
+drwxrwxr-x 2 jrust jrust 4096 Nov 24 12:32 hourly.1
+drwxrwxr-x 2 jrust jrust 4096 Nov 24 12:31 hourly.2
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:37 pm: hourly backups for example
+Created destination directory: /home/jrust/testing/ribs/backups/
+
+-= Beginning backups for example
+
+Created directory for example: /home/jrust/testing/ribs/backups/example/
+building file list ... done
+created directory /home/jrust/testing/ribs/backups/example/hourly.0
+test dir/
+test dir/README
+test dir/docs/
+test dir/docs/mp3/
+test dir/docs/stuff.txt
+test dir/include.mp3
+test dir/junk
+
+Number of files: 7
+Number of files transferred: 4
+Total file size: 130 bytes
+Total transferred file size: 130 bytes
+Literal data: 130 bytes
+Matched data: 0 bytes
+File list size: 164
+Total bytes written: 464
+Total bytes read: 100
+
+wrote 464 bytes read 100 bytes 1128.00 bytes/sec
+total size is 130 speedup is 0.23
+
+Post command: if [ -d /home/jrust/testing/ribs/backups/example/hourly.1 ]; then tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+
+Additional information:
+total 4
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:37 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 3 jrust jrust 4096 Nov 24 12:37 hourly.0
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+//retal/it 34G 18G 17G 52% /mnt/smb/s
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+November 24, 2004, 12:37 pm: hourly backups for example
+
+-= Beginning backups for example
+
+building file list ... done
+test dir/
+test dir/README
+
+Number of files: 7
+Number of files transferred: 1
+Total file size: 135 bytes
+Total transferred file size: 71 bytes
+Literal data: 71 bytes
+Matched data: 0 bytes
+File list size: 164
+Total bytes written: 283
+Total bytes read: 40
+
+wrote 283 bytes read 40 bytes 646.00 bytes/sec
+total size is 135 speedup is 0.42
+
+Post command: if [ -d /home/jrust/testing/ribs/backups/example/hourly.1 ]; then tar czv -C /home/jrust/testing/ribs/backups/example/hourly.1 -f backup.tar.gz .; rm -rf /home/jrust/testing/ribs/backups/example/hourly.1; mkdir /home/jrust/testing/ribs/backups/example/hourly.1; mv backup.tar.gz /home/jrust/testing/ribs/backups/example/hourly.1/; fi
+./
+./test dir/
+./test dir/README
+
+Additional information:
+total 8
+lrwxrwxrwx 1 jrust jrust 49 Nov 24 12:37 current -> /home/jrust/testing/ribs/backups/example/hourly.0
+drwxrwxr-x 3 jrust jrust 4096 Nov 24 12:37 hourly.0
+drwxrwxr-x 2 jrust jrust 4096 Nov 24 12:37 hourly.1
+Filesystem Size Used Avail Use% Mounted on
+/dev/hda7 487M 328M 134M 72% /
+/dev/hda1 198M 9.7M 178M 6% /boot
+none 506M 0 506M 0% /dev/shm
+/dev/hda8 29G 24G 4.2G 85% /home
+/dev/hda6 487M 9.8M 452M 3% /tmp
+/dev/hda2 4.9G 3.9G 743M 85% /usr
+/dev/hda3 981M 659M 273M 71% /var
+//retal/it 34G 18G 17G 52% /mnt/smb/s
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
2 test dir/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 test dir/.svn/empty-file
No changes.
47 test dir/.svn/entries
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1093"
+ name=""
+ committed-date="2004-03-12T18:23:51.732701Z"
+ url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir"
+ last-author="jrust"
+ kind="dir"
+ uuid="050cec29-0bbb-0310-b500-ffd5b9db3264"
+ revision="1622"/>
+<entry
+ committed-rev="1092"
+ name="include.mp3"
+ text-time="2004-03-12T17:24:10.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="9bf93f8b11f4b4e95ab3398d2bdaae09"
+ last-author="jrust"
+ kind="file"/>
+<entry
+ name="my mp3"
+ kind="dir"
+ copyfrom-rev="1092"
+ copyfrom-url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir/mp3"/>
+<entry
+ committed-rev="1092"
+ name="junk"
+ text-time="2004-03-12T17:24:10.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="e06f7ef8216f6b8fdb024d202cae3f00"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:23.000000Z"/>
+<entry
+ name="docs"
+ kind="dir"/>
+<entry
+ committed-rev="1092"
+ name="README"
+ text-time="2004-11-24T20:38:22.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="f9a7cd0fd8a028530f9326e943ae2fc7"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:23.000000Z"/>
+</wc-entries>
1 test dir/.svn/format
@@ -0,0 +1 @@
+4
1 test dir/.svn/prop-base/README.svn-base
@@ -0,0 +1 @@
+END
1 test dir/.svn/prop-base/junk.svn-base
@@ -0,0 +1 @@
+END
1 test dir/.svn/props/README.svn-work
@@ -0,0 +1 @@
+END
1 test dir/.svn/props/junk.svn-work
@@ -0,0 +1 @@
+END
1 test dir/.svn/text-base/README.svn-base
@@ -0,0 +1 @@
+This is a test backup directory that can be used to test out RIBS
1 test dir/.svn/text-base/include.mp3.svn-base
@@ -0,0 +1 @@
+bah dee da dum
1 test dir/.svn/text-base/junk.svn-base
@@ -0,0 +1 @@
+This should be included in the backup
1 test dir/README
@@ -0,0 +1 @@
+This is a test backup directory that can be used to test out RIBS
2 test dir/docs/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 test dir/docs/.svn/empty-file
No changes.
28 test dir/docs/.svn/entries
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1092"
+ name=""
+ committed-date="2004-03-12T18:13:32.741088Z"
+ url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir/docs"
+ last-author="jrust"
+ kind="dir"
+ uuid="050cec29-0bbb-0310-b500-ffd5b9db3264"
+ revision="1622"/>
+<entry
+ name="mp3"
+ kind="dir"/>
+<entry
+ committed-rev="1092"
+ name="stuff.txt"
+ text-time="2004-03-12T17:24:10.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="64a673683c8d53407e77ad62a75d911f"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:23.000000Z"/>
+<entry
+ name="junk"
+ kind="dir"/>
+</wc-entries>
1 test dir/docs/.svn/format
@@ -0,0 +1 @@
+4
1 test dir/docs/.svn/prop-base/stuff.txt.svn-base
@@ -0,0 +1 @@
+END
1 test dir/docs/.svn/props/stuff.txt.svn-work
@@ -0,0 +1 @@
+END
1 test dir/docs/.svn/text-base/stuff.txt.svn-base
@@ -0,0 +1 @@
+Stuff here
2 test dir/docs/junk/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 test dir/docs/junk/.svn/empty-file
No changes.
22 test dir/docs/junk/.svn/entries
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1092"
+ name=""
+ committed-date="2004-03-12T18:13:32.741088Z"
+ url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir/docs/junk"
+ last-author="jrust"
+ kind="dir"
+ uuid="050cec29-0bbb-0310-b500-ffd5b9db3264"
+ revision="1622"/>
+<entry
+ committed-rev="1092"
+ name="junk.txt"
+ text-time="2004-03-12T17:24:10.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="a99556a87dd8fbaf2b645e31e4e6b527"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:23.000000Z"/>
+</wc-entries>
1 test dir/docs/junk/.svn/format
@@ -0,0 +1 @@
+4
1 test dir/docs/junk/.svn/prop-base/junk.txt.svn-base
@@ -0,0 +1 @@
+END
1 test dir/docs/junk/.svn/props/junk.txt.svn-work
@@ -0,0 +1 @@
+END
1 test dir/docs/junk/.svn/text-base/junk.txt.svn-base
@@ -0,0 +1 @@
+Directory should be excluded
1 test dir/docs/junk/junk.txt
@@ -0,0 +1 @@
+Directory should be excluded
2 test dir/docs/mp3/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 test dir/docs/mp3/.svn/empty-file
No changes.
22 test dir/docs/mp3/.svn/entries
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1092"
+ name=""
+ committed-date="2004-03-12T18:13:32.741088Z"
+ url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir/docs/mp3"
+ last-author="jrust"
+ kind="dir"
+ uuid="050cec29-0bbb-0310-b500-ffd5b9db3264"
+ revision="1622"/>
+<entry
+ committed-rev="1092"
+ name="booroo.mp3"
+ text-time="2004-03-12T17:24:10.000000Z"
+ committed-date="2004-03-12T18:13:32.741088Z"
+ checksum="fd1e17db6a053bedcc5e502c270d4593"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:23.000000Z"/>
+</wc-entries>
1 test dir/docs/mp3/.svn/format
@@ -0,0 +1 @@
+4
1 test dir/docs/mp3/.svn/prop-base/booroo.mp3.svn-base
@@ -0,0 +1 @@
+END
1 test dir/docs/mp3/.svn/props/booroo.mp3.svn-work
@@ -0,0 +1 @@
+END
1 test dir/docs/mp3/.svn/text-base/booroo.mp3.svn-base
@@ -0,0 +1 @@
+This should not make it into the backup
1 test dir/docs/mp3/booroo.mp3
@@ -0,0 +1 @@
+This should not make it into the backup
1 test dir/docs/stuff.txt
@@ -0,0 +1 @@
+Stuff here
1 test dir/include.mp3
@@ -0,0 +1 @@
+bah dee da dum
1 test dir/junk
@@ -0,0 +1 @@
+This should be included in the backup
2 test dir/my mp3/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 test dir/my mp3/.svn/empty-file
No changes.
22 test dir/my mp3/.svn/entries
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1093"
+ name=""
+ committed-date="2004-03-12T18:23:51.732701Z"
+ url="svn://www.codejanitor.com/home/cjsvn/trunk/ribs/test%20dir/my%20mp3"
+ last-author="jrust"
+ kind="dir"
+ uuid="050cec29-0bbb-0310-b500-ffd5b9db3264"
+ revision="1622"/>
+<entry
+ committed-rev="1093"
+ name="test.mp3"
+ text-time="2004-03-12T18:01:19.000000Z"
+ committed-date="2004-03-12T18:23:51.732701Z"
+ checksum="7360f7768fc3bd706bda030862a65514"
+ last-author="jrust"
+ kind="file"
+ prop-time="2004-02-16T22:51:22.000000Z"/>
+</wc-entries>
1 test dir/my mp3/.svn/format
@@ -0,0 +1 @@
+4
1 test dir/my mp3/.svn/prop-base/test.mp3.svn-base
@@ -0,0 +1 @@
+END
1 test dir/my mp3/.svn/props/test.mp3.svn-work
@@ -0,0 +1 @@
+END
1 test dir/my mp3/.svn/text-base/test.mp3.svn-base
@@ -0,0 +1 @@
+Start singing now ;)
1 test dir/my mp3/test.mp3
@@ -0,0 +1 @@
+Start singing now ;)

0 comments on commit a2fb14e

Please sign in to comment.
Something went wrong with that request. Please try again.