]> git.ipfire.org Git - ipfire-3.x.git/blame - tools/mkliveramfs
mkinitramfs: Fix --action=add flags for newer version of udev.
[ipfire-3.x.git] / tools / mkliveramfs
CommitLineData
c7271994
MT
1#!/bin/bash
2HEADER="\
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
27VERBOSE=
28FORCE=
29TARGET=
30KERNEL=$(uname -r)
31MODULES=
32
33TMPDIR=$(mktemp -d)
34
35# Check if we are root
36if [ $UID != 0 ]; then
37 error "$0 must be run as root."
38 exit 1
39fi
40
41# Usage
42function 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
50function 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
62function is_verbose() {
63 [ -n "$VERBOSE" ] && return 0
64 return 1
65}
66
67# Like is_verbose but prints
68# the content of $VERBOSE
69function get_verbose() {
70 echo "$VERBOSE"
71 is_verbose
72}
73
74# Prints text if verbose is on
75function vecho() {
76 is_verbose && echo "$@"
77}
78
79# Prints error if verbose is on
80function error() {
81 vecho "$@" >&2
82}
83
84function 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
92function findone() {
93 find "$@" | awk '{ print $1; exit; }'
94}
95
96function findall() {
97 find "$@"
98}
99
100qpushd() {
101 pushd "$1" >/dev/null 2>&1
102}
103
104qpopd() {
105 popd >/dev/null 2>&1
106}
107
108function 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
117function 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)
136EOF
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
153There are missing files on your system. The dynamic object $bin
154requires ${NAMES[$n]} n order to properly function. mkinitramfs cannot continue.
155EOF
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
173function 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
232function 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...
249function 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
271function 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
282function 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
296vecho "Loading module $i..."
297modprobe $i
298EOF
299 done
300 fi
301}
302
303resolve_device_name() {
304 if [[ "$1" =~ ^/dev ]]; then
305 echo $1
306 else
307 findfs $1
308 fi
309}
310
311function 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
337function 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
346function resolve_device_name() {
347 if [[ "$1" =~ ^/dev ]]; then
348 echo $1
349 else
350 findfs $1
351 fi
352}
353
354function 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
369findblockdevinsys() {
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
378findstoragedriverinsys () {
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
414function 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
440while [ $# -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
472done
473
474TARGET=${target-$TARGET}
475KERNEL=${kernel-$KERNEL}
476
477if [ -z "$TARGET" ]; then
478 usage
479 exit 1
480fi
481
482[[ "$TARGET" =~ "^/" ]] && TARGET="$PWD/$TARGET"
483
484if [ -z "$FORCE" ] && [ -e "$TARGET" ]; then
485 echo "Image $TARGET already exists. Use -f to overwrite"
486 exit 1
487fi
488
489# Changing to our dir, where we do our actions in
490qpushd $TMPDIR || exit 1
491
492# Make directory structure
493mkdir -p bin sbin dev sys proc sysroot \
494 etc/udev/rules.d lib/udev/rules.d
495
496# Install some essential binaries
497install 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
505for f in $(find /etc/modprobe.d -type f); do
506 install $f
507done
508
509# Install an empty fstab
510touch $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
519if [ -e "/etc/sysconfig/console" ]; then
520 install /etc/sysconfig/console
521 . /etc/sysconfig/console
522fi
523[ -z "$FONT" ] && FONT="LatArCyrHeb-16"
524for 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
535done
536
537cat > init <<'EOF'
538#!/bin/sh
539
540# Mounting directories
541mount -t proc proc /proc
542mount -t sysfs /sys /sys
543mount -t tmpfs -o mode=0755 udev /dev
544
545# Silencing kernel
546echo > /proc/sys/kernel/printk "1 4 1 7"
547
548# Adding important dev nodes
549mknod /dev/console c 5 1
550mknod /dev/null c 1 3
551mknod /dev/kmsg c 1 11
552mknod /dev/ptmx c 5 2
553mknod /dev/fb c 29 0
554mknod /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!)
559for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
560 mknod /dev/tty$i c 4 $i
561done
562
563for i in 0 1 2 3 ; do
564 mknod /dev/ttyS$i c 4 $(($i + 64))
565done
566
567mkdir -m 1777 /dev/shm
568ln -s /proc/self/fd /dev/fd
569ln -s fd/0 /dev/stdin
570ln -s fd/1 /dev/stdout
571ln -s fd/2 /dev/stderr
572
573mkdir /dev/pts
574mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
575
576exec sbin/real-init
577EOF
578chmod 755 init
579
580# Write out real-init
581touch sbin/real-init; chmod 755 sbin/real-init
582cat > sbin/real-init <<'EOF'
583#!/bin/bash
584$HEADER
585
586export PATH=/sbin:/bin:/usr/sbin:/usr/bin
587export TERM=linux
588
589init="/sbin/init"
590VERBOSE=-v
591
592READONLY=0
593SHELL=0
594ESHELL=0
595
596function emergency_shell()
597{
598 echo "Bug in initramfs /init detected. Dropping to a shell. Good luck!"
599 echo
600 bash
601}
602trap "emergency_shell" 0 2
603
604# exit immediately if a command fails
605set -e
606
607# Setting verbose mode
608function 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
620function is_verbose() {
621 [ -n "$VERBOSE" ] && return 0
622 return 1
623}
624
625# Like is_verbose but prints
626# the content of $VERBOSE
627function get_verbose() {
628 echo "$VERBOSE"
629 is_verbose
630}
631
632# Prints text if verbose is on
633function vecho() {
634 if is_verbose; then echo "$@"; fi
635}
636
637# Prints error if verbose is on
638function error() {
639 vecho "$@" >&2
640}
641
642/lib/udev/console_init tty0
643
644# Disable hotplugging
645echo "" > /proc/sys/kernel/hotplug
646
647# Parse kernel commandline options
648for 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
685done
686
687vecho "kernel commandline: $(cat /proc/cmdline)"
688EOF
689
690if [ "${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
704PATH=/usr/sbin:/sbin:/usr/bin:/bin
705
706function 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
718function 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
738function ip_in_subnet() {
739 local netmask
740 netmask=$(_netmask $2)
741 [ $(( $(ip_encode $1) & $netmask)) = $(( $(ip_encode ${2%/*}) & $netmask )) ]
742}
743
744function _netmask() {
745 local vlsm
746 vlsm=${1#*/}
747 [ $vlsm -eq 0 ] && echo 0 || echo $(( -1 << $(( 32 - $vlsm )) ))
748}
749
750dhconfig() {
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
809new_prefix=$(mask_to_cidr ${new_subnet_mask})
810
811case "${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 ;;
849esac
850
851EOF
852 chmod 755 sbin/dhclient-script
853fi
854
855# Modules needed by the live system
856MODULES="$MODULES aufs squashfs loop vfat ehci-hcd ohci-hcd uhci-hcd usb-storage"
857
858# Add all storage modules
859for module in /lib/modules/$KERNEL/kernel/drivers/{ata,message/fusion,pcmcia,scsi{,/*}}/*; do
860 MODULES="$MODULES $(basename ${module/.ko})"
861done
862
863# Creating folders
864mkdir -p mnt/{source,tmpfs,overlayfs,squashfs}
865
866cat >> sbin/real-init <<'EOF'
867
868netdevice=eth0
869
870# Users can override rootfs target on the kernel commandline
871for 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
895done
896
897# generate udev rules to generate /dev/root symlink
898if [ -z $root ] ; then
899 root=/dev/something
900else
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
968fi
969
970if [ "$type" = "block" ]; then
971 thingtomount=/dev/root
972
973elif [ "$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
982fi
983
984echo "udev_log=\"error\"" >> /etc/udev/udev.conf
985
986# rules for loading modules
987echo -n "ACTION==\"add\", SUBSYSTEM==\"?*\", ENV{MODALIAS}==\"?*\", RUN+=\"/sbin/modprobe $" >> /etc/udev/rules.d/10-modprobe.rules
988echo "env{MODALIAS}\"" >> /etc/udev/rules.d/10-modprobe.rules
989echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\" RUN+=\"/sbin/modprobe sg\"" >> /etc/udev/rules.d/10-modprobe.rules
990echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\", SYSFS{type}==\"0|7|14\", RUN+=\"/sbin/modprobe sd_mod\"" >> /etc/udev/rules.d/10-modprobe.rules
991echo "ACTION==\"add\", SUBSYSTEM==\"scsi_device\", SYSFS{type}==\"[45]\", RUN+=\"/sbin/modprobe sr_mod\"" >> /etc/udev/rules.d/10-modprobe.rules
992echo "SUBSYSTEM==\"mmc\", RUN+=\"/sbin/modprobe mmc_block\"" >> /etc/udev/rules.d/10-modprobe.rules
993
994if [ "${type}" = "block" ]; then
995 # FIXME: hack since sr_mod seems to fail to get loaded sometimes (#239657)
996 modprobe sr_mod
997fi
998
999modprobe loop max_loop=16
1000
1001vecho "Starting udevd..."
1002udevd --daemon
1003
1004vecho "Creating devices..."
e1f6992d 1005udevadm trigger --action=add
c7271994
MT
1006
1007if [ "${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
1049fi
1050
1051if [ "$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
1069fi
1070
1071if [ "$SHELL" == "1" ] ; then
1072 echo "Shell requested on kernel commandline. Exit to continue booting."
1073 echo
1074 bash
1075fi
1076
1077if [ "${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
1098fi
1099
1100if [ ! -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
1110fi
1111
1112if is_verbose; then
1113 vecho "Mounting $thingtomount..."
1114 ls -lh $thingtomount
1115fi
1116
1117if [ "x$READONLY" == "x1" ] ; then
1118 rootflags="$rootflags,ro"
1119else
1120 rootflags="$rootflags,rw"
1121fi
1122
1123if [ -n $rootflags ]; then
1124 mountoptions=" -o$rootflags"
1125fi
1126
1127[ -n "$rootfstype" ] && rootfstype="-t $rootfstype"
1128
1129mount -n $rootfstype $mountoptions $thingtomount /mnt/source
1130
1131if [ "$?" != "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
1140fi
1141
1142mount -n -t tmpfs none /mnt/tmpfs
1143aufsmountoptions="br:/mnt/tmpfs=rw"
1144
1145count=0
1146for 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))
1152done
1153
1154count=0
1155for 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
1160done
1161
1162mount -t aufs -o $aufsmountoptions none /sysroot
1163
1164for 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
1168done
1169
1170# Shutting down network
1171if [ "${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
1179fi
1180
1181if [ "$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
1186fi
1187
1188if [ -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
1201else
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
1209fi
1210
1211EOF
1212
1213finalize