]> code.delx.au - monosys/blob - bsnap/bsnap
notes: fix raspi install notes, also @home -> @username
[monosys] / bsnap / bsnap
1 #!/bin/bash
2
3 set -eu
4
5 function snap {
6 unsnap
7
8 mkdir -p /a
9
10 dispatch snap < /etc/fstab
11 }
12
13 function unsnap {
14 tac /etc/fstab | dispatch unsnap
15
16 if [ -d "/a" ]; then
17 rmdir /a
18 fi
19 }
20
21 function dispatch {
22 local action="" snaptype=""
23 local dev="" mnt="" fstype="" opts="" dump=""
24
25 while read -r dev mnt fstype opts dump pass; do
26 snaptype="$(get_snaptype "$fstype" "$dump")"
27 if [ -z "$snaptype" ]; then
28 continue
29 fi
30 action="${1}_${snaptype}"
31 echo "$action $mnt"
32 "$action" "$dev" "$mnt" "$opts"
33 done
34 }
35
36 function get_snaptype {
37 local fstype="$1" dump="$2"
38 if [ "$dump" = "1" ]; then
39 echo bind
40 elif [ "$dump" = "2" ] && [ "$fstype" = "btrfs" ]; then
41 echo btrfs
42 elif [ "$dump" = "2" ]; then
43 echo lvm
44 fi
45 }
46
47 function snap_bind {
48 local mnt="$2"
49 mount --bind "${mnt}" "/a${mnt}"
50 }
51
52 function unsnap_bind {
53 local snapmnt="/a$2"
54 if mountpoint -q "$snapmnt"; then
55 umount "$snapmnt"
56 fi
57 }
58
59 function snap_lvm {
60 local mnt="$2"
61 local lvname="" vgname=""
62 read -r lvname vgname _ < <(get_lvm_vgname_lvname "${mnt}")
63
64 echo "snapshot ${vgname}/${lvname}"
65 lvcreate -L1G --snapshot --name "${lvname}-snap" "${vgname}/${lvname}"
66 mount -o ro "/dev/${vgname}/${lvname}-snap" "/a${mnt}"
67 }
68
69 function unsnap_lvm {
70 local mnt="$2"
71 local lvname="" vgname=""
72
73 if mountpoint -q "/a$mnt"; then
74 umount "/a$mnt"
75 fi
76
77 read -r lvname vgname _ < <(get_lvm_vgname_lvname "${mnt}")
78 if lvdisplay "${vgname}/${lvname}-snap" &> /dev/null; then
79 lvremove -f "${vgname}/${lvname}-snap"
80 fi
81 }
82
83 function get_lvm_vgname_lvname {
84 local mnt="$1" subvol=""
85 lvdisplay --noheadings -C "$(findmnt -n -o source "$mnt")"
86 }
87
88 function snap_btrfs {
89 local mnt="$2" opts="$3" snapdir=""
90
91 snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
92 btrfs subvolume snapshot "$mnt" "$snapdir"
93
94 mount --bind "$snapdir" "/a${mnt}"
95 }
96
97 function unsnap_btrfs {
98 local mnt="$2" opts="$3" snapdir=""
99
100 local snapmnt="/a$2"
101 if mountpoint -q "$snapmnt"; then
102 umount "$snapmnt"
103 fi
104
105 snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
106 if [ -d "$snapdir" ]; then
107 btrfs subvolume delete "$snapdir"
108 fi
109 }
110
111 function get_btrfs_snapshot_dir {
112 local opts="$1" mnt="$2" subvol=""
113 subvol="$(echo "$opts" | sed -nE 's/^.*\bsubvol=([^,]+)\b.*$/\1/p')"
114 if [ -z "$subvol" ]; then
115 echo "Unknown subvol for mountpoint: $mnt"
116 exit 1
117 fi
118 echo "/.snapshots/tmp-bsnap-${subvol}"
119 }
120
121 if [ "$(id -u)" -ne 0 ]; then
122 echo "Must be root"
123 exit 1
124 fi
125
126 if [ "${1:-}" = "off" ]; then
127 unsnap
128 elif [ "${1:-}" = "on" ]; then
129 snap
130 else
131 echo "Usage: $0 on|off"
132 exit 1
133 fi