summaryrefslogtreecommitdiff
path: root/src/initrd/btrfs-create.sh
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-05-01 01:34:54 -0400
committerAndrew Cady <d@jerkface.net>2016-05-01 01:34:54 -0400
commita9a594f2034c0a077f4d17a3b7f0caf1cf50626e (patch)
tree9722971ea97cbc89987737575f4f9b7aab88affc /src/initrd/btrfs-create.sh
parent6a5412e0b15fc68844ffd16f029e3f002b9cfb43 (diff)
rename now-ill-named "lvm-create"
Diffstat (limited to 'src/initrd/btrfs-create.sh')
-rw-r--r--src/initrd/btrfs-create.sh299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/initrd/btrfs-create.sh b/src/initrd/btrfs-create.sh
new file mode 100644
index 0000000..d4a8bdf
--- /dev/null
+++ b/src/initrd/btrfs-create.sh
@@ -0,0 +1,299 @@
1#!/bin/sh
2
3losetup() { /sbin/losetup "$@"; }
4
5luks_secret()
6{
7 local parms=$-; # this junk keeps set -x from being too annoying
8 set +x
9 [ -n "$luks_secret" ] || luks_secret="$(head -c256 /dev/urandom)"
10 printf %s "$luks_secret"
11 case $parms in *x*) set -x; set -x ;; esac
12}
13
14floor4()
15{
16 # Negatives round up, but aren't used.
17 echo $(($1 / 4 * 4))
18}
19
20ceil4()
21{
22 local x="$1"
23 [ $((x % 4)) -eq 0 ] || x=$((x + 4 - x % 4))
24 printf '%d\n' "$x"
25}
26
27. loop-layer.sh
28
29losetup_layers()
30{
31 bootwait samizdat-cdrom
32 local fs fs_rw
33 for fs in /cdrom/rootfs/*.btrfs; do
34 fs_rw=/"${fs##*/}".rw
35 dd if=/dev/zero of="$fs_rw" bs=1M count=10
36 losetup_snapshot "$fs" "$fs_rw" || return
37 done
38}
39
40init_samizdat()
41{
42 local blockdev="$1" imgfile="$2" uuid
43
44 losetup_layers || return
45 modprobe btrfs || return
46 btrfs device scan || return
47
48 uuid=$(choose_uuid) || return
49 [ "$uuid" ] || return
50
51 mount -t btrfs UUID="$uuid" /root || return
52
53 btrfs device add "$blockdev" /root || return
54 mount -o rw,remount /root || return
55 samizdat_movemounts "$imgfile" || return
56
57 initialize_root_filesystem || return
58
59 bootdone root-mounted
60}
61
62samizdat_movemounts()
63{
64 local imgfile="$1" mountpoint
65
66 if [ "$imgfile" ]; then
67 mountpoint=$(mountpoint_of "$imgfile") || return
68 mkdir /root/outerfs
69 mount -o move "$mountpoint" /root/outerfs
70 fi
71 mkdir /root/cdrom
72 mount -o move /cdrom /root/cdrom
73 mkdir -p /run/initramfs/samizdat/log
74 cp /var/log/* /run/initramfs/samizdat/log
75 true
76}
77
78mountpoint_of()
79{
80 local f="$1"
81 while ! mountpoint -q "$f"; do
82 f=$(dirname "$f")
83 [ "$f" != '.' ] || return 1
84 done
85 printf '%s\n' "$f"
86}
87
88initialize_root_filesystem()
89{
90 rm -r /root/root
91 btrfs subvolume create /root/root || return
92 mv /gpg/gnupghome /root/root/.gnupg || return
93
94 rmdir /root/srv
95 btrfs subvolume create /root/srv
96 rm -r /root/var/cache/apt/archives
97 btrfs subvolume create /root/var/cache/apt/archives || return
98
99 rmdir /root/home
100 btrfs subvolume create /root/home || return
101
102 [ -x /root/sbin/mdadm ] || cp /sbin/mdadm /root/sbin/
103 # Copy these over unconditionally, because they ought to remain in sync with
104 # the initrd.
105 cp /bin/mdadm-dup.sh /root/sbin/
106 cp /bin/samizdat-eject.sh /root/sbin/
107
108 sed -i -e 's/^root:x:/root::/' /root/etc/passwd
109 cp /patchroot/* /root/root/
110
111 true
112}
113
114# Get the uuid of the filesystem with the most devices,
115# excluding filesystems that don't incorporate loop devices.
116# This is used to choose the latest seed -- which should have
117# the most layers.
118choose_uuid()
119{
120 local seen_loop= seen_uuid= seen_devs=
121 btrfs filesystem show |
122 while read line; do
123 case "$line" in
124 Label*)
125 seen_uuid=${line##*uuid: }
126 seen_devs=
127 seen_loop=
128 ;;
129 *Total\ devices*)
130 seen_devs=${line#*Total devices }
131 seen_devs=${seen_devs%% *}
132 ;;
133 *path\ /dev/mapper/*)
134 seen_loop=t;;
135 esac
136 [ "$seen_loop" ] && echo "$seen_devs $seen_uuid"
137 done |
138 uniq | sort -nr | head -n1 | (read _ x; echo $x)
139}
140
141filesystem_incomplete()
142{
143 local n
144 n=$(btrfs filesystem show "$1" | sed -ne 's/.*Total devices \([^ ]*\) .*/\1/p')
145 [ "$n" != 1 ]
146}
147
148open_samizdat()
149{
150 local imgfile="$1" keyfile="$2"
151 open_samizdat_blockdev "$imgfile" "$keyfile" || return
152 local blockdev=/dev/mapper/samizdatcrypt fs
153
154 # For this part, we don't necessarily need the cdrom.
155 # Unfortunately the init_gpg code is still getting the GPG key there.
156 if filesystem_incomplete "$blockdev"; then
157 losetup_layers
158 fi
159 modprobe btrfs || return
160 btrfs device scan || return
161 mount -t btrfs "$blockdev" /root || return
162 samizdat_movemounts "$imgfile"
163 LoSetup -D
164 bootdone root-mounted
165}
166
167init_samizdat_lodev()
168{
169 local imgfile="$1" megs=$(ceil4 "$2") dev
170 truncate -s ${megs}M "$imgfile" || return
171 dev=$(losetup -f) && losetup "$dev" "$imgfile" || return
172 echo "$dev"
173}
174
175open_samizdat_blockdev()
176{
177 local imgfile="$1" keyfile="$2" dev
178 local cryptname=samizdatcrypt
179 dev=$(losetup -f) && losetup "$dev" "$imgfile" || return
180
181 gpg2 --verify "$keyfile" || return
182 # The first --decrypt merely strips the signature. The option is
183 # poorly named for that case.
184 gpg2 --decrypt "$keyfile" | gpg2 --decrypt | cryptsetup --key-file - luksOpen "$dev" "$cryptname" || return
185
186 [ -b /dev/mapper/"$cryptname" ] || return
187
188}
189
190init_samizdat_blockdev()
191{
192 local imgfile="$1" megs="$2" keyfile="$3" dev
193 local cryptname=samizdatcrypt
194
195 dev=$(init_samizdat_lodev "$imgfile" "$megs") || return
196
197 [ ! -b /dev/mapper/"$cryptname" ] || return
198
199 luks_secret >/dev/null
200 luks_secret | gpg2 --default-recipient-self --encrypt --armor | gpg2 --clearsign --output "$keyfile" || return
201
202 luks_secret | cryptsetup luksFormat "$dev" - || return
203 cryptsetup luksDump "$dev" >&2
204 luks_secret | cryptsetup --key-file - luksOpen "$dev" "$cryptname" || return
205
206 [ -b /dev/mapper/"$cryptname" ] || return
207}
208
209majmin()
210{
211 local dev="$1" major minor
212 eval $(stat -c 'major=%t minor=%T' "$dev") || return
213 [ "$major" -a "$minor" ] || return
214 printf '%d:%d\n' 0x$major 0x$minor
215}
216
217cryptdev_to_dev()
218{
219 local dev="$1" majmin
220 majmin=$(majmin "$dev") || return
221 set -- /sys/dev/block/$majmin/slaves/*
222 [ $# = 1 ] || return
223
224 cryptsetup status "$dev" |while read k v; do if [ "$k" = device: ]; then echo $v; break; fi; done
225}
226
227cryptdev_to_backing_file()
228{
229 local dev="$1" majmin result
230 majmin="$(majmin "$dev")" || return
231 set -- /sys/dev/block/$majmin/slaves/*
232 [ $# = 1 ] || return
233 read result < "$1"/loop/backing_file || return
234 printf '%s\n' "$result"
235}
236
237lodev_to_file()
238{
239 local result majmin dev="$1"
240 majmin="$(majmin "$dev")" || return
241 read result < /sys/dev/block/$majmin/loop/backing_file || return
242 printf '%s' "$result"
243}
244
245mountpoint_to_dev()
246{
247 local wantmp="$1" dev mp rest
248 mountpoint -q "$wantmp" || return
249 while read dev mp rest; do if [ "$mp" = "$wantmp" ]; then echo "$dev"; return; fi; done < /proc/mounts
250 return 1
251}
252
253get_cdrom_sizelimit()
254{
255 # returns bytes
256 local dev="$1" sectors
257 sectors=$(blockdev --getsz "$dev") || return
258 if dd count=2 if="$dev" bs=2048 skip=$((sectors/4 - 2)) of=/dev/null 2>/dev/null; then
259 return
260 else
261 echo $(((sectors-8)*512))
262 fi
263}
264
265init_gpg()
266{
267 bootwait samizdat-cdrom
268 export GNUPGHOME=/gpg/gnupghome
269 mkdir -p "$GNUPGHOME"
270 (umask 077; rsync --exclude '/luks-key*' --ignore-existing -rpP /cdrom/gnupghome/ "$GNUPGHOME")
271
272 if samizdat-password-agent >/var/log/samizdat-password-agent.log 2>&1; then
273 clear
274 true
275 else
276 false
277 fi
278}
279
280start_meter()
281{
282 local startmsg="$*"
283 (exec >&4
284 clear
285 echo -n $startmsg
286 set +x
287 while sleep 2; do
288 echo -n .
289 done) &
290 meterpid=$!
291}
292
293stop_meter()
294{
295 local endmsg="$*"
296 kill $meterpid
297 echo " $endmsg" >&4
298}
299