diff options
author | Andrew Cady <d@jerkface.net> | 2016-04-29 14:36:26 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2016-04-29 14:36:30 -0400 |
commit | 153d299a41b9be4e15dab1ca29bb93a74bd2445d (patch) | |
tree | 96fbfbe7c64f0b3f02f3d755e2b129917785bb98 /src/initrd/lvm-create.sh | |
parent | 5f41fb879ca830e5ad3345878e59072f3d6573bc (diff) |
fix paths (in progress)
Diffstat (limited to 'src/initrd/lvm-create.sh')
-rw-r--r-- | src/initrd/lvm-create.sh | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/initrd/lvm-create.sh b/src/initrd/lvm-create.sh new file mode 100644 index 0000000..d4a8bdf --- /dev/null +++ b/src/initrd/lvm-create.sh | |||
@@ -0,0 +1,299 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | losetup() { /sbin/losetup "$@"; } | ||
4 | |||
5 | luks_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 | |||
14 | floor4() | ||
15 | { | ||
16 | # Negatives round up, but aren't used. | ||
17 | echo $(($1 / 4 * 4)) | ||
18 | } | ||
19 | |||
20 | ceil4() | ||
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 | |||
29 | losetup_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 | |||
40 | init_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 | |||
62 | samizdat_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 | |||
78 | mountpoint_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 | |||
88 | initialize_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. | ||
118 | choose_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 | |||
141 | filesystem_incomplete() | ||
142 | { | ||
143 | local n | ||
144 | n=$(btrfs filesystem show "$1" | sed -ne 's/.*Total devices \([^ ]*\) .*/\1/p') | ||
145 | [ "$n" != 1 ] | ||
146 | } | ||
147 | |||
148 | open_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 | |||
167 | init_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 | |||
175 | open_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 | |||
190 | init_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 | |||
209 | majmin() | ||
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 | |||
217 | cryptdev_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 | |||
227 | cryptdev_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 | |||
237 | lodev_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 | |||
245 | mountpoint_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 | |||
253 | get_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 | |||
265 | init_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 | |||
280 | start_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 | |||
293 | stop_meter() | ||
294 | { | ||
295 | local endmsg="$*" | ||
296 | kill $meterpid | ||
297 | echo " $endmsg" >&4 | ||
298 | } | ||
299 | |||