summaryrefslogtreecommitdiff
path: root/src/retain-snapshots
blob: 9c44f05c3f4b40d59488db0d753ab90cbbe080e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/bin/bash
set -e
set -o pipefail

default_retain_years=7
retain_years= # TODO: read retain_years from .propagation

use_clock_time= # Delete according to clock time (WARNING: eventually deletes all data)


# Never edit this glob.
# Generated via: date -Ins | sed 's/[0-9]/[0-9]/g'
datetime_glob='[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]'

snapshot_prefix='.snapshot~'

main()
{
        delete=
        if [ "$1" = --delete ]
        then
                delete=$1
                shift
        fi
        [ $# = 1 ] || exit
        case "$1" in
                /*) ;;
                *) exit 1 ;;
        esac

        cd "$1" || exit
        find . -maxdepth 1 -type d -name "$snapshot_prefix""$datetime_glob" -print0 | sort -zrn | retain
}

is_readonly_subvolume()
{
        [ -d "$1" ]
        btrfs subvolume show -- "$1" | sed -En -e'/^\tFlags:.*\breadonly\b/{q0}' -e'${q1}'
}

btrfs_subvolume_delete()
{
        if [ "$delete" = --delete ]
        then
                btrfs subvolume delete "$@"
        else
                >&2 echo btrfs subvolume delete "$@"
        fi
}

# Delete all snapshots that we do not retain.
# The retention period is specified in a ".propagation" file.
# If not specified it is 7 years.
# Retain the most recent snapshot within any     year   of the   last 7 years.
# Retain the most recent snapshot within any    month   of the   last 365 days.
# Retain the most recent snapshot within any      day   of the   last 15 days.
# Retain the most recent snapshot within any     hour   of the   last 24 hours.
# Retain the most recent snapshot within any   minute   of the   last hour.
# Retain any snapshot created in the last minute.

retain()
{
        2>/dev/null [ "$retain_years" -ge 1 ] || retain_years=$default_retain_years

        _year= _month= _day= _hour= _minute= _second= _nanosecond=
        now= first=y
        if [ "$use_clock_time" ]
        then
                now=$(date +%s)
        fi
        while read -d '' line
        do
                is_readonly_subvolume "$line" || break
                dateline=${line#*/"$snapshot_prefix"}
                [ "$dateline" != "$line" ]
                before=$(date -d "$dateline" +%s)
                [ "$now" ] || now=$before
                age=$((now - before))

                IFS='~-T:,' read year month day hour minute second nanosecond <<< "$dateline"

                keep=
                if [ "$first" ]
                then
                        keep="latest -> $line"
                        first=
                elif [ "$year" != "$_year" ] && [ "$age" -lt $((retain_years * 366 * 24 * 60 * 60)) ]
                then
                        keep="$year -> $line"
                elif [ "$month" != "$_month" ] && [ "$age" -lt $((366 * 24 * 60 * 60)) ]
                then
                        keep="$year-$month -> $line"
                elif [ "$day" != "$_day" ] && [ "$age" -lt $((15 * 24 * 60 * 60)) ]
                then
                        keep="$year-$month-$day -> $line"
                elif [ "$hour" != "$_hour" ] && [ "$age" -lt $((24 * 60 * 60)) ]
                then
                        keep="$year-$month-${day}T$hour -> $line"
                elif [ "$minute" != "$_minute" ] && [ "$age" -lt $((60 * 60)) ]
                then
                        keep="$year-$month-${day}T$hour:$minute -> $line"
                elif [ "$age" -lt 60 ]
                then
                        keep="recent -> $line"
                fi

                if [ "$keep" ]
                then
                        (set -- $keep
                        printf '%-20s -> %s\n' "$1" "$3" >&2)
                else
                        btrfs_subvolume_delete -- "$line"
                fi

                _year=$year
                _month=$month
                _day=$day
                _hour=$hour
                _minute=$minute
                _second=$second
        done
}

main "$@"