]>
Commit | Line | Data |
---|---|---|
b32f9594 JR |
1 | #!/bin/sh |
2 | ||
3 | PREREQ="" | |
4 | ||
5 | prereqs() | |
6 | { | |
7 | echo "$PREREQ" | |
8 | } | |
9 | ||
10 | case $1 in | |
11 | prereqs) | |
12 | prereqs | |
13 | exit 0 | |
14 | ;; | |
15 | esac | |
16 | ||
17 | . /usr/share/initramfs-tools/hook-functions | |
18 | ||
19 | get_root_device() { | |
20 | local device mount type options dump pass | |
21 | ||
22 | if [ ! -r /etc/fstab ]; then | |
23 | return 1 | |
24 | fi | |
25 | ||
26 | grep '^[^#]' /etc/fstab | \ | |
27 | while read device mount type options dump pass; do | |
28 | if [ "$mount" = "/" ]; then | |
29 | echo "$device" | |
30 | return | |
31 | fi | |
32 | done | |
33 | } | |
34 | ||
35 | get_resume_devices() { | |
36 | local device opt count dupe candidates devices | |
37 | candidates="" | |
38 | ||
39 | # First, get a list of potential resume devices | |
40 | ||
41 | # uswsusp | |
42 | if [ -e /etc/uswsusp.conf ]; then | |
43 | device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/uswsusp.conf) | |
44 | if [ -n "$device" ]; then | |
45 | candidates="$candidates $device" | |
46 | fi | |
47 | fi | |
48 | ||
49 | # uswsusp - again... | |
50 | if [ -e /etc/suspend.conf ]; then | |
51 | device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/suspend.conf) | |
52 | if [ -n "$device" ]; then | |
53 | candidates="$candidates $device" | |
54 | fi | |
55 | fi | |
56 | ||
57 | # regular swsusp | |
58 | for opt in $(cat /proc/cmdline); do | |
59 | case $opt in | |
60 | resume=*) | |
61 | device="${opt#resume=}" | |
62 | candidates="$candidates $device" | |
63 | ;; | |
64 | esac | |
65 | done | |
66 | ||
67 | # initramfs-tools | |
68 | if [ -e /etc/initramfs-tools/conf.d/resume ]; then | |
69 | device=$(sed -rn 's/^RESUME[[:space:]]*=[[:space:]]*// p' /etc/initramfs-tools/conf.d/resume) | |
70 | if [ -n "$device" ]; then | |
71 | candidates="$candidates $device" | |
72 | fi | |
73 | fi | |
74 | ||
75 | # Now check the sanity of all candidates | |
76 | devices="" | |
77 | count=0 | |
78 | for device in $candidates; do | |
79 | # Weed out clever defaults | |
80 | if [ "$device" = "<path_to_resume_device_file>" ]; then | |
81 | continue | |
82 | fi | |
83 | ||
84 | # Weed out duplicates | |
85 | dupe=0 | |
86 | for opt in $devices; do | |
87 | if [ "$device" = "$opt" ]; then | |
88 | dupe=1 | |
89 | fi | |
90 | done | |
91 | if [ $dupe -eq 1 ]; then | |
92 | continue | |
93 | fi | |
94 | ||
95 | # This device seems ok | |
96 | devices="$devices $device" | |
97 | count=$(( $count + 1 )) | |
98 | done | |
99 | ||
100 | if [ $count -gt 1 ]; then | |
101 | echo "cryptsetup: WARNING: found more than one resume device candidate:" >&2 | |
102 | for device in $devices; do | |
103 | echo " $device" >&2 | |
104 | done | |
105 | fi | |
106 | ||
107 | if [ $count -gt 0 ]; then | |
108 | echo $devices | |
109 | fi | |
110 | ||
111 | return 0 | |
112 | } | |
113 | ||
114 | node_is_in_crypttab() { | |
115 | local node | |
116 | node="$1" | |
117 | ||
118 | grep -q ^$node /etc/crypttab | |
119 | return $? | |
120 | } | |
121 | ||
122 | get_lvm_deps() { | |
123 | local node deps maj min depnode | |
124 | node="$1" | |
125 | ||
126 | if [ -z $node ]; then | |
127 | echo "cryptsetup: WARNING: get_lvm_deps - invalid arguments" >&2 | |
128 | return 1 | |
129 | fi | |
130 | ||
131 | if ! deps=$(dmsetup deps "$node" 2> /dev/null | sed 's/[^:]*: *//;s/[ (]//g;s/)/ /g'); then | |
132 | echo "cryptsetup: WARNING: failed to find deps for $node" >&2 | |
133 | return 1 | |
134 | fi | |
135 | ||
136 | # We should now have a list of major,minor pairs, e.g. "3,2 3,3" | |
137 | for dep in $deps; do | |
138 | maj=${dep%,*} | |
139 | min=${dep#*,} | |
140 | depnode=$(dmsetup ls | sed -n "s/\\([^ ]*\\) *($maj, $min)/\\1/p" | sed -e "s/[ \t]*$//") | |
141 | if [ -z "$depnode" ]; then | |
142 | continue | |
143 | fi | |
144 | if [ "$(dmsetup table "$depnode" 2> /dev/null | cut -d' ' -f3)" != "crypt" ]; then | |
145 | get_lvm_deps "$depnode" | |
146 | continue | |
147 | fi | |
148 | echo "$depnode" | |
149 | done | |
150 | ||
151 | return 0 | |
152 | } | |
153 | ||
154 | get_device_opts() { | |
155 | local target source link extraopts rootopts opt | |
156 | target="$1" | |
157 | extraopts="$2" | |
158 | KEYSCRIPT="" | |
159 | OPTIONS="" | |
160 | ||
161 | if [ -z "$target" ]; then | |
162 | echo "cryptsetup: WARNING: get_device_opts - invalid arguments" >&2 | |
163 | return 1 | |
164 | fi | |
165 | ||
166 | opt=$( grep ^$target /etc/crypttab | head -1 | sed 's/[[:space:]]\+/ /g' ) | |
167 | source=$( echo $opt | cut -d " " -f2 ) | |
168 | key=$( echo $opt | cut -d " " -f3 ) | |
169 | rootopts=$( echo $opt | cut -d " " -f4- ) | |
170 | ||
171 | if [ -z "$opt" ] || [ -z "$source" ] || [ -z "$key" ] || [ -z "$rootopts" ]; then | |
172 | echo "cryptsetup: WARNING: invalid line in /etc/crypttab - $opt" >&2 | |
173 | return 1 | |
174 | fi | |
175 | ||
176 | # Sanity checks for $source | |
177 | if [ -h "$source" ]; then | |
178 | link=$(readlink -nqe "$source") | |
179 | if [ -z "$link" ]; then | |
180 | echo "cryptsetup: WARNING: $source is a dangling symlink" >&2 | |
181 | return 1 | |
182 | fi | |
183 | ||
184 | if [ "$link" != "${link#/dev/mapper/}" ]; then | |
185 | echo "cryptsetup: NOTE: using $link instead of $source for $target" >&2 | |
186 | source="$link" | |
187 | fi | |
188 | fi | |
189 | ||
190 | # Sanity checks for $key | |
191 | if [ "$key" = "/dev/random" ] || [ "$key" = "/dev/urandom" ]; then | |
192 | echo "cryptsetup: WARNING: target $target has a random key, skipped" >&2 | |
193 | return 1 | |
194 | fi | |
195 | ||
196 | if [ -n "$extraopts" ]; then | |
197 | rootopts="$extraopts,$rootopts" | |
198 | fi | |
199 | ||
200 | # We have all the basic options, let's go trough them | |
201 | OPTIONS="target=$target,source=$source,key=$key" | |
202 | local IFS=", " | |
203 | unset HASH_FOUND | |
204 | unset LUKS_FOUND | |
205 | for opt in $rootopts; do | |
206 | case $opt in | |
207 | cipher=*) | |
208 | OPTIONS="$OPTIONS,$opt" | |
209 | ;; | |
210 | hash=*) | |
211 | OPTIONS="$OPTIONS,$opt" | |
212 | HASH_FOUND=1 | |
213 | ;; | |
214 | size=*) | |
215 | OPTIONS="$OPTIONS,$opt" | |
216 | ;; | |
217 | lvm=*) | |
218 | OPTIONS="$OPTIONS,$opt" | |
219 | ;; | |
220 | keyscript=*) | |
221 | opt=${opt#keyscript=} | |
222 | if [ ! -x "/lib/cryptsetup/scripts/$opt" ] && [ ! -x "$opt" ]; then | |
223 | echo "cryptsetup: WARNING: target $target has an invalid keyscript, skipped" >&2 | |
224 | return 1 | |
225 | fi | |
226 | KEYSCRIPT="$opt" | |
227 | OPTIONS="$OPTIONS,keyscript=/keyscripts/$(basename "$opt")" | |
228 | ;; | |
229 | tries=*) | |
230 | OPTIONS="$OPTIONS,$opt" | |
231 | ;; | |
232 | luks) | |
233 | LUKS_FOUND=1 | |
234 | ;; | |
235 | *) | |
236 | # Presumably a non-supported option | |
237 | ;; | |
238 | esac | |
239 | done | |
240 | ||
241 | # Warn for missing hash option, unless we have a LUKS partition | |
242 | if [ -z "$HASH_FOUND" ] && [ -z "$LUKS_FOUND" ]; then | |
243 | echo "WARNING: Option hash missing in crypttab for target $target, assuming ripemd160." >&2 | |
244 | echo " If this is wrong, this initramfs image will not boot." >&2 | |
245 | echo " Please read /usr/share/doc/cryptsetup/README.initramfs.gz and add" >&2 | |
246 | echo " the correct hash option to your /etc/crypttab." >&2 | |
247 | fi | |
248 | ||
249 | # If keyscript is set, the "key" is just an argument to the script | |
250 | if [ "$key" != "none" ] && [ -z "$KEYSCRIPT" ]; then | |
251 | echo "cryptsetup: WARNING: target $target uses a key file, skipped" >&2 | |
252 | return 1 | |
253 | fi | |
254 | } | |
255 | ||
256 | get_device_modules() { | |
257 | local node value cipher blockcipher ivhash | |
258 | node="$1" | |
259 | ||
260 | # Check the ciphers used by the active root mapping | |
261 | value=$(dmsetup table "$node" | cut -d " " -f4) | |
262 | cipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f1) | |
263 | blockcipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f2) | |
264 | ivhash=$(echo "$value" | cut -d ":" -s -f2) | |
265 | ||
266 | if [ -n "$cipher" ]; then | |
267 | echo "$cipher" | |
268 | else | |
269 | return 1 | |
270 | fi | |
271 | ||
272 | if [ -n "$blockcipher" ] && [ "$blockcipher" != "plain" ]; then | |
273 | echo "$blockcipher" | |
274 | fi | |
275 | ||
276 | if [ -n "$ivhash" ] && [ "$ivhash" != "plain" ]; then | |
277 | echo "$ivhash" | |
278 | fi | |
279 | return 0 | |
280 | } | |
281 | ||
282 | canonical_device() { | |
283 | local dev altdev | |
284 | dev="$1" | |
285 | ||
286 | altdev="${dev#LABEL=}" | |
287 | if [ "$altdev" != "$dev" ]; then | |
288 | dev="/dev/disk/by-label/$altdev" | |
289 | fi | |
290 | ||
291 | altdev="${dev#UUID=}" | |
292 | if [ "$altdev" != "$dev" ]; then | |
293 | dev="/dev/disk/by-uuid/$altdev" | |
294 | fi | |
295 | ||
296 | if [ -h "$dev" ]; then | |
297 | dev=$(readlink -e "$dev") | |
298 | fi | |
299 | ||
300 | altdev="${dev#/dev/mapper/}" | |
301 | if [ "$altdev" != "$dev" ]; then | |
302 | echo "$altdev" | |
303 | return 0 | |
304 | fi | |
305 | ||
306 | return 1 | |
307 | } | |
308 | ||
309 | add_device() { | |
310 | local node nodes opts lastopts i count | |
311 | nodes="$1" | |
312 | opts="" # Applied to all nodes | |
313 | lastopts="" # Applied to last node | |
314 | ||
315 | if [ -z "$nodes" ]; then | |
316 | return 0 | |
317 | fi | |
318 | ||
319 | # Check that it is a node under /dev/mapper/ | |
320 | nodes=$(canonical_device "$nodes") || return 0 | |
321 | ||
322 | # Can we find this node in crypttab | |
323 | if ! node_is_in_crypttab "$nodes"; then | |
324 | # dm node but not in crypttab, is it a lvm device backed by dm-crypt nodes? | |
325 | lvmnodes=$(get_lvm_deps "$nodes") || return 1 | |
326 | ||
327 | # not backed by any dm-crypt nodes; stop here | |
328 | if [ -z "$lvmnodes" ]; then | |
329 | return 0 | |
330 | fi | |
331 | ||
332 | # It is a lvm device! | |
333 | lastopts="lvm=$nodes" | |
334 | nodes="$lvmnodes" | |
335 | fi | |
336 | ||
337 | # Prepare to setup each node | |
338 | count=$(echo "$nodes" | wc -w) | |
339 | i=1 | |
340 | for node in $nodes; do | |
341 | # Prepare the additional options | |
342 | if [ $i -eq $count ]; then | |
343 | if [ -z "$opts" ]; then | |
344 | opts="$lastopts" | |
345 | else | |
346 | opts="$opts,$lastopts" | |
347 | fi | |
348 | fi | |
349 | ||
350 | # Get crypttab root options | |
351 | if ! get_device_opts "$node" "$opts"; then | |
352 | continue | |
353 | fi | |
354 | echo "$OPTIONS" >> "$DESTDIR/conf/conf.d/cryptroot" | |
355 | ||
356 | # If we have a keyscript, make sure it is included | |
357 | if [ -n "$KEYSCRIPT" ]; then | |
358 | if [ ! -d "$DESTDIR/keyscripts" ]; then | |
359 | mkdir "$DESTDIR/keyscripts" | |
360 | fi | |
361 | ||
362 | if [ -e "/lib/cryptsetup/scripts/$KEYSCRIPT" ]; then | |
363 | copy_exec "/lib/cryptsetup/scripts/$KEYSCRIPT" /keyscripts | |
364 | elif [ -e "$KEYSCRIPT" ]; then | |
365 | copy_exec "$KEYSCRIPT" /keyscripts | |
366 | else | |
367 | echo "cryptsetup: WARNING: failed to find keyscript $KEYSCRIPT" >&2 | |
368 | continue | |
369 | fi | |
370 | fi | |
371 | ||
372 | # Calculate needed modules | |
373 | modules=$(get_device_modules $node | sort | uniq) | |
374 | if [ -z "$modules" ]; then | |
375 | echo "cryptsetup: WARNING: failed to determine cipher modules to load for $node" >&2 | |
376 | continue | |
377 | fi | |
378 | echo dm_mod | |
379 | echo dm_crypt | |
380 | echo "$modules" | |
381 | ||
382 | i=$(( $i + 1 )) | |
383 | done | |
384 | ||
385 | return 0 | |
386 | } | |
387 | ||
388 | add_crypto_modules() { | |
389 | local mod file altmod found genericfound | |
390 | mod="$1" | |
391 | found="" | |
392 | genericfound="" | |
393 | ||
394 | if [ -z "$mod" ]; then | |
395 | return 1 | |
396 | fi | |
397 | ||
398 | # We have several potential sources of modules (in order of preference): | |
399 | # | |
400 | # a) /lib/modules/$VERSION/kernel/arch/$ARCH/crypto/$mod-$specific.ko | |
401 | # b) /lib/modules/$VERSION/kernel/crypto/$mod_generic.ko | |
402 | # c) /lib/modules/$VERSION/kernel/crypto/$mod.ko | |
403 | # | |
404 | # and (currently ignored): | |
405 | # | |
406 | # d) /lib/modules/$VERSION/kernel/drivers/crypto/$specific-$mod.ko | |
407 | ||
408 | for file in $(find "$MODULESDIR/kernel/arch/" -name "$mod-*.ko"); do | |
409 | altmod="${file##*/}" | |
410 | altmod="${altmod%.ko}" | |
411 | manual_add_modules "$altmod" | |
412 | found="yes" | |
413 | done | |
414 | ||
415 | for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}_generic.ko"); do | |
416 | altmod="${file##*/}" | |
417 | altmod="${altmod%.ko}" | |
418 | manual_add_modules "$altmod" | |
419 | found="yes" | |
420 | genericfound="yes" | |
421 | done | |
422 | ||
423 | if [ -z "$genericfound" ]; then | |
424 | for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}.ko"); do | |
425 | altmod="${file##*/}" | |
426 | altmod="${altmod%.ko}" | |
427 | manual_add_modules "$altmod" | |
428 | found="yes" | |
429 | done | |
430 | fi | |
431 | ||
432 | if [ -z "$found" ]; then | |
433 | return 1 | |
434 | fi | |
435 | ||
436 | return 0 | |
437 | } | |
438 | ||
439 | # | |
440 | # Begin real processing | |
441 | # | |
442 | ||
443 | setup="no" | |
444 | rootdev="" | |
445 | resumedevs="" | |
446 | ||
447 | # Find the root and resume device(s) | |
448 | if [ -r /etc/crypttab ]; then | |
449 | rootdev=$(get_root_device) | |
450 | if [ -z "$rootdev" ]; then | |
451 | echo "cryptsetup: WARNING: could not determine root device from /etc/fstab" >&2 | |
452 | fi | |
453 | resumedevs=$(get_resume_devices) | |
454 | fi | |
455 | ||
456 | # Load the config opts and modules for each device | |
457 | for dev in $rootdev $resumedevs; do | |
458 | if ! modules=$(add_device "$dev"); then | |
459 | echo "cryptsetup: FAILURE: could not determine configuration for $dev" >&2 | |
460 | continue | |
461 | fi | |
462 | ||
463 | setup="yes" | |
464 | for mod in $modules; do | |
465 | add_crypto_modules $mod | |
466 | done | |
467 | done | |
468 | ||
469 | # With large initramfs, we always add a basic subset of modules | |
470 | if [ "$MODULES" != "dep" ]; then | |
471 | for mod in aes sha256 cbc; do | |
472 | add_crypto_modules $mod | |
473 | done | |
474 | fi | |
475 | ||
476 | # See if we need to add the basic components | |
477 | if [ "$MODULES" != "dep" ] || [ "$setup" = "yes" ]; then | |
478 | for mod in dm_mod dm_crypt; do | |
479 | manual_add_modules $mod | |
480 | done | |
481 | ||
482 | copy_exec /sbin/cryptsetup | |
483 | copy_exec /sbin/dmsetup | |
484 | # copy_exec /lib/cryptsetup/askpass | |
485 | fi | |
486 | ||
487 | exit 0 |