Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- # btrfs-snapshots.sh 1.1
- # Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems
- # See https://copy.com/WI9AXqTH2nD4 or as a "subversion" of http://pastebin.com/YfZUnytT
- # Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
- # Here's my crontab:
- # 00,15,30,45 * * * * /usr/local/bin/btrfs-snapshots.sh frequently 4
- # 38 * * * * /usr/local/bin/btrfs-snapshots.sh hourly 24
- # 08 00 * * * /usr/local/bin/btrfs-snapshots.sh daily 7
- # 08 12 * * 0 /usr/local/bin/btrfs-snapshots.sh weekly 4
- if [ "$#" -ne 2 ]; then
- echo "Usage: $0 SNAPSHOT_TAG NUM_SNAPSHOTS
- Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems.
- Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
- Here's my crontab:
- 00,15,30,45 * * * * $0 frequently 4
- 38 * * * * $0 hourly 24
- 08 00 * * * $0 daily 7
- 08 12 * * 0 $0 weekly 4"
- exit 1
- fi
- # "Tag" to use for snapshots
- SNAPSHOT_TAG="$1"
- # How many of those snapshots to keep
- NUM_SNAPSHOTS="$2"
- # Helper veriables
- # A "prefix" for all the snapshots
- snap_prefix="snapshot:$SNAPSHOT_TAG:"
- # "Now"
- snap_date="`date +%Y-%m-%d--%H.%M.%S.%N`"
- # Name of the script
- script_name=`basename "$0"`
- # Messages are logged to syslog
- # facility: auth, authpriv (for security information of a sensitive nature), cron, daemon, ftp, kern (can't be generated from user process), lpr, mail, news, security (deprecated synonym for auth), syslog, user, uucp, and local0 to local7
- log_fac="local5"
- # tag
- log_tag="$script_name"
- # Add path to btrfs-progs dev version to beginning of $PATH
- # Needs a post 2013-02-01 15:55:06 (commit 64edc851da59c47b92ee6830101be0854add7f09)
- # version of btrfs-progs from http://git.kernel.org/cgit/linux/kernel/git/mason/btrfs-progs.git/commit/
- # because of issues with "btrfs subv list"
- btrfs_progs_dev_path="/home/a/Copy/Computerkram/Programme/btrfs-progs.dev/bin"
- PATH="$btrfs_progs_dev_path:$PATH"
- # Find all btrfs filesystems
- btrfs fi show 2>/dev/null | awk '/ path / {print $NF}' | while read dev; do
- # Find uuid and label
- set -- `btrfs fi show 2>/dev/null | grep -B2 " path $dev" | grep "Label:" | sed 's,.*: \(.*\) uuid: \(.*\),\1 \2,'`
- label="$1"
- uuid="$2"
- logger -t "$log_tag" -p "$log_fac.info" -- "Processing filesystem with label $label and uuid $uuid on $dev"
- # Change the "dev" name ("path") so, that it is usable; ie. / -> .
- safe_dev=`echo "$dev" | tr / .`
- # Create a directory for the temporary mountpoint
- tmp_mount_dir=`mktemp -d "/tmp/.btrfs.mount.$uuid.$safe_dev.XXXXXX"`
- # Mount the current btrfs there
- if ! mount -t btrfs "$dev" "$tmp_mount_dir"; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: mount -t btrfs $dev $tmp_mount_dir"
- exit 1
- fi
- # Create snapshots for the "root" volume
- if ! btrfs subv snaps -r "$tmp_mount_dir" "$tmp_mount_dir/,$snap_prefix$snap_date" > /dev/null; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir $tmp_mount_dir/,$snap_prefix$snap_date"
- exit 1
- else
- logger -t "$log_tag" -p "$log_fac.info" -- "Created snapshot $Path,$snap_prefix$snap_date for root volume of fs with uuid $uuid"
- fi
- # Find old, no longer wanted snapshots with the "tag" of this subvolume
- # - list all (read only + writable) snapshots of this filesystem
- # - list only those for current "path" (-> subvolume) and prefix
- # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
- # - again list all snapshots of current path
- # - sort and list only only those, which are shown just once
- # - -> a list of those snapshots, which are to go
- (btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix" | tail -"$NUM_SNAPSHOTS"; btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix") | sort | uniq -u | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
- # Delete the snapshot
- if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
- exit 1
- else
- logger -t "$log_tag" -p "$log_fac.info" -- "Removed snapshot $PathDel"
- fi
- done
- # List all non read-only (ie. writable) subvolumes
- # - create a list of ALL subvolumes (read only + writable)
- # - create a list of writable subvolumes
- # - sort those two lists
- # - list only those, which are show just once; ie. the read only subvolumes
- (btrfs subv list -ar $tmp_mount_dir; btrfs subv list -a $tmp_mount_dir) | sort | uniq -u | while read _id Id _gen Gen _top _level Toplevel _path Path; do
- # Create the snapshot
- if ! btrfs subv snaps -r "$tmp_mount_dir/$Path" "$tmp_mount_dir/$Path,$snap_prefix$snap_date" > /dev/null; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir/$Path $tmp_mount_dir/$Path,$snap_prefix$snap_date"
- exit 1
- else
- logger -t "$log_tag" -p "$log_fac.info" -- "Created snapshot $Path,$snap_prefix$snap_date for subvolume $Path"
- fi
- # Find old, no longer wanted snapshots with the "tag" of this subvolume
- # - list all (read only + writable) snapshots of this filesystem
- # - list only those for current "path" (-> subvolume) and prefix
- # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
- # - again list all snapshots of current path
- # - sort and list only only those, which are shown just once
- # - -> a list of those snapshots, which are to go
- (btrfs subv list -r "$tmp_mount_dir" | grep " path $Path,$snap_prefix" | tail -"$NUM_SNAPSHOTS"; btrfs subv list -r "$tmp_mount_dir" | grep " path $Path,$snap_prefix") | sort | uniq -u | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
- # Delete the snapshot
- if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
- exit 1
- else
- logger -t "$log_tag" -p "$log_fac.info" -- "Removed snapshot $PathDel"
- fi
- done
- done
- # Unmount the filesystem
- if ! umount "$tmp_mount_dir"; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: umount$tmp_mount_dir"
- # Not fatal
- # exit 1
- fi
- # Remove the directory where the filesystem was mounted
- if ! rmdir "$tmp_mount_dir"; then
- logger -t "$log_tag" -p "$log_fac.err" -- "Error! Could not do: rmdir $tmp_mount_dir"
- # Not fatal
- # exit 1
- fi
- done
- # Done ☺
- exit 0
- # EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement