Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- VERSION=2.20
- ZFS=/usr/sbin/zfs
- # (jdefelice) modified this to work with ZFS snapshots
- # This is a bash version of John C. Bowman's C++ program powershift,
- # distributed with rlbackup. There are two functional differences: This
- # version includes the delimiter with the directory or file base, and this
- # version does not retain the access and modification times of rotated files
- # and directories. The original C++ code is copyright John C. Bowman. This
- # code is copyright David Coppit.
- # Syntax: powershift directory_or_file_base [n]
- #
- # Generate a geometric progression of backup files or directories by
- # retaining, after the first n (>= 2) backups, only every every second backup,
- # then every fourth backup, and so on, for each successive power of 2 (except
- # for intermediate files necessary to accomplish this).
- #
- # Path are constructed from the first argument concatenated with a number
- # generated by this program. New backups should be placed into the rotation as
- # a concatenated file ending with "0".
- #
- # EXAMPLE #1: DIRECTORIES
- #
- # For the default value of n=2, successive applications of
- #
- # mkdir -p dir/0; powershift 'dir/'
- #
- # will shift dir/i to dir/i+1 for i=0,1,2,... while retaining (along with
- # necessary intermediate files) only the sequence
- #
- # dir/1 dir/2 dir/4 dir/8 dir/16 dir/32 dir/64...
- #
- # EXAMPLE #2: FILES
- #
- # The command
- #
- # echo > name.log0; powershift name.log 4
- #
- # will retain (disregarding intermediate files)
- #
- # name.log1 name.log2 name.log3 name.log4 name.log6 name.log10 name.log18
- # name.log34 name.log66...
- #
- # This program is free software; you can redistribute it and/or modify it
- # under the terms of the GNU General Public License version 2 as published by
- # the Free Software Foundation.
- #
- # 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., 675 Mass
- # Ave, Cambridge, MA 02139, USA.
- function stagger() {
- let RESULT="$1 + ( $1 >> 1 )";
- }
- function snapshot_exists() {
- local SNAP=/$TARGET/.zfs/snapshot/$1
- echo checking for $SNAP
- test -d $SNAP
- }
- function file_name() {
- local SUM;
- SUM=$(($1 + OFFSET));
- RESULT="$FILESTEM.$SUM";
- }
- # First arg is the message
- # Second arg is a file path relative to the current directory
- function fatal_error() {
- local MESSAGE=$1;
- if (( $# == 2 )); then
- MESSAGE="$MESSAGE "`pwd`;
- if [ -n $2 ]; then
- MESSAGE="$MESSAGE/";
- fi
- MESSAGE="$MESSAGE$2";
- fi
- echo "$MESSAGE: $?" 1>&2;
- exit 1;
- }
- function recursive_delete() {
- #echo rm -rf $1
- echo $ZFS destroy -r ${TARGET}@$1
- if ! $ZFS destroy -r ${TARGET}@$1 2>/dev/null; then
- fatal_error "Cannot remove" $1;
- fi;
- }
- # The original C++ version fixed up the modified time so that it didn't change
- # after the rename. We can't do that in bash, unfortunately
- function rename() {
- #echo mv $1 $2;
- echo $ZFS rename -r ${TARGET}@$1 ${TARGET}@$2
- $ZFS rename -r ${TARGET}@$1 ${TARGET}@$2
- }
- function power() {
- local I=$1;
- local STAGGER_I_FILENAME;
- local N;
- local N_FILENAME;
- local I_FILENAME;
- stagger $I;
- file_name $RESULT;
- STAGGER_I_FILENAME=$RESULT;
- if snapshot_exists $STAGGER_I_FILENAME; then
- let "SHIFTED=$1 << 1";
- power $SHIFTED;
- N=$RESULT;
- let "I=$N >> 1";
- stagger $I;
- file_name $RESULT;
- STAGGER_I_FILENAME=$RESULT;
- if snapshot_exists $STAGGER_I_FILENAME; then
- file_name $N;
- N_FILENAME=$RESULT;
- rename $STAGGER_I_FILENAME $N_FILENAME;
- fi
- file_name $I;
- recursive_delete $RESULT;
- else
- file_name $I;
- I_FILENAME=$RESULT;
- if snapshot_exists $I_FILENAME; then
- rename $I_FILENAME $STAGGER_I_FILENAME;
- fi
- fi
- RESULT=$I;
- }
- function powershift() {
- TARGET=$1
- SNAP=$2
- N=$3
- FILESTEM=$SNAP;
- if (( $N < 2 )); then
- echo "n must be >= 2" 1>&2;
- exit 1;
- fi
- let OFFSET=$N-2;
- file_name -$OFFSET;
- OFFSET_FILENAME=$RESULT;
- if snapshot_exists $OFFSET_FILENAME; then
- #touch $OFFSET_FILENAME; # Timestamp the latest backup;
- power 2;
- for (( I=2; I >= -$OFFSET; I-- )); do
- file_name $I;
- I_FILENAME=$RESULT;
- let "IPLUSONE=$I+1";
- file_name $IPLUSONE;
- IPLUSONE_FILENAME=$RESULT;
- if snapshot_exists $I_FILENAME; then
- rename $I_FILENAME $IPLUSONE_FILENAME;
- fi
- done
- fi
- }
- usage() {
- scriptname=`/usr/bin/basename $0`
- echo "$scriptname: Take and rotate snapshots on a ZFS file system"
- echo
- echo " Usage:"
- echo " $scriptname target snap_name count"
- echo
- echo " target: ZFS file system to act on"
- echo " snap_name: Base name for snapshots, to be followed by a '.' and"
- echo " an integer indicating relative age of the snapshot"
- echo " count: Number of snapshots in the snap_name.number format to"
- echo " keep at one time, before powershift. Newest ends in '.0'."
- echo
- exit
- }
- # Basic argument checks:
- if [ -z $3 ] ; then
- usage
- fi
- if [ ! -z $4 ] ; then
- usage
- fi
- powershift $@
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement