diff options
author | Andrew Cady <d@jerkface.net> | 2023-05-28 19:25:16 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2023-05-28 19:25:16 -0400 |
commit | 76f0e0e68939d64ac5ed2ccb3d21bf98337168af (patch) | |
tree | b705dad1e56a02c8cb9da9163b0ecb7a2e681c25 | |
parent | b1ca342c72ad58a48b822fc9fa9374506c590d44 (diff) |
btrfs-scan from other repo
-rwxr-xr-x | src/btrfs-scan | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/btrfs-scan b/src/btrfs-scan new file mode 100755 index 0000000..ab9f771 --- /dev/null +++ b/src/btrfs-scan | |||
@@ -0,0 +1,157 @@ | |||
1 | #!/bin/bash | ||
2 | set -e -o pipefail | ||
3 | |||
4 | confdir=/etc/btrfs | ||
5 | blacklist=$confdir/blacklist.txt | ||
6 | |||
7 | with_subvolumes() | ||
8 | { | ||
9 | btrfs subvolume list / -a | | ||
10 | while read _ id _ gen _ _ toplevel _ path | ||
11 | do | ||
12 | "$@" | ||
13 | done | ||
14 | } | ||
15 | |||
16 | fixup_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 | compute_paths | ||
31 | "$@" | ||
32 | } | ||
33 | |||
34 | is_our_snapshot() | ||
35 | { | ||
36 | case "$1" in | ||
37 | */.snapshot~* ) true ;; | ||
38 | *) false ;; | ||
39 | esac | ||
40 | } | ||
41 | |||
42 | filter_blacklist() | ||
43 | { | ||
44 | if is_our_snapshot "$path_fixed" | ||
45 | then | ||
46 | if [ -e "$conf_name" ] | ||
47 | then | ||
48 | printf '%20s %s\n' delete "$conf_name" >&2 | ||
49 | printf '%20s %s\n' '(snapshot) lose' "$path_fixed" >&2 | ||
50 | fi | ||
51 | return | ||
52 | |||
53 | # Re-reading the blacklist file once per snapshot is not ideal, | ||
54 | # but is fine. | ||
55 | elif [ "$blacklist" -a -f "$blacklist" ] | ||
56 | then | ||
57 | while read pattern | ||
58 | do | ||
59 | if [[ $path_fixed == $pattern ]] | ||
60 | then | ||
61 | if [ -e "$conf_name" ] | ||
62 | then | ||
63 | printf '%20s %s\n' delete "$conf_name" >&2 | ||
64 | fi | ||
65 | printf '%20s %s\n' '(blacklist) lose' "$path_fixed" >&2 | ||
66 | return | ||
67 | fi | ||
68 | done < "$blacklist" | ||
69 | fi | ||
70 | "$@" | ||
71 | } | ||
72 | |||
73 | compute_paths() | ||
74 | { | ||
75 | source=$path_fixed | ||
76 | source_escaped=$(systemd-escape "$source") | ||
77 | conf_dir=/etc/btrfs/remotes | ||
78 | conf_name="$conf_dir"/$destination_host$source_escaped.json | ||
79 | } | ||
80 | |||
81 | mirror() | ||
82 | { | ||
83 | if [ -e "$conf_name" ] | ||
84 | then | ||
85 | return | ||
86 | fi | ||
87 | set -- \ | ||
88 | jq -c -n '{source: $source, destination: $destination}' \ | ||
89 | --arg destination "$destination$source_escaped" \ | ||
90 | --arg source "$source" | ||
91 | |||
92 | if [ ! "$NO_ACT" ] | ||
93 | then | ||
94 | conf_temp=$conf_name~$(date -Ins) | ||
95 | { | ||
96 | "$@" > "$conf_temp" | ||
97 | mv -T -- "$conf_temp" "$conf_name" | ||
98 | printf '%20s %s\n' 'add' "$path_fixed" >&2 | ||
99 | } || { | ||
100 | rm -- "$conf_temp" | ||
101 | false | ||
102 | } | ||
103 | fi | ||
104 | |||
105 | if [ "$ONLY_ONCE" ] | ||
106 | then | ||
107 | exit 0 | ||
108 | fi | ||
109 | } | ||
110 | |||
111 | usage() | ||
112 | { | ||
113 | cat <<END | ||
114 | usage: $0 [-n] [-r] | ||
115 | END | ||
116 | } | ||
117 | |||
118 | case "$0" in | ||
119 | ./* ) PATH=${0%/*}:$PATH ;; | ||
120 | esac | ||
121 | |||
122 | case "$(id -u)" in | ||
123 | 0 ) ;; | ||
124 | * ) exec sudo --preserve-env=VERBOSE "$0" "$@" || exit ;; | ||
125 | esac | ||
126 | |||
127 | while [ $# -gt 0 ] | ||
128 | do | ||
129 | case "$1" in | ||
130 | -- ) shift | ||
131 | break ;; | ||
132 | -n ) NO_ACT=y ;; | ||
133 | -r ) export RESUME=y ;; | ||
134 | -v ) VERBOSE=y ;; | ||
135 | --once ) ONLY_ONCE=y ;; | ||
136 | --destination ) DESTINATION=$2 | ||
137 | shift ;; | ||
138 | -* ) usage | ||
139 | exit 1 ;; | ||
140 | * ) break ;; | ||
141 | esac | ||
142 | shift | ||
143 | done | ||
144 | |||
145 | [ "$DESTINATION" ] | ||
146 | |||
147 | destination_host=${DESTINATION%%:*} | ||
148 | destination_basename=$(hostname) && [ "$destination_basename" ] || destination_basename=btrfs | ||
149 | case "$DESTINATION" in | ||
150 | */ ) destination=$DESTINATION$destination_basename ;; | ||
151 | [a-zA-Z]* ) destination=$DESTINATION ;; | ||
152 | * ) exit 1 ;; | ||
153 | esac | ||
154 | |||
155 | ssh root@"$destination_host" true || read -p 'Could not log in. Continue? ' | ||
156 | |||
157 | with_subvolumes fixup_path filter_blacklist mirror | ||