]> git.pld-linux.org Git - projects/geninitrd.git/blobdiff - geninitrd
- swsusp support from mis@pld-linux
[projects/geninitrd.git] / geninitrd
index 675b4bb6ae3387364cb88766394efcbdc70bde23..ea7d438e56abd1086cc8fec876b239626602f9fe 100755 (executable)
--- a/geninitrd
+++ b/geninitrd
@@ -7,8 +7,7 @@
 # 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
@@ -18,6 +17,7 @@ PROGRAM=${0##*/}
 # 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=""
@@ -47,7 +47,7 @@ proc_partitions=no
 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]"
@@ -79,8 +79,31 @@ warn() {
        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
@@ -92,15 +115,28 @@ die() {
 
 # 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 find any of: $@"
+       debug "find_tool: did not find any of: $n"
        return 1
 }
 
@@ -119,11 +155,10 @@ geninitrd_load_mods() {
 
 # 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
@@ -154,20 +189,39 @@ mount_dev() {
                : '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() {
@@ -220,10 +274,11 @@ mount_run() {
        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'
@@ -232,29 +287,38 @@ umount_all() {
        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.
 #
@@ -283,7 +347,7 @@ busybox_applet() {
                # 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
@@ -315,6 +379,15 @@ ikconfig() {
        /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
@@ -349,9 +422,38 @@ find_depmod() {
                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
 }
@@ -402,15 +504,19 @@ inst() {
        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
@@ -432,35 +538,44 @@ inst_exec() {
 
        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
@@ -515,7 +630,7 @@ find_modules_for_devpath() {
                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"
@@ -557,6 +672,16 @@ find_modules_for_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/
@@ -631,12 +756,19 @@ firmware_install_module() {
        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
@@ -673,9 +805,22 @@ modules_install() {
                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
 }
@@ -686,6 +831,8 @@ modules_add_linuxrc() {
        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}
@@ -698,7 +845,7 @@ modules_add_linuxrc() {
                        options="scan=sync $options"
                fi
 
-               if [ -n "$verbose" ]; then
+               if [ x"$verbose" = x"-v" ]; then
                        s=""
                        if [ "$options" ]; then
                                s="$s with options [$options]"
@@ -706,7 +853,7 @@ modules_add_linuxrc() {
                        if [ "$usleep" ]; then
                                s="$s and $usleep usleep"
                        fi
-                       debug "Loading module [$module]$s"
+                       verbose "Loading module [$module]$s"
                fi
 
                if [ -n "$firmware" ]; then
@@ -749,7 +896,7 @@ initrd_gen_devices() {
                        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
@@ -757,16 +904,23 @@ initrd_gen_devices() {
 
 
 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
@@ -783,58 +937,141 @@ initrd_gen_initramfs_switchroot() {
 
        # 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("%d",substr(c,1,2));
-                                       min = sprintf("%d",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
-               fi
+                               if (maj >= 0 && min >= 0) {     printf("maj=%s; min=%s;\n", maj, min);  }
+                               if (partition) {                printf("device=/dev/%s;\n", partition); }
+                       }' /proc/partitions)"
 
-               if [ "$device" = '/dev/no_partition_found' ]; then
+               if [ -z "$device" ]; then
+                       if [ "$DEBUGINITRD" -a "$DEBUGINITRD" != 'sh' ]; then
+                               cat /proc/partitions
+                       fi
                        device=$ROOT
                fi
 
-               [ -n "$ROOTFSFLAGS" ] && ROOTFSFLAGS="-o $ROOTFSFLAGS"
+               if [ "$device" -a ! -b $device -a "$maj$min" ]; then
+                       mknod -m 660 $device b $maj $min
+               fi
 
-               mount -t $ROOTFS -r $device $ROOTFSFLAGS /newroot || echo "Mount of rootfs failed."
+               # XXX hack, fallback to rootdev from geninitrd time
+               if [ ! -e "$device" ]; then
+       EOF
+       add_linuxrc <<-EOF
+                       device="$rootdev"
+       EOF
+       add_linuxrc <<-'EOF'
+                       echo "DEVICE set to $device based on fstab entry from initrd gen time"
+               fi
+
+               # 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 $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."
@@ -859,21 +1096,20 @@ sym_exists() {
                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
@@ -898,6 +1134,10 @@ find_compressor() {
                        sym=unlzo
                        prog=/usr/bin/lzop
                        ;;
+               zstd)
+                       sym=zstd
+                       prog=/usr/bin/zstd
+                       ;;
                none|no)
                        # any existing sym will work
                        sym=initrd_load
@@ -913,7 +1153,7 @@ find_compressor() {
                fi
        done
 
-       debug "using gzip for compressor (fallback)"
+       verbose "using gzip for compressor (fallback)"
        echo gzip
 }
 
@@ -940,6 +1180,9 @@ compress_image() {
        lzo)
                lzop -9 < "$IMAGE" > "$tmp" || return $?
                ;;
+       zstd)
+               zstd -9 < "$IMAGE" > "$tmp" || return $?
+               ;;
        none|no)
                cat < "$IMAGE" > "$tmp" || return $?
                ;;
@@ -948,6 +1191,16 @@ compress_image() {
        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
@@ -956,7 +1209,7 @@ if [ ! -f /proc/mounts ]; then
        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
@@ -992,6 +1245,9 @@ while [ $# -gt 0 ]; do
        --without-fbcondecor)
                FB_CON_DECOR=no
                ;;
+       --without-swsusp)
+               USE_SWSUSP=no
+               ;;
        --with-suspend)
                USE_SUSPEND=yes
                ;;
@@ -1047,7 +1303,12 @@ while [ $# -gt 0 ]; do
                exit 0
                ;;
        -v)
-               verbose=-v
+               if [ x"$verbose" = x"-v" ]; then
+                       verbose="-v -v"
+               else
+                       verbose="-v"
+               fi
+               exec 3>&1
                ;;
        --compress)
                COMPRESS=$2
@@ -1122,18 +1383,17 @@ if [ "$(id -u)" != 0 ]; then
        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"
@@ -1159,24 +1419,46 @@ if [ -z "$INITRDFS" ]; then
        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")
@@ -1229,8 +1511,12 @@ if is_yes "$USE_SUSPEND"; then
        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"
 
@@ -1250,14 +1536,15 @@ if is_yes "$USE_TUXONICE"; then
        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"
@@ -1265,17 +1552,18 @@ chmod a+rx "$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
@@ -1284,12 +1572,20 @@ ln -s busybox $DESTDIR/bin/initrd-busybox
 
 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
@@ -1298,15 +1594,21 @@ 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
@@ -1315,13 +1617,27 @@ add_linuxrc <<-'EOF'
                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'
@@ -1341,6 +1657,10 @@ add_linuxrc <<-'EOF'
        fi
 EOF
 
+# mount early
+mount_tmp
+mount_run
+
 modules_add_linuxrc $MODULES
 
 # TODO: rewrite for busybox
@@ -1359,11 +1679,11 @@ modules_add_linuxrc $MODULES
 
 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
@@ -1374,21 +1694,27 @@ if is_yes "$have_nfs"; then
 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="
        "
@@ -1417,6 +1743,7 @@ add_linuxrc <<-'EOF'
                esac
        done
        IFS=$ifs
+fi
 EOF
 
 if [ "$INITRDFS" = "initramfs" ]; then
@@ -1428,12 +1755,14 @@ fi
 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
@@ -1466,19 +1795,21 @@ case "$INITRDFS" in
        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.
@@ -1494,6 +1825,14 @@ else
        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"
 
This page took 0.070844 seconds and 4 git commands to generate.