# based on mkinitrd from RedHat Linux
#
-GENINITRD_RCSID='$Revision$ $Date:: $'
-R=${GENINITRD_RCSID#* *}; VERSION=${R%% *}
+VERSION='devel'
PROGRAM=${0##*/}
. /etc/rc.d/init.d/functions
# list of geninitrd modules which need setup routine after commandline args parsing
GENINITRD_MODS=""
COMPRESS=yes
+LILO_MICROCODE=yes
STRIP=/usr/bin/strip
target=""
kernel=""
usage() {
echo "Usage: $PROGRAM [--version] [-v] [-f] [--ifneeded] [--preload <module>]"
echo " [--with=<module>] [--image-version] [--fstab=<fstab>] [--nocompress]"
- echo " [--compress=yes|xz|lzma|bzip2|gzip|lzo]"
+ echo " [--compress=yes|zstd|xz|lzma|bzip2|gzip|lzo]"
echo " [--nostrip ] [--strip PATH/strip] [--strip=PATH/strip]"
echo " [--initrdfs=rom|initramfs|ext2|cram] [--modules-conf=<modules.conf>]"
echo " [--with-bootsplash] [--without-bootsplash]"
msg "WARNING: $*" >&2
}
+verbose() {
+ [ -n "$verbose" ] && msg "$*" >&3
+}
+
debug() {
- [ -n "$verbose" ] && msg "$*" >&2
+ [ x"$verbose" = x"-v -v" ] && msg "$*" >&3
+}
+
+# add initrd code to print to kmsg
+# @param string message
+# @param int loglevel. defaults to "6" (info)
+# Log levels can be:
+# Name String Meaning
+# KERN_EMERG "0" Emergency messages, system is about to crash or is unstable
+# KERN_ALERT "1" Something bad happened and action must be taken immediately
+# KERN_CRIT "2" A critical condition occurred like a serious hardware/software failure
+# KERN_ERR "3" An error condition, often used by drivers to indicate difficulties with the hardware
+# KERN_WARNING "4" A warning, meaning nothing serious by itself but might indicate problems
+# KERN_NOTICE "5" Nothing serious, but notably nevertheless. Often used to report security events.
+# KERN_INFO "6" Informational message e.g. startup information at driver initialization
+# KERN_DEBUG "7" Debug messages
+# KERN_CONT "c" "continued" line of log printout (only done after a line that had no enclosing \n)
+kmsg() {
+ local msg="$1" level=${2:-6}
+ echo "echo '<$level>$msg' > /dev/kmsg" | add_linuxrc
}
# aborts program abnormally
# find program from specified paths
find_tool() {
- local x
+ local x p b n
+ local paths="$initrd_dirs /bin /sbin /usr/bin /usr/sbin"
for x in "$@"; do
+ debug "find_tool: checking $x"
if [ -x "$x" ]; then
echo $x
- debug "find_tool: found $x"
+ verbose "find_tool: found $x"
return 0
fi
+ n="$x"
+ for p in $paths; do
+ b=$(basename $x)
+ debug "find_tool: checking $p/$b"
+ if [ -x "$p/$b" ]; then
+ echo $p/$b
+ verbose "find_tool: found $p/$b"
+ return 0
+ fi
+ n="$n $p/$b"
+ done
done
- debug "find_tool: did not found any of: $@"
+ debug "find_tool: did not find any of: $n"
return 1
}
# setup geninitrd modules
geninitrd_setup_mods() {
- local mod rcsid
+ local mod
for mod in $GENINITRD_MODS; do
- eval rcsid=$(echo \$$mod | LC_ALL=C tr '[a-z]' '[A-Z]')_RCSID
- debug "# $rcsid (mod-$mod)"
+ debug "# $mod"
# some mods want init
if type setup_mod_$mod > /dev/null; then
: 'Creating /dev'
if ! mount -t devtmpfs -o mode=0755,nosuid devtmpfs /dev > /dev/null 2>&1; then
mount -o mode=0755,nosuid -t tmpfs tmpfs /dev
- mknod /dev/console c 5 1
- mknod /dev/null c 1 3
- mknod /dev/zero c 1 5
- mknod /dev/random c 1 8
- mknod /dev/snapshot c 10 231
- mknod /dev/urandom c 1 9
- mknod /dev/ptmx c 5 2
- mknod /dev/kmsg c 1 11
+ mknod -m 600 /dev/console c 5 1
+ mknod -m 666 /dev/null c 1 3
+ mknod -m 666 /dev/zero c 1 5
+ mknod -m 666 /dev/random c 1 8
+ mknod -m 600 /dev/snapshot c 10 231
+ mknod -m 666 /dev/urandom c 1 9
+ mknod -m 666 /dev/ptmx c 5 2
+ mknod -m 644 /dev/kmsg c 1 11
fi
mkdir /dev/pts
mkdir /dev/shm
EOF
}
+# load font
+load_font() {
+ local font
+ [ ! -r /etc/sysconfig/console ] && return
+ . /etc/sysconfig/console
+ if [ -n "$CONSOLEFONT" ]; then
+ font=$(ls -1 /lib/kbd/consolefonts/${CONSOLEFONT}*.gz 2> /dev/null)
+ if [ -n "$font" ]; then
+ verbose "Loading font $font"
+ busybox_applet loadfont
+ inst_d "/lib/kbd/consolefonts"
+ cp -a "$font" "$DESTDIR/lib/kbd/consolefonts/"
+ gunzip ${DESTDIR}/lib/kbd/consolefonts/${CONSOLEFONT}*.gz
+ font=${font%.gz}
+ echo "loadfont < $font" | add_linuxrc
+ fi
+ fi
+}
+
# generate code to mount /proc on initrd
# can be called multiple times
mount_proc() {
fi
run_mounted=yes
- echo "mount -t tmpfs run /run" | add_linuxrc
+ echo "mount -t tmpfs run /run -o mode=0755,noexec,nosuid,nodev" | add_linuxrc
}
# unmount all mountpoints mounted by geninitrd
+# try to move pseudo filesystems to newroot if possible
umount_all() {
add_linuxrc <<-'EOF'
EOF
if is_yes "$run_mounted"; then
- echo 'mount --bind /run /newroot/run' | add_linuxrc
- echo 'umount /run' | add_linuxrc
+ add_linuxrc <<-EOF
+ mount -n --move /run /newroot/run
+ EOF
run_mounted=no
fi
if is_yes "$dev_mounted"; then
- echo 'umount /dev' | add_linuxrc
+ add_linuxrc <<-EOF
+ mount --bind /dev /newroot/dev
+ umount /dev
+ EOF
dev_mounted=no
fi
if is_yes "$sys_mounted"; then
- echo 'umount /sys' | add_linuxrc
+ add_linuxrc <<-EOF
+ mount --bind /sys /newroot/sys
+ umount /sys
+ EOF
sys_mounted=no
fi
+ if is_yes "$proc_mounted"; then
+ add_linuxrc <<-EOF
+ mount --bind /proc /newroot/proc
+ umount /proc
+ EOF
+ proc_mounted=no
+ fi
if is_yes "$tmp_mounted"; then
echo 'umount /tmp' | add_linuxrc
tmp_mounted=no
fi
- if is_yes "$proc_mounted"; then
- echo 'umount /proc' | add_linuxrc
- proc_mounted=no
- fi
}
-
# Checks if busybox has support for APPLET(s)
# Exits from geninitrd if the support is not present.
#
# try cache
eval have='$'busybox_have_$applet
if [ -z "$have" ]; then
- have=$(echo "$busybox_functions" | egrep -c "( |^)$applet(,|$)")
+ have=$(echo "$busybox_functions" | grep -Ec "( |^)$applet(,|$)")
if [ "$have" = 0 ]; then
warn "This setup requires busybox-initrd compiled with applet '$applet' support"
err=1
/lib/geninitrd/extract-ikconfig /boot/vmlinuz-$kernel
}
+# @param $module
+basename_module() {
+ local module=$1
+
+ module=${module##*/}
+ module=${module%$modext*}
+ echo $module
+}
+
# Finds module dependencies
#
# @param $module
warn "If $module isn't compiled in kernel then this initrd may not start your system."
fi
+ local smodule
+
echo "$modprobe" | \
while read insmod modpath options; do
- [ "$insmod" = "insmod" ] && echo $modpath
+ if [ "$insmod" = "insmod" ]; then
+
+ # XXX: find a away to autodetect
+ smodule=$(basename_module $modpath)
+ case "$smodule" in
+ btrfs)
+ warn "mounting multidevice btrfs volume requires rootfsflags=device=/dev/...,device=/dev/... kernel option"
+ find_depmod "-libcrc32c"
+ ;;
+ ext4)
+ find_depmod "-libcrc32c"
+ ;;
+ crc-t10dif)
+ find_depmod "-crct10dif-pclmul"
+ find_depmod "-crct10dif"
+ ;;
+ libcrc32c)
+ find_depmod "-crc32c-intel"
+ find_depmod "-crc32c"
+ ;;
+ virtio_blk|virtio_scsi)
+ find_depmod "-virtio_pci"
+ find_depmod "-virtio_mmio"
+ ;;
+ esac
+
+ echo $modpath
+ fi
done
return 0
}
local dest=$1
set -- $src
local parentDir=$(dirname $DESTDIR$dest)
- [ ! -d "$parentDir" ] && (debug "+ mkdir -p $parentDir"; mkdir -p $parentDir)
- debug "+ cp $* $DESTDIR$dest"
- cp -HR "$@" "$DESTDIR$dest"
+ if [ ! -d "$parentDir" ]; then
+ verbose "+ mkdir -p DESTDIR${parentDir#$DESTDIR}"
+ mkdir -p $parentDir
+ fi
+ verbose "+ cp $* DESTDIR$dest"
+ cp -HRp "$@" "$DESTDIR$dest"
}
inst_d() {
if [ $# = 0 ]; then
die 'Usage: inst_d <destination> <destination>'
fi
+ local dir
for dir in "$@"; do
install -d "$DESTDIR$dir"
done
inst "$@" $dest
- local obj lib libs
+ local obj lib libs libs_additional libdir
for obj in "$@"; do
case "$obj" in
- /lib/ld-linux.so.2 | /lib64/ld-linux-x86-64.so.2)
+ /lib/ld-linux.so.2 | /lib64/ld-linux-x86-64.so.2 | /libx32/ld-linux-x32.so.2)
continue
+ ;;
+ /lib/libpthread.so* | /lib64/libpthread.so* | /libx32/libpthread.so*)
+ libs_additional="${obj%/libpthread*}/libgcc_s.so.1"
+ ;;
esac
- libs=$(ldd "$obj" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
- for lib in $libs; do
- if [ ! -f "$DESTDIR/$_lib/${lib##*/}" ]; then
- inst_d /$_lib
- inst_exec $lib /$_lib
+
+ libs=$(ldd "$obj" 2> /dev/null | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
+ for lib in $libs $libs_additional; do
+ libdir=$(cd $(dirname "$lib"); pwd)
+ if [ ! -f "$DESTDIR/$lib" ]; then
+ inst_d $libdir
+ inst_exec $lib $libdir
fi
done
done
# hack for uclibc linked binaries requiring this fixed path
# XXX: shouldn't rpath be used here instead so th
- if [ -f $DESTDIR/$_lib/libc.so.0 ]; then
- local lib=$DESTDIR/$_lib/libc.so.0
- lib=$(ldd "$lib" | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
- local libdir=$(cd $(dirname "$lib"); pwd)
- if [ ! -e $DESTDIR$libdir ]; then
- libdir=$(dirname "$libdir")
- inst_d $libdir
- debug "+ ln -s /$_lib $DESTDIR$libdir"
- ln -s /$_lib $DESTDIR$libdir
+ for _lib in $(get_libdir LIBDIR); do
+ if [ -f $DESTDIR/$_lib/libc.so.0 ]; then
+ lib=$DESTDIR/$_lib/libc.so.0
+ lib=$(ldd "$lib" 2> /dev/null | awk '/statically|linux-(gate|vdso)\.so/{next} NF == 2 {print $1} /=/{print $3}' | sort -u)
+ libdir=$(cd $(dirname "$lib"); pwd)
+ if [ ! -e $DESTDIR$libdir ]; then
+ libdir=$(dirname "$libdir")
+ inst_d $libdir
+ verbose "+ ln -s /$_lib $DESTDIR$libdir"
+ ln -s /$_lib $DESTDIR$libdir
+ break
+ fi
fi
- fi
+ done
}
# output modules.conf / modprobe.conf
echo "$modprobe_conf_cache"
}
+# return options for MODULE
+# @param $1 module name
+modprobe_options() {
+ local module=$1
+ local options=$(modprobe_conf | awk -vmodule="$module" '{ if ($1 == "options" && $2 == module) { for(i=3;i<=NF;i++) printf("%s ",$i); }}')
+ echo ${options# }
+}
+
#
# defaults to modprobe -c if not told otherwise, this means include statements
# work from there.
devpath=$(readlink -f "$devpath")
fi
- debug "Finding modules for device path $devpath"
+ verbose "Finding modules for device path $devpath"
if is_luks "$devpath"; then
find_modules_luks "$devpath"
return
fi
+ if [[ "$devpath" == /dev/nvme* ]]; then
+ find_module "nvme"
+ return
+ fi
+
+ if [[ "$devpath" == /dev/bcache* ]]; then
+ find_modules_bcache "$devpath"
+ return
+ fi
+
if [[ "$devpath" == /dev/rd/* ]]; then
find_module "DAC960"
rootdev_add=/dev/rd/
local module="$1"
local firmware_files="$2"
- debug "Adding Firmwares ($firmware_files) to initrd for module $module"
+ verbose "Adding Firmwares ($firmware_files) to initrd for module $module"
# firmware not yet installed
if [ ! -f "$DESTDIR/lib/firmware/firmware.sh" ]; then
inst_d /lib/firmware
cat << 'EOF' >> "$DESTDIR/lib/firmware/firmware.sh"
#!/bin/sh -e
+# handle only firmware add requests
+if [ "$SUBSYSTEM" != "firmware" ]; then
+ exit 0
+fi
+if [ "$ACTION" != "add" ]; then
+ exit 0
+fi
echo 1 > /sys$DEVPATH/loading
cat "/lib/firmware/$FIRMWARE" > /sys$DEVPATH/data
echo 0 > /sys$DEVPATH/loading
MODULEDIR=${mod%/*}
inst_d "/lib/modules/$kernel/$MODULEDIR"
cp -a "/lib/modules/$kernel/$mod" "$DESTDIR/lib/modules/$kernel/$mod"
- gunzip "$DESTDIR/lib/modules/$kernel/$mod" 2> /dev/null
+ case $mod in
+ *.gz)
+ gunzip "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress gz"
+ mod=${mod%.gz}
+ ;;
+ *.xz)
+ xz -d "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress xz"
+ mod=${mod%.xz}
+ ;;
+ *.bz2)
+ bzip2 -d "$DESTDIR/lib/modules/$kernel/$mod" || die "Can't uncompress bz2"
+ mod=${mod%.bz2}
+ ;;
+ esac
if [ "$STRIP" ] && [ -x "$STRIP" ]; then
- $STRIP -g --remove-section=.comment "$DESTDIR/lib/modules/$kernel/${mod%.gz}"
+ $STRIP -g --remove-section=.comment "$DESTDIR/lib/modules/$kernel/${mod}"
fi
done
}
for mod in "$@"; do
# module path without optional compression
modpath=${mod%.gz}
+ modpath=${modpath%.xz}
+ modpath=${modpath%.bz2}
# name of the module
local module=${modpath##*/}; module=${module%$modext}
- local options=$(modprobe_conf | awk -vmodule="$module" '{ if ($1 == "options" && $2 == module) { for(i=3;i<=NF;i++) printf("%s ",$i); }}' | xargs)
+ local options=$(modprobe_options "$module")
local genericname=$(echo $module | tr - _)
local usleep=$(eval echo \$MODULE_${genericname}_USLEEP)
local firmware=$(eval echo \$MODULE_${genericname}_FIRMWARE)
options="scan=sync $options"
fi
- if [ -n "$verbose" ]; then
+ if [ x"$verbose" = x"-v" ]; then
s=""
if [ "$options" ]; then
s="$s with options [$options]"
if [ "$usleep" ]; then
s="$s and $usleep usleep"
fi
- debug "Loading module [$module]$s"
+ verbose "Loading module [$module]$s"
fi
if [ -n "$firmware" ]; then
while read major minor blocks dev rest; do
node=/dev/$dev
mkdir -p ${node%/*}
- [ -e $node ] || mknod $node b $major $minor
+ [ -e $node ] || mknod -m 660 $node b $major $minor
done
)
EOF
initrd_gen_setrootdev() {
- debug "Adding rootfs finding based on kernel cmdline root= option support."
+ verbose "Adding rootfs finding based on kernel cmdline root= option support."
busybox_applet ls
+ debug "Current /proc/partitions:\n$(sed -e 's,^,| ,' /proc/partitions)"
add_linuxrc <<-'EOF'
if [ "${ROOT##/dev/}" != "${ROOT}" ]; then
rootnr="$(busybox awk -v rootnode="${ROOT##/dev/}" '$4 == rootnode { print 256 * $1 + $2 }' /proc/partitions)"
- # fallback to ls
- if [ -z "$rootnr" ]; then
+ # fallback to ls, try two different formats
+ # http://lists.pld-linux.org/mailman/pipermail/pld-devel-en/2014-May/023915.html
+ if [ "${rootnr:-0}" = 0 -a -e "$ROOT" ]; then
+ # busybox up to 1.22
rootnr="$(busybox ls -lL ${ROOT} | busybox awk '{if (/^b/) { print 256 * $3 + $4; }}')"
fi
- if [ -n "$rootnr" ]; then
+ if [ "${rootnr:-0}" = 0 -a -e "$ROOT" ]; then
+ # busybox 1.22 and upwards
+ rootnr="$(busybox ls -lL ${ROOT} | busybox awk '{if (/^b/) { print 256 * $5 + $6; }}')"
+ fi
+ if [ "${rootnr:-0}" -gt 0 ]; then
echo "$rootnr" > /proc/sys/kernel/real-root-dev
fi
fi
# parse 'root=xxx' kernel commandline
# We support passing root as hda3 /dev/hda3 0303 0x0303 and 303
+
+ # from lilo-23.2/readme/README:
+ # root=<device> changes the root device. This overrides settings that may
+ # have been made in the boot image and on the LILO command line. <device> is
+ # either the hexadecimal device number or the full path name of the device,
+ # e.g. /dev/hda3 [*]
+ #
+ # * The device names are hard-coded in the kernel. Therefore, only the
+ # "standard" names are supported and some less common devices may not be
+ # recognized. In those cases, only numbers can be used.
+ busybox_applet cat
add_linuxrc <<-'EOF'
- device=/dev/no_partition_found
- eval "$(busybox awk -v c="$ROOT" '
+ device=
+ eval "$(busybox awk -v root="$ROOT" '
+ function h2d(str, hstr, res, num, n, digit, i) { # http://9fans.net/archive/2006/09/261
+ hstr = "0123456789abdcef"; res = 0;
+ n = split(tolower(str), digit, "");
+
+ for (i = 1; i <= n; i++) {
+ num = index(hstr, digit[i]) - 1;
+ res = res + (num * 16 ^ (n - i));
+ }
+ return res;
+ }
BEGIN {
- num_pattern_short = "[0-9a-f][0-9a-f][0-9a-f]";
- num_pattern = "[0-9a-f]" num_pattern_short;
+ num_pattern_short = "[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]";
+ num_pattern = "[0-9a-fA-F]" num_pattern_short;
dev_pattern = "[hms][a-z][a-z]([0-9])+";
- partition = "no_partition_found";
- min = -1; maj = -1;
-
- sub("^0x", "", c);
- if (c ~ "^" num_pattern_short "$") sub("^", "0", c);
- if (c ~ "^" num_pattern "$") {
- maj = sprintf("%s",substr(c,1,2));
- min = sprintf("%s",substr(c,3));
+ partition = ""; min = -1; maj = -1;
+
+ if (root ~ "^\/dev\/" dev_pattern "$" || root ~ "^" dev_pattern "$") { # see if we have /dev/hdX or hdX, we can just take partition name
+ partition = root; sub("^/dev/", "", partition);
+ } else { # unify values first
+ if (root ~ "^" num_pattern_short "$") { # change "303" => "0x0303"
+ root = "0x0" root
+ } else if (root ~ "^" num_pattern "$") { # change "0303" => "0x0303"
+ root = "0x" root
+ }
+ maj = h2d(substr(root, 3, 2));
+ min = h2d(substr(root, 5, 2));
}
- if (c ~ "^\/dev\/" dev_pattern "$") sub("^/dev/","", c);
- if (c ~ "^" dev_pattern "$") partition = c;
}
-
- $4 == partition { maj = $1; min = $2; }
+ partition && $4 == partition { maj = $1; min = $2; }
$1 == maj && $2 == min { partition = $4; }
-
END {
- if (maj >= 0 && min >= 0) {
- printf("device=/dev/%s; maj=%s; min=%s;\n", partition, maj, min);
- }
- }
- ' /proc/partitions)"
- if [ "$device" != '/dev/no_partition_found' -a ! -b $device ]; then
- mknod $device b $maj $min
+ if (maj >= 0 && min >= 0) { printf("maj=%s; min=%s;\n", maj, min); }
+ if (partition) { printf("device=/dev/%s;\n", partition); }
+ }' /proc/partitions)"
+
+ if [ -z "$device" ]; then
+ if [ "$DEBUGINITRD" -a "$DEBUGINITRD" != 'sh' ]; then
+ cat /proc/partitions
+ fi
+ device=$ROOT
+ fi
+
+ if [ "$device" -a ! -b $device -a "$maj$min" ]; then
+ mknod -m 660 $device b $maj $min
fi
- EOF
+ # XXX hack, fallback to rootdev from geninitrd time
+ if [ ! -e "$device" ]; then
+ EOF
add_linuxrc <<-EOF
- rootdev=$rootdev
- rootfs=$rootFs
+ device="$rootdev"
EOF
-
add_linuxrc <<-'EOF'
- if [ "$device" = '/dev/no_partition_found' ]; then
- device=$rootdev
+ echo "DEVICE set to $device based on fstab entry from initrd gen time"
fi
- [ -n "$ROOTFSFLAGS" ] && ROOTFSFLAGS="-o $ROOTFSFLAGS"
+ # XXX hack, if no device, try to parse it from /proc/partitions using /proc/sys/kernel/real-root-dev
+ if [ ! -e "$device" ]; then
+ rrd=$(cat /proc/sys/kernel/real-root-dev)
+ major=$(($rrd / 256))
+ minor=$(($rrd % 256))
+
+ while read pmajor pminor blocks dev rest; do
+ # skip header and empty line
+ [ -z "$pmajor" -o "$pmajor" = "major" ] && continue
+
+ if [ $pmajor = $major -a $pminor = $minor ]; then
+ device=/dev/$dev
+ echo "DEVICE set to $device based on real-root-dev"
+ fi
+ done < /proc/partitions
+ fi
+
+ [ -n "$ROOTFLAGS" ] && ROOTFLAGS="-o $ROOTFLAGS"
- mount -t $rootfs -r $device $ROOTFSFLAGS /newroot || echo "Mount of rootfs failed."
- init="$(echo "$CMDLINE" | busybox awk '/init=\// { gsub(/.*init=/,NIL,$0); gsub(/ .*/,NIL,$0); print }')"
+ mount -t $ROOTFS -r $device $ROOTFLAGS /newroot || echo "Mount of rootfs failed."
+ init=$INIT
if [ -z "$init" -o ! -x "/newroot$init" ]; then
init=/sbin/init
fi
EOF
+ busybox_applet dmesg
+ busybox_applet tail
+ add_linuxrc <<-'EOF'
+ if [ "$DEBUGINITRD" -a "$DEBUGINITRD" != 'sh' ]; then
+ echo "Last 20 lines of dmesg:"
+ dmesg | tail -n 20
+ fi
+
+ EOF
+
+ kmsg "geninitrd/$VERSION switching root"
+
umount_all
- busybox_applet switch_root
+ busybox_applet switch_root usleep
add_linuxrc <<-'EOF'
[ ! -e /newroot/dev/console ] && mknod -m 660 /newroot/dev/console c 5 1
+
+ # switch root to empty dir will make kernel panic, so sleep 10s before it
+ # switch_root needs to be pid 1, so there's no other way to recover from here
+ # if /dev is missing, switch root will likely fail, give debug shell before that
+ if [ ! -d /newroot/dev ]; then
+ echo "/dev is missing, switch_root will likely fail"
+ echo "if you booted with debugrd=sh, then you be given shell and you might able to recover this situation"
+ debugshell
+ [ "$DEBUGINITRD" ] || usleep 10000000
+ fi
+
+ # systemd[1]: /usr appears to be on its own filesytem and is not
+ # already mounted. This is not a supported setup. Some things will
+ # probably break (sometimes even silently) in mysterious ways. Consult
+ # http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
+ # for more information.
+ echo trying to mount /usr
+ chroot /newroot mount -n /usr
+
exec switch_root /newroot $init ${1:+"$@"}
+ # FIXME: this code is never executed, as "exec" does not return!
+
echo "Error! initramfs should not reach this place."
echo "It probably means you've got old version of busybox, with broken"
echo "initramfs support. Trying to boot anyway, but won't promise anything."
return 1
fi
- awk -vc=1 -vsymbol="$symbol" '$2 == "T" && $3 == symbol {c = 0} END {exit c}' $mapfile
+ awk -vc=1 -vsymbol="$symbol" '(tolower($2) == "t" || tolower($2) == "d") && $3 == symbol {c = 0} END {exit c}' $mapfile
}
# find best compressor (or forced one) for initrd
find_compressor() {
local mode="$1"
- # fastest initrd decompression speed is first
- local compressors='lzo gzip xz lzma bzip2'
+ local compressors='zstd xz lzma bzip2 gzip lzo'
# a specified one, take it
if ! is_yes "$mode"; then
compressors="$mode"
fi
- debug "finding compressor: $compressors (via $mode)"
+ verbose "finding compressor: $compressors (via $mode)"
# check for compressor validity
local c prog map=/boot/System.map-$kernel
for c in $compressors; do
sym=unlzo
prog=/usr/bin/lzop
;;
+ zstd)
+ sym=zstd
+ prog=/usr/bin/zstd
+ ;;
none|no)
# any existing sym will work
sym=initrd_load
fi
done
- debug "using gzip for compressor (fallback)"
+ verbose "using gzip for compressor (fallback)"
echo gzip
}
lzo)
lzop -9 < "$IMAGE" > "$tmp" || return $?
;;
+ zstd)
+ zstd -9 < "$IMAGE" > "$tmp" || return $?
+ ;;
none|no)
cat < "$IMAGE" > "$tmp" || return $?
;;
mv -f "$tmp" "$target"
}
+# prepend file to image
+prepend_file_to_image() {
+ local file="$1" target="$2" tmp
+ tmp=$(mktemp "$target".XXXXXX) || die "mktemp failed"
+
+ cat "$file" "$target" > "$tmp" || return $?
+
+ mv -f "$tmp" "$target"
+}
+
if [ -r /etc/sysconfig/geninitrd ]; then
. /etc/sysconfig/geninitrd
fi
warn "/proc filesystem not mounted, may cause wrong results or failure."
fi
-geninitrd_load_mods ide luks multipath dmraid lvm md blkid udev tuxonice suspend fbsplash condecor bootsplash uvesafb nfs sata scsi usbkbd
+geninitrd_load_mods ide luks multipath dmraid lvm md blkid udev swsusp tuxonice suspend fbsplash condecor bootsplash uvesafb nfs sata scsi usbkbd bcache
while [ $# -gt 0 ]; do
case $1 in
--without-fbcondecor)
FB_CON_DECOR=no
;;
+ --without-swsusp)
+ USE_SWSUSP=no
+ ;;
--with-suspend)
USE_SUSPEND=yes
;;
exit 0
;;
-v)
- verbose=-v
+ if [ x"$verbose" = x"-v" ]; then
+ verbose="-v -v"
+ else
+ verbose="-v"
+ fi
+ exec 3>&1
;;
--compress)
COMPRESS=$2
die "You need to be root to generate initrd"
fi
-if [ -d /lib64 -a -d /usr/lib64 ]; then
- _lib=lib64
-else
- _lib=lib
-fi
+for dir in libx32 lib64 lib; do
+ initrd_dir=/usr/$dir/initrd
+ if [ -d "$initrd_dir" ]; then
+ initrd_dirs="$initrd_dirs $initrd_dir"
+ fi
+done
-initrd_dir=/usr/$_lib/initrd
kernel_version=$(echo "$kernel" | awk -F. '{gsub(/[_-].*/, "", $0); print sprintf("%03d%03d",$1,$2)}')
kernel_version_long=$(echo "$kernel" | awk -F. '{gsub(/[_-].*/, "", $0); print sprintf("%03d%03d%03d",$1,$2,$3)}')
-debug "# $GENINITRD_RCSID (geninitrd)"
-debug "Using _lib: $_lib"
+verbose "# geninitrd $VERSION"
debug "Using initrd_dir: $initrd_dir"
busybox=$(find_tool $initrd_dir/busybox $initrd_dir/initrd-busybox /bin/initrd-busybox) || die "Couldn't find busybox suitable for initrd"
fi
fi
-case "$INITRDFS" in
- ext2)
- [ -x /sbin/mke2fs ] || die "/sbin/mke2fs is missing"
- ;;
- rom|romfs)
- [ -x /sbin/genromfs ] || die "/sbin/genromfs is missing"
- ;;
- cram|cramfs)
- [ -x /sbin/mkcramfs ] || die "/sbin/mkcramfs is missing"
- ;;
- initramfs)
- [ -x /bin/cpio ] || die "/bin/cpio is missing"
- [ -x /usr/bin/find ] || die "/usr/bin/find is missing"
- ;;
- *)
- die "Filesystem $INITRDFS on initrd is not supported"
- ;;
-esac
+check_initrd_fs() {
+ local s sfound sym p prog map=/boot/System.map-$kernel
+ case "$INITRDFS" in
+ ext2)
+ # TODO: symbols to check in case of ext2 used via ext3/4 subsystem
+ sym=init_ext2_fs
+ prog=/sbin/mke2fs
+ ;;
+ rom|romfs)
+ sym=init_romfs_fs
+ prog=/sbin/genromfs
+ ;;
+ cram|cramfs)
+ sym=init_cramfs_fs
+ prog=/sbin/mkcramfs
+ ;;
+ initramfs)
+ sym=__initramfs_start
+ prog="/bin/cpio /usr/bin/find"
+ ;;
+ *)
+ die "Filesystem $INITRDFS on initrd is not supported by geninitrd"
+ ;;
+ esac
+
+ # only one is needed (for cases like ext2 via ext2 or via ext3 or via ext4 subsysytem)
+ sfound=0
+ for s in $sym; do
+ sym_exists $map $s && sfound=1
+ break
+ done
+ if [ "$sfound" -eq "0" ]; then
+ die "Filesystem $INITRDFS on initrd is not supported by kernel"
+ fi
+
+ for p in $prog; do
+ [ ! -x "$p" ] && die "$prog is missing"
+ done
+}
+check_initrd_fs
if [ -L "$target" ]; then
target=$(readlink -f "$target")
find_modules_suspend
fi
+if is_yes "$USE_SWSUSP"; then
+ find_modules_swsusp
+fi
+
find_root "$fstab" || exit
-debug "Using $rootdev as device for rootfs"
+verbose "Using $rootdev as device for rootfs"
find_modules_for_devpath "$rootdev"
find_module "-lzf"
fi
+find_modules_uvesafb
find_modules_fbsplash
if [ -n "$ifneeded" -a -z "$MODULES" ]; then
- debug "No modules are needed -- not building initrd image."
+ verbose "No modules are needed -- not building initrd image."
exit 0
fi
-debug "Building initrd..."
+verbose "Building initrd..."
DESTDIR=$(mktemp -d -t initrd.XXXXXX) || die "mktemp failed"
RCFILE="$DESTDIR/linuxrc"
> "$RCFILE"
ln -s linuxrc $DESTDIR/init
# create dirs that we really need
-inst_d /{lib,bin,etc,dev{,/pts,/shm},loopfs,var,proc,run,sys}
+inst_d /{lib,bin,sbin,etc,dev{,/pts,/shm},loopfs,var,proc,run,sys,tmp}
modules_install "$MODULES"
# mknod'ing the devices instead of copying them works both with and
# without devfs...
-mknod "$DESTDIR/dev/console" c 5 1
-mknod "$DESTDIR/dev/null" c 1 3
-mknod "$DESTDIR/dev/zero" c 1 5
-mknod "$DESTDIR/dev/random" c 1 8
-mknod "$DESTDIR/dev/urandom" c 1 9
+mknod -m 600 "$DESTDIR/dev/console" c 5 1
+mknod -m 666 "$DESTDIR/dev/null" c 1 3
+mknod -m 666 "$DESTDIR/dev/zero" c 1 5
+mknod -m 666 "$DESTDIR/dev/random" c 1 8
+mknod -m 666 "$DESTDIR/dev/urandom" c 1 9
+mknod -m 644 "$DESTDIR/dev/kmsg" c 1 11
inst_exec $busybox /bin/busybox
ln -s busybox $DESTDIR/bin/sh
add_linuxrc <<EOF
#!/bin/sh
-# initrd generated by:
-# $GENINITRD_RCSID
+# initrd generated by geninitrd/$VERSION
+# on $(LC_ALL=C date)
EOF
+load_font
mount_proc
+
+kmsg "geninitrd/$VERSION starting"
+
+inst_d /lib/geninitrd/
+inst /lib/geninitrd/functions.initrd /lib/geninitrd/functions.initrd
+
+add_linuxrc <<-EOF
+ . /lib/geninitrd/functions.initrd
+ # builtin defaults from geninitrd
+ ROOT=$rootdev
+ ROOTFS=$rootFs
+EOF
add_linuxrc <<-'EOF'
read CMDLINE < /proc/cmdline
for arg in $CMDLINE; do
- if [ "${arg}" = "debuginitrd" ]; then
+ if [ "${arg}" = "debuginitrd" ] || [ "${arg}" = "debugrd" ]; then
DEBUGINITRD=yes
fi
- if [ "${arg##debuginitrd=}" != "${arg}" ]; then
- DEBUGINITRD=${arg##debuginitrd=}
+ if [ "${arg##debuginitrd=}" != "${arg}" ] || [ "${arg##debugrd=}" != "${arg}" ]; then
+ DEBUGINITRD=${arg##debug*rd=}
fi
if [ "${arg##root=}" != "${arg}" ]; then
ROOT=${arg##root=}
fi
+ if [ "${arg##rootfs=}" != "${arg}" ]; then
+ ROOTFS=${arg##rootfs=}
+ fi
+ if [ "${arg##rootflags=}" != "${arg}" ]; then
+ ROOTFLAGS=${arg##rootflags=}
+ fi
if [ "${arg##rootfsflags=}" != "${arg}" ]; then
ROOTFSFLAGS=${arg##rootfsflags=}
fi
+ if [ "${arg##init=}" != "${arg}" ]; then
+ INIT=${arg##init=}
+ fi
done
- # make debugshell() invoke subshell if $DEBUGINITRD=sh
+ # handling of invalid, rootfsflags, option
+ if [ -n "$ROOTFSFLAGS" ]; then
+ if [ -n "$ROOTFLAGS" ]; then
+ ROOTFLAGS="$ROOTFLAGS,$ROOTFSFLAGS"
+ else
+ ROOTFLAGS="$ROOTFSFLAGS"
+ fi
+ fi
+
if [ "$DEBUGINITRD" = "sh" ]; then
+ # export some vars to subshell for debug to work
+ export CMDLINE ROOT ROOTFS ROOTDEV ROOTFLAGS DEBUGINITRD INIT
+ export LVM_ROOTVG LVM_SUSPENDVG LVM_VGVOLUMES
+ export rootnr attrs majmin major minor device
+
+ # make debugshell() invoke subshell if $DEBUGINITRD=sh
debugshell() {
EOF
if is_yes "$RUN_SULOGIN_ON_ERR"; then
add_linuxrc <<-'EOF'
- echo "debug shell disabled by /etc/sysconfig/system:RUN_SULOGIN_ON_ERR setting"
+ echo "debug shell disabled by RUN_SULOGIN_ON_ERR=yes from /etc/sysconfig/system during initrd generation time"
EOF
else
add_linuxrc <<-'EOF'
fi
EOF
+# mount early
+mount_tmp
+mount_run
+
modules_add_linuxrc $MODULES
# TODO: rewrite for busybox
if is_yes "$USE_UDEV"; then
initrd_gen_udev
+else
+ initrd_gen_mdev
fi
-find_modules_uvesafb
initrd_gen_uvesafb
-
initrd_gen_luks
initrd_gen_dmraid
initrd_gen_multipath
else
initrd_gen_md
initrd_gen_lvm
+ initrd_gen_bcache
+ initrd_gen_blkid
initrd_gen_luks
initrd_gen_setrootdev
fi
-initrd_gen_tuxonice
-initrd_gen_suspend
-
# additional devs always needed
[ ! -e "$DESTDIR/$rootdev_add" ] && inst $rootdev_add /dev
initrd_gen_stop_udevd
+initrd_gen_stop_mdev
initrd_gen_stop_uvesafb
+# resume after killing local processes
+initrd_gen_tuxonice
+initrd_gen_suspend
+initrd_gen_swsusp
+
# clean up env
add_linuxrc <<-'EOF'
+if [ ! "$DEBUGINITRD" ]; then
ifs=$IFS
IFS="
"
[ -z "$i" ] && continue
case "$i" in
- root|PATH|HOME|TERM)
+ ROOT|PATH|HOME|TERM)
:
;;
*)
- echo "unset $i"
+ unset $i
;;
esac
done
IFS=$ifs
+fi
EOF
if [ "$INITRDFS" = "initramfs" ]; then
initrd_gen_fbsplash
initrd_gen_fbcondecor
+debug "Current /linuxrc:\n$(sed -e 's,^,| ,' $DESTDIR/linuxrc)"
+
IMAGE=$(mktemp -t initrd.img-XXXXXX) || die "mktemp failed"
IMAGESIZE=$(du -ks $DESTDIR | awk '{print int(($1+1023+512)/1024)*1024}')
-debug "image size: $IMAGESIZE KiB ($DESTDIR)"
+verbose "image size: $IMAGESIZE KiB ($DESTDIR)"
-debug "Creating $INITRDFS image $IMAGE"
+verbose "Creating $INITRDFS image $IMAGE"
case "$INITRDFS" in
ext2)
dd if=/dev/zero of="$IMAGE" bs=1k count="$IMAGESIZE" 2> /dev/null
die "Filesystem $INITRDFS not supported by $PROGRAM"
esac
-CONFIG_BLK_DEV_RAM_SIZE=$(ikconfig | awk -F= '/^CONFIG_BLK_DEV_RAM_SIZE/{print $2}')
-if [ -z "$CONFIG_BLK_DEV_RAM_SIZE" ]; then
- CONFIG_BLK_DEV_RAM_SIZE=4096
- warn "No CONFIG_BLK_DEV_RAM_SIZE detected, fallback to $CONFIG_BLK_DEV_RAM_SIZE"
-fi
+if [ "$INITRDFS" != "initramfs" ]; then
+ CONFIG_BLK_DEV_RAM_SIZE=$(ikconfig | awk -F= '/^CONFIG_BLK_DEV_RAM_SIZE/{print $2}')
+ if [ -z "$CONFIG_BLK_DEV_RAM_SIZE" ]; then
+ CONFIG_BLK_DEV_RAM_SIZE=4096
+ warn "No CONFIG_BLK_DEV_RAM_SIZE detected, fallback to $CONFIG_BLK_DEV_RAM_SIZE"
+ fi
-if [ "$IMAGESIZE" -gt $CONFIG_BLK_DEV_RAM_SIZE ]; then
- warn "Your image size is larger than $CONFIG_BLK_DEV_RAM_SIZE, Be sure to boot kernel with ramdisk_size=$IMAGESIZE!"
+ if [ "$IMAGESIZE" -gt $CONFIG_BLK_DEV_RAM_SIZE ]; then
+ warn "Your image size is larger than $CONFIG_BLK_DEV_RAM_SIZE, Be sure to boot kernel with ramdisk_size=$IMAGESIZE!"
+ fi
fi
if ! is_no "$COMPRESS"; then
compressor=$(find_compressor "$COMPRESS")
- debug "Compressing $target with $compressor"
+ verbose "Compressing $target with $compressor"
# TODO: the image name (specified from kernel.spec) already contains
# extension, which is .gz most of the time.
cp -a "$IMAGE" "$target"
fi
+# microcode support for lilo
+if ! is_no "$LILO_MICROCODE"; then
+ if [ -x /sbin/lilo -a -f "/boot/intel-ucode.img" ]; then
+ verbose "Prepending $target with microcode image /boot/intel-ucode.img for LILO"
+ prepend_file_to_image "/boot/intel-ucode.img" "$target"
+ fi
+fi
+
# XXX. check if bootsplash can output data to tmp dir not directly to initramfs image.
initrd_gen_bootsplash "$target"