reworked logic
[rrq/nilfs2sss.git] / sss.sh
1 #!/bin/bash
2 #
3 # Snapshot Snapping Scheme
4 #
5 # This is a cron bot to manage the snapshots of an nilfs2 file system,
6 # so as to preserve 7 most recent daily, 4 most recent weekly and 12
7 # most recent monthly snapshots, in addition to labelled ones.
8 #
9 # The cron bot is expected to run once a minute
10
11 # The hour-of-day to preserve as daily snapshot
12 KEEPHH=12
13
14 # The day-of-month to preserve as monthly snapshot
15 KEEPDD=15
16
17 DEV=$1
18 if [ -z "$DEV" ] ; then
19     DEVS=( $( mount | grep nilfs2 | sed 's/ .*//' ) )
20     DEV=${DEVS[0]}
21     if [ -z "$DEV" ] ; then
22         echo "Error* cannot find a mounted nilfs2 partition" >&2
23         exit 1
24     fi
25 fi
26
27 FIVELY="$(date -d '-5 minutes' '+%Y-%m-%d %H:%M:%S')"
28 HOURLY="$(date -d '-1 hour' '+%Y-%m-%d %H:%M:%S')"
29 DAILY="$(date -d '-1 day' '+%Y-%m-%d %H:%M:%S')"
30 MONTHLY="$(date -d '-1 month' '+%Y-%m-%d %H:%M:%S')"
31 WEEKLY="$(date -d '-7 days' '+%Y-%m-%d %H:%M:%S')"
32 YEARLY="$(date -d '-1 year' '+%Y-%m-%d %H:%M:%S')"
33
34 function older_than_a_year() {
35     #echo "--- $CNO $DATE $TIME" >&2
36     [[ ! "$TS" < "$YEARLY" ]] && return 1
37     #echo "# keep the first snapshot of older years: $CNO $DATE $TIME" >&2
38     if [ "$KEEPYY" = "${DATE:0:4}" ] ; then
39         echo "$DEV: discard year duplicate $CNO $DATE $TIME" >&2
40         chcp cp $DEV $CNO
41     else
42         KEEPYY="${DATE:0:4}"
43     fi
44     return 0
45 }
46
47 function older_than_a_month() {
48     [[ ! "$TS" < "$MONTHLY" ]] && return 1
49     #echo "# keep the first snapshot of older months" >&2
50     if [ "$KEEPMM" = "${DATE:0:7}" ] ; then
51         echo "$DEV: discard month duplicate $CNO $DATE $TIME" >&2
52         chcp cp $DEV $CNO
53     else
54         KEEPMM="${DATE:0:7}"
55     fi
56     return 0
57 }
58
59 function older_than_a_week() {
60     [[ ! "$TS" < "$WEEKLY" ]] && return 1
61     if [[ "${DATE:8:2}" < "$KEEPDD" ]] ; then
62         #echo "# keep latest when before choice date: $CNO $DATE $TIME" >&2
63         if [ -n "$KEEPWW0" ] ; then
64             echo "$DEV: discard outed $KEEPWW0" >&2
65             chcp cp $DEV $KEEPWW0
66         fi
67         KEEPWW0=( $CNO $DATE $TIME ) 
68     else
69         #echo "# keep first when at or after choice date: $CNO $DATE $TIME" >&2
70         if [ -z "$KEEPWW" ] ; then
71             if [ -n "$KEEPWW0" ] ; then
72                 echo "$DEV: discard outed $KEEPWW0" >&2
73                 chcp cp $DEV $KEEPWW0
74             fi
75             KEEPWW=( $CNO $DATE $TIME )
76             continue
77         else
78             echo "$DEV: discard monthly extras: $CNO $DATE $TIME" >&2
79             chcp cp $DEV $CNO
80         fi
81     fi
82     return 0
83 }
84
85 function older_than_a_day() {
86     [[ ! "$TS" < "$DAILY" ]] && return 1
87     if [[ "${TIME:0:2}" < "$KEEPHH" ]] ; then
88         #echo "# keep latest when before choice hour: $CNO $DATE $TIME" >&2
89         if [ -n "$KEPTHH0" ] ; then
90             echo "$DEV: discard outed $KEPTHH0" >&2
91             chcp cp $DEV $KEPTHH0
92         fi
93         KEPTHH0=( $CNO $DATE $TIME )
94     else
95         #echo "# keep first when at/after choice hour: $CNO $DATE $TIME" >&2
96         if [ -z "$KEPTHH" ] ; then
97             if [ -n "$KEPTHH0" ] ; then
98                 echo "$DEV: discard outed $KEPTHH0" >&2
99                 chcp cp $DEV $KEPTHH0
100                 KEPTHH0=
101             fi
102             KEPTHH=( $CNO $DATE $TIME )
103         else
104             echo "$DEV: discard daily extras: $CNO $DATE $TIME" >&2
105             chcp cp $DEV $CNO
106         fi
107     fi
108 }
109
110 function older_than_an_hour() {
111     [[ ! "$TS" < "$HOURLY" ]] && return 1
112     #echo "# keep first of each hour: $CNO $DATE $TIME" >&2
113     if [[ "$KEPT55"  != "${TIME:0:2}" ]] ; then
114         KEPT55="${TIME:0:2}"
115     else
116         echo "$DEV: discard hourly duplicate: $CNO $DATE $TIME" >&2
117         chcp cp $DEV $CNO
118     fi
119     return 0
120 }
121
122 function older_than_5_minutes() {
123     if [[ ! "$TS" < "$FIVELY" ]] ; then
124         echo "$CNO $DATE $TIME is within last five minutes"
125     else
126         : # no noise here
127         if [[ "$TS" < "$NEXT" ]] ; then
128             echo "$DEV: discard 5-minutely duplicate: $CNO $DATE $TIME" >&2
129             chcp cp $DEV $CNO
130         else
131             T=${TS:0:15}$(( ( ${TS:15:1} / 5 ) * 5 )):00
132             NEXT="$(date -d "5 minutes $T" '+%Y-%m-%d %H:%M:%S')"
133             #echo "NEXT=$NEXT" >&2
134         fi
135     fi
136 }
137
138 { flock 9
139
140 date "+$DEV: %Y-%m-%d %H:%M:%S ---- checking" >&2
141 lscp -s $DEV | while read CNO DATE TIME REST ; do
142     TS="$DATE $TIME"
143     [ "$CNO" = "CNO" ] ||
144         older_than_a_year ||
145         older_than_a_month ||
146         older_than_a_week ||
147         older_than_a_day ||
148         older_than_an_hour ||
149         older_than_5_minutes
150 done | if read X ; then
151     :
152 elif [[ $(( $(date +%M|sed 's/^0//') % 5 )) = 0 ]] ; then
153     date "+$DEV: new snapshot at %Y-%m-%d %H:%M:%S" >&2
154     mkcp -s $DEV
155 fi
156 } 9> /var/run/lock/sss.lock