summaryrefslogtreecommitdiff
path: root/btrfs-functions.sh
diff options
context:
space:
mode:
Diffstat (limited to 'btrfs-functions.sh')
-rw-r--r--btrfs-functions.sh137
1 files changed, 137 insertions, 0 deletions
diff --git a/btrfs-functions.sh b/btrfs-functions.sh
new file mode 100644
index 0000000..3648c24
--- /dev/null
+++ b/btrfs-functions.sh
@@ -0,0 +1,137 @@
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 printf '%s\n' "$mp/$path"
104}
105
106btrfs_replace_default_subvolume_with()
107{
108 $(ARGS_NE new_default)
109 local old_default subvol_id
110 old_default=$(btrfs_show_default_path "$new_default") || die
111
112 [ "$new_default" = "$old_default" ] && return
113
114 subvol_id=$(btrfs_show_subvolume_id "$new_default") || die
115 btrfs subvolume set-default "$subvol_id" "$new_default" || die
116 btrfs subvolume delete "$old_default"
117 sex mv "$new_default" "$old_default"
118}
119
120btrfs_show_subvolume_id()
121{
122 $(ARGS_NE path)
123 local result
124 result=$(btrfs subvolume show "$path" | sed -n -e 's/^[ \t]*Subvolume ID:[ \t]*//p')
125 if [ "$result" ]
126 then printf '%s\n' "$result"
127 else false
128 fi
129}
130
131with_dir()
132{
133 $(ARGS_NE d)
134 shift
135 [ -d "$d" ] || return 0
136 "$@" "$d"
137}