My original snapshot script
[zfs-ubuntu/.git] / snap.sh
1 #!/bin/bash
2
3 exec >> /var/log/snap.log 2>&1
4
5 # This script makes a number of assumptions about how I am handling things.
6 #  * filesystems are mounted on the directory with the same name.  It is
7 #    possible to mount them elsewhere in Solaris but I do not.
8 #   * examples
9 #     * "tank" is mounted on /tank
10 #     * "tank/home" is mounted on /tank/home
11 #  * this script only handles one zfs filesystem, a wrapper should be created
12 #    to handle more
13 #  * this script handles all snapshots that are named in this format:
14 #    YYYY-MM-DD.hh.mm
15 #   * It ignores other snapshots
16
17 # This converts the YYYY-MM-DD.hh.mm format to an integer.
18 datetime_to_minutes() {
19   perl -n -e '/(\d+)-(\d+)-(\d+)\.(\d+)\.(\d+)/; print $1 * 527040 + $2 * 44640 + $3 * 1440 + $4 * 60 + $5,"\n"'
20 }
21
22 datetime_to_minutes2() {
23   perl -n -e '/(\d+)-(\d+)-(\d+)\.(\d+)\.(\d+)/; $monthadj=int(($2-1)/3)-1; $minadj=int($5/15); $houradj=int($4/3); print $1 * 1048576 + ( $2 + $monthadj ) * 65536 + $3 * 2048 + ( $4 + $houradj ) * 64 + $5 + $minadj,"\n"'
24 }
25
26 # This number is the number of equally spaced snapshots that should exist over
27 # any given period in the past.
28
29 filesystem=$1
30 numsnapshots=$2
31
32 snapshotdir="/${filesystem}/.zfs/snapshot"
33
34 # Get the various components of the date
35 datetime=${ZFSDATETIME:-$(date +%Y-%m-%d.%H.%M)}
36
37 # Create the snapshot for this minute
38 echo "-I- Creating ${filesystem}@${datetime}"
39 zfs snapshot "${filesystem}@${datetime}"
40
41 lockdir="/tmp/zfs-admin-lock"
42 if ! mkdir "$lockdir" >/dev/null 2>&1; then
43   exit 0
44 fi
45 cleanup() { rm -rf "$lockdir"; }
46 trap cleanup EXIT
47
48 minutes=$(echo $datetime | datetime_to_minutes)
49
50 # Trim them down
51 snapshots=$(ls -d ${snapshotdir}/????-??-??.??.?? 2>/dev/null)
52 for snapshot in $snapshots; do
53   snapminutes=$(echo "$snapshot" | sed 's,.*/,,' | datetime_to_minutes)
54   snapminutes2=$(echo "$snapshot" | sed 's,.*/,,' | datetime_to_minutes2)
55   age=$((minutes - snapminutes))
56   window=1
57   while true; do
58     if [ $age -lt $((window * numsnapshots)) ]; then
59       case $((snapminutes2 % window)) in
60         0) ;;
61         *)
62           snapname=$(echo "$snapshot" |
63                        sed 's,/\(.*\)/.zfs/snapshot/\(.*\),\1@\2,')
64           echo "-I- Destroying $snapname"
65           zfs destroy "$snapname"
66         ;;
67       esac
68       break
69     fi
70     window=$((window*2))
71   done
72 done