summaryrefslogtreecommitdiff
path: root/src/push-btrfs-scan
diff options
context:
space:
mode:
Diffstat (limited to 'src/push-btrfs-scan')
-rwxr-xr-xsrc/push-btrfs-scan191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/push-btrfs-scan b/src/push-btrfs-scan
new file mode 100755
index 0000000..bc97d00
--- /dev/null
+++ b/src/push-btrfs-scan
@@ -0,0 +1,191 @@
1#!/bin/bash
2set -e -o pipefail
3
4confdir=/etc/btrfs
5blacklist=$confdir/blacklist.txt
6
7with_subvolumes()
8{
9 btrfs subvolume list / -a |
10 while read _ id _ gen _ _ toplevel _ path
11 do
12 "$@"
13 done
14}
15
16fixup_path()
17{
18 if ! [ "$root" ]
19 then
20 case "$path" in
21 '<FS_TREE>'/* ) root=${path#*/} ;;
22 * ) exit 1 ;;
23 esac
24 fi
25 case "$path" in
26 '<FS_TREE>'/"$root"/* ) path_fixed=${path#*/$root} ;;
27 "$root"/* ) path_fixed=${path#$root} ;;
28 * ) return ;;
29 esac
30 "$@"
31}
32
33is_our_snapshot()
34{
35 case "$1" in
36 */.snapshot~* ) true ;;
37 *) false ;;
38 esac
39}
40
41filter_readonly()
42{
43 if btrfs subvolume show -r "$id" / | sed -Ene '/^\tFlags:.*\breadonly\b/{p;q1}' -e '$q'
44 then
45 if [ -e "$conf_name" ]
46 then
47 printf '%20s %s\n' delete "$conf_name" >&2
48 fi
49 printf '%20s %s\n' '(snapshot) lose' "$path_fixed" >&2
50 return
51 fi
52 "$@"
53}
54
55filter_snapshot_filename()
56{
57 if is_our_snapshot "$path_fixed"
58 then
59 if [ -e "$conf_name" ]
60 then
61 printf '%20s %s\n' delete "$conf_name" >&2
62 fi
63 printf '%20s %s\n' '(snapshot) lose' "$path_fixed" >&2
64 return
65 fi
66 "$@"
67}
68
69systemctl_disable_quiet()
70{
71 ! systemctl is-enabled "$@" 2>/dev/null || systemctl disable "$@"
72}
73
74timer_prefix=/etc/systemd/system/default.target.wants/push-btrfs@borges
75unset blacklist_patterns
76declare -a blacklist_patterns
77filter_blacklist()
78{
79 if [ "$blacklist" -a -f "$blacklist" ]
80 then
81 if ! [ -v blacklist_patterns ]
82 then
83 readarray -t blacklist_patterns < "$blacklist"
84 fi
85
86 for pattern in "${blacklist_patterns[@]}"
87 do
88 if [[ $path_fixed == $pattern ]]
89 then
90 printf '%20s %s\n' '(blacklist) lose' "$path_fixed" >&2
91 if [ -e "$conf_name" ]
92 then
93 printf '%20s %s\n' delete "$conf_name" >&2
94 rm "$conf_name"
95 fi
96 timer=$destination_host$(systemd-escape "$path_fixed").timer
97 systemctl_disable_quiet "$timer"
98 return
99 fi
100 done
101 fi
102 "$@"
103}
104
105compute_paths()
106{
107 source=$path_fixed
108 source_escaped=$(systemd-escape "$source")
109 conf_dir=/etc/btrfs/remotes
110 conf_name="$conf_dir"/$destination_host$source_escaped.json
111 "$@"
112}
113
114mirror()
115{
116 if [ -e "$conf_name" ]
117 then
118 return
119 fi
120 set -- \
121 jq -c -n '{source: $source, destination: $destination}' \
122 --arg destination "$destination$source_escaped" \
123 --arg source "$source"
124
125 if [ ! "$NO_ACT" ]
126 then
127 conf_temp=$conf_name~$(date -Ins)
128 {
129 "$@" > "$conf_temp"
130 mv -T -- "$conf_temp" "$conf_name"
131 printf '%20s %s\n' 'add' "$path_fixed" >&2
132 } || {
133 rm -- "$conf_temp"
134 false
135 }
136 fi
137
138 if [ "$ONLY_ONCE" ]
139 then
140 exit 0
141 fi
142}
143
144usage()
145{
146cat <<END
147usage: $0 [-n] [-r]
148END
149}
150
151case "$0" in
152 ./* ) PATH=${0%/*}:$PATH ;;
153esac
154
155case "$(id -u)" in
156 0 ) ;;
157 * ) exec sudo --preserve-env=VERBOSE "$0" "$@" || exit ;;
158esac
159
160while [ $# -gt 0 ]
161do
162 case "$1" in
163 -- ) shift
164 break ;;
165 -n ) NO_ACT=y ;;
166 -r ) export RESUME=y ;;
167 -v ) VERBOSE=y ;;
168 --once ) ONLY_ONCE=y ;;
169 --destination ) DESTINATION=$2
170 shift ;;
171 -* ) usage
172 exit 1 ;;
173 * ) break ;;
174 esac
175 shift
176done
177
178destination_file=/etc/btrfs/destination.txt
179[ "$DESTINATION" ] || read DESTINATION < "$destination_file"
180
181destination_host=${DESTINATION%%:*}
182destination_basename=$(hostname) && [ "$destination_basename" ] || destination_basename=btrfs
183case "$DESTINATION" in
184 */ ) destination=$DESTINATION$destination_basename ;;
185 [a-zA-Z]* ) destination=$DESTINATION ;;
186 * ) exit 1 ;;
187esac
188
189ssh root@"$destination_host" true || read -p 'Could not log in. Continue? '
190
191with_subvolumes fixup_path compute_paths filter_snapshot_filename filter_blacklist mirror