#!/bin/sh # geninitrd # # by PLD Linux Team # # based on mkinitrd from RedHat Linux # GENINITRD_RCSID='$Revision$ $Date:: $' R=${GENINITRD_RCSID#* *}; VERSION=${R%% *} PROGRAM=${0##*/} . /etc/rc.d/init.d/functions . /lib/geninitrd/functions . /etc/sysconfig/system # list of geninitrd modules which need setup routine after commandline args parsing GENINITRD_MODS="" COMPRESS=yes STRIP=/usr/bin/strip target="" kernel="" force="" verbose="" MODULES="" img_vers="" fstab=/etc/fstab modext=.o rootdev_nr=0 # device node for rootfs from fstab rootdev="" # internal variables # is /dev on tmpfs dev_mounted=no # is /proc mounted proc_mounted=no # is /sys mounted sys_mounted=no # is /tmp mounted on tmpfs tmp_mounted=no # are /dev nodes already created from /proc/devices info? proc_partitions=no usage() { echo "Usage: $PROGRAM [--version] [-v] [-f] [--ifneeded] [--preload ]" echo " [--with=] [--image-version] [--fstab=] [--nocompress]" echo " [--compress=yes|xz|lzma|bzip2|gzip|lzo]" echo " [--nostrip ] [--strip PATH/strip] [--strip=PATH/strip]" echo " [--initrdfs=rom|initramfs|ext2|cram] [--modules-conf=]" echo " [--with-bootsplash] [--without-bootsplash]" echo " [--with-fbsplash] [--without-fbsplash]" echo " [--with-fbcondecor] [--without-fbcondecor]" echo " [--lvmtoolsversion=1|2] [--with-udev] [--without-udev]" echo " [--with-suspend] [--without-suspend]" echo " [--with-tuxonice] [--without-tuxonice]" echo " [--without-dmraid]" echo " [--with-multipath=DEVPATH] [--without-multipath]" echo " [--without-blkid] [--without-luks]" echo " " echo "" echo "Example:" local kdir kver dir=${target:-/boot} for kdir in /lib/modules/*; do [ -d $kdir ] || continue kver=${kdir##*/} echo " $0 -f --initrdfs=initramfs $dir/initrd-$kver.gz $kver $verbose" done | sort -V } msg() { echo "$PROGRAM: $*" } warn() { msg "WARNING: $*" >&2 } debug() { [ -n "$verbose" ] && msg "$*" >&2 } # aborts program abnormally die() { local rc=${2:-1} msg "ERROR: $1" >&2 exit $rc } # find program from specified paths find_tool() { local x for x in "$@"; do if [ -x "$x" ]; then echo $x debug "find_tool: found $x" return 0 fi done debug "find_tool: did not find any of: $@" return 1 } # loads geninitrd modules geninitrd_load_mods() { local mod for mod in "$@"; do if [ ! -f /lib/geninitrd/mod-$mod.sh ]; then die "$mod geninitrd module can't be loaded" fi . /lib/geninitrd/mod-$mod.sh GENINITRD_MODS="$GENINITRD_MODS $mod" done } # setup geninitrd modules geninitrd_setup_mods() { local mod rcsid for mod in $GENINITRD_MODS; do eval rcsid=$(echo \$$mod | LC_ALL=C tr '[a-z]' '[A-Z]')_RCSID debug "# $rcsid (mod-$mod)" # some mods want init if type setup_mod_$mod > /dev/null; then eval setup_mod_$mod fi done } # append text to /linuxrc # takes STDIN as input add_linuxrc() { cat >> "$RCFILE" } # generate code to mount /dev on tmpfs and create initial nodes # can be called multiple times. /dev is cleaned up (umounted) automatically at # the end of script. mount_dev() { # we already generated tmpfs code; return if is_yes "$dev_mounted"; then return fi dev_mounted=yes busybox_applet mount mknod mkdir add_linuxrc <<-EOF : '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 fi mkdir /dev/pts mkdir /dev/shm EOF } # generate code to mount /proc on initrd # can be called multiple times mount_proc() { if is_yes "$proc_mounted"; then return fi proc_mounted=yes if [ "$INITRDFS" = "initramfs" ]; then # /proc is mounted with initramfs 2.6.22.14 kernel # XXX: remove when it is clear why proc was already mounted echo "[ -f /proc/cmdline ] || mount -t proc none /proc" | add_linuxrc else echo "mount -t proc none /proc" | add_linuxrc fi } # generate code to mount /sys on initrd # can be called multiple times mount_sys() { if is_yes "$sys_mounted"; then return fi sys_mounted=yes echo "mount -t sysfs none /sys" | add_linuxrc } # generate code to mount /tmp on initrd # can be called multiple times mount_tmp() { if [ "$INITRDFS" = "initramfs" ]; then # initramfs is read-write filesystem, no need for tmpfs return fi if is_yes "$tmp_mounted"; then return fi tmp_mounted=yes echo "mount -t tmpfs none /tmp" | add_linuxrc } # generate code to mount /run on initrd # can be called multiple times mount_run() { if is_yes "$run_mounted"; then return fi run_mounted=yes echo "mount -t tmpfs run /run" | add_linuxrc } # unmount all mountpoints mounted by geninitrd umount_all() { add_linuxrc <<-'EOF' : Last shell before umounting all and giving control over to real init. debugshell EOF if is_yes "$run_mounted"; then echo 'mount --bind /run /newroot/run' | add_linuxrc echo 'umount /run' | add_linuxrc run_mounted=no fi if is_yes "$dev_mounted"; then echo 'umount /dev' | add_linuxrc dev_mounted=no fi if is_yes "$sys_mounted"; then echo 'umount /sys' | add_linuxrc sys_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. # # NB! XXX do not output to STDOUT, it will appear in initrd images in some cases! busybox_applet() { local err=0 applet if [ -z "$busybox_functions" ]; then local tmp=$($busybox 2>&1) # BusyBox v1.1.3 says applet not found if it's not called 'busybox'. if [[ "$tmp" = *applet\ not\ found* ]]; then local t=$(mktemp -d) ln -s $busybox $t/busybox local tmp=$($t/busybox 2>&1) rm -rf $t fi busybox_functions=$(echo "$tmp" | \ sed -ne '/Currently defined functions:/,$p' | \ xargs | sed -e 's,.*Currently defined functions: ,,' ) fi for applet in $*; do local have # try cache eval have='$'busybox_have_$applet if [ -z "$have" ]; then have=$(echo "$busybox_functions" | egrep -c "( |^)$applet(,|$)") if [ "$have" = 0 ]; then warn "This setup requires busybox-initrd compiled with applet '$applet' support" err=1 fi eval busybox_have_$applet=$have fi done if [ $err = 1 ]; then die "Aborted" fi } # Extract the .config file from a kernel image # uses extract-ikconfig from kernel sources (scripts/extract-ikconfig) ikconfig() { local kofile=$(modinfo -k $kernel -n configs 2> /dev/null) if [ -n "$kofile" ]; then /lib/geninitrd/extract-ikconfig $kofile return fi # see if config available as separate file if [ -f /boot/config-$kernel ]; then cat /boot/config-$kernel return fi # finally try vmlinuz itself /lib/geninitrd/extract-ikconfig /boot/vmlinuz-$kernel } # Finds module dependencies # # @param $module # # Outputs full path to module and it's dependencies find_depmod() { local module="$1" local skiperrors=0 # if module is prefixed with dash, we should ignore errors if the module # can't be found. if [ ${module#-} != $module ]; then skiperrors=1 module=${module#-} fi # This works when user has module-init-tools installed even on 2.4 kernels local modprobe modprobe=$(modprobe --set-version $kernel --show-depends $module --ignore-install 2>&1) if [ $? != 0 ]; then if [ $skiperrors = 1 ]; then return 0 fi echo >&2 "$modprobe" if ! is_no "$EXIT_IF_MISSING"; then die "$module: module not found for $kernel kernel" fi warn "$module: module not found for $kernel kernel" warn "If $module isn't compiled in kernel then this initrd may not start your system." fi echo "$modprobe" | \ while read insmod modpath options; do [ "$insmod" = "insmod" ] && echo $modpath done return 0 } find_firmware() { local module="$1" # no firmware support in 2.4 kernels if [ "$kernel_version_long" -lt "002005048" ]; then return fi echo -n $(NEW_MODINFO=1 modinfo -k $kernel -F firmware $module 2>/dev/null | xargs) } # @param $module find_module() { local mod depmod module=$1 depmod=$(find_depmod $module) || exit 1 for mod in $depmod; do mod=${mod#/lib/modules/$kernel/} # add each module only once local m have=0 for m in $MODULES; do [ $m = $mod ] && have=1 done if [ $have = 0 ]; then MODULES="$MODULES $mod" fi done } # install a file to temporary mount image. # it will operate recursively (copying directories) # and will symlink destinations if source is symlink. inst() { if [ $# -lt 2 ]; then die 'Usage: inst [] ' fi local src i=0 c=$(($# - 1)) while [ $i -lt $c ]; do src="$src $1" i=$((i + 1)) shift done 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" } inst_d() { if [ $# = 0 ]; then die 'Usage: inst_d ' fi for dir in "$@"; do install -d "$DESTDIR$dir" done } # install executable and it's shared libraries inst_exec() { if [ $# -lt 2 ]; then die "Invalid params ($@), Usage: inst_exec [, ] " fi local src i=0 c=$(($# - 1)) while [ $i -lt $c ]; do src="$src $1" i=$((i + 1)) shift done local dest=$1 set -- $src inst "$@" $dest local obj lib libs for obj in "$@"; do case "$obj" in /lib/ld-linux.so.2 | /lib64/ld-linux-x86-64.so.2) continue 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 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 fi fi } # output modules.conf / modprobe.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. cache_modprobe_conf() { if [ "$kernel_version" -lt "002005" ]; then modulefile=/etc/modules.conf if [ ! -f "$modulefile" -a -f /etc/conf.modules ]; then modulefile=/etc/conf.modules fi fi if [ -n "$modulefile" ]; then debug "Using $modulefile for modules config" modprobe_conf_cache=$(cat $modulefile | awk '!/^[\t ]*#/ { print }') else debug "Using modprobe -c to get modules config" modprobe_conf_cache=$(modprobe -c --set-version $kernel | awk '!/^[\t ]*#/ { print }') fi } # find modules for $devpath find_modules_for_devpath() { local devpath="$1" if [ -z "$devpath" ]; then die "No argument passed to find_modules_for_devpath() - is your /etc/fstab correct?" fi if [[ "$devpath" = /dev/dm-* ]]; then # /dev/dm-3 -> /dev/mapper/sil_ahbgadcbchfc3 devpath=$(dm_node "$devpath") fi if [ -L "$devpath" ] && ! is_lvm "$devpath" && ! is_luks "$devpath"; then # sanitize things like: # /dev/block/104:2 -> /dev/cciss/c0d0p2 devpath=$(readlink -f "$devpath") fi debug "Finding modules for device path $devpath" if is_luks "$devpath"; then find_modules_luks "$devpath" return fi if is_nfs "$devpath"; then find_modules_nfs "$devpath" return fi if is_md "$devpath"; then find_modules_md "$devpath" return fi if is_multipath "$devpath"; then if find_modules_multipath "$devpath"; then return fi # fallback fi if is_dmraid "$devpath"; then if find_modules_dmraid "$devpath"; then return fi # fallback fi if is_scsi "$devpath"; then find_modules_scsi "$devpath" return fi if is_ide "$devpath"; then find_modules_ide "$devpath" return fi if [[ "$devpath" == /dev/rd/* ]]; then find_module "DAC960" rootdev_add=/dev/rd/ return fi if [[ "$devpath" == /dev/ida/* ]]; then find_module "cpqarray" rootdev_add=/dev/ida/ return fi if [[ "$devpath" == /dev/cciss/* ]]; then rootdev_add=/dev/cciss/ # load hpsa for future kernels, cciss for backwards compat if [ "$kernel_version_long" -ge "003000000" ]; then find_module "hpsa" "-cciss" find_modules_scsi "$devpath" else find_module "cciss" fi return fi if [[ "$devpath" == /dev/ataraid/* ]]; then find_modules_ide find_module "ataraid" ataraidmodules=$(modprobe_conf | awk '/ataraid_hostadapter/ { print $3 }') if [ -n "$ataraidmodules" ]; then # FIXME: think about modules compiled in kernel die "ataraid_hostadapter alias not defined in modprobe.conf! Please set it and run $PROGRAM again." fi for n in $ataraidmodules; do find_module "$n" done rootdev_add=/dev/ataraid/ return fi # check to see if we need to set up a loopback filesystem if [[ "$devpath" == /dev/loop* ]]; then die "Sorry, root on loop device isn't supported." # TODO: rewrite for bsp and make nfs ready if [ ! -x /sbin/losetup ]; then die "losetup is missing" fi key="^# $(echo $devpath | awk -F/ '{print($3);}' | tr '[a-z]' '[A-Z]'):" if ! is_yes "`awk '/'$key'/ { print( "yes"); }' $fstab`"; then die "The root filesystem is on a $devpath, but there is no magic entry in $fstab for this device. Consult the $PROGRAM man page for more information" fi line="`awk '/'$key'/ { print $0; }' $fstab`" loopDev="$(echo $line | awk '{print $3}')" loopFs="$(echo $line | awk '{print $4}')" loopFile="$(echo $line | awk '{print $5}')" BASICMODULES="$BASICMODULES -loop" find_module "-$loopFs" BASICMODULES="$BASICMODULES -${loopFs}" return fi if is_lvm "$devpath"; then find_modules_lvm "$devpath" return fi } firmware_install_module() { local module="$1" local firmware_files="$2" debug "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 echo 1 > /sys$DEVPATH/loading cat "/lib/firmware/$FIRMWARE" > /sys$DEVPATH/data echo 0 > /sys$DEVPATH/loading exit 0 EOF chmod 755 "$DESTDIR/lib/firmware/firmware.sh" # setup firmware loader agent echo "echo -n "/lib/firmware/firmware.sh" > /proc/sys/kernel/hotplug" | add_linuxrc fi for firmware in $firmware_files; do if [ -f "/lib/firmware/$kernel/$firmware" ]; then FIRMWAREDIR=${firmware%/*} [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR inst /lib/firmware/$kernel/$firmware /lib/firmware/$firmware elif [ -f "/lib/firmware/$firmware" ]; then FIRMWAREDIR=${firmware%/*} [ "$FIRMWAREDIR" != "$firmware" ] && inst_d /lib/firmware/$FIRMWAREDIR inst /lib/firmware/$firmware /lib/firmware/$firmware else warn "Possible missing firmware file /lib/firmware/$firmware or /lib/firmware/$kernel/$firmware for module $module." fi done mount_sys } modules_install() { local modules="$1" local mod for mod in $modules; do 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 if [ "$STRIP" ] && [ -x "$STRIP" ]; then $STRIP -g --remove-section=.comment "$DESTDIR/lib/modules/$kernel/${mod%.gz}" fi done } modules_add_linuxrc() { local mod modpath for mod in "$@"; do # module path without optional compression modpath=${mod%.gz} # name of the module local module=${modpath##*/}; module=${module%$modext} local options=$(modprobe_options "$module") local genericname=$(echo $module | tr - _) local usleep=$(eval echo \$MODULE_${genericname}_USLEEP) local firmware=$(eval echo \$MODULE_${genericname}_FIRMWARE) if [ "$module" = "scsi_mod" -a "$kernel_version_long" -ge "002006030" ]; then options="scan=sync $options" fi if [ -n "$verbose" ]; then s="" if [ "$options" ]; then s="$s with options [$options]" fi if [ "$usleep" ]; then s="$s and $usleep usleep" fi debug "Loading module [$module]$s" fi if [ -n "$firmware" ]; then firmware_install_module "$module" "$firmware" else for file in $(find_firmware "$module"); do firmware_install_module "$module" "$file" done fi echo "insmod /lib/modules/$kernel/$modpath $options" | add_linuxrc if [ -n "$usleep" ]; then echo "usleep $usleep" | add_linuxrc fi if [ "$module" = "scsi_wait_scan" ]; then if [ "$(busybox_applet rmmod 2>/dev/null; echo $?)" = 0 ]; then echo "rmmod scsi_wait_scan" | add_linuxrc fi fi done } # Generates /dev nodes based on /proc/partitions information. # Needs /proc mounted. # Can be called multiple times. initrd_gen_devices() { if is_yes "$proc_partitions"; then return fi proc_partitions=yes mount_dev add_linuxrc <<-'EOF' : 'Making device nodes' cat /proc/partitions | ( # ignore first two lines: header, empty line read b; read b while read major minor blocks dev rest; do node=/dev/$dev mkdir -p ${node%/*} [ -e $node ] || mknod $node b $major $minor done ) EOF } initrd_gen_setrootdev() { debug "Adding rootfs finding based on kernel cmdline root= option support." busybox_applet ls 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 rootnr="$(busybox ls -lL ${ROOT} | busybox awk '{if (/^b/) { print 256 * $3 + $4; }}')" fi if [ -n "$rootnr" ]; then echo "$rootnr" > /proc/sys/kernel/real-root-dev fi fi EOF } initrd_gen_initramfs_switchroot() { inst_d /newroot if [ "$rootdev" = "/dev/nfs" ]; then echo "rootfs on NFS root=/dev/nfs" else [ ! -e "$DESTDIR/$rootdev" ] && inst $rootdev $rootdev fi # parse 'root=xxx' kernel commandline # We support passing root as hda3 /dev/hda3 0303 0x0303 and 303 add_linuxrc <<-'EOF' device= eval "$(busybox awk -v c="$ROOT" ' BEGIN { num_pattern_short = "[0-9a-f][0-9a-f][0-9a-f]"; num_pattern = "[0-9a-f]" num_pattern_short; dev_pattern = "[hms][a-z][a-z]([0-9])+"; partition = ""; 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)); } if (c ~ "^\/dev\/" dev_pattern "$") sub("^/dev/","", c); if (c ~ "^" dev_pattern "$") partition = c; } partition && $4 == partition { maj = $1; min = $2; } $1 == maj && $2 == min { partition = $4; } END { 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 device=$ROOT fi if [ "$device" -a ! -b $device ]; then mknod $device b $maj $min fi [ -n "$ROOTFSFLAGS" ] && ROOTFSFLAGS="-o $ROOTFSFLAGS" mount -t $ROOTFS -r $device $ROOTFSFLAGS /newroot || echo "Mount of rootfs failed." init=$INIT if [ -z "$init" -o ! -x "/newroot$init" ]; then init=/sbin/init fi EOF umount_all busybox_applet switch_root add_linuxrc <<-'EOF' [ ! -e /newroot/dev/console ] && mknod -m 660 /newroot/dev/console c 5 1 exec switch_root /newroot $init ${1:+"$@"} 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." exec chroot /newroot $init ${1:+"$@"} echo "Failed to chroot!" debugshell EOF # we need /init being real file, not symlink, otherwise the initramfs will # not be ran by pid 1 which is required for switch_root mv $DESTDIR/linuxrc $DESTDIR/init ln -s init $DESTDIR/linuxrc } # find if $symbol exists in System.map $mapfile sym_exists() { local mapfile="$1" local symbol="$2" if [ ! -f $mapfile ]; then # missing mapfile (not a pld kernel?) return 1 fi awk -vc=1 -vsymbol="$symbol" '$2 == "T" && $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' # a specified one, take it if ! is_yes "$mode"; then compressors="$mode" fi debug "finding compressor: $compressors (via $mode)" # check for compressor validity local c prog map=/boot/System.map-$kernel for c in $compressors; do case $c in xz) sym=unxz prog=/usr/bin/xz ;; lzma) sym=unlzma prog=/usr/bin/xz ;; bzip2) sym=bzip2 prog=/usr/bin/bzip2 ;; gzip) sym=gunzip prog=/bin/gzip ;; lzo) sym=unlzo prog=/usr/bin/lzop ;; none|no) # any existing sym will work sym=initrd_load prog=/bin/cat ;; *) die "Unknown compressor $c" ;; esac if sym_exists $map $sym && [ -x $prog ]; then echo $c return fi done debug "using gzip for compressor (fallback)" echo gzip } # compresses kernel image image # in function so we could retry with other compressor on failure compress_image() { local compressor="$1" IMAGE="$2" target="$3" tmp tmp=$(mktemp "$target".XXXXXX) || die "mktemp failed" case "$compressor" in xz) # don't use -9 here since kernel won't understand it xz --format=xz --check=crc32 --lzma2=preset=6e,dict=1MiB < "$IMAGE" > "$tmp" || return $? ;; lzma) xz --format=lzma -9 < "$IMAGE" > "$tmp" || return $? ;; bzip2) bzip2 -9 < "$IMAGE" > "$tmp" || return $? ;; gzip) gzip -9 < "$IMAGE" > "$tmp" || return $? ;; lzo) lzop -9 < "$IMAGE" > "$tmp" || return $? ;; none|no) cat < "$IMAGE" > "$tmp" || return $? ;; esac mv -f "$tmp" "$target" } if [ -r /etc/sysconfig/geninitrd ]; then . /etc/sysconfig/geninitrd fi 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 while [ $# -gt 0 ]; do case $1 in --fstab=*) fstab=${1#--fstab=} ;; --fstab) fstab=$2 shift ;; --modules-conf=*) modulefile=${1#--modules-conf=} ;; --modules-conf) modulefile=$2 shift ;; --with-bootsplash) BOOT_SPLASH=yes ;; --without-bootsplash) BOOT_SPLASH=no ;; --with-fbsplash) FB_SPLASH=yes ;; --without-fbsplash) FB_SPLASH=no ;; --with-fbcondecor) FB_CON_DECOR=yes ;; --without-fbcondecor) FB_CON_DECOR=no ;; --with-suspend) USE_SUSPEND=yes ;; --without-suspend) USE_SUSPEND=no ;; --with-suspend2 | --with-tuxonice) USE_TUXONICE=yes ;; --without-suspend2 | --without-tuxonice) USE_TUXONICE=no ;; --lvmversion=*) LVMTOOLSVERSION=${1#--lvmversion=} ;; --lvmtoolsversion=*) LVMTOOLSVERSION=${1#--lvmtoolsversion=} ;; --lvmtoolsversion|--lvmversion) LVMTOOLSVERSION=$2 shift ;; --without-udev) USE_UDEV=no ;; --with-udev) USE_UDEV=yes ;; --without-dmraid) USE_DMRAID=no ;; --without-multipath) USE_MULTIPATH=no ;; --with-multipath=*) USE_MULTIPATH=${1#--with-multipath=} ;; --without-blkid) USE_BLKID=no ;; --without-luks) USE_LUKS=no ;; --with=*) BASICMODULES="$BASICMODULES ${1#--with=}" ;; --with) BASICMODULES="$BASICMODULES $2" shift ;; --version) echo "$PROGRAM: version $VERSION" exit 0 ;; -v) verbose=-v ;; --compress) COMPRESS=$2 ;; --compress=*) COMPRESS="${1#--compress=}" ;; --nocompress) COMPRESS=no ;; --nostrip) STRIP= ;; --strip=*) STRIP="${1#--strip=}" ;; --strip) STRIP=$2 shift ;; --ifneeded) ifneeded=1 ;; -f) force=1 ;; --preload=*) PREMODS="$PREMODS ${1#--preload=}" ;; --preload) PREMODS="$PREMODS $2" shift ;; --fs=* | --fs) die "--fs option is obsoleted. Use --initrdfs instead" ;; --initrdfs=*) INITRDFS=${1#--initrdfs=} ;; --initrdfs) INITRDFS=$2 shift ;; --image-version) img_vers=yes ;; --ide-only-root) ide_only_root="yes" ;; *) if [ -z "$target" ]; then target="$1" elif [ -z "$kernel" ]; then kernel="$1" else usage exit 1 fi ;; esac shift done if [ -z "$target" -o -z "$kernel" ]; then usage exit 1 fi # main() 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 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" 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" # we setup mods after parsing command line args geninitrd_setup_mods if [ ! -f /boot/vmlinuz-"$kernel" ]; then warn "/boot/vmlinuz-$kernel doesn't exist, is your /boot mounted?" fi if [ -z "$INITRDFS" ]; then if [ -n "$FS" ]; then # FS= can came only via /etc/sysconfig/geninitrd likely? die "FS configuration option is obsoleted. Use INITRDFS instead" fi # default value if [ "$kernel_version" -ge "002005" ]; then INITRDFS="initramfs" else INITRDFS="rom" 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 if [ -L "$target" ]; then target=$(readlink -f "$target") fi if [ -n "$img_vers" ]; then target="$target-$kernel" fi if [ -z "$force" -a -f "$target" ]; then die "$target already exists." fi if [ ! -d "/lib/modules/$kernel" ]; then die "/lib/modules/$kernel is not a directory." fi if [ "$kernel_version" -ge "002005" ]; then modext=".ko" fi cache_modprobe_conf for n in $PREMODS; do find_module "$n" done if [ "$FBMODULE" ]; then find_module "$FBMODULE" fi # autodetect USB keyboards find_modules_usbkbd # allow forcing loading SCSI and/or IDE modules # XXX: where ADDSCSI cames from? drop? if is_yes "$ADDSCSI"; then find_modules_scsi fi # autodetect SATA modules find_modules_sata # XXX: where ADDIDE cames from? drop? if is_yes "$ADDIDE"; then find_modules_ide fi if is_yes "$USE_SUSPEND"; then find_modules_suspend fi find_root "$fstab" || exit debug "Using $rootdev as device for rootfs" find_modules_for_devpath "$rootdev" # if USE_MULTIPATH is path to device, scan that too # this is to bootstrap multipath setup into initrd. if ! is_no "$USE_MULTIPATH" && ! is_yes "$USE_MULTIPATH"; then find_modules_multipath $USE_MULTIPATH fi find_module "-$rootFs" for n in $BASICMODULES; do find_module "$n" done if is_yes "$USE_TUXONICE"; then find_module "-lzf" fi find_modules_fbsplash if [ -n "$ifneeded" -a -z "$MODULES" ]; then debug "No modules are needed -- not building initrd image." exit 0 fi debug "Building initrd..." DESTDIR=$(mktemp -d -t initrd.XXXXXX) || die "mktemp failed" RCFILE="$DESTDIR/linuxrc" > "$RCFILE" 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} 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 inst_exec $busybox /bin/busybox ln -s busybox $DESTDIR/bin/sh # for older busyboxes who had /bin/initrd-busybox as EXEPATH ln -s busybox $DESTDIR/bin/initrd-busybox add_linuxrc <> "$RCFILE" # echo "mount -t $loopFs $loopDev /loopfs" >> "$RCFILE" # echo "echo Setting up loopback device $rootdev" >> $RCFILE # echo "losetup $rootdev /loopfs$loopFile" >> "$RCFILE" #fi if is_yes "$USE_UDEV"; then initrd_gen_udev fi find_modules_uvesafb initrd_gen_uvesafb initrd_gen_luks initrd_gen_dmraid initrd_gen_multipath initrd_gen_blkid if is_yes "$have_nfs"; then initrd_gen_nfs else initrd_gen_md initrd_gen_lvm 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_uvesafb # clean up env add_linuxrc <<-'EOF' ifs=$IFS IFS=" " for i in $(export -p); do i=${i#declare -x } # ksh/bash i=${i#export } # busybox case "$i" in *=*) : ;; *) continue ;; esac i=${i%%=*} [ -z "$i" ] && continue case "$i" in ROOT|PATH|HOME|TERM) : ;; *) unset $i ;; esac done IFS=$ifs EOF if [ "$INITRDFS" = "initramfs" ]; then initrd_gen_initramfs_switchroot else umount_all fi initrd_gen_fbsplash initrd_gen_fbcondecor 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)" debug "Creating $INITRDFS image $IMAGE" case "$INITRDFS" in ext2) dd if=/dev/zero of="$IMAGE" bs=1k count="$IMAGESIZE" 2> /dev/null # NOTE: ext2 label is max 16 chars mke2fs -q -F -b 1024 -m 0 -L "PLD/$kernel" "$IMAGE" 2>/dev/null 1>&2 tune2fs -i 0 "$IMAGE" >/dev/null 2>&1 local tmpmnt=$(mktemp -d -t initrd.mnt-XXXXXX) debug "Mounting ext2 image $IMAGE to $tmpmnt" mount -o loop -t ext2 "$IMAGE" "$tmpmnt" || die "mount failed, check dmesg(1)" # We don't need this directory, so let's save space rm -rf "$tmpmnt"/lost+found debug "Copy recursively $DESTDIR -> $tmpmnt" cp -a $DESTDIR/* $tmpmnt umount "$IMAGE" rmdir "$tmpmnt" ;; rom|romfs) genromfs -f "$IMAGE" -d "$DESTDIR" -V "PLD Linux/$kernel (geninitrd/$VERSION)" ;; cram|cramfs) mkcramfs "$DESTDIR" "$IMAGE" ;; initramfs) (cd $DESTDIR; find . | cpio --quiet -H newc -o > "$IMAGE") ;; *) 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 [ "$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 if ! is_no "$COMPRESS"; then compressor=$(find_compressor "$COMPRESS") debug "Compressing $target with $compressor" # TODO: the image name (specified from kernel.spec) already contains # extension, which is .gz most of the time. compress_image "$compressor" "$IMAGE" "$target" || { if [ $compressor != gzip ]; then warn "Could not compress with $compressor, retrying with gzip" compress_image gzip "$IMAGE" "$target" || die "compress failed with gzip" $? else die "Could not compress image with $compressor" fi } else cp -a "$IMAGE" "$target" fi # XXX. check if bootsplash can output data to tmp dir not directly to initramfs image. initrd_gen_bootsplash "$target" rm -rf "$DESTDIR" "$IMAGE" # vim:ts=4:sw=4:noet:fdm=marker