Advertisement
jdefelice

zfs powershift.sh

Apr 6th, 2012
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 6.18 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. VERSION=2.20
  4. ZFS=/usr/sbin/zfs
  5.  
  6. # (jdefelice) modified this to work with ZFS snapshots
  7.  
  8. # This is a bash version of John C. Bowman's C++ program powershift,
  9. # distributed with rlbackup. There are two functional differences: This
  10. # version includes the delimiter with the directory or file base, and this
  11. # version does not retain the access and modification times of rotated files
  12. # and directories. The original C++ code is copyright John C.  Bowman.  This
  13. # code is copyright David Coppit.
  14.  
  15. # Syntax: powershift directory_or_file_base [n]
  16. #
  17. # Generate a geometric progression of backup files or directories by
  18. # retaining, after the first n (>= 2) backups, only every every second backup,
  19. # then every fourth backup, and so on, for each successive power of 2 (except
  20. # for intermediate files necessary to accomplish this).
  21. #
  22. # Path are constructed from the first argument concatenated with a number
  23. # generated by this program. New backups should be placed into the rotation as
  24. # a concatenated file ending with "0".
  25. #
  26. # EXAMPLE #1: DIRECTORIES
  27. #
  28. # For the default value of n=2, successive applications of
  29. #
  30. # mkdir -p dir/0; powershift 'dir/'
  31. #
  32. # will shift dir/i to dir/i+1 for i=0,1,2,... while retaining (along with
  33. # necessary intermediate files) only the sequence
  34. #
  35. # dir/1 dir/2 dir/4 dir/8 dir/16 dir/32 dir/64...
  36. #
  37. # EXAMPLE #2: FILES
  38. #
  39. # The command
  40. #
  41. # echo > name.log0; powershift name.log 4
  42. #
  43. # will retain (disregarding intermediate files)
  44. #
  45. # name.log1 name.log2 name.log3 name.log4 name.log6 name.log10 name.log18
  46. # name.log34 name.log66...
  47. #
  48. # This program is free software; you can redistribute it and/or modify it
  49. # under the terms of the GNU General Public License version 2 as published by
  50. # the Free Software Foundation.
  51. #
  52. # This program is distributed in the hope that it will be useful, but WITHOUT
  53. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  54. # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  55. # more details.
  56. #
  57. # You should have received a copy of the GNU General Public License along with
  58. # this program; if not, write to the Free Software Foundation, Inc., 675 Mass
  59. # Ave, Cambridge, MA 02139, USA.
  60.  
  61. function stagger() {
  62.  
  63.         let RESULT="$1 + ( $1 >> 1 )";
  64. }
  65.  
  66. function snapshot_exists() {
  67.         local SNAP=/$TARGET/.zfs/snapshot/$1
  68.         echo checking for $SNAP
  69.         test -d $SNAP
  70. }
  71.  
  72. function file_name() {
  73.         local SUM;
  74.  
  75.         SUM=$(($1 + OFFSET));
  76.         RESULT="$FILESTEM.$SUM";
  77. }
  78.  
  79. # First arg is the message
  80. # Second arg is a file path relative to the current directory
  81. function fatal_error() {
  82.         local MESSAGE=$1;
  83.  
  84.         if (( $# == 2 )); then
  85.                 MESSAGE="$MESSAGE "`pwd`;
  86.  
  87.                 if [ -n $2 ]; then
  88.                         MESSAGE="$MESSAGE/";
  89.                 fi
  90.  
  91.                 MESSAGE="$MESSAGE$2";
  92.         fi
  93.  
  94.         echo "$MESSAGE: $?" 1>&2;
  95.  
  96.         exit 1;
  97. }
  98.  
  99. function recursive_delete() {
  100.         #echo rm -rf $1
  101.         echo $ZFS destroy -r ${TARGET}@$1
  102.         if ! $ZFS destroy -r ${TARGET}@$1 2>/dev/null; then
  103.                 fatal_error "Cannot remove" $1;
  104.         fi;
  105. }
  106.  
  107. # The original C++ version fixed up the modified time so that it didn't change
  108. # after the rename. We can't do that in bash, unfortunately
  109. function rename() {
  110.         #echo mv $1 $2;
  111.         echo $ZFS rename -r ${TARGET}@$1 ${TARGET}@$2
  112.         $ZFS rename -r ${TARGET}@$1 ${TARGET}@$2
  113. }
  114.  
  115. function power() {
  116.         local I=$1;
  117.         local STAGGER_I_FILENAME;
  118.         local N;
  119.         local N_FILENAME;
  120.         local I_FILENAME;
  121.  
  122.         stagger $I;
  123.         file_name $RESULT;
  124.  
  125.         STAGGER_I_FILENAME=$RESULT;
  126.  
  127.         if snapshot_exists $STAGGER_I_FILENAME; then
  128.                 let "SHIFTED=$1 << 1";
  129.                 power $SHIFTED;
  130.                 N=$RESULT;
  131.                 let "I=$N >> 1";
  132.  
  133.                 stagger $I;
  134.                 file_name $RESULT;
  135.                 STAGGER_I_FILENAME=$RESULT;
  136.  
  137.                 if snapshot_exists $STAGGER_I_FILENAME; then
  138.                         file_name $N;
  139.                         N_FILENAME=$RESULT;
  140.  
  141.                         rename $STAGGER_I_FILENAME $N_FILENAME;
  142.                 fi
  143.  
  144.                 file_name $I;
  145.                 recursive_delete $RESULT;
  146.         else
  147.                 file_name $I;
  148.                 I_FILENAME=$RESULT;
  149.  
  150.                 if snapshot_exists $I_FILENAME; then
  151.                         rename $I_FILENAME $STAGGER_I_FILENAME;
  152.                 fi
  153.         fi
  154.  
  155.         RESULT=$I;
  156. }
  157.  
  158. function powershift() {
  159.         TARGET=$1
  160.         SNAP=$2
  161.         N=$3
  162.  
  163.         FILESTEM=$SNAP;
  164.  
  165.         if (( $N < 2 )); then
  166.                 echo "n must be >= 2" 1>&2;
  167.                 exit 1;
  168.         fi
  169.  
  170.         let OFFSET=$N-2;
  171.  
  172.         file_name -$OFFSET;
  173.         OFFSET_FILENAME=$RESULT;
  174.         if snapshot_exists $OFFSET_FILENAME; then
  175.                 #touch $OFFSET_FILENAME; # Timestamp the latest backup;
  176.  
  177.                 power 2;
  178.  
  179.                 for (( I=2; I >= -$OFFSET; I-- )); do
  180.                         file_name $I;
  181.                         I_FILENAME=$RESULT;
  182.  
  183.                         let "IPLUSONE=$I+1";
  184.                         file_name $IPLUSONE;
  185.                         IPLUSONE_FILENAME=$RESULT;
  186.  
  187.                         if snapshot_exists $I_FILENAME; then
  188.                                 rename $I_FILENAME $IPLUSONE_FILENAME;
  189.                         fi
  190.                 done
  191.         fi
  192. }
  193.  
  194. usage() {
  195.     scriptname=`/usr/bin/basename $0`
  196.     echo "$scriptname: Take and rotate snapshots on a ZFS file system"
  197.     echo
  198.     echo "  Usage:"
  199.     echo "  $scriptname target snap_name count"
  200.     echo
  201.     echo "  target:    ZFS file system to act on"
  202.     echo "  snap_name: Base name for snapshots, to be followed by a '.' and"
  203.     echo "             an integer indicating relative age of the snapshot"
  204.     echo "  count:     Number of snapshots in the snap_name.number format to"
  205.     echo "             keep at one time, before powershift.  Newest ends in '.0'."
  206.     echo
  207.     exit
  208. }
  209.  
  210. # Basic argument checks:
  211. if [ -z $3 ] ; then
  212.     usage
  213. fi
  214.  
  215. if [ ! -z $4 ] ; then
  216.     usage
  217. fi
  218.  
  219. powershift $@
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement