diff options
Diffstat (limited to 'src/btrfs-functions.sh')
-rw-r--r-- | src/btrfs-functions.sh | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/btrfs-functions.sh b/src/btrfs-functions.sh new file mode 100644 index 0000000..b83b94d --- /dev/null +++ b/src/btrfs-functions.sh | |||
@@ -0,0 +1,161 @@ | |||
1 | push() | ||
2 | { | ||
3 | $(ARGS_NE mnt src dst_dir) | ||
4 | |||
5 | now=$(date +%F.%H%M%S) || die | ||
6 | snap_dir=$mnt/snapshot.$now | ||
7 | prev_dir=$mnt/snapshot.prev | ||
8 | |||
9 | local BTRFS_RECEIVE_DESTINATION_PATH="$dst_dir" | ||
10 | push_helper true "$snap_dir" "$prev_dir" "$src" local_btrfs_receiver | ||
11 | } | ||
12 | |||
13 | push_simple() | ||
14 | { | ||
15 | $(ARGS_NE mnt src dst_dir) | ||
16 | local BTRFS_RECEIVE_DESTINATION_PATH="$dst_dir" | ||
17 | push_helper false "$mnt" "$src" local_btrfs_receiver | ||
18 | } | ||
19 | |||
20 | sex() | ||
21 | { | ||
22 | (set -x; "$@") | ||
23 | } | ||
24 | |||
25 | local_btrfs_receiver() | ||
26 | { | ||
27 | btrfs receive "$BTRFS_RECEIVE_DESTINATION_PATH" | ||
28 | } | ||
29 | |||
30 | shellescape() | ||
31 | { | ||
32 | if [ "$BASH_VERSION" ]; then | ||
33 | printf %q "$1" | ||
34 | else | ||
35 | bash -c 'printf %q "$1"' bash "$1" | ||
36 | fi | ||
37 | } | ||
38 | |||
39 | remote_btrfs_receiver() | ||
40 | { | ||
41 | ssh "$BTRFS_RECEIVE_DESTINATION_HOST" -- "btrfs receive $(shellescape "$BTRFS_RECEIVE_DESTINATION_PATH")" | ||
42 | } | ||
43 | |||
44 | push_helper() | ||
45 | { | ||
46 | $(ARGS keep_as_prev snap_dir prev_dir src dst_pipe) | ||
47 | $(NONEMPTY keep_as_prev snap_dir src dst_pipe) | ||
48 | |||
49 | local full_dest rw_dest | ||
50 | |||
51 | btrfs subvolume snapshot -r "$src" "$snap_dir" || die | ||
52 | |||
53 | if [ "$prev_dir" -a -d "$prev_dir" ]; then | ||
54 | btrfs send -p "$prev_dir" "$snap_dir" | ||
55 | else | ||
56 | btrfs send "$snap_dir" | ||
57 | fi | "$dst_pipe" || die | ||
58 | |||
59 | if [ "$dst_pipe" = local_btrfs_receiver ]; then | ||
60 | local dst="$BTRFS_RECEIVE_DESTINATION_PATH" | ||
61 | full_dest=$dst/$(basename "$snap_dir") | ||
62 | rw_dest=$full_dest.rw | ||
63 | btrfs subvolume snapshot "$full_dest" "$rw_dest" || die | ||
64 | btrfs_replace_default_subvolume_with "$rw_dest" | ||
65 | fi | ||
66 | |||
67 | if $keep_as_prev && [ "$prev_dir" ] | ||
68 | then | ||
69 | # keep the pushed snapshot in order to reuse it on subsequent pushes. | ||
70 | with_dir "$prev_dir" btrfs subvolume delete || die | ||
71 | sex mv "$snap_dir" "$prev_dir" || die | ||
72 | else | ||
73 | btrfs subvolume delete "$snap_dir" | ||
74 | fi | ||
75 | } | ||
76 | |||
77 | btrfs_mountpoint() | ||
78 | { | ||
79 | $(ARGS_NE dir) | ||
80 | btrfs filesystem show -m "$dir" >/dev/null 2>&1 | ||
81 | } | ||
82 | |||
83 | btrfs_get_mountpoint() | ||
84 | { | ||
85 | $(ARGS_NE dir) | ||
86 | while [ "$dir" -a "$dir" != '.' ]; do | ||
87 | if btrfs_mountpoint "$dir" | ||
88 | then printf '%s\n' "$dir" | ||
89 | return | ||
90 | fi | ||
91 | dir=$(dirname "$dir") | ||
92 | done | ||
93 | false | ||
94 | } | ||
95 | |||
96 | btrfs_show_default_path() | ||
97 | { | ||
98 | $(ARGS_NE mp) | ||
99 | local path | ||
100 | mp=$(btrfs_get_mountpoint "$mp") || die # TODO: fix caller? | ||
101 | btrfs_mountpoint "$mp" || die "not a mountpoint: $mp" | ||
102 | path=$(btrfs subvolume get-default "$mp"/|sed -n -e 's/.* path //p') | ||
103 | if [ "$path" ]; then | ||
104 | printf '%s\n' "$mp/$path" | ||
105 | else | ||
106 | printf '%s\n' "$mp" | ||
107 | fi | ||
108 | } | ||
109 | |||
110 | btrfs_show_default_id() | ||
111 | { | ||
112 | $(ARGS_NE mp) | ||
113 | local id | ||
114 | mp=$(btrfs_get_mountpoint "$mp") || die # TODO: fix caller? | ||
115 | btrfs_mountpoint "$mp" || die "not a mountpoint: $mp" | ||
116 | id=$(btrfs subvolume get-default "$mp"/|sed -n -e 's/^ID \([^ ]*\) .*/\1/p') | ||
117 | [ "$id" ] || return | ||
118 | echo $id | ||
119 | } | ||
120 | |||
121 | btrfs_replace_default_subvolume_with() | ||
122 | { | ||
123 | $(ARGS_NE new_default) | ||
124 | local old_default old_default_id new_default_id | ||
125 | old_default_id=$(btrfs_show_default_id "$new_default") || die | ||
126 | new_default_id=$(btrfs_show_subvolume_id "$new_default") || die | ||
127 | |||
128 | [ "$new_default_id" = "$old_default_id" ] && return | ||
129 | |||
130 | if [ "$old_default_id" != 5 ]; then | ||
131 | old_default=$(btrfs_show_default_path "$new_default") || die | ||
132 | else | ||
133 | old_default= | ||
134 | fi | ||
135 | |||
136 | btrfs subvolume set-default "$new_default_id" "$new_default" || die | ||
137 | |||
138 | if [ "$old_default" ]; then | ||
139 | btrfs subvolume delete "$old_default" | ||
140 | sex mv "$new_default" "$old_default" | ||
141 | fi | ||
142 | } | ||
143 | |||
144 | btrfs_show_subvolume_id() | ||
145 | { | ||
146 | $(ARGS_NE path) | ||
147 | local result | ||
148 | result=$(btrfs subvolume show "$path" | sed -n -e 's/^[ \t]*Subvolume ID:[ \t]*//p; s/.*is toplevel subvolume/5/p') | ||
149 | if [ "$result" ] | ||
150 | then printf '%s\n' "$result" | ||
151 | else false | ||
152 | fi | ||
153 | } | ||
154 | |||
155 | with_dir() | ||
156 | { | ||
157 | $(ARGS_NE d) | ||
158 | shift | ||
159 | [ -d "$d" ] || return 0 | ||
160 | "$@" "$d" | ||
161 | } | ||