diff options
author | Andrew Cady <d@jerkface.net> | 2023-05-24 11:22:34 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2023-05-24 11:22:34 -0400 |
commit | cf930327a1b78f3168aae700d7867af77fad5905 (patch) | |
tree | 4ab3d0ca05c2f5a015e07fae0bc8254603459d23 | |
parent | 203d7252bbfc371aedf3618f23fe61a0f44c4a7f (diff) |
improve retain-snapshots
-rwxr-xr-x | retain-snapshots | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/retain-snapshots b/retain-snapshots new file mode 100755 index 0000000..86f0120 --- /dev/null +++ b/retain-snapshots | |||
@@ -0,0 +1,108 @@ | |||
1 | #!/bin/bash | ||
2 | default_retain_years=7 | ||
3 | retain_years= # TODO: read retain_years from .propagation | ||
4 | |||
5 | use_clock_time= # Delete according to clock time (WARNING: eventually deletes all data) | ||
6 | |||
7 | |||
8 | # Never edit this regex. | ||
9 | # Generated via: date -Ins | sed 's/[0-9]/[0-9]/g' | ||
10 | datetime_regexp='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]:[0-9][0-9]' | ||
11 | |||
12 | snapshot_prefix='.snapshot~' | ||
13 | |||
14 | main() | ||
15 | { | ||
16 | [ $# = 1 ] || exit | ||
17 | case "$1" in | ||
18 | /*) ;; | ||
19 | *) exit 1 ;; | ||
20 | esac | ||
21 | |||
22 | # Using `cd "$1"` and `find .` allows the path to contain | ||
23 | # newlines, while simple `find "$1"` would break the script. | ||
24 | # NB: Our snapshot name itself never contains whitespace. | ||
25 | cd "$1" || exit | ||
26 | find . -maxdepth 1 -type d -name "$snapshot_prefix""$datetime_regexp" | sort -rn | retain | ||
27 | } | ||
28 | |||
29 | is_readonly_subvolume() | ||
30 | { | ||
31 | [ -d "$1" ] | ||
32 | btrfs subvolume show -- "$1" | sed -En -e'/^\tFlags:.*\breadonly\b/{q0}' -e'${q1}' | ||
33 | } | ||
34 | |||
35 | btrfs_subvolume_delete() | ||
36 | { | ||
37 | >&2 echo btrfs subvolume delete "$@" | ||
38 | } | ||
39 | |||
40 | # Delete all snapshots that we do not retain. | ||
41 | # The retention period is specified in a ".propagation" file. | ||
42 | # If not specified it is 7 years. | ||
43 | # Retain the most recent snapshot within any year of the last 7 years. | ||
44 | # Retain the most recent snapshot within any month of the last 365 days. | ||
45 | # Retain the most recent snapshot within any day of the last 7 days. | ||
46 | # Retain the most recent snapshot within any hour of the last 24 hours. | ||
47 | # Retain the most recent snapshot within any minute of the last hour. | ||
48 | # Retain any snapshot created in the last minute. | ||
49 | |||
50 | retain() | ||
51 | { | ||
52 | 2>/dev/null [ "$retain_years" -ge 1 ] || retain_years=$default_retain_years | ||
53 | |||
54 | _year= _month= _day= _hour= _minute= _second= _nanosecond= | ||
55 | now= | ||
56 | if [ "$use_clock_time" ] | ||
57 | then | ||
58 | now=$(date +%s) | ||
59 | fi | ||
60 | while read line | ||
61 | do | ||
62 | is_readonly_subvolume "$line" || break | ||
63 | dateline=${line#*/"$snapshot_prefix"} | ||
64 | [ "$dateline" != "$line" ] | ||
65 | before=$(date -d "$dateline" +%s) | ||
66 | [ "$now" ] || now=$before | ||
67 | age=$((now - before)) | ||
68 | |||
69 | IFS='~-T:,' read year month day hour minute second nanosecond <<< "$dateline" | ||
70 | |||
71 | keep= | ||
72 | if [ "$year" != "$_year" ] && [ "$age" -lt $((retain_years * 366 * 24 * 60 * 60)) ] | ||
73 | then | ||
74 | keep="$year -> $line" | ||
75 | elif [ "$month" != "$_month" ] && [ "$age" -lt $((366 * 24 * 60 * 60)) ] | ||
76 | then | ||
77 | keep="$year-$month -> $line" | ||
78 | elif [ "$day" != "$_day" ] && [ "$age" -lt $((7 * 24 * 60 * 60)) ] | ||
79 | then | ||
80 | keep="$year-$month-$day -> $line" | ||
81 | elif [ "$hour" != "$_hour" ] && [ "$age" -lt $((24 * 60 * 60)) ] | ||
82 | then | ||
83 | keep="$year-$month-${day}T$hour -> $line" | ||
84 | elif [ "$minute" != "$_minute" ] && [ "$age" -lt $((60 * 60)) ] | ||
85 | then | ||
86 | keep="$year-$month-${day}T$hour:$minute -> $line" | ||
87 | elif [ "$age" -lt 60 ] | ||
88 | then | ||
89 | keep="recent -> $line" | ||
90 | fi | ||
91 | |||
92 | if [ "$keep" ] | ||
93 | then | ||
94 | echo "$keep" >&2 | ||
95 | else | ||
96 | btrfs_subvolume_delete -- "$line" | ||
97 | fi | ||
98 | |||
99 | _year=$year | ||
100 | _month=$month | ||
101 | _day=$day | ||
102 | _hour=$hour | ||
103 | _minute=$minute | ||
104 | _second=$second | ||
105 | done | ||
106 | } | ||
107 | |||
108 | main "$@" | ||