summaryrefslogtreecommitdiff
path: root/src/btrfs-functions.sh
diff options
context:
space:
mode:
Diffstat (limited to 'src/btrfs-functions.sh')
-rw-r--r--src/btrfs-functions.sh161
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 @@
1push()
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
13push_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
20sex()
21{
22 (set -x; "$@")
23}
24
25local_btrfs_receiver()
26{
27 btrfs receive "$BTRFS_RECEIVE_DESTINATION_PATH"
28}
29
30shellescape()
31{
32 if [ "$BASH_VERSION" ]; then
33 printf %q "$1"
34 else
35 bash -c 'printf %q "$1"' bash "$1"
36 fi
37}
38
39remote_btrfs_receiver()
40{
41 ssh "$BTRFS_RECEIVE_DESTINATION_HOST" -- "btrfs receive $(shellescape "$BTRFS_RECEIVE_DESTINATION_PATH")"
42}
43
44push_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
77btrfs_mountpoint()
78{
79 $(ARGS_NE dir)
80 btrfs filesystem show -m "$dir" >/dev/null 2>&1
81}
82
83btrfs_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
96btrfs_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
110btrfs_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
121btrfs_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
144btrfs_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
155with_dir()
156{
157 $(ARGS_NE d)
158 shift
159 [ -d "$d" ] || return 0
160 "$@" "$d"
161}