-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsnapshot
More file actions
executable file
·142 lines (118 loc) · 3.95 KB
/
snapshot
File metadata and controls
executable file
·142 lines (118 loc) · 3.95 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env bash
set -euo pipefail
DEFAULT_MAX_AGE=60
function main() {
local rootDevice
rootDevice=$(mount | grep -F 'on / type' | awk '{print $1}')
local maxAlterInTagen="$1"
ensure_root_permissions
ensure_btrfs "${rootDevice}"
local mountDir
mountDir="$(mktemp -d)"
local snapshots="${mountDir}/@snapshots"
sudo mount -o subvolid=0 "${rootDevice}" "${mountDir}"
ensure_snapshots_subvolume "$snapshots"
local newSnapshotsRoot
newSnapshotsRoot="${snapshots}/$(date +%Y-%m-%d_%H:%M:%S)"
remove_old_snapshots "${maxAlterInTagen}" "${snapshots}"
create_snapshots "${mountDir}" "${newSnapshotsRoot}"
sudo umount "${mountDir}"
rmdir "${mountDir}"
}
function parse_args() {
maxAlterInTagen=${DEFAULT_MAX_AGE}
while [[ $# -gt 0 ]]; do
case "${1}" in
-h | --help)
print_usage
exit 0
;;
--max-age)
maxAlterInTagen="$2"
shift
;;
*)
echo "Unbekannte Option '$1'. Abbruch." >&2
exit 1
;;
esac
shift
done
}
function print_usage() {
cat <<EOF
Usage: $(basename "${BASH_SOURCE[0]}") [-h|--help] [--max-age <AGE>]
Script description here.
Available options:
-h, --help Print this help and exit
--max-age Maximum age of snapshots in days. Defaults to ${DEFAULT_MAX_AGE}.
EOF
}
function ensure_root_permissions() {
if ! sudo -v; then
echo Unverzichtbare Rootrechte sind nicht verfügbar. Abbruch! >&2
exit 1
fi
}
function ensure_btrfs() {
local rootDevice="$1"
# Wenn das Dateisystem auf $rootDevice nicht BtrFS ist, sind Schnappschüsse
# nicht möglich. Dies wird hier geprüft. Ggf. wird das Skript hier
# verlassen.
#
# Um das snapshot-Skript auch auf nicht-BtrFS-Systemen im distup-Alias
# verwenden zu können, ist der Exit-Code trotzdem "0".
if [[ $(lsblk -o FSTYPE "${rootDevice}" | tail -n1) != "btrfs" ]]; then
echo Gerät "${rootDevice}" ist kein BtrFS-Dateisystem. Es wird kein Snapshot gemacht! >&2
exit 0
fi
}
function ensure_snapshots_subvolume() {
local snapshots="$1"
if ! [[ -d "$snapshots" ]]; then
sudo btrfs subvol create "$snapshots"
fi
if ! sudo btrfs subvolume show "$snapshots" &>/dev/null; then
echo "Verzeichnis für Snapshots existiert, aber ist kein BtrFS-Subvolume. Fahre trotzdem fort." >&2
fi
}
function remove_old_snapshots() {
# Lösche alle Snapshots, die älter sind als $maxTage Tage.
local maxTage="$1"
local snapshots="$2"
local schwelle
schwelle=$(date --date "${maxTage} days ago" +%s)
local dateDir
while IFS= read -r -d '' dateDir; do
local dirDate
dirDate="$(basename "${dateDir}")"
local whenCreated
whenCreated="$(date +%s -d "${dirDate/_/ }")"
if [[ "${whenCreated}" -le "${schwelle}" ]]; then
local curSnapshot
while IFS= read -r -d '' curSnapshot; do
# Es wird angenommen, dass alle Unterordner von ${dateDir}
# Snapshots sind. Dadurch vereinfacht sich diese Schleife
# ungemein.
sudo btrfs subvolume delete "${curSnapshot}" | sed "s!${mountDir}/!!g"
done < <(find "${dateDir}" -mindepth 1 -maxdepth 1 -print0)
sudo rmdir "${dateDir}"
fi
done < <(find "${snapshots}" -mindepth 1 -maxdepth 1 -print0)
}
function create_snapshots() {
# neue Snapshots anlegen
local mountDir="${1}"
local dest="${2}"
sudo mkdir "${dest}"
local srcSubvol
sudo btrfs subvolume list "${mountDir}" |
grep -Ev '/|@snapshots' |
cut -d' ' -f9 |
while read -r srcSubvol; do
sudo btrfs subvolume "snapshot" -r "${mountDir}/${srcSubvol}" "${dest}/${srcSubvol}" |
sed "s!${mountDir}/!!g"
done
}
parse_args "$@"
main "${maxAlterInTagen}"