Advertisement
alexs77

btrfs-snapshots.sh 1.2

May 3rd, 2013
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/sh
  2.  
  3. # btrfs-snapshots.sh 1.2
  4. # Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems
  5.  
  6. # See https://copy.com/WI9AXqTH2nD4 or as a
  7. # "subversion" of http://pastebin.com/VXu6JxJw
  8.  
  9. # Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
  10.  
  11. # Here's my crontab:
  12. # 00,15,30,45  * * * *  /usr/local/bin/btrfs-snapshots.sh frequently  4
  13. # 38           * * * *  /usr/local/bin/btrfs-snapshots.sh hourly     24
  14. # 08          00 * * *  /usr/local/bin/btrfs-snapshots.sh daily       7
  15. # 08          12 * * 0  /usr/local/bin/btrfs-snapshots.sh weekly      4
  16.  
  17. if [ "$#" -ne 2 ]; then
  18.     echo "Usage: $0 SNAPSHOT_TAG NUM_SNAPSHOTS
  19. Create hourly, daily, weekly, and monthly snapshots of btrfs filesystems.
  20.  
  21. Based somewhat on http://article.gmane.org/gmane.comp.file-systems.btrfs/12609
  22.  
  23. Here's my crontab:
  24. 00,15,30,45  * * * *  $0 frequently  4
  25. 38           * * * *  $0 hourly     24
  26. 08          00 * * *  $0 daily       7
  27. 08          12 * * 0  $0 weekly      4"
  28.     exit 1
  29. fi
  30.  
  31. # "Tag" to use for snapshots
  32. SNAPSHOT_TAG="$1"
  33. # How many of those snapshots to keep
  34. NUM_SNAPSHOTS="$2"
  35.  
  36. # Helper veriables
  37. # A "prefix" for all the snapshots
  38. snap_prefix="snapshot:$SNAPSHOT_TAG:"
  39. # "Now"
  40. snap_date="`date +%Y-%m-%d--%H.%M.%S.%N`"
  41. # Name of the script
  42. script_name=`basename "$0"`
  43.  
  44. # Messages are logged to syslog
  45. # facility: auth, authpriv (for security information of a sensitive nature),
  46. # cron, daemon, ftp, kern (can't be generated from user process), lpr, mail,
  47. # news, security (deprecated synonym for auth), syslog, user, uucp, and
  48. # local0 to local7
  49. log_fac="local5"
  50. # tag
  51. log_tag="$script_name"
  52.  
  53. # Add path to btrfs-progs dev version to beginning of $PATH
  54. # Needs a post 2013-02-01 15:55:06 (commit 64edc851da59c47b92ee6830101be0854add7f09)
  55. # version of btrfs-progs from http://git.kernel.org/cgit/linux/kernel/git/mason/btrfs-progs.git/commit/
  56. # because of issues with "btrfs subv list"
  57. btrfs_progs_dev_path="/home/a/Copy/Computerkram/Programme/btrfs-progs.dev/bin"
  58. PATH="$btrfs_progs_dev_path:$PATH"
  59.  
  60. # Find all btrfs filesystems
  61. btrfs fi show 2>/dev/null | awk '/ path / {print $NF}' | while read dev; do
  62.     # Find uuid and label
  63.     set -- `btrfs fi show 2>/dev/null | grep -B2 " path $dev" | \
  64.      grep "Label:" | sed  's,.*: \(.*\)  uuid: \(.*\),\1 \2,'`
  65.     label="$1"
  66.     uuid="$2"
  67.     logger -t "$log_tag" -p "$log_fac.info" -- \
  68.      "Processing filesystem with label $label and uuid $uuid on $dev"
  69.     # Change the "dev" name ("path") so, that it is usable; ie. / -> .
  70.     safe_dev=`echo "$dev" | tr / .`
  71.     # Create a directory for the temporary mountpoint
  72.     tmp_mount_dir=`mktemp -d "/tmp/.btrfs.mount.$uuid.$safe_dev.XXXXXX"`
  73.     # Mount the current btrfs there
  74.     if ! mount -t btrfs "$dev" "$tmp_mount_dir"; then
  75.         logger -t "$log_tag" -p "$log_fac.err" -- \
  76.          "Error! Could not do: mount -t btrfs $dev $tmp_mount_dir"
  77.         exit 1
  78.     fi
  79.    
  80.     # Create snapshots for the "root" volume
  81.     _snap_name="$tmp_mount_dir/,$snap_prefix$snap_date"
  82.     if ! btrfs subv snaps -r "$tmp_mount_dir" "$_snap_name" > /dev/null; then
  83.         logger -t "$log_tag" -p "$log_fac.err" -- \
  84.          "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir $_snap_name"
  85.         exit 1
  86.     else
  87.         logger -t "$log_tag" -p "$log_fac.info" -- \
  88.         "Created snapshot $Path,$snap_prefix$snap_date for root volume of fs with uuid $uuid"
  89.     fi
  90.     # Find old, no longer wanted snapshots with the "tag" of this subvolume
  91.     # - list all (read only + writable) snapshots of this filesystem
  92.     # - list only those for current "path" (-> subvolume) and prefix
  93.     # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
  94.     # - again list all snapshots of current path
  95.     # - sort and list only only those, which are shown just once
  96.     # - -> a list of those snapshots, which are to go
  97.     (btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix" \
  98.      | tail -"$NUM_SNAPSHOTS"
  99.      btrfs subv list -r "$tmp_mount_dir" | grep " path ,$snap_prefix") \
  100.      | sort | uniq -u \
  101.      | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
  102.         # Delete the snapshot
  103.         if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
  104.             logger -t "$log_tag" -p "$log_fac.err" -- \
  105.              "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
  106.             exit 1
  107.         else
  108.             logger -t "$log_tag" -p "$log_fac.info" -- \
  109.              "Removed snapshot $PathDel"
  110.         fi
  111.     done
  112.    
  113.     # List all non read-only (ie. writable) subvolumes
  114.     # - create a list of ALL subvolumes (read only + writable)
  115.     # - create a list of writable subvolumes
  116.     # - sort those two lists
  117.     # - list only those, which are show just once; ie. the read only subvolumes
  118.     (btrfs subv list -ar $tmp_mount_dir; btrfs subv list -a $tmp_mount_dir) \
  119.      | sort | uniq -u \
  120.      | while read _id Id _gen Gen _top _level Toplevel _path Path; do
  121.         # Create the snapshot
  122.         _snap_name="$tmp_mount_dir/$Path,$snap_prefix$snap_date"
  123.         if ! btrfs subv snaps -r "$tmp_mount_dir/$Path" "$_snap_name" > /dev/null; then
  124.             logger -t "$log_tag" -p "$log_fac.err" -- \
  125.              "Error! Could not do: btrfs subv snaps -r $tmp_mount_dir/$Path $_snap_name"
  126.             exit 1
  127.         else
  128.             logger -t "$log_tag" -p "$log_fac.info" -- \
  129.              "Created snapshot $Path,$snap_prefix$snap_date for subvolume $Path"
  130.         fi
  131.         # Find old, no longer wanted snapshots with the "tag" of this subvolume
  132.         # - list all (read only + writable) snapshots of this filesystem
  133.         # - list only those for current "path" (-> subvolume) and prefix
  134.         # - list only the last $NUM_SNAPSHOTS snapshots -> those are to "survive"
  135.         # - again list all snapshots of current path
  136.         # - sort and list only only those, which are shown just once
  137.         # - -> a list of those snapshots, which are to go
  138.         (btrfs subv list -r "$tmp_mount_dir" \
  139.          | grep " path $Path,$snap_prefix" | tail -"$NUM_SNAPSHOTS"
  140.          btrfs subv list -r "$tmp_mount_dir"|grep " path $Path,$snap_prefix") \
  141.          | sort | uniq -u \
  142.          | while read __id IdDel __gen GenDel __top __level ToplevelDel __path PathDel; do
  143.             # Delete the snapshot
  144.             if ! btrfs subv del "$tmp_mount_dir/$PathDel" > /dev/null; then
  145.                 logger -t "$log_tag" -p "$log_fac.err" -- \
  146.                  "Error! Could not do: btrfs subv del $tmp_mount_dir/$PathDel"
  147.                 exit 1
  148.             else
  149.                 logger -t "$log_tag" -p "$log_fac.info" -- \
  150.                  "Removed snapshot $PathDel"
  151.             fi
  152.         done
  153.     done
  154.     # Unmount the filesystem
  155.     if ! umount "$tmp_mount_dir"; then
  156.         logger -t "$log_tag" -p "$log_fac.err" -- \
  157.          "Error! Could not do: umount$tmp_mount_dir"
  158.         # Not fatal
  159.         # exit 1
  160.     fi
  161.     # Remove the directory where the filesystem was mounted
  162.     if ! rmdir "$tmp_mount_dir"; then
  163.         logger -t "$log_tag" -p "$log_fac.err" -- \
  164.          "Error! Could not do: rmdir $tmp_mount_dir"
  165.         # Not fatal
  166.         # exit 1
  167.     fi
  168. done
  169.  
  170. # Done ☺
  171. exit 0
  172. # EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement