various fixes
[distro-setup] / mount-latest-subvol
1 #!/bin/bash
2
3 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
4
5 errcatch() {
6 set -E; shopt -s extdebug
7 _err-trap() {
8 err=$?
9 exec >&2
10 set +x
11 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:in \`$BASH_COMMAND' returned $err"
12 bash-trace 2
13 echo "$0: exiting with code $err"
14 exit $err
15 }
16 trap _err-trap ERR
17 set -o pipefail
18 }
19 bash-trace() {
20 local -i argc_index=0 arg frame i start=${1:-1} max_indent=8 indent
21 local source
22 local extdebug=false
23 if [[ $(shopt -p extdebug) == *-s* ]]; then
24 extdebug=true
25 fi
26
27 for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do
28 argc=${BASH_ARGC[frame]}
29 argc_index+=$argc
30 ((frame < start)) && continue
31 if (( ${#BASH_SOURCE[@]} > 1 )); then
32 source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:"
33 fi
34 indent=$((frame-start+1))
35 indent=$((indent < max_indent ? indent : max_indent))
36 printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}"
37 if $extdebug; then
38 for ((i=argc_index-1; i >= argc_index-argc; i--)); do
39 printf " %s" "${BASH_ARGV[i]}"
40 done
41 fi
42 echo \'
43 done
44 }
45 errcatch
46
47 tu() {
48 while read -r line; do
49 file="$1"
50 grep -xFq "$line" "$file" || tee -a "$file"<<<"$line"
51 done
52 }
53 e() { printf "%s\n" "$*"; "$@"; }
54 mnt() {
55 dir=$1
56 if ! mountpoint $dir >/dev/null; then
57 mkdir -p $dir
58 e mount $dir
59 fi
60 }
61
62 ret=0
63
64 first_root_crypt=$(awk '$2 == "/" {print $1}' /etc/mtab)
65 tu /etc/fstab <<EOF
66 $first_root_crypt /q btrfs noatime,subvol=q 0 0
67 /q/a /a none bind 0 0
68 EOF
69 case $HOSTNAME in
70 treetowl|x2|frodo)
71 tu /etc/fstab <<EOF
72 $first_root_crypt /p btrfs noatime,subvol=p 0 0
73 EOF
74 ;;
75 esac
76 if [[ $HOSTNAME == treetowl ]]; then
77 # partitioned it with fai partitioner outside of fai,
78 # because it\'s worth it to have 1% space reserved for boot and
79 # swap partitions in case I ever want to boot off those drives.
80 # as root:
81 # . /a/bin/fai/fai-wrapper
82 # eval-fai-classfile /a/bin/fai/fai/config/class/51-multi-boot
83 # fai-setclass ROTATIONAL
84 # export LUKS_DIR=/q/root/luks/
85 # # because the partition nums existed already
86 # fai-setclass REPARTITION
87 # /a/bin/fai/fai/config/hooks/partition.DEFAULT
88
89 # just the first in the btrfs raid
90 dev=ata-TOSHIBA_MD04ACA500_84REK6NTFS9A-part1
91 tu /etc/fstab <<EOF
92 /dev/mapper/crypt_dev_$dev /i btrfs noatime,subvol=i 0 0
93 EOF
94 tu /etc/crypttab <<EOF
95 crypt_dev_$dev /dev/disk/by-id/$dev /q/root/luks/host-treetowl discard,luks
96 EOF
97
98 else
99 tu /etc/fstab <<'EOF'
100 /q/i /i none bind 0 0
101 EOF
102
103 fi
104
105 for vol in q p; do
106 d=/$vol
107 if ! awk '{print $2}' /etc/fstab | grep -xF $d &>/dev/null; then
108 continue
109 fi
110
111
112 binds=()
113 roots=($d)
114 while true; do
115 new_roots=()
116 for r in ${roots[@]}; do
117 # /q/a /a none bind 0 0
118 new_roots+=($(sed -rn "s#^$r/\S+\s+(\S+)\s+none\s+bind\s.*#\1#p" /etc/fstab))
119 done
120 (( ${#new_roots} )) || break
121 binds+=(${new_roots[@]})
122 roots=( ${new_roots[@]} )
123 done
124
125 if e check-subvol-stale $d; then
126 for b in ${binds[@]}; do
127 mnt $b
128 done
129 continue
130 fi
131
132 last_snap=$(</nocow/btrfs-stale/$vol)
133 if [[ ! $last_snap ]]; then
134 echo "$0: error. empty last_snap var"
135 ret=1
136 continue
137 fi
138
139 umount_ret=true
140 unmounted=()
141 for dir in $(echo $d ${binds[*]}\ |tac -s\ ); do
142 if mountpoint $dir; then
143 if e umount -R $dir; then
144 unmounted+=($dir)
145 else
146 umount_ret=false
147 echo "$0: failed to umount $dir"
148 break
149 fi
150 fi
151 done
152
153 if ! $umount_ret; then
154 for dir in ${unmounted[@]}; do
155 mnt $dir
156 done
157 ret=1
158 continue
159 fi
160
161 cd /mnt/root
162 if [[ -e $vol ]]; then
163 e btrfs sub del $vol
164 fi
165 # Note, we make a few assumptions in this script, like
166 # $d was not a different subvol id than $vol, and
167 # things otherwise didn't get mounted very strangely.
168 e btrfs sub snapshot btrbk/$last_snap $vol
169 for dir in $d ${binds[@]}; do
170 e mnt $dir
171 done
172 done
173 exit $ret