3 ###############################################################################
5 # IPFire.org - A linux based firewall #
6 # Copyright (C) 2009 Michael Tremer & Christian Schmidt #
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. #
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. #
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/>. #
21 ###############################################################################
24 ## GLOBAL VARIABLES ARE UPPERCASE
25 ## LOCAL VARIABLES ARE LOWERCASE
35 # Check if we are root
36 if [ $UID != 0 ]; then
37 error
"$0 must be run as root."
43 echo "$0 [--help] [-f] [-v] <out-initrd-image> <kernel-version>"
44 echo " [--with=<module>]"
46 echo "example: $0 /boot/myinitramfs.img \`uname -r\`"
49 # Setting verbose mode
50 function set_verbose
() {
61 # Returns if verbose is on or not
62 function is_verbose
() {
63 [ -n "$VERBOSE" ] && return 0
67 # Like is_verbose but prints
68 # the content of $VERBOSE
69 function get_verbose
() {
74 # Prints text if verbose is on
76 is_verbose
&& echo "$@"
79 # Prints error if verbose is on
87 vecho
"[TASK] Compressing image $TARGET..."
88 (cd $TMPDIR && find . |
cpio -H newc
--quiet -o >|
$IMAGE) ||
exit 1
89 gzip -c9 $IMAGE > $TARGET
93 find "$@" |
awk '{ print $1; exit; }'
101 pushd "$1" >/dev
/null
2>&1
108 function read_link
() {
109 READLINK
=$
(readlink
$1)
110 if grep -q "^/" <<< $READLINK; then
113 echo "$(dirname $1)/$READLINK"
117 function get_dso_deps
() {
124 local LDSO
="/lib/ld-linux.so.2"
127 while read NAME I0 FILE ADDR I1
; do
128 [ "$FILE" == "not" ] && FILE
="$FILE $ADDR"
129 [ "$NAME" == "not" ] && NAME
="$NAME $I0"
134 $(LD_TRACE_PRELINKING=1 LD_WARN= LD_TRACE_LOADED_OBJECTS=1 \
135 $LDSO $bin 2>/dev/null)
138 [ ${#FILES[*]} -eq 0 ] && return 1
140 # we don't want the name of the binary in the list
141 if [ "${FILES[0]}" == "$bin" ]; then
144 [ ${#FILES[*]} -eq 1 ] && return 1
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
153 There are missing files on your system. The dynamic object $bin
154 requires ${NAMES[$n]} n order to properly function. mkinitramfs cannot continue.
160 TLIBDIR
=`echo "$FILE" | sed 's,\(/lib[^/]*\)/.*$,\1,'`
161 BASE
=`basename "$FILE"`
162 if [ -f "$TLIBDIR/$BASE" ]; then
163 FILE
="$TLIBDIR/$BASE"
178 ## Check if this is an absolute path
179 if [ "$(basename $file)" = "$file" ]; then
185 [ -e "$dest" ] && continue
187 mkdir
-p "$(dirname $dest)" 2>/dev
/null
189 local old_indent
=$INDENT
192 [ "${file%%.ko}" != "${file}" ] && msg
="[KMOD]"
193 [ -L "$file" ] && msg
="[SYML]"
194 #vecho "$msg$INDENT$file -> $dest"
195 vecho
"$msg$INDENT$file"
197 # Check if $file is a symlink
198 if [ -L "$file" ]; then
199 install $
(read_link
$file)
202 if [ "${file%%.ko}" != "${file}" ]; then
203 for i
in $
(moduledep
$file); do
204 [ "$(locatemodule $i)" = "$file" ] && continue
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
217 for firmware
in $
(modinfo
-F firmware
$file 2>/dev
/null
); do
218 firmware
="/lib/firmware/$firmware"
219 [ -e "$firmware" ] && install $firmware
222 for dep
in $
(get_dso_deps
"$file"); do
231 # find module dependencies
232 function moduledep
() {
234 if [ "$1" == "--ignore-install" ]; then
235 mpargs
="$mpargs --ignore-install"
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) }' | \
242 [ "${foo%%.ko}" != "$1" ] && \
243 echo -n "${foo%%.ko} "; \
247 # XXX May be, we can drop this...
248 # This loops to make sure it resolves dependencies of dependencies of...
249 function resolvemoduledeps
() {
257 while [ $before != $after ]; do
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"
265 modules
=$
(for i
in $newmodules; do echo $i; done |
sort -u)
266 after
=$
(wc -c <<< $modules)
271 function locatemodule
() {
273 if [ "$1" == "--ignore-install" ]; then
274 mpargs
="$mpargs --ignore-install"
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
282 function installmodule
() {
286 [ "$module" = "--load" ] && load
=1
287 module
=$
(locatemodule
$module)
288 [ -z "$module" ] && continue
292 if [ "$load" = "1" ]; then
294 [ "$module" = "--load" ] && continue
295 cat >> $TMPDIR/sbin
/real-init
<<EOF
296 vecho "Loading module $i..."
303 resolve_device_name
() {
304 if [[ "$1" =~ ^
/dev
]]; then
311 function finalize
() {
315 installmodule
$MODULES
317 # Build module deps file so we can use modprobe
318 vecho
"[TASK] Running depmod..."
319 depmod
-a -b "$TMPDIR" $KERNEL
322 install /etc
/ld.so.conf
323 [ -d "/etc/ld.so.conf.d" ] && \
324 for i
in $
(find /etc
/ld.so.conf.d
-type f
); do
327 vecho
"[TASK] Running ldconfig..."
332 rm -rf $TMPDIR 2>/dev
/null
335 # resolve a device node to its major:minor numbers in decimal or hex
336 function get_numeric_dev
() {
338 if [ "$1" == "hex" ]; then
341 ls -lH "$2" |
awk '{ sub(/,/, "", $5); printf("'"$fmt"'", $5, $6); }'
345 function resolve_device_name
() {
346 if [[ "$1" =~ ^
/dev
]]; then
353 function finddevnoinsys
() {
355 if [ -n "$majmin" ]; then
356 dev
=$
(for x
in /sys
/block
/* ; do find $x/ -name dev
; done |
while read device
; do \
357 echo "$majmin" |
cmp -s $device && echo $device ; done)
358 if [ -n "$dev" ]; then
368 findblockdevinsys
() {
369 devname
=$
(resolve_device_name
"$1")
370 if [[ "$devname" =~ ^
/sys
/block
/ ]]; then
373 majmin
=$
(get_numeric_dev dec
$devname)
374 finddevnoinsys
"$majmin"
377 findstoragedriverinsys
() {
378 while [ ! -L device
]; do
379 for slave
in $
(ls -d slaves
/* 2>/dev
/null
) ; do
380 slavename
=${slave##*/}
381 case " $slavestried " in
386 slavestried
="$slavestried $slavename"
388 findstoragedriverinsys
393 [ "$PWD" = "/sys" ] && return
396 cd $
(read_link .
/device
)
397 if echo $PWD |
grep -q /virtio-pci
/ ; then
398 installmodule
--load virtio_pci
400 while [ "$PWD" != "/sys/devices" ]; do
402 if [ -f modalias
]; then
403 installmodule
--load $
(cat modalias
)
406 [ -z "$deps" -a -L driver
/module
] && \
407 deps
=$
(basename $
(read_link driver
/module
))
408 installmodule
--load $deps
413 function findstoragedriver
() {
415 case " $handleddevices " in
418 *) handleddevices
="$handleddevices $device" ;;
420 vecho
"[INFO] Looking for driver for device $device"
421 if [[ "$device" =~ ^
/sys
]]; then
425 device
=$
(echo "$device" |
sed 's,/,!,g')
426 if [ -d /sys
/block
/$device/ ]; then
427 sysfs
="/sys/block/$device"
429 sysfs
=$
(for x
in /sys
/block
/*; do findone
$x/ -type d
-name $device; done)
431 [ -z "$sysfs" ] && return
433 findstoragedriverinsys
439 while [ $# -gt 0 ] ; do
452 MODULES
="$MODULES ${1#--with=*}"
458 if [ -z "$target" ] ; then
460 elif [ -z "$kernel" ] ; then
463 echo "Unknown option or parameter \"$1\""
473 TARGET
=${target-$TARGET}
474 KERNEL
=${kernel-$KERNEL}
476 if [ -z "$TARGET" ]; then
481 [[ "$TARGET" =~
"^/" ]] && TARGET
="$PWD/$TARGET"
483 if [ -z "$FORCE" ] && [ -e "$TARGET" ]; then
484 echo "Image $TARGET already exists. Use -f to overwrite"
488 # Changing to our dir, where we do our actions in
489 qpushd
$TMPDIR ||
exit 1
491 # Make directory structure
492 mkdir
-p bin sbin dev sys proc sysroot \
493 etc
/udev
/rules.d lib
/udev
/rules.d
495 # Install some essential binaries
496 install bash blkid
chmod cat cut
dd dmesg env
find grep head ip kbd_mode \
497 kill killall5
less ln \
498 ls lsmod mkdir mknod modprobe mount mountpoint openvt pidof ps
rm sed \
499 setfont sh
sleep switch_root udevadm udevd umount \
500 /lib
/udev
/console_init
502 # Copy modprobe.conf and friends over
503 [ -e /etc
/modprobe.conf
] && install /etc
/modprobe.conf
504 for f
in $
(find /etc
/modprobe.d
-type f
); do
508 # Install an empty fstab
509 touch $TMPDIR/etc
/fstab
511 # terminfo bits make things work better if you fall into interactive mode
512 [ -d "/usr/lib/terminfo" ] && \
513 for f
in $
(find /usr
/lib
/terminfo
-type f
); do
518 if [ -e "/etc/sysconfig/console" ]; then
519 install /etc
/sysconfig
/console
520 .
/etc
/sysconfig
/console
522 [ -z "$FONT" ] && FONT
="LatArCyrHeb-16"
523 for i
in /lib
/kbd
/consolefonts
/$FONT.
*; do
524 mkdir
-p $TMPDIR/$
(dirname $i) 2>/dev
/null || true
539 # Mounting directories
540 mount -t proc proc /proc
541 mount -t sysfs /sys /sys
542 mount -t tmpfs -o mode=0755 udev /dev
545 echo > /proc/sys/kernel/printk "1 4 1 7"
547 # Adding important dev nodes
548 mknod /dev/console c 5 1
549 mknod /dev/null c 1 3
550 mknod /dev/kmsg c 1 11
551 mknod /dev/ptmx c 5 2
553 mknod /dev/systty c 4 0
555 # XXX really we need to openvt too, in case someting changes the
556 # color palette and then changes vts on fbcon before gettys start.
558 for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
559 mknod /dev/tty$i c 4 $i
562 for i in 0 1 2 3 ; do
563 mknod /dev/ttyS$i c 4 $(($i + 64))
566 mkdir -m 1777 /dev/shm
567 ln -s /proc/self/fd /dev/fd
568 ln -s fd/0 /dev/stdin
569 ln -s fd/1 /dev/stdout
570 ln -s fd/2 /dev/stderr
573 mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
579 # Write out real-init
580 touch sbin
/real-init
; chmod 755 sbin
/real-init
581 cat > sbin
/real-init
<<'EOF'
585 export PATH=/sbin:/bin:/usr/sbin:/usr/bin
595 function emergency_shell()
597 echo "Bug in initramfs /init detected. Dropping to a shell. Good luck!"
601 trap "emergency_shell" 0 2
603 # exit immediately if a command fails
606 # Setting verbose mode
607 function set_verbose() {
618 # Returns if verbose is on or not
619 function is_verbose() {
620 [ -n "$VERBOSE" ] && return 0
624 # Like is_verbose but prints
625 # the content of $VERBOSE
626 function get_verbose() {
631 # Prints text if verbose is on
633 if is_verbose; then echo "$@"; fi
636 # Prints error if verbose is on
641 /lib/udev/console_init tty0
643 # Disable hotplugging
644 echo "" > /proc/sys/kernel/hotplug
646 # Parse kernel commandline options
647 for o in $(cat /proc/cmdline) ; do
668 echo "blacklist ${o#blacklist=}" >> /etc/modprobe.conf
671 m=$(echo $o |cut -s -d . -f 1)
672 opt=$(echo $o |cut -s -d . -f 2-)
673 if [ -z "$m" -o -z "$opt" ]; then
676 p=$(echo $opt |cut -s -d = -f 1)
677 v=$(echo $opt |cut -s -d = -f 2-)
678 if [ -z "$p" -o -z "$v" ]; then
681 echo "options $m $p=$v" >> /etc/modprobe.conf
686 vecho "kernel commandline: $(cat /proc/cmdline)"
689 if [ "${WITH_NET}" = "1" ]; then
690 MODULES
="$MODULES af_packet"
691 for module
in /lib
/modules
/$KERNEL/kernel
/drivers
/net
/{,*/}*; do
692 MODULES
="$MODULES $(basename ${module/.ko})"
695 install arping curl dhclient ip
ping sha1sum /etc
/nsswitch.conf \
696 /usr
/lib
/libnsl.so
/usr
/lib
/libnss_
{dns
,files
}.so
697 mkdir
-p $TMPDIR/var
/lib
/dhclient
2>/dev
/null
699 cat > sbin
/dhclient-script
<<'EOF'
702 PATH=/usr/sbin:/sbin:/usr/bin:/bin
704 function ip_encode() {
709 int=$(( $(( $int << 8 )) | $field ))
716 function mask_to_cidr() {
722 x=$(( 128 << 24 )) # 0x80000000
724 while [ $(( $x & $mask )) -ne 0 ]; do
725 [ $mask -eq $x ] && mask=0 || mask=$(( $mask << 1 ))
729 if [ $(( $mask & 2147483647 )) -ne 0 ]; then # 2147483647 = 0x7fffffff
730 echo "Invalid net mask: $1" >&2
736 function ip_in_subnet() {
738 netmask=$(_netmask $2)
739 [ $(( $(ip_encode $1) & $netmask)) = $(( $(ip_encode ${2%/*}) & $netmask )) ]
742 function _netmask() {
745 [ $vlsm -eq 0 ] && echo 0 || echo $(( -1 << $(( 32 - $vlsm )) ))
749 if [ -n "${old_ip_address}" ] &&
750 [ ! "${old_ip_address}" = "${new_ip_address}" ]; then
751 # IP address changed. Bringing down the interface will delete all
752 # routes, and clear the ARP cache.
753 ip -family inet addr flush dev ${interface} >/dev/null 2>&1
754 ip -family inet link set dev ${interface} down
757 if [ "${reason}" = "BOUND" ] || [ "${reason}" = "REBOOT" ] ||
758 [ ! "${old_ip_address}" = "${new_ip_address}" ] ||
759 [ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] ||
760 [ ! "${old_network_number}" = "${new_network_number}" ] ||
761 [ ! "${old_broadcast_address}" = "${new_broadcast_address}" ] ||
762 [ ! "${old_routers}" = "${new_routers}" ] ||
763 [ ! "${old_interface_mtu}" = "${new_interface_mtu}" ]; then
764 ip -family inet addr add ${new_ip_address}/${new_prefix} \
765 broadcast ${new_broadcast_address} dev ${interface}
767 if [ -n "${new_interface_mtu}" ]; then
768 ip link set ${interface} mtu ${new_interface_mtu}
771 for router in ${new_routers}; do
772 if ! ip_in_subnet ${router} ${new_ip_address}/${new_prefix}; then
775 ip route replace default via ${router}
780 if [ "${reason}" = "RENEW" ] && \
781 [ "${new_domain_name}" = "${old_domain_name}" ] && \
782 [ "${new_domain_name_servers}" = "${old_domain_name_servers}" ]; then
786 if [ -n "${new_domain_name}" ] || [ -n "${new_domain_name_servers}" ] || \
787 [ -n "${new_domain_search}" ]; then
789 echo "; generated by $0" > /etc/resolv.conf
791 if [ -n "${new_domain_search}" ]; then
792 echo "search ${new_domain_search//\\032/ }" >> /etc/resolv.conf
793 elif [ -n "${new_domain_name}" ]; then
794 echo "search ${new_domain_name//\\032/ }" >> /etc/resolv.conf
797 for nameserver in ${new_domain_name_servers} ; do
798 echo "nameserver ${nameserver}" >> /etc/resolv.conf
802 if [ -n "${new_host_name}" ]; then
803 hostname ${new_host_name}
807 new_prefix=$(mask_to_cidr ${new_subnet_mask})
815 ip -family inet addr flush dev ${interface} >/dev/null 2>&1
816 ip -family inet link set ${interface} up
821 if [ -z "${new_ip_address}" ] || [ -z "${interface}" ] || \
822 arping -q -f -c 2 -w 3 -D -I ${interface} ${new_ip_address}; then
829 BOUND|RENEW|REBIND|REBOOT)
834 EXPIRE|FAIL|RELEASE|STOP)
835 if [ -n "${old_ip_address}" ]; then
836 # Shut down interface, which will delete routes and clear arp cache.
837 ip -family inet addr flush dev ${interface} >/dev/null 2>&1
838 ip -family inet link set ${interface} down
844 echo "Unhandled state: ${reason}" >&2
850 chmod 755 sbin
/dhclient-script