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