]>
Commit | Line | Data |
---|---|---|
c7271994 MT |
1 | #!/bin/bash |
2 | HEADER="\ | |
3 | ############################################################################### | |
4 | # # | |
5 | # IPFire.org - A linux based firewall # | |
6 | # Copyright (C) 2009 Michael Tremer & Christian Schmidt # | |
7 | # # | |
8 | # This program is free software: you can redistribute it and/or modify # | |
9 | # it under the terms of the GNU General Public License as published by # | |
10 | # the Free Software Foundation, either version 3 of the License, or # | |
11 | # (at your option) any later version. # | |
12 | # # | |
13 | # This program is distributed in the hope that it will be useful, # | |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
16 | # GNU General Public License for more details. # | |
17 | # # | |
18 | # You should have received a copy of the GNU General Public License # | |
19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
20 | # # | |
21 | ############################################################################### | |
22 | " | |
23 | ||
24 | ## GLOBAL VARIABLES ARE UPPERCASE | |
25 | ## LOCAL VARIABLES ARE LOWERCASE | |
26 | ||
27 | VERBOSE= | |
28 | FORCE= | |
29 | TARGET= | |
30 | KERNEL=$(uname -r) | |
31 | MODULES= | |
32 | ||
33 | TMPDIR=$(mktemp -d) | |
34 | ||
35 | # Check if we are root | |
36 | if [ $UID != 0 ]; then | |
37 | error "$0 must be run as root." | |
38 | exit 1 | |
39 | fi | |
40 | ||
41 | # Usage | |
42 | function usage() { | |
43 | echo "$0 [--help] [-f] [-v] <out-initrd-image> <kernel-version>" | |
44 | echo " [--with=<module>]" | |
45 | echo | |
46 | echo "example: $0 /boot/myinitramfs.img \`uname -r\`" | |
47 | } | |
48 | ||
49 | # Setting verbose mode | |
50 | function set_verbose() { | |
51 | case "$1" in | |
52 | yes|y|on|1) | |
53 | VERBOSE=-v | |
54 | ;; | |
55 | no|n|off|0) | |
56 | VERBOSE= | |
57 | ;; | |
58 | esac | |
59 | } | |
60 | ||
61 | # Returns if verbose is on or not | |
62 | function is_verbose() { | |
63 | [ -n "$VERBOSE" ] && return 0 | |
64 | return 1 | |
65 | } | |
66 | ||
67 | # Like is_verbose but prints | |
68 | # the content of $VERBOSE | |
69 | function get_verbose() { | |
70 | echo "$VERBOSE" | |
71 | is_verbose | |
72 | } | |
73 | ||
74 | # Prints text if verbose is on | |
75 | function vecho() { | |
76 | is_verbose && echo "$@" | |
77 | } | |
78 | ||
79 | # Prints error if verbose is on | |
80 | function error() { | |
81 | vecho "$@" >&2 | |
82 | } | |
83 | ||
84 | function compress() { | |
85 | cd - >/dev/null | |
86 | IMAGE=$(mktemp) | |
87 | vecho "[TASK] Compressing image $TARGET..." | |
88 | (cd $TMPDIR && find . | cpio -H newc --quiet -o >| $IMAGE) || exit 1 | |
89 | gzip -c9 $IMAGE > $TARGET | |
90 | } | |
91 | ||
92 | function findone() { | |
93 | find "$@" | awk '{ print $1; exit; }' | |
94 | } | |
95 | ||
96 | function findall() { | |
97 | find "$@" | |
98 | } | |
99 | ||
100 | qpushd() { | |
101 | pushd "$1" >/dev/null 2>&1 | |
102 | } | |
103 | ||
104 | qpopd() { | |
105 | popd >/dev/null 2>&1 | |
106 | } | |
107 | ||
108 | function read_link() { | |
109 | READLINK=$(readlink $1) | |
110 | if grep -q "^/" <<< $READLINK; then | |
111 | echo $READLINK | |
112 | else | |
113 | echo "$(dirname $1)/$READLINK" | |
114 | fi | |
115 | } | |
116 | ||
117 | function get_dso_deps() { | |
118 | local bin="$1" | |
119 | shift | |
120 | ||
121 | declare -a FILES | |
122 | declare -a NAMES | |
123 | ||
124 | local LDSO="/lib/ld-linux.so.2" | |
125 | ||
126 | declare -i n=0 | |
127 | while read NAME I0 FILE ADDR I1 ; do | |
128 | [ "$FILE" == "not" ] && FILE="$FILE $ADDR" | |
129 | [ "$NAME" == "not" ] && NAME="$NAME $I0" | |
130 | NAMES[$n]="$NAME" | |
131 | FILES[$n]="$FILE" | |
132 | let n++ | |
133 | done << EOF | |
134 | $(LD_TRACE_PRELINKING=1 LD_WARN= LD_TRACE_LOADED_OBJECTS=1 \ | |
135 | $LDSO $bin 2>/dev/null) | |
136 | EOF | |
137 | ||
138 | [ ${#FILES[*]} -eq 0 ] && return 1 | |
139 | ||
140 | # we don't want the name of the binary in the list | |
141 | if [ "${FILES[0]}" == "$bin" ]; then | |
142 | FILES[0]="" | |
143 | NAMES[0]="" | |
144 | [ ${#FILES[*]} -eq 1 ] && return 1 | |
145 | fi | |
146 | ||
147 | declare -i n=0 | |
148 | while [ $n -lt ${#FILES[*]} ]; do | |
149 | local FILE="${FILES[$n]}" | |
150 | local NAME="${NAMES[$n]}" | |
151 | if [ "$FILE" == "not found" -o "$NAME" == "not found" ]; then | |
152 | cat 1>&2 <<EOF | |
153 | There are missing files on your system. The dynamic object $bin | |
154 | requires ${NAMES[$n]} n order to properly function. mkinitramfs cannot continue. | |
155 | EOF | |
156 | return 1 | |
157 | fi | |
158 | case "$FILE" in | |
159 | /lib*) | |
160 | TLIBDIR=`echo "$FILE" | sed 's,\(/lib[^/]*\)/.*$,\1,'` | |
161 | BASE=`basename "$FILE"` | |
162 | if [ -f "$TLIBDIR/$BASE" ]; then | |
163 | FILE="$TLIBDIR/$BASE" | |
164 | fi | |
165 | FILES[$n]="$FILE" | |
166 | ;; | |
167 | esac | |
168 | let n++ | |
169 | done | |
170 | echo "${FILES[@]}" | |
171 | } | |
172 | ||
173 | function install() { | |
174 | local file dest | |
175 | for file in $@; do | |
176 | local msg="[FILE]" | |
177 | ||
178 | ## Check if this is an absolute path | |
179 | if [ "$(basename $file)" = "$file" ]; then | |
180 | file=$(which $file) | |
181 | fi | |
182 | ||
183 | # Destination file | |
184 | dest="$TMPDIR$file" | |
185 | [ -e "$dest" ] && continue | |
186 | ||
187 | mkdir -p "$(dirname $dest)" 2>/dev/null | |
188 | ||
189 | local old_indent=$INDENT | |
190 | INDENT=" $INDENT" | |
191 | ||
192 | [ "${file%%.ko}" != "${file}" ] && msg="[KMOD]" | |
193 | [ -L "$file" ] && msg="[SYML]" | |
194 | #vecho "$msg$INDENT$file -> $dest" | |
195 | vecho "$msg$INDENT$file" | |
196 | ||
197 | # Check if $file is a symlink | |
198 | if [ -L "$file" ]; then | |
199 | install $(read_link $file) | |
200 | fi | |
201 | ||
202 | if [ "${file%%.ko}" != "${file}" ]; then | |
203 | for i in $(moduledep $file); do | |
204 | [ "$(locatemodule $i)" = "$file" ] && continue | |
205 | installmodule $i | |
206 | done | |
207 | fi | |
208 | ||
209 | cp -ld $file $dest | |
210 | ||
211 | # Check if file is a script file | |
212 | if [ "$(dd if=$file bs=2 count=1 2>/dev/null)" = "#!" ]; then | |
213 | install $(head -n 1 $file | cut -c3-) | |
214 | # Check if file is a kernel module | |
215 | elif [ "${file%%.ko}" != "${file}" ]; then | |
216 | local firmware | |
217 | for firmware in $(modinfo -F firmware $file 2>/dev/null); do | |
218 | firmware="/lib/firmware/$firmware" | |
219 | [ -e "$firmware" ] && install $firmware | |
220 | done | |
221 | else | |
222 | for dep in $(get_dso_deps "$file"); do | |
223 | install $dep | |
224 | done | |
225 | fi | |
226 | ||
227 | INDENT=$old_indent | |
228 | done | |
229 | } | |
230 | ||
231 | # find module dependencies | |
232 | function moduledep() { | |
233 | local deps mpargs | |
234 | if [ "$1" == "--ignore-install" ]; then | |
235 | mpargs="$mpargs --ignore-install" | |
236 | shift | |
237 | fi | |
238 | local module=$(basename ${1%%.ko}) | |
239 | modprobe $mpargs --set-version $KERNEL --show-depends $module 2>/dev/null | \ | |
240 | awk '/^insmod / { print gensub(".*/","","g",$2) }' | \ | |
241 | while read foo; do \ | |
242 | [ "${foo%%.ko}" != "$1" ] && \ | |
243 | echo -n "${foo%%.ko} "; \ | |
244 | done | |
245 | } | |
246 | ||
247 | # XXX May be, we can drop this... | |
248 | # This loops to make sure it resolves dependencies of dependencies of... | |
249 | function resolvemoduledeps () { | |
250 | local dep | |
251 | local deps | |
252 | local module | |
253 | local newmodules | |
254 | local modules=$@ | |
255 | ||
256 | before=0; after=1 | |
257 | while [ $before != $after ]; do | |
258 | newmodules= | |
259 | before=$(wc -c <<< $modules) | |
260 | for module in $modules; do | |
261 | deps=$(moduledep $module) | |
262 | is_verbose && echo "Module $module depends on: $deps" | |
263 | newmodules="$newmodules $module $deps" | |
264 | done | |
265 | modules=$(for i in $newmodules; do echo $i; done | sort -u) | |
266 | after=$(wc -c <<< $modules) | |
267 | done | |
268 | echo $modules | |
269 | } | |
270 | ||
271 | function locatemodule() { | |
272 | local mpargs="" | |
273 | if [ "$1" == "--ignore-install" ]; then | |
274 | mpargs="$mpargs --ignore-install" | |
275 | shift | |
276 | fi | |
277 | local path=$(modprobe $mpargs --set-version $KERNEL --show-depends $1 2>/dev/null | \ | |
278 | awk '/^insmod / { print $2; }' | tail -n 1) | |
279 | [ -n "$path" -a -f "$path" ] && echo $path | |
280 | } | |
281 | ||
282 | function installmodule() { | |
283 | local module | |
284 | local load | |
285 | for module in $@; do | |
286 | [ "$module" = "--load" ] && load=1 | |
287 | module=$(locatemodule $module) | |
288 | [ -z "$module" ] && continue | |
289 | ||
290 | install $module | |
291 | done | |
292 | if [ "$load" = "1" ]; then | |
293 | for module in $@; do | |
294 | [ "$module" = "--load" ] && continue | |
295 | cat >> $TMPDIR/sbin/real-init <<EOF | |
296 | vecho "Loading module $i..." | |
297 | modprobe $i | |
298 | EOF | |
299 | done | |
300 | fi | |
301 | } | |
302 | ||
303 | resolve_device_name() { | |
304 | if [[ "$1" =~ ^/dev ]]; then | |
305 | echo $1 | |
306 | else | |
307 | findfs $1 | |
308 | fi | |
309 | } | |
310 | ||
311 | function finalize() { | |
312 | qpopd | |
313 | ||
314 | # Adding modules | |
315 | depmod -a $KERNEL | |
316 | installmodule $MODULES | |
317 | ||
318 | # Build module deps file so we can use modprobe | |
319 | vecho "[TASK] Running depmod..." | |
320 | depmod -a -b "$TMPDIR" $KERNEL | |
321 | ||
322 | # ldconfig | |
323 | install /etc/ld.so.conf | |
324 | [ -d "/etc/ld.so.conf.d" ] && \ | |
325 | for i in $(find /etc/ld.so.conf.d -type f); do | |
326 | install $i | |
327 | done | |
328 | vecho "[TASK] Running ldconfig..." | |
329 | ldconfig -r $TMPDIR | |
330 | ||
331 | # Compressing | |
332 | compress | |
333 | rm -rf $TMPDIR 2>/dev/null | |
334 | } | |
335 | ||
336 | # resolve a device node to its major:minor numbers in decimal or hex | |
337 | function get_numeric_dev() { | |
338 | ( fmt="%d:%d" | |
339 | if [ "$1" == "hex" ]; then | |
340 | fmt="%x:%x" | |
341 | fi | |
342 | ls -lH "$2" | awk '{ sub(/,/, "", $5); printf("'"$fmt"'", $5, $6); }' | |
343 | ) 2>/dev/null | |
344 | } | |
345 | ||
346 | function resolve_device_name() { | |
347 | if [[ "$1" =~ ^/dev ]]; then | |
348 | echo $1 | |
349 | else | |
350 | findfs $1 | |
351 | fi | |
352 | } | |
353 | ||
354 | function finddevnoinsys() { | |
355 | majmin="$1" | |
356 | if [ -n "$majmin" ]; then | |
357 | dev=$(for x in /sys/block/* ; do find $x/ -name dev ; done | while read device ; do \ | |
358 | echo "$majmin" | cmp -s $device && echo $device ; done) | |
359 | if [ -n "$dev" ]; then | |
360 | dev=${dev%%/dev} | |
361 | dev=${dev%%/} | |
362 | echo "$dev" | |
363 | return 0 | |
364 | fi | |
365 | fi | |
366 | return 1 | |
367 | } | |
368 | ||
369 | findblockdevinsys() { | |
370 | devname=$(resolve_device_name "$1") | |
371 | if [[ "$devname" =~ ^/sys/block/ ]]; then | |
372 | echo "$devname" | |
373 | fi | |
374 | majmin=$(get_numeric_dev dec $devname) | |
375 | finddevnoinsys "$majmin" | |
376 | } | |
377 | ||
378 | findstoragedriverinsys () { | |
379 | while [ ! -L device ]; do | |
380 | for slave in $(ls -d slaves/* 2>/dev/null) ; do | |
381 | slavename=${slave##*/} | |
382 | case " $slavestried " in | |
383 | *" $slavename "*) | |
384 | continue | |
385 | ;; | |
386 | *) | |
387 | slavestried="$slavestried $slavename" | |
388 | qpushd $slave | |
389 | findstoragedriverinsys | |
390 | qpopd | |
391 | ;; | |
392 | esac | |
393 | done | |
394 | [ "$PWD" = "/sys" ] && return | |
395 | cd .. | |
396 | done | |
397 | cd $(read_link ./device) | |
398 | if echo $PWD | grep -q /virtio-pci/ ; then | |
399 | installmodule --load virtio_pci | |
400 | fi | |
401 | while [ "$PWD" != "/sys/devices" ]; do | |
402 | deps= | |
403 | if [ -f modalias ]; then | |
404 | installmodule --load $(cat modalias) | |
405 | fi | |
406 | ||
407 | [ -z "$deps" -a -L driver/module ] && \ | |
408 | deps=$(basename $(read_link driver/module)) | |
409 | installmodule --load $deps | |
410 | cd .. | |
411 | done | |
412 | } | |
413 | ||
414 | function findstoragedriver() { | |
415 | for device in $@; do | |
416 | case " $handleddevices " in | |
417 | *" $device "*) | |
418 | continue ;; | |
419 | *) handleddevices="$handleddevices $device" ;; | |
420 | esac | |
421 | vecho "[INFO] Looking for driver for device $device" | |
422 | if [[ "$device" =~ ^/sys ]]; then | |
423 | device=${device##*/} | |
424 | fi | |
425 | sysfs="" | |
426 | device=$(echo "$device" | sed 's,/,!,g') | |
427 | if [ -d /sys/block/$device/ ]; then | |
428 | sysfs="/sys/block/$device" | |
429 | else | |
430 | sysfs=$(for x in /sys/block/*; do findone $x/ -type d -name $device; done) | |
431 | fi | |
432 | [ -z "$sysfs" ] && return | |
433 | qpushd $sysfs | |
434 | findstoragedriverinsys | |
435 | qpopd | |
436 | done | |
437 | } | |
438 | ||
439 | # Main | |
440 | while [ $# -gt 0 ] ; do | |
441 | case $1 in | |
442 | --help) | |
443 | usage | |
444 | exit 0 | |
445 | ;; | |
446 | -f|--force) | |
447 | FORCE=yes | |
448 | ;; | |
449 | -v|--verbose) | |
450 | set_verbose on | |
451 | ;; | |
452 | --with=*) | |
453 | MODULES="$MODULES ${1#--with=*}" | |
454 | ;; | |
455 | --with-net) | |
456 | WITH_NET=1 | |
457 | ;; | |
458 | *) | |
459 | if [ -z "$target" ] ; then | |
460 | target=$1 | |
461 | elif [ -z "$kernel" ] ; then | |
462 | kernel=$1 | |
463 | else | |
464 | echo "Unknown option or parameter \"$1\"" | |
465 | usage | |
466 | exit 1 | |
467 | fi | |
468 | ;; | |
469 | esac | |
470 | ||
471 | shift | |
472 | done | |
473 | ||
474 | TARGET=${target-$TARGET} | |
475 | KERNEL=${kernel-$KERNEL} | |
476 | ||
477 | if [ -z "$TARGET" ]; then | |
478 | usage | |
479 | exit 1 | |
480 | fi | |
481 | ||
482 | [[ "$TARGET" =~ "^/" ]] && TARGET="$PWD/$TARGET" | |
483 | ||
484 | if [ -z "$FORCE" ] && [ -e "$TARGET" ]; then | |
485 | echo "Image $TARGET already exists. Use -f to overwrite" | |
486 | exit 1 | |
487 | fi | |
488 | ||
489 | # Changing to our dir, where we do our actions in | |
490 | qpushd $TMPDIR || exit 1 | |
491 | ||
492 | # Make directory structure | |
493 | mkdir -p bin sbin dev sys proc sysroot \ | |
494 | etc/udev/rules.d lib/udev/rules.d | |
495 | ||
496 | # Install some essential binaries | |
497 | install bash blkid chmod cat cut dmesg env find grep head ip kbd_mode \ | |
498 | kill killall5 less ln \ | |
499 | ls lsmod mkdir mknod modprobe mount mountpoint openvt pidof ps rm sed \ | |
500 | setfont sh sleep switch_root udevadm udevd umount \ | |
501 | /lib/udev/console_init | |
502 | ||
503 | # Copy modprobe.conf and friends over | |
504 | [ -e /etc/modprobe.conf ] && install /etc/modprobe.conf | |
505 | for f in $(find /etc/modprobe.d -type f); do | |
506 | install $f | |
507 | done | |
508 | ||
509 | # Install an empty fstab | |
510 | touch $TMPDIR/etc/fstab | |
511 | ||
512 | # terminfo bits make things work better if you fall into interactive mode | |
513 | [ -d "/usr/lib/terminfo" ] && \ | |
514 | for f in $(find /usr/lib/terminfo -type f); do | |
515 | install $f | |
516 | done | |
517 | ||
518 | # Add localization | |
519 | if [ -e "/etc/sysconfig/console" ]; then | |
520 | install /etc/sysconfig/console | |
521 | . /etc/sysconfig/console | |
522 | fi | |
523 | [ -z "$FONT" ] && FONT="LatArCyrHeb-16" | |
524 | for i in /lib/kbd/consolefonts/$FONT.*; do | |
525 | mkdir -p $TMPDIR/$(dirname $i) 2>/dev/null || true | |
526 | cp -f $i $TMPDIR/$i | |
527 | case "$i" in | |
528 | *.gz) | |
529 | gzip -fd $TMPDIR/$i | |
530 | ;; | |
531 | *.bz2) | |
532 | bzip2 -fd $TMPDIR/$i | |
533 | ;; | |
534 | esac | |
535 | done | |
536 | ||
537 | cat > init <<'EOF' | |
538 | #!/bin/sh | |
539 | ||
540 | # Mounting directories | |
541 | mount -t proc proc /proc | |
542 | mount -t sysfs /sys /sys | |
543 | mount -t tmpfs -o mode=0755 udev /dev | |
544 | ||
545 | # Silencing kernel | |
546 | echo > /proc/sys/kernel/printk "1 4 1 7" | |
547 | ||
548 | # Adding important dev nodes | |
549 | mknod /dev/console c 5 1 | |
550 | mknod /dev/null c 1 3 | |
551 | mknod /dev/kmsg c 1 11 | |
552 | mknod /dev/ptmx c 5 2 | |
553 | mknod /dev/fb c 29 0 | |
554 | mknod /dev/systty c 4 0 | |
555 | ||
556 | # XXX really we need to openvt too, in case someting changes the | |
557 | # color palette and then changes vts on fbcon before gettys start. | |
558 | # (yay, fbcon bugs!) | |
559 | for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do | |
560 | mknod /dev/tty$i c 4 $i | |
561 | done | |
562 | ||
563 | for i in 0 1 2 3 ; do | |
564 | mknod /dev/ttyS$i c 4 $(($i + 64)) | |
565 | done | |
566 | ||
567 | mkdir -m 1777 /dev/shm | |
568 | ln -s /proc/self/fd /dev/fd | |
569 | ln -s fd/0 /dev/stdin | |
570 | ln -s fd/1 /dev/stdout | |
571 | ln -s fd/2 /dev/stderr | |
572 | ||
573 | mkdir /dev/pts | |
574 | mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts | |
575 | ||
576 | exec sbin/real-init | |
577 | EOF | |
578 | chmod 755 init | |
579 | ||
580 | # Write out real-init | |
581 | touch sbin/real-init; chmod 755 sbin/real-init | |
582 | cat > sbin/real-init <<'EOF' | |
583 | #!/bin/bash | |
584 | $HEADER | |
585 | ||
586 | export PATH=/sbin:/bin:/usr/sbin:/usr/bin | |
587 | export TERM=linux | |
588 | ||
589 | init="/sbin/init" | |
590 | VERBOSE=-v | |
591 | ||
592 | READONLY=0 | |
593 | SHELL=0 | |
594 | ESHELL=0 | |
595 | ||
596 | function emergency_shell() | |
597 | { | |
598 | echo "Bug in initramfs /init detected. Dropping to a shell. Good luck!" | |
599 | echo | |
600 | bash | |
601 | } | |
602 | trap "emergency_shell" 0 2 | |
603 | ||
604 | # exit immediately if a command fails | |
605 | set -e | |
606 | ||
607 | # Setting verbose mode | |
608 | function set_verbose() { | |
609 | case "$1" in | |
610 | yes|y|on|1) | |
611 | VERBOSE=-v | |
612 | ;; | |
613 | no|n|off|0) | |
614 | VERBOSE= | |
615 | ;; | |
616 | esac | |
617 | } | |
618 | ||
619 | # Returns if verbose is on or not | |
620 | function is_verbose() { | |
621 | [ -n "$VERBOSE" ] && return 0 | |
622 | return 1 | |
623 | } | |
624 | ||
625 | # Like is_verbose but prints | |
626 | # the content of $VERBOSE | |
627 | function get_verbose() { | |
628 | echo "$VERBOSE" | |
629 | is_verbose | |
630 | } | |
631 | ||
632 | # Prints text if verbose is on | |
633 | function vecho() { | |
634 | if is_verbose; then echo "$@"; fi | |
635 | } | |
636 | ||
637 | # Prints error if verbose is on | |
638 | function error() { | |
639 | vecho "$@" >&2 | |
640 | } | |
641 | ||
642 | /lib/udev/console_init tty0 | |
643 | ||
644 | # Disable hotplugging | |
645 | echo "" > /proc/sys/kernel/hotplug | |
646 | ||
647 | # Parse kernel commandline options | |
648 | for o in $(cat /proc/cmdline) ; do | |
649 | case $o in | |
650 | init=*) | |
651 | init=${o#init=} | |
652 | ;; | |
653 | ro) | |
654 | READONLY=1 | |
655 | ;; | |
656 | rw) | |
657 | READONLY=0 | |
658 | ;; | |
659 | quiet) | |
660 | set_verbose no | |
661 | ;; | |
662 | shell) | |
663 | SHELL=1 | |
664 | ;; | |
665 | eshell) | |
666 | ESHELL=1 | |
667 | ;; | |
668 | blacklist=*) | |
669 | echo "blacklist ${o#blacklist=}" >> /etc/modprobe.conf | |
670 | ;; | |
671 | *) | |
672 | m=$(echo $o |cut -s -d . -f 1) | |
673 | opt=$(echo $o |cut -s -d . -f 2-) | |
674 | if [ -z "$m" -o -z "$opt" ]; then | |
675 | continue | |
676 | fi | |
677 | p=$(echo $opt |cut -s -d = -f 1) | |
678 | v=$(echo $opt |cut -s -d = -f 2-) | |
679 | if [ -z "$p" -o -z "$v" ]; then | |
680 | continue | |
681 | fi | |
682 | echo "options $m $p=$v" >> /etc/modprobe.conf | |
683 | ;; | |
684 | esac | |
685 | done | |
686 | ||
687 | vecho "kernel commandline: $(cat /proc/cmdline)" | |
688 | EOF | |
689 | ||
690 | if [ "${WITH_NET}" = "1" ]; then | |
691 | MODULES="$MODULES af_packet" | |
692 | for module in /lib/modules/$KERNEL/kernel/drivers/net/{,*/}*; do | |
693 | MODULES="$MODULES $(basename ${module/.ko})" | |
694 | done | |
695 | ||
696 | install arping curl dhclient ip ping sha1sum /etc/nsswitch.conf \ | |
697 | /usr/lib/libnsl.so /usr/lib/libnss_{dns,files}.so | |
698 | touch etc/hosts | |
699 | mkdir -p $TMPDIR/var/lib/dhclient 2>/dev/null | |
700 | ||
701 | cat > sbin/dhclient-script <<'EOF' | |
702 | #!/bin/sh | |
703 | ||
704 | PATH=/usr/sbin:/sbin:/usr/bin:/bin | |
705 | ||
706 | function ip_encode() { | |
707 | IFS=. | |
708 | ||
709 | local int=0 | |
710 | for field in $1; do | |
711 | int=$(( $(( $int << 8 )) | $field )) | |
712 | done | |
713 | ||
714 | echo $int | |
715 | unset IFS | |
716 | } | |
717 | ||
718 | function mask_to_cidr() { | |
719 | local mask | |
720 | mask=$(ip_encode $1) | |
721 | local cidr | |
722 | cidr=0 | |
723 | local x | |
724 | x=$(( 128 << 24 )) # 0x80000000 | |
725 | ||
726 | while [ $(( $x & $mask )) -ne 0 ]; do | |
727 | [ $mask -eq $x ] && mask=0 || mask=$(( $mask << 1 )) | |
728 | cidr=$(($cidr + 1)) | |
729 | done | |
730 | ||
731 | if [ $(( $mask & 2147483647 )) -ne 0 ]; then # 2147483647 = 0x7fffffff | |
732 | echo "Invalid net mask: $1" >&2 | |
733 | else | |
734 | echo $cidr | |
735 | fi | |
736 | } | |
737 | ||
738 | function ip_in_subnet() { | |
739 | local netmask | |
740 | netmask=$(_netmask $2) | |
741 | [ $(( $(ip_encode $1) & $netmask)) = $(( $(ip_encode ${2%/*}) & $netmask )) ] | |
742 | } | |
743 | ||
744 | function _netmask() { | |
745 | local vlsm | |
746 | vlsm=${1#*/} | |
747 | [ $vlsm -eq 0 ] && echo 0 || echo $(( -1 << $(( 32 - $vlsm )) )) | |
748 | } | |
749 | ||
750 | dhconfig() { | |
751 | if [ -n "${old_ip_address}" ] && | |
752 | [ ! "${old_ip_address}" = "${new_ip_address}" ]; then | |
753 | # IP address changed. Bringing down the interface will delete all | |
754 | # routes, and clear the ARP cache. | |
755 | ip -family inet addr flush dev ${interface} >/dev/null 2>&1 | |
756 | ip -family inet link set dev ${interface} down | |
757 | fi | |
758 | ||
759 | if [ "${reason}" = "BOUND" ] || [ "${reason}" = "REBOOT" ] || | |
760 | [ ! "${old_ip_address}" = "${new_ip_address}" ] || | |
761 | [ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] || | |
762 | [ ! "${old_network_number}" = "${new_network_number}" ] || | |
763 | [ ! "${old_broadcast_address}" = "${new_broadcast_address}" ] || | |
764 | [ ! "${old_routers}" = "${new_routers}" ] || | |
765 | [ ! "${old_interface_mtu}" = "${new_interface_mtu}" ]; then | |
766 | ip -family inet addr add ${new_ip_address}/${new_prefix} \ | |
767 | broadcast ${new_broadcast_address} dev ${interface} | |
768 | ||
769 | if [ -n "${new_interface_mtu}" ]; then | |
770 | ip link set ${interface} mtu ${new_interface_mtu} | |
771 | fi | |
772 | ||
773 | for router in ${new_routers}; do | |
774 | if ! ip_in_subnet ${router} ${new_ip_address}/${new_prefix}; then | |
775 | continue | |
776 | fi | |
777 | ip route replace default via ${router} | |
778 | break | |
779 | done | |
780 | fi | |
781 | ||
782 | if [ "${reason}" = "RENEW" ] && \ | |
783 | [ "${new_domain_name}" = "${old_domain_name}" ] && \ | |
784 | [ "${new_domain_name_servers}" = "${old_domain_name_servers}" ]; then | |
785 | return | |
786 | fi | |
787 | ||
788 | if [ -n "${new_domain_name}" ] || [ -n "${new_domain_name_servers}" ] || \ | |
789 | [ -n "${new_domain_search}" ]; then | |
790 | ||
791 | echo "; generated by $0" > /etc/resolv.conf | |
792 | ||
793 | if [ -n "${new_domain_search}" ]; then | |
794 | echo "search ${new_domain_search//\\032/ }" >> /etc/resolv.conf | |
795 | elif [ -n "${new_domain_name}" ]; then | |
796 | echo "search ${new_domain_name//\\032/ }" >> /etc/resolv.conf | |
797 | fi | |
798 | ||
799 | for nameserver in ${new_domain_name_servers} ; do | |
800 | echo "nameserver ${nameserver}" >> /etc/resolv.conf | |
801 | done | |
802 | fi | |
803 | ||
804 | if [ -n "${new_host_name}" ]; then | |
805 | hostname ${new_host_name} | |
806 | fi | |
807 | } | |
808 | ||
809 | new_prefix=$(mask_to_cidr ${new_subnet_mask}) | |
810 | ||
811 | case "${reason}" in | |
812 | MEDIUM) | |
813 | exit 0 | |
814 | ;; | |
815 | ||
816 | PREINIT) | |
817 | ip -family inet addr flush dev ${interface} >/dev/null 2>&1 | |
818 | ip -family inet link set ${interface} up | |
819 | exit 0 | |
820 | ;; | |
821 | ||
822 | ARPCHECK|ARPSEND) | |
823 | if [ -z "${new_ip_address}" ] || [ -z "${interface}" ] || \ | |
824 | arping -q -f -c 2 -w 3 -D -I ${interface} ${new_ip_address}; then | |
825 | exit 0 | |
826 | else | |
827 | exit 1 | |
828 | fi | |
829 | ;; | |
830 | ||
831 | BOUND|RENEW|REBIND|REBOOT) | |
832 | dhconfig | |
833 | exit 0 | |
834 | ;; | |
835 | ||
836 | EXPIRE|FAIL|RELEASE|STOP) | |
837 | if [ -n "${old_ip_address}" ]; then | |
838 | # Shut down interface, which will delete routes and clear arp cache. | |
839 | ip -family inet addr flush dev ${interface} >/dev/null 2>&1 | |
840 | ip -family inet link set ${interface} down | |
841 | fi | |
842 | exit 0 | |
843 | ;; | |
844 | ||
845 | *) | |
846 | echo "Unhandled state: ${reason}" >&2 | |
847 | exit 1 | |
848 | ;; | |
849 | esac | |
850 | ||
851 | EOF | |
852 | chmod 755 sbin/dhclient-script | |
853 | fi | |
854 | ||
855 | # Modules needed by the live system | |
856 | MODULES="$MODULES aufs squashfs loop vfat ehci-hcd ohci-hcd uhci-hcd usb-storage" | |
857 | ||
858 | # Add all storage modules | |
859 | for module in /lib/modules/$KERNEL/kernel/drivers/{ata,message/fusion,pcmcia,scsi{,/*}}/*; do | |
860 | MODULES="$MODULES $(basename ${module/.ko})" | |
861 | done | |
862 | ||
863 | # Creating folders | |
864 | mkdir -p mnt/{source,tmpfs,overlayfs,squashfs} | |
865 | ||
866 | cat >> sbin/real-init <<'EOF' | |
867 | ||
868 | netdevice=eth0 | |
869 | ||
870 | # Users can override rootfs target on the kernel commandline | |
871 | for o in $(cat /proc/cmdline); do | |
872 | case $o in | |
873 | root=*) | |
874 | root=${o#root=} | |
875 | ;; | |
876 | rootflags=*) | |
877 | rootflags=${o#rootflags=} | |
878 | ;; | |
879 | rootfstype=*) | |
880 | rootfstype=${o#rootfstype=} | |
881 | ;; | |
882 | net=*) | |
883 | net=${o#net=} | |
884 | ;; | |
885 | netdevice=*) | |
886 | netdevice=${o#netdevice=} | |
887 | ;; | |
888 | gateway=*) | |
889 | gateway=${o#gateway=} | |
890 | ;; | |
891 | dns=*) | |
892 | dns="$dns ${o#dns=}" | |
893 | ;; | |
894 | esac | |
895 | done | |
896 | ||
897 | # generate udev rules to generate /dev/root symlink | |
898 | if [ -z $root ] ; then | |
899 | root=/dev/something | |
900 | else | |
901 | case $root in | |
902 | /dev/disk/by-label/*) | |
903 | type="block" | |
904 | LABEL=${root#/dev/disk/by-label/} | |
905 | echo "SUBSYSTEM==\"block\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$LABEL\", SYMLINK+=\"root\"" > /etc/udev/rules.d/00-label.rules | |
906 | if is_verbose; then | |
907 | echo "Added udev rule 00-label.rules:" | |
908 | cat /etc/udev/rules.d/00-label.rules | |
909 | fi | |
910 | type="block" | |
911 | ;; | |
912 | CDLABEL=*) | |
913 | CDLABEL=${root#CDLABEL=} | |
914 | echo "KERNEL==\"hd[a-z]\", BUS==\"ide\", SYSFS{removable}==\"1\", ATTRS{media}==\"cdrom\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$CDLABEL\", SYMLINK+=\"root\"" > /etc/udev/rules.d/00-cdlabel.rules | |
915 | echo "KERNEL==\"sr[0-9]\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$CDLABEL\", SYMLINK+=\"root\"" >> /etc/udev/rules.d/00-cdlabel.rules | |
916 | echo "KERNEL==\"scd[0-9]\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$CDLABEL\", SYMLINK+=\"root\"" >> /etc/udev/rules.d/00-cdlabel.rules | |
917 | echo "KERNEL==\"pcd[0-9]\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$CDLABEL\", SYMLINK+=\"root\"" >> /etc/udev/rules.d/00-cdlabel.rules | |
918 | if is_verbose; then | |
919 | echo "Added udev rule 00-cdlabel.rules:" | |
920 | cat /etc/udev/rules.d/00-cdlabel.rules | |
921 | fi | |
922 | type="block" | |
923 | ;; | |
924 | LABEL=*) | |
925 | LABEL=${root#LABEL=} | |
926 | echo "SUBSYSTEM==\"block\", PROGRAM=\"/sbin/blkid -s LABEL -o value %N\", RESULT==\"$LABEL\", SYMLINK+=\"root\"" > /etc/udev/rules.d/00-label.rules | |
927 | if is_verbose; then | |
928 | echo "Added udev rule 00-label.rules:" | |
929 | cat /etc/udev/rules.d/00-label.rules | |
930 | fi | |
931 | type="block" | |
932 | ;; | |
933 | /dev/disk/by-id/*) | |
934 | UUID=${root#/dev/disk/by-id/} | |
935 | echo "SUBSYSTEM==\"block\", PROGRAM=\"/sbin/blkid -s UUID -o value %N\", RESULT==\"$UUID\", SYMLINK+=\"root\"" > /etc/udev/rules.d/01-uuid.rules | |
936 | if is_verbose; then | |
937 | echo "Added udev rule 01-uuid.rules:" | |
938 | cat /etc/udev/rules.d/01-uuid.rules | |
939 | fi | |
940 | type="block" | |
941 | ;; | |
942 | UUID=*) | |
943 | UUID=${root#UUID=} | |
944 | echo "SUBSYSTEM==\"block\", PROGRAM=\"/sbin/blkid -s UUID -o value %N\", RESULT==\"$UUID\", SYMLINK+=\"root\"" > /etc/udev/rules.d/01-uuid.rules | |
945 | if is_verbose; then | |
946 | echo "Added udev rule 01-uuid.rules:" | |
947 | cat /etc/udev/rules.d/01-uuid.rules | |
948 | fi | |
949 | type="block" | |
950 | ;; | |
951 | http://*|https://*|ftp*://*|ftps://*|scp://*|sftp://*) | |
952 | thingtofetch="${root}" | |
953 | type="download" | |
954 | ||
955 | # When doing http(s) transfers, compress the data | |
956 | if [ "${thingtofetch:0:4}" = "http" ]; then | |
957 | curloptions="--compressed" | |
958 | fi | |
959 | ;; | |
960 | /dev/*) | |
961 | ln -s $root /dev/root | |
962 | type="block" | |
963 | ;; | |
964 | *) | |
965 | thingtomount=$root | |
966 | ;; | |
967 | esac | |
968 | fi | |
969 | ||
970 | if [ "$type" = "block" ]; then | |
971 | thingtomount=/dev/root | |
972 | ||
973 | elif [ "$type" = "download" ]; then | |
974 | rootflags="loop" | |
975 | thingtomount=/${thingtofetch##*/} | |
976 | ||
977 | # If no network configuration was given, | |
978 | # we'll try dhcp | |
979 | if [ -z "${net}" ]; then | |
980 | net="dhcp" | |
981 | fi | |
982 | fi | |
983 | ||
984 | echo "udev_log=\"error\"" >> /etc/udev/udev.conf | |
985 | ||
986 | # rules for loading modules | |
987 | echo -n "ACTION==\"add\", SUBSYSTEM==\"?*\", ENV{MODALIAS}==\"?*\", RUN+=\"/sbin/modprobe $" >> /etc/udev/rules.d/10-modprobe.rules | |
988 | echo "env{MODALIAS}\"" >> /etc/udev/rules.d/10-modprobe.rules | |
989 | echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\" RUN+=\"/sbin/modprobe sg\"" >> /etc/udev/rules.d/10-modprobe.rules | |
990 | echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\", SYSFS{type}==\"0|7|14\", RUN+=\"/sbin/modprobe sd_mod\"" >> /etc/udev/rules.d/10-modprobe.rules | |
991 | echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\", SYSFS{type}==\"[45]\", RUN+=\"/sbin/modprobe sr_mod\"" >> /etc/udev/rules.d/10-modprobe.rules | |
992 | echo "SUBSYSTEM==\"mmc\", RUN+=\"/sbin/modprobe mmc_block\"" >> /etc/udev/rules.d/10-modprobe.rules | |
993 | ||
994 | if [ "${type}" = "block" ]; then | |
995 | # FIXME: hack since sr_mod seems to fail to get loaded sometimes (#239657) | |
996 | modprobe sr_mod | |
997 | fi | |
998 | ||
999 | modprobe loop max_loop=16 | |
1000 | ||
1001 | vecho "Starting udevd..." | |
1002 | udevd --daemon | |
1003 | ||
1004 | vecho "Creating devices..." | |
e1f6992d | 1005 | udevadm trigger --action=add |
c7271994 MT |
1006 | |
1007 | if [ "${type}" = "download" ]; then | |
1008 | # Wait 30 seconds for network to appear. | |
1009 | COUNTDOWN=30 | |
1010 | while [ "x$COUNTDOWN" != "x0" ] ; do | |
1011 | is_verbose && echo -n "." | |
1012 | ||
1013 | if ip link show $netdevice &>/dev/null; then | |
1014 | COUNTDOWN=0 | |
1015 | continue | |
1016 | fi | |
1017 | ||
1018 | COUNTDOWN=$(($COUNTDOWN - 1)) | |
1019 | sleep 1 | |
1020 | done | |
1021 | vecho # Blank line | |
1022 | ||
1023 | ip link set $netdevice up | |
1024 | if [ "$net" = "dhcp" ]; then | |
1025 | vecho "Getting an IP address by DHCP..." | |
1026 | dhclient $(get_verbose) $netdevice | |
1027 | else | |
1028 | vecho "Setting IP address $net..." | |
1029 | ip addr add $net dev $netdevice | |
1030 | fi | |
1031 | if [ -n "$gateway" ]; then | |
1032 | vecho "Setting default gateway $gateway..." | |
1033 | ip route add default via $gateway | |
1034 | fi | |
1035 | if [ -n "$dns" ]; then | |
1036 | vecho "Setting up dns server $dns..." | |
1037 | echo "nameserver $dns" > /etc/resolv.conf | |
1038 | fi | |
1039 | if [ -n "$gateway" ]; then | |
1040 | vecho "Pinging gateway $gateway..." | |
1041 | if ! ping -c3 -w10 $gateway &>/dev/null; then | |
1042 | echo "This box does not seem to have a connection" | |
1043 | echo "to the default gateway $gateway." | |
1044 | echo "You may fix this now and continue then:" | |
1045 | echo | |
1046 | bash | |
1047 | fi | |
1048 | fi | |
1049 | fi | |
1050 | ||
1051 | if [ "$type" = "download" ]; then | |
1052 | curloptions="${curloptions} --connect-timeout 30 --output ${thingtomount}" | |
1053 | #curloptions="${curloptions} --write-out=\"Fetched %{url_effective} in %{time_total}s (%{speed_download} bytes/s).\"" | |
1054 | ||
1055 | vecho "Running donwload..." | |
1056 | vecho " $thingtofetch" | |
1057 | ||
1058 | curl ${curloptions} ${thingtofetch} | |
1059 | ||
1060 | if [ "$?" != "0" ]; then | |
1061 | echo "An error occured when fetching ${thingtomount}:" | |
1062 | echo " Command: ${curl} ${thingtofetch}" | |
1063 | echo | |
1064 | echo "You now get a shell to download the file manually." | |
1065 | echo "Exit to continue booting." | |
1066 | echo | |
1067 | bash | |
1068 | fi | |
1069 | fi | |
1070 | ||
1071 | if [ "$SHELL" == "1" ] ; then | |
1072 | echo "Shell requested on kernel commandline. Exit to continue booting." | |
1073 | echo | |
1074 | bash | |
1075 | fi | |
1076 | ||
1077 | if [ "${type}" = "block" ]; then | |
1078 | # Wait 90 seconds for $thingtomount to appear. | |
1079 | COUNTDOWN=90 | |
1080 | while [ "x$COUNTDOWN" != "x0" ] ; do | |
1081 | is_verbose && echo -n "." | |
1082 | ||
1083 | if [ -e $thingtomount ]; then | |
1084 | COUNTDOWN=0 | |
1085 | continue | |
1086 | fi | |
1087 | # this is kind of lame, but we could have had a situation | |
1088 | # where we were unable to read the volume id. so trigger | |
1089 | # another run through the block devs | |
1090 | if [ "x$COUNTDOWN" = "x30" ]; then | |
e1f6992d | 1091 | udevadm trigger --action=add --subsystem-match=block |
c7271994 MT |
1092 | fi |
1093 | ||
1094 | COUNTDOWN=$(($COUNTDOWN - 1)) | |
1095 | sleep 1 | |
1096 | done | |
1097 | vecho # Blank line | |
1098 | fi | |
1099 | ||
1100 | if [ ! -e $thingtomount ] ; then | |
1101 | echo | |
1102 | echo "--------------------------------------" | |
1103 | echo "WARNING: Cannot find root file system!" | |
1104 | echo "--------------------------------------" | |
1105 | echo | |
1106 | echo "Create symlink $thingtomount and then exit this shell to continue" | |
1107 | echo "the boot sequence." | |
1108 | echo | |
1109 | bash | |
1110 | fi | |
1111 | ||
1112 | if is_verbose; then | |
1113 | vecho "Mounting $thingtomount..." | |
1114 | ls -lh $thingtomount | |
1115 | fi | |
1116 | ||
1117 | if [ "x$READONLY" == "x1" ] ; then | |
1118 | rootflags="$rootflags,ro" | |
1119 | else | |
1120 | rootflags="$rootflags,rw" | |
1121 | fi | |
1122 | ||
1123 | if [ -n $rootflags ]; then | |
1124 | mountoptions=" -o$rootflags" | |
1125 | fi | |
1126 | ||
1127 | [ -n "$rootfstype" ] && rootfstype="-t $rootfstype" | |
1128 | ||
1129 | mount -n $rootfstype $mountoptions $thingtomount /mnt/source | |
1130 | ||
1131 | if [ "$?" != "0" ]; then | |
1132 | echo "---------------------------------" | |
1133 | echo "WARNING: Cannot mount rootfs!" | |
1134 | echo "---------------------------------" | |
1135 | echo | |
1136 | echo "Dropping to a shell. " | |
1137 | echo "Mount /mnt/source and exit shell to continue. Good luck!" | |
1138 | echo | |
1139 | bash | |
1140 | fi | |
1141 | ||
1142 | mount -n -t tmpfs none /mnt/tmpfs | |
1143 | aufsmountoptions="br:/mnt/tmpfs=rw" | |
1144 | ||
1145 | count=0 | |
1146 | for overlay in $(find /mnt/source -name "*.overlay" 2>/dev/null); do | |
1147 | vecho "Setting up overlay ${overlay}..." | |
1148 | mkdir -p /mnt/overlay${count} 2>/dev/null | |
1149 | mount -n -t squashfs -o loop,ro ${overlay} /mnt/overlay${count} | |
1150 | aufsmountoptions="$aufsmountoptions:/mnt/overlay${count}=rr" | |
1151 | count=$((${count} + 1)) | |
1152 | done | |
1153 | ||
1154 | count=0 | |
1155 | for sfs in $(find /mnt/source -name "*.sfs" 2>/dev/null); do | |
1156 | vecho "Setting up squashed fs ${sfs}..." | |
1157 | mount -n -t squashfs -o loop,ro ${sfs} /mnt/squashfs | |
1158 | aufsmountoptions="$aufsmountoptions:/mnt/squashfs=rr" | |
1159 | break | |
1160 | done | |
1161 | ||
1162 | mount -t aufs -o $aufsmountoptions none /sysroot | |
1163 | ||
1164 | for i in $(cd /mnt; ls); do | |
1165 | mountpoint /mnt/$i >/dev/null || continue | |
1166 | mkdir -p /sysroot/mnt/$i || : | |
1167 | mount --move /mnt/$i /sysroot/mnt/$i | |
1168 | done | |
1169 | ||
1170 | # Shutting down network | |
1171 | if [ "${type}" = "download" ]; then | |
1172 | if [ "${net}" = "dhcp" ]; then | |
1173 | kill $(pidof dhclient) | |
1174 | else | |
1175 | ip address flush dev ${netdevice} | |
1176 | fi | |
1177 | ip link set ${netdevice} down | |
1178 | ip route flush table main | |
1179 | fi | |
1180 | ||
1181 | if [ "$ESHELL" == "1" ]; then | |
1182 | echo "Shell requested on kernel commandline." | |
1183 | echo "Rootfs is mounted ro on /sysroot. Exit to continue booting." | |
1184 | echo | |
1185 | bash | |
1186 | fi | |
1187 | ||
1188 | if [ -x /sysroot$init ]; then | |
1189 | # Leave initramfs and transition to rootfs | |
1190 | kill $(pidof udevd) | |
1191 | vecho "Transfering control to $init" | |
1192 | ||
1193 | exec switch_root /sysroot ${init} | |
1194 | echo "---------------------------------" | |
1195 | echo "WARNING: Error switching to real rootfs!" | |
1196 | echo "---------------------------------" | |
1197 | echo | |
1198 | echo "Dropping to a shell. Good luck!" | |
1199 | echo | |
1200 | bash | |
1201 | else | |
1202 | echo "---------------------------------------------------------" | |
1203 | echo "WARNING: Requested $init binary does not exist on rootfs." | |
1204 | echo "---------------------------------------------------------" | |
1205 | echo | |
1206 | echo "Dropping to a shell. Good luck!" | |
1207 | echo | |
1208 | bash | |
1209 | fi | |
1210 | ||
1211 | EOF | |
1212 | ||
1213 | finalize |