#!/bin/bash --norc
#
# mkinitrd
#
# Copyright 2005-2008 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Author(s): Erik Troan
# Elliot Lee
# Miguel de Icaza
# Christian 'Dr. Disk' Hechelmann
# Michael K. Johnson
# Pierre Habraken
# Jakub Jelinek
# Carlo Arenas Belon (carenas@chasqui.lared.net.pe>
# Keith Owens
# Bernhard Rosenkraenzer
# Matt Wilson
# Trond Eivind Glomsrød
# Jeremy Katz
# Preston Brown
# Bill Nottingham
# Guillaume Cottenceau
# Peter Jones
#
error()
{
NONL=""
if [ "$1" == "-n" ]; then
NONL="-n"
shift
fi
echo $NONL "$@" >&2
}
if [ $UID != 0 ]; then
error "mkinitrd must be run as root."
exit 1
fi
export MALLOC_PERTURB_=204
PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
export PATH
. /etc/rc.d/init.d/functions
# Set the umask. For iscsi, the initrd can contain plaintext
# password (chap secret), so only allow read by owner.
umask 077
VERSION=6.0.39
PROBE="yes"
MODULES=""
PREMODS=""
DMDEVS=""
ncryptodevs=0
nlatecryptodevs=0
NET_LIST=""
LD_SO_CONF=/etc/ld.so.conf
LD_SO_CONF_D=/etc/ld.so.conf.d/
[ -e /etc/sysconfig/mkinitrd ] && . /etc/sysconfig/mkinitrd
CONFMODS="$MODULES"
MODULES=""
ARCH=$(uname -m | sed -e 's/s390x/s390/')
compress=1
allowmissing=""
target=""
kernel=""
force=""
verbose=""
img_vers=""
builtins=""
modulefile=/etc/modules.conf
[ "$ARCH" != "s390" ] && withusb=1
rc=0
dynamic=""
nolvm=""
nodmraid=""
IMAGESIZE=8000
PRESCSIMODS=""
fstab="/etc/fstab"
vg_list=""
net_list="$NET_LIST"
vecho()
{
NONL=""
if [ "$1" == "-n" ]; then
NONL="-n"
shift
fi
[ -n "$verbose" ] && echo $NONL "$@"
}
usage () {
if [ "$1" == "-n" ]; then
cmd=echo
else
cmd=error
fi
$cmd "usage: `basename $0` [--version] [--help] [-v] [-f] [--preload ]"
$cmd " [--force-scsi-probe | --omit-scsi-modules]"
$cmd " [--image-version] [--force-raid-probe | --omit-raid-modules]"
$cmd " [--with=] [--force-lvm-probe | --omit-lvm-modules]"
$cmd " [--builtin=] [--omit-dmraid] [--net-dev=]"
$cmd " [--fstab=] [--nocompress] "
$cmd ""
$cmd " (ex: `basename $0` /boot/initrd-2.2.5-15.img 2.2.5-15)"
if [ "$1" == "-n" ]; then
exit 0
else
exit 1
fi
}
moduledep() {
vecho -n "Looking for deps of module $1"
deps=""
deps=$(modprobe --set-version $kernel --show-depends $1 2>/dev/null| awk '/^insmod / { print gensub(".*/","","g",$2) }' | while read foo ; do [ "${foo%%.ko}" != "$1" ] && echo -n "${foo%%.ko} " ; done)
[ -n "$deps" ] && vecho ": $deps" || vecho
}
locatemodule() {
fmPath=$(modprobe --set-version $kernel --show-depends $1 2>/dev/null | awk '/^insmod / { print $2; }' | tail -1)
if [ -n "$fmPath" -a -f "$fmPath" ]; then
return 0
fi
for modExt in o.gz o ko ; do
for modDir in /lib/modules/$kernel/updates /lib/modules/$kernel ; do
if [ -d $modDir ]; then
fmPath=$(findone $modDir -name $1.$modExt)
if [ -n "$fmPath" -a -f "$fmPath" ]; then
return 0
fi
fi
done
done
return 1
}
expandModules() {
items=$*
for m in $items ; do
char=$(echo $m | cut -c1)
if [ $char = '=' ]; then
NAME=$(echo $m | cut -c2-)
if [ "$NAME" = "ata" ]; then
MODS="$MODS $(cat /lib/modules/$kernel/modules.block |egrep '(ata|ahci)' |sed -e 's/.ko//')"
else
MODS="$MODS $(cat /lib/modules/$kernel/modules.$NAME |sed -e 's/.ko//')"
fi
else
MODS="$MODS $m"
fi
done
echo $MODS
}
qpushd() {
pushd "$1" >/dev/null 2>&1
}
qpopd() {
popd >/dev/null 2>&1
}
findone() {
echo nash-find "$@" | /sbin/nash --force --quiet \
| /bin/awk '{ print $1; exit; }'
}
findall() {
echo nash-find "$@" | /sbin/nash --force --quiet
}
dm_get_uuid() {
echo nash-dm get_uuid "$1" | /sbin/nash --force --quiet
}
resolve_device_name() {
echo nash-resolveDevice "$1" | /sbin/nash --forcequiet
}
DSO_DEPS=""
LDSO=""
get_dso_deps() {
bin="$1" ; shift
DSO_DEPS=""
declare -a FILES
declare -a NAMES
# this is a hack, but the only better way requires binutils or elfutils
# be installed. i.e., we need readelf to find the interpretter.
if [ -z "$LDSO" ]; then
for ldso in /lib*/ld*.so* ; do
[ -L $ldso ] && continue
[ -x $ldso ] || continue
$ldso --verify $bin >/dev/null 2>&1 || continue
LDSO="$ldso"
done
fi
# I still hate shell.
declare -i n=0
while read NAME I0 FILE ADDR I1 ; do
[ "$FILE" == "not" ] && FILE="$FILE $ADDR"
NAMES[$n]="$NAME"
FILES[$n]="$FILE"
let n++
done << EOF
$(LD_TRACE_PRELINKING=1 LD_WARN= LD_TRACE_LOADED_OBJECTS=1 \
$LDSO $bin 2>/dev/null)
EOF
[ ${#FILES[*]} -eq 0 ] && return 1
# we don't want the name of the binary in the list
if [ "${FILES[0]}" == "$bin" ]; then
FILES[0]=""
NAMES[0]=""
[ ${#FILES[*]} -eq 1 ] && return 1
fi
declare -i n=0
while [ $n -lt ${#FILES[*]} ]; do
FILE="${FILES[$n]}"
if [ "$FILE" == "not found" ]; then
cat 1>&2 < []"
return 1
fi
local file="$1" ; shift
local root="${1%%/}/" ; shift
local dest="${1##/}" ; shift
[ -z "$dest" ] && dest="${file##/}"
local old_indent_chars=${indent_chars}
indent_chars="${indent_chars} "
indent=${indent_chars:2}
mkdir -p "$root/$(dirname $dest)"
local RET=0
local target=""
[ -L "$file" ] && target=$(readlink "$file")
if [ -n "$target" -a "$dest" != "$target" ]; then
if [ -e "$root$dest" ]; then
#vecho "${indent}$root/$dest already exists"
RET=0
else
vecho "${indent}$file -> $root$dest"
ln -sf "$target" "$root$dest"
inst "$target" "$root"
l=`echo "$x" | sed -n 's,\(/lib[^/]*\)/.*$,\1,p'`
if [ -n "$l" ]; then
inst "$x" "$root" "$l"/`basename "$x"`
else
inst "$x" "$root"
fi
RET=$?
indent_chars=${old_indent_chars}
return $RET
fi
fi
local SHEBANG=$(dd if="$file" bs=2 count=1 2>/dev/null)
if [ "$SHEBANG" == '#!' ]; then
# We're intentionally not playing the "what did this moron run
# in his shell script" game. There's nothing but pain in that.
local interp=$(head -1 "$file" | sed 's/^#! *//')
inst "$interp" "$root"
RET=$?
indent_chars=${old_indent_chars}
return $RET
fi
if [ -e "$root$dest" ]; then
#vecho "${indent}$root$dest already exists"
RET=0
else
if [ -n "$target" -a -L "$target" ]; then
inst "$target" "$root"
RET=$?
else
vecho "${indent}$file -> $root$dest"
cp -aL "$file" "$root$dest"
get_dso_deps "$file"
local DEPS="$DSO_DEPS"
for x in $DEPS ; do
TLIBDIR=`echo "$x" | sed 's,\(/lib[^/]*\)/.*$,\1,'`
BASE=`basename "$x"`
inst "$x" "$root" "$TLIBDIR/$BASE"
done
RET=$?
fi
fi
indent_chars=${old_indent_chars}
return $RET
}
finddevnoinsys() {
majmin="$1"
if [ -n "$majmin" ]; then
dev=$(for x in /sys/block/* ; do findall $x/ -name dev ; done | while read device ; do \
echo "$majmin" | cmp -s $device && echo $device ; done)
if [ -n "$dev" ]; then
dev=${dev%%/dev}
dev=${dev%%/}
echo "$dev"
return 0
fi
fi
return 1
}
findblockdevinsys() {
devname=$(resolve_device_name "$1")
if [[ "$devname" =~ ^/sys/block/ ]]; then
echo "$devname"
fi
# check if it's a dm-crypt device. if so, just return the /dev/mapper path
if [[ "$devname" =~ ^/dev/mapper/ ]]; then
type=$(/sbin/dmsetup table $(basename $devname) | awk '{print $3}')
if [ "$type" == "crypt" ]; then
echo "$devname"
return 0
fi
fi
majmin=$(get_numeric_dev dec $devname)
finddevnoinsys "$majmin"
}
findstoragedriverinsys () {
while [ ! -L device ]; do
[ "$PWD" = "/sys" ] && return
cd ..
done
cd $(readlink ./device)
if is_iscsi $PWD; then
handleiscsi "$PWD"
return
fi
while [ "$PWD" != "/sys/devices" ]; do
deps=
if [ -f modalias ]; then
moduledep $(cat modalias)
fi
[ -z "$deps" -a -L driver/module ] && \
deps=$(basename $(readlink driver/module))
for driver in $deps ; do
findmodule $driver
done
cd ..
done
}
findstoragedriver () {
for device in $@ ; do
case " $handleddevices " in
*" $device "*)
continue ;;
*) handleddevices="$handleddevices $device" ;;
esac
if [[ "$device" =~ "^md[0-9]+" ]]; then
vecho "Found RAID component $device"
handleraid "$device"
continue
fi
vecho "Looking for driver for device $device"
if [[ "$device" =~ ^(dm-|mapper/) ]]; then
majmin=$(get_numeric_dev dec "/dev/$device")
sysfs=$(finddevnoinsys $majmin)
handledm $(echo "$majmin" |cut -d : -f 1) $(echo "$majmin" |cut -d : -f 2)
else
if [[ "$device" =~ ^/sys ]]; then
device=${device##*/}
fi
sysfs=$(for x in /sys/block/* ; do findone -type d $x/ -name $device; done)
fi
[ -z "$sysfs" ] && return
qpushd $sysfs
findstoragedriverinsys
qpopd
done
}
findnetdriver() {
for device in $@ ; do
case " $handleddevices " in
*" $device "*)
continue ;;
*) handleddevices="$handleddevices $device" ;;
esac
if [ -f /sys/class/net/$device/device/modalias ]; then
modalias=$(cat /sys/class/net/$device/device/modalias)
moduledep $modalias
for driver in $deps ; do
findmodule $driver
done
elif [ "$(basename $(readlink /sys/class/net/$device/device/bus) 2>/dev/null)" = "xen" ]; then
findmodule xennet # FIXME: hack for xennet sucking
else
findmodule $(ethtool -i $device | awk '/^driver:/ { print $2 }')
fi
done
}
iscsi_get_rec_val() {
# The open-iscsi 742 release changed to using flat files in
# /var/lib/iscsi.
result=$(grep "^${2} = " "$1" | sed -e s'/.* = //')
}
iscsi_set_parameters() {
path=$1
vecho setting iscsi parameters
# Check once before getting explicit values, so we can output a decent
# error message.
declare -a iparams=( $(/sbin/iscsiadm -m session 2>/dev/null) )
if [[ -z "${iparams[*]}" ]]; then
echo Unable to find iscsi record for $path
exit 1
fi
nit_name=$(grep "^InitiatorName=" /etc/iscsi/initiatorname.iscsi | \
sed -e "s/^InitiatorName=//")
tgt_name=${iparams[3]}
# edit ipaddr:port,portalgrp -> ipaddr,port,portalgrp
iportal=${iparams[2]/:/,}
declare -a ipt=( $(echo ${iportal//,/ }) )
tgt_ipaddr=${ipt[0]}
tgt_port=${ipt[1]}
tpgt=${ipt[2]}
path=/var/lib/iscsi/nodes/${tgt_name}/${tgt_ipaddr},${tgt_port}
# Note: we get chap secrets (passwords) in plaintext, and also store
# them in the initrd.
iscsi_get_rec_val $path "node.session.auth.username"
chap=${result}
if [ -n "${chap}" -a "${chap}" != "" ]; then
chap="-u ${chap}"
iscsi_get_rec_val $path "node.session.auth.password"
chap_pw="-w ${result}"
else
chap=""
fi
iscsi_get_rec_val $path "node.session.auth.username_in"
chap_in=${result}
if [ -n "${chap_in}" -a "${chap_in}" != "" ]; then
chap_in="-U ${chap_in}"
iscsi_get_rec_val $path "node.session.auth.password_in"
chap_in_pw="-W ${result}"
else
chap_in=""
fi
}
emit_iscsi () {
if [ -n "${iscsi_devs}" ]; then
inst /sbin/iscsistart "$MNTIMAGE" /bin/iscsistart
emit "echo Attaching to iSCSI storage"
for dev in ${iscsi_devs}; do
iscsi_set_parameters $dev
# recid is not really used, just use 0 for it
emit "/bin/iscsistart -t ${tgt_name} -i ${nit_name} \
-g ${tpgt} -a ${tgt_ipaddr} ${chap} ${chap_pw} \
${chap_in} ${chap_in_pw}"
done
fi
}
is_iscsi() {
path=$1
if echo $path | grep -q "/platform/host[0-9]*/session[0-9]*/target[0-9]*:[0-9]*:[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*"; then
return 0
else
return 1
fi
}
handledm() {
major=$1
minor=$2
while read dmstart dmend dmtype r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 ; do
case "$dmtype" in
crypt)
slavedev=$(finddevnoinsys $r3)
slavedev=${slavedev##*/}
cryptsetup isLuks "/dev/$slavedev" 2>/dev/null || continue
find_base_dm_mods
findmodule dm-crypt
for mod in $(echo $r0 | tr ':-' ' ') ; do
findmodule --skiperrors $mod
done
dmname=$(dmsetup info -j $major -m $minor -c --noheadings -o name)
# do the device resolution dance to get /dev/mapper/foo
# since 'lvm lvs' doesn't like dm-X device nodes
if [[ "$slavedev" =~ ^dm- ]]; then
majmin=$(get_numeric_dev dec "/dev/$slavedev")
for dmdev in /dev/mapper/* ; do
dmnum=$(get_numeric_dev dev $dmdev)
if [ $dmnum = $majmin ]; then
slavedev=${dmdev#/dev/}
break
fi
done
fi
# determine if $slavedev is an LV
# if so, add the device to latecryptodevs
# if not, add the device to cryptodevs
local vg=$(lvshow /dev/$slavedev)
if [ -n "$vg" ]; then
eval latecryptodev${ncryptodevs}='"'/dev/$slavedev $dmname'"'
let nlatecryptodevs++
else
eval cryptodev${ncryptodevs}='"'/dev/$slavedev $dmname'"'
let ncryptodevs++
fi
handlelvordev "/dev/$slavedev"
;;
esac
done << EOF
$(dmsetup table -j $major -m $minor 2>/dev/null)
EOF
}
handleiscsi() {
vecho "Found iscsi component $1"
findmodule iscsi_tcp
# We call iscsi_set_parameters once here to figure out what network to
# use (it sets tgt_ipaddr), and once again to emit iscsi values,
# not very efficient.
iscsi_set_parameters $1
iscsi_devs="$iscsi_devs $1"
netdev=$(/sbin/ip route get to $tgt_ipaddr | \
sed 's|.*dev \(.*\).*|\1|g' | awk '{ print $1; exit }')
addnetdev $netdev
}
handleraid() {
local start=0
if [ -n "$noraid" -o ! -f /proc/mdstat ]; then
return 0
fi
levels=$(awk "/^$1[ ]*:/ { print\$4 }" /proc/mdstat)
devs=$(gawk "/^$1[ ]*:/ { print gensub(\"\\\\[[0-9]*\\\\]\",\"\",\"g\",gensub(\"^md.*raid[0-9]*\",\"\",\"1\")) }" /proc/mdstat)
for level in $levels ; do
case $level in
linear)
findmodule linear
start=1
;;
multipath)
findmodule multipath
start=1
;;
raid[01456] | raid10)
findmodule $level
findmodule raid456
start=1
;;
*)
error "raid level $level (in /proc/mdstat) not recognized"
;;
esac
done
findstoragedriver $devs
if [ "$start" = 1 ]; then
raiddevices="$raiddevices $1"
fi
return $start
}
lvshow() {
lvm lvs --ignorelockingfailure --noheadings -o vg_name \
$1 2>/dev/null | egrep -v '^ *(WARNING:|Volume Groups with)'
}
vgdisplay() {
lvm vgdisplay --ignorelockingfailure -v $1 2>/dev/null |
sed -n 's/PV Name//p'
}
dmmods_found="n"
find_base_dm_mods()
{
[ "$dmmods_found" == "n" ] || return
findmodule -dm-mod
# DM requires all of these to be there in case someone used the
# feature. broken. (#132001)
findmodule -dm-mirror
findmodule -dm-zero
findmodule -dm-snapshot
dmmods_found="y"
}
handlelvordev() {
[ -n "$1" ] || return 0
local vg=$(lvshow $1)
if [ -n "$vg" ]; then
vg=`echo $vg` # strip whitespace
case " $vg_list " in
*" $vg "*) ;;
*) vg_list="$vg_list $vg"
for device in $(vgdisplay $vg) ; do
findstoragedriver ${device##/dev/}
done
[ -z "$nolvm" ] && find_base_dm_mods
;;
esac
else
findstoragedriver ${1##/dev/}
fi
}
handlenetdev() {
local dev=$1
source /etc/sysconfig/network
if [ ! -f /etc/sysconfig/network-scripts/ifcfg-$dev ]; then
error "unable to find network device configuration for $dev"
else
source /etc/sysconfig/network-scripts/ifcfg-$dev
fi
if [ x"$BOOTPROTO" = x ]; then
error "bootproto not specified for $dev, assuming DHCP"
BOOTPROTO=dhcp
fi
[ -n "$IPADDR" ] && IPSTR="$IPSTR --ip $IPADDR"
[ -n "$NETMASK" ] && IPSTR="$IPSTR --netmask $NETMASK"
[ -n "$GATEWAY" ] && IPSTR="$IPSTR --gateway $GATEWAY"
[ -n "$ETHTOOL_OPTS" ] && IPSTR="$IPSTR --ethtool \"$ETHTOOL_OPTS\""
[ -n "$MTU" ] && IPSTR="$IPSTR --mtu $MTU"
if [ -n "$IPADDR" ]; then
[ -z "$DOMAIN" ] && DOMAIN=$(awk '/^search / { print gensub("^search ","",1) }' /etc/resolv.conf)
if [ -z "$DNS1" ]; then
DNS1=$(awk '/^nameserver / { ORS="" ; if (x > 0) print "," ; printf "%s", $2 ; x = 1}' /etc/resolv.conf)
fi
fi
[ -n "$DOMAIN" ] && IPSTR="$IPSTR --domain \"$DOMAIN\""
if [ -n "$DNS1" ]; then
if [ -n "$DNS2" ]; then
IPSTR="$IPSTR --dns $DNS1,$DNS2"
else
IPSTR="$IPSTR --dns $DNS1"
fi
fi
network="network --device $dev --bootproto $BOOTPROTO $IPSTR"
if [ "$BOOTPROTO" = "dhcp" ]; then
dhclient_leases_cmd="cp /var/lib/dhclient/dhclient.leases /sysroot/dev/.dhclient-$dev.leases"
mkdir -p $MNTIMAGE/var/lib/dhclient
fi
}
addnetdev() {
vecho "Adding network device $1"
findnetdriver "$1"
net_list="$net_list $1"
}
handlenfs() {
remote=${1%%:*}
remoteip=$(host $remote | awk '/ address / { print $4 ; exit 0; }')
# assume, if it didn't resolve, that it's an IP
[ -z "$remoteip" ] && remoteip=$remote
netdev=`/sbin/ip route get to $remoteip |sed 's|.*dev \(.*\).*|\1|g' |awk '{ print $1; exit }'`
addnetdev $netdev
}
savedargs=$*
while [ $# -gt 0 ]; do
case $1 in
--fstab*)
if [ "$1" != "${1##--fstab=}" ]; then
fstab=${1##--fstab=}
else
fstab=$2
shift
fi
;;
--with-usb*)
if [ "$1" != "${1##--with-usb=}" ]; then
usbmodule=${1##--with-usb=}
else
usbmodule="usb-storage"
fi
basicmodules="$basicmodules $usbmodule"
unset usbmodule
;;
--without-usb)
withusb=0
;;
--with-avail*)
if [ "$1" != "${1##--with-avail=}" ]; then
modname=${1##--with-avail=}
else
modname=$2
shift
fi
availmodules="$availmodules $modname"
;;
--without*)
if [ "$1" != "${1##--without=}" ]; then
modname=${1##--without=}
else
modname=$2
shift
fi
excludemodules="$excludemodules $modname"
;;
--with*)
if [ "$1" != "${1##--with=}" ]; then
modname=${1##--with=}
else
modname=$2
shift
fi
basicmodules="$basicmodules $modname"
;;
--builtin*)
if [ "$1" != "${1##--builtin=}" ]; then
modname=${1##--builtin=}
else
modname=$2
shift
fi
builtins="$builtins $modname"
;;
--version)
echo "mkinitrd: version $VERSION"
exit 0
;;
-v)
verbose=-v
;;
--nocompress)
compress=""
;;
--ifneeded)
# legacy
;;
-f)
force=1
;;
--preload*)
if [ "$1" != "${1##--preload=}" ]; then
modname=${1##--preload=}
else
modname=$2
shift
fi
PREMODS="$PREMODS $modname"
;;
--force-scsi-probe)
forcescsi=1
;;
--omit-scsi-modules)
PRESCSIMODS=""
noscsi=1
;;
--force-raid-probe)
forceraid=1
;;
--omit-raid-modules)
noraid=1
;;
--force-lvm-probe)
forcelvm=1
;;
--omit-lvm-modules)
nolvm=1
;;
--omit-dmraid)
nodmraid=1
;;
--image-version)
img_vers=yes
;;
--allow-missing)
allowmissing=yes
;;
--net-dev*)
if [ "$1" != "${1##--net-dev=}" ]; then
net_list="$net_list ${1##--net-dev=}"
else
net_list="$net_list $2"
shift
fi
;;
--noresume)
noresume=1
;;
--rootdev*)
if [ "$1" != "${1##--rootdev=}" ]; then
rootdev="${1##--rootdev=}"
else
rootdev="$2"
shift
fi
;;
--rootfs*)
if [ "$1" != "${1##--rootfs=}" ]; then
rootfs="${1##--rootfs=}"
else
rootfs="$2"
shift
fi
;;
--rootopts*)
if [ "$1" != "${1##--rootopts=}" ]; then
rootopts="${1##--rootopts=}"
else
rootopts="$2"
shift
fi
;;
--loopdev*)
if [ "$1" != "${1##--loopdev=}" ]; then
loopdev="${1##--loopdev=}"
else
loopdev="$2"
shift
fi
;;
--loopfs*)
if [ "$1" != "${1##--loopfs=}" ]; then
loopfs="${1##--loopfs=}"
else
loopfs="$2"
shift
fi
;;
--loopopts*)
if [ "$1" != "${1##--loopopts=}" ]; then
loopopts="${1##--loopopts=}"
else
loopopts="$2"
shift
fi
;;
--looppath*)
if [ "$1" != "${1##--looppath=}" ]; then
looppath="${1##--looppath=}"
else
looppath="$2"
shift
fi
;;
--help)
usage -n
;;
*)
if [ -z "$target" ]; then
target=$1
elif [ -z "$kernel" ]; then
kernel=$1
else
usage
fi
;;
esac
shift
done
if [ -z "$target" -o -z "$kernel" ]; then
usage
fi
if [ -n "$img_vers" ]; then
target="$target-$kernel"
fi
if [ -z "$force" -a -f $target ]; then
error "$target already exists."
exit 1
fi
if [ -n "$forcescsi" -a -n "$noscsi" ]; then
error "Can't both force scsi probe and omit scsi modules"
exit 1
fi
if [ -n "$forceraid" -a -n "$noraid" ]; then
error "Can't both force raid probe and omit raid modules"
exit 1
fi
if [ -n "$forcelvm" -a -n "$nolvm" ]; then
error "Can't both force LVM probe and omit LVM modules"
exit 1
fi
if [ ! -d /lib/modules/$kernel ]; then
error 'No modules available for kernel "'${kernel}'".'
exit 1
fi
if [ "$LIVEOS" = "yes" ]; then
# this is a live system, we need to fork off to mkliveinitrd for now
exec /usr/libexec/mkliveinitrd $savedargs
fi
vecho "Creating initramfs"
modulefile=/etc/modprobe.conf
# find a temporary directory which doesn't use tmpfs
if [ -z "$loopfs" ]; then
TMPDIR="/tmp"
else
TMPDIR=""
for t in /tmp /var/tmp /root ${PWD}; do
if [ ! -d $t ]; then continue; fi
if ! access -w $t ; then continue; fi
fs=$(df -T $t 2>/dev/null | awk '{line=$1;} END {printf $2;}')
if [ "$fs" != "tmpfs" ]; then
TMPDIR=$t
break
fi
done
fi
if [ -z "$TMPDIR" ]; then
error "no temporary directory could be found."
exit 1
fi
if [ $TMPDIR = "/root" -o $TMPDIR = "${PWD}" ]; then
error "WARNING: using $TMPDIR for temporary files"
fi
PREMODS=$(expandModules $PREMODS)
PRESCSIMODS=$(expandModules $PRESCSIMODS)
availmodules=$(expandModules $availmodules)
basicmodules=$(expandModules $basicmodules)
for n in $PREMODS; do
findmodule $n
done
if [ "$withusb" == "1" ]; then
findmodule ehci-hcd
findmodule ohci-hcd
findmodule uhci-hcd
fi
if [ "x$PROBE" == "xyes" ]; then
[ -z "$rootfs" ] && rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' $fstab)
[ -z "$rootopts" ] && rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' $fstab)
[ -z "$rootopts" ] && rootopts="defaults"
# in case the root filesystem is modular
findmodule -${rootfs}
[ -z "$rootdev" ] && rootdev=$(awk '/^[ \t]*[^#]/ { if ($2 == "/") { print $1; }}' $fstab)
# check if it's nfsroot
physdev=""
if [ "$rootfs" == "nfs" -a "x$net_list" == "x" ]; then
handlenfs $rootdev
else
# check if it's root by label
if [[ "$rootdev" =~ ^(UUID=|LABEL=) ]]; then
rootdev=$(resolve_device_name "$rootdev")
fi
rootopts=$(echo $rootopts | sed -e 's/^r[ow],//' -e 's/,_netdev//' -e 's/_netdev//' -e 's/,r[ow],$//' -e 's/,r[ow],/,/' -e 's/^r[ow]$/defaults/' -e 's/$/,ro/')
physdev=$(findblockdevinsys "$rootdev")
physdev=${physdev##*/dev/}
if [ -n "$physdev" ]; then
vecho "Found root device $physdev for $rootdev"
else
physdev="$rootdev"
fi
fi
if [ "$rootfs" != "nfs" ]; then
if [ -n "$physdev" -a "$physdev" != "$rootdev" ]; then
handlelvordev "$physdev"
fi
handlelvordev $rootdev
fi
# find the first swap dev which would get used for swsusp
swsuspdev=$(awk '/^[ \t]*[^#]/ { if ($3 == "swap") { print $1; exit }}' $fstab)
if [[ "$swsuspdev" =~ ^(UUID=|LABEL=) ]]; then
swsuspdev=$(resolve_device_name "$swsuspdev")
fi
suspdev=$(findblockdevinsys "$swsuspdev")
suspdev=${suspdev##*/dev/}
if [ -n "$suspdev" ]; then
swsuspdev="$suspdev"
fi
unset suspdev
if [ -n "$swsuspdev" ]; then
handlelvordev "$swsuspdev"
fi
fi
if [ -n "$forcescsi" -o -z "$noscsi" -a "x$PROBE" == "xyes" ]; then
if [ ! -f $modulefile ]; then
modulefile=/etc/conf.modules
fi
if [ -f $modulefile ]; then
scsimodules=`grep "alias[[:space:]]\+scsi_hostadapter" $modulefile | grep -v '^[ ]*#' | LC_ALL=C sort -u | awk '{ print $3 }'`
if [ -n "$scsimodules" ]; then
for n in $scsimodules; do
# for now allow scsi modules to come from anywhere. There are some
# RAID controllers with drivers in block/
findmodule $n
done
fi
fi
fi
# If we have dasd devices, include the necessary modules (S/390)
if [ "x$PROBE" == "xyes" -a -d /proc/dasd ]; then
findmodule -dasd_mod
findmodule -dasd_eckd_mod
findmodule -dasd_fba_mod
fi
# Loopback root support
# loopdev : device or nfs server:path file is on
# looppath : filename
# loopfs : filesystem of loopdev
# loopots : options to mount loopfs
if [ -n "${loopfs}" ] || [[ "$rootopts" =~ "loop" ]]; then
# FIXME: probe this somehow?
rootdev=/dev/loop0
[ -z "$rootopts" ] && rootopts="defaults"
findmodule loop
findmodule -${loopfs}
if [ "$loopfs" == "nfs" -a "x$net_list" == "x" ]; then
handlenfs $loopdev
fi
# FIXME: label support
if [ "$loopfs" != "nfs" ]; then
handlelvordev $loopdev
fi
fi
# If we use LVM or dm-based raid, include dm-mod
# XXX: dm not really supported yet.
testdm=""
[ -z "$nodmraid" ] && testdm="yes"
[ "x$PROBE" != "xyes" ] && testdm=""
if [ -n "$testdm" \
-a -x /sbin/dmsetup \
-a -x /sbin/dmraid \
-a -e /dev/mapper/control ]; then
dmout=$(/sbin/dmsetup ls 2>/dev/null)
if [ "$dmout" != "No devices found" -a "$dmout" != "" ]; then
RAIDS=$(/sbin/dmraid -s -craidname 2>/dev/null | grep -vi "no raid disks")
# I fucking hate shell.
lineno=1
PREV=""
LINE=""
while :; do
PREV="$LINE"
LINE=$(/sbin/dmsetup table | head -$lineno | tail -1)
if [ "$LINE" == "$PREV" ]; then
break;
fi
eval $(echo $LINE | \
while read NAME START END TYPE TABLE ; do
echo NAME=\"$(sed 's/:$//'<<< "$NAME")\"
echo START=\"$START\"
echo END=\"$END\"
echo TYPE=\"$TYPE\"
echo TABLE=\"$TABLE\"
done)
case "$TYPE" in
multipath|emc)
# ugggh. We could try to fish the module name out, but it
# requires real parsing...
# XXX also covered by #132001
for mod in $TABLE ; do
DMMODS="$DMMODS $([[ "$mod" =~ "[[:alpha:]]" ]] && echo "$mod")"
done
DMDEVS="$DMDEVS $NAME"
;;
*)
for raid in $RAIDS ; do
if [ "$raid" == "$NAME" ]; then
dmname=$(resolve_dm_name $NAME)
DMDEVS="$DMDEVS $dmname"
RAIDS=$(sed 's/ $NAME //' <<< "$RAIDS")
break
fi
done
;;
esac
lineno=$(($lineno + 1))
done
[ -n "$DMDEVS" ] && find_base_dm_mods
DMDEVS=$(tr ' ' '\n' <<< $DMDEVS | sort -u)
for mod in $(tr ' ' '\n' <<< $DMMODS | sort -u) ; do
findmodule -dm-$mod
done
fi
fi
for n in $basicmodules; do
findmodule $n
done
for n in $CONFMODS; do
findmodule $n
done
vecho "Using modules: $MODULES"
MNTIMAGE=`mktemp -d ${TMPDIR}/initrd.XXXXXX`
IMAGE=`mktemp ${TMPDIR}/initrd.img.XXXXXX`
RCFILE=$MNTIMAGE/init
cemit()
{
cat >> $RCFILE
}
emit()
{
NONL=""
if [ "$1" == "-n" ]; then
NONL="-n"
shift
fi
echo $NONL "$@" >> $RCFILE
}
emitdm()
{
vecho "Adding dm map \"$1\""
UUID=$(dm_get_uuid "$1")
if [ -n "$UUID" ]; then
UUID="--uuid $UUID"
fi
emit dm create "$1" $UUID $(/sbin/dmsetup table "$1")
}
emitdms()
{
[ -z "$DMDEVS" ] && return 0
echo dm list $DMDEVS | nash --force --quiet | while read ACTION NAME ; do
case $ACTION in
rmparts)
emit rmparts "$NAME"
;;
create)
emitdm "$NAME"
;;
part)
emit dm partadd "$NAME"
;;
esac
done
}
if [ -z "$MNTIMAGE" -o -z "$IMAGE" ]; then
error "Error creating temporaries. Try again"
exit 1
fi
mkdir -p $MNTIMAGE
mkdir -p $MNTIMAGE/firmware
mkdir -p $MNTIMAGE/lib/modules/$kernel
mkdir -p $MNTIMAGE/bin
mkdir -p $MNTIMAGE/etc
mkdir -p $MNTIMAGE/dev
mkdir -p $MNTIMAGE/lib
mkdir -p $MNTIMAGE/proc
mkdir -p $MNTIMAGE/sys
mkdir -p $MNTIMAGE/sysroot
ln -s bin $MNTIMAGE/sbin
vecho "Building initrd in $MNTIMAGE"
inst /sbin/nash "$MNTIMAGE" /bin/nash
inst /sbin/modprobe "$MNTIMAGE" /bin/modprobe
inst /sbin/rmmod "$MNTIMAGE" /bin/rmmod
if [ -e /etc/fstab.sys ]; then
inst /etc/fstab.sys "$MNTIMAGE"
fi
installmodule()
{
MODULE=$1
fmPath=""
locatemodule $MODULE
MODULE=$fmPath
if [ -z "$MODULE" ]; then
return
fi
if [ -x /usr/bin/strip ]; then
/usr/bin/strip -g $verbose $MODULE -o $MNTIMAGE/lib/modules/$kernel/$(basename $MODULE)
else
inst "$MODULE" "$MNTIMAGE" "/lib/modules/$kernel/$(basename $MODULE)"
fi
for fw in $(/sbin/modinfo -F firmware $MODULE 2>/dev/null); do
if [ -f /lib/firmware/$fw ]; then
inst "/lib/firmware/$fw" "$MNTIMAGE" "/firmware/$fw"
fi
done
}
# This loops to make sure it resolves dependencies of dependencies of...
resdeps () {
items="$*"
before=1
after=2
while [ $before != $after ]; do
before=`echo $items | wc -c`
list=""
for i in $items; do
deps=""
moduledep $i
list="$list $deps"
# need to handle prescsimods here -- they need to go _after_ scsi_mod
if [ "$i" = "scsi_mod" ]; then
list="$list $PRESCSIMODS"
MODULES="$MODULES $PRESCSIMODS"
PRESCSIMODS=""
locatemodule scsi_wait_scan
if [ -n "$fmPath" -a -f "$fmPath" ]; then
scsi_wait_scan="yes"
fi
fi
done
items=$(for n in $items $list; do echo $n; done | sort -u)
after=`echo $items | wc -c`
done
resolved=$items
}
# exclude specific modules
# (must be done before resolution of deps)
excludemods() {
items="$*"
output=""
for i in $items; do
for x in $excludemodules; do
if [ "$i" = "$x" ]; then
continue 2
fi
done
output="$output $i"
done
echo $output
}
if [ -n "$excludemodules" ]; then
MODULES=$(excludemods $MODULES)
availmodules=$(excludemods $availmodules)
fi
resdeps $MODULES $availmodules
for MODULE in $resolved; do
installmodule $MODULE
done
# mknod'ing the devices instead of copying them works both with and
# without devfs...
mkdir $MNTIMAGE/dev/mapper
mknod $MNTIMAGE/dev/ram0 b 1 0
mknod $MNTIMAGE/dev/ram1 b 1 1
ln -sf ram1 $MNTIMAGE/dev/ram
mknod $MNTIMAGE/dev/null c 1 3
mknod $MNTIMAGE/dev/zero c 1 5
mknod $MNTIMAGE/dev/systty c 4 0
if ! echo "$(uname -m)" | grep -q "s390"; then
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
mknod $MNTIMAGE/dev/tty$i c 4 $i
done
fi
for i in 0 1 2 3 ; do
mknod $MNTIMAGE/dev/ttyS$i c 4 $(($i + 64))
done
mknod $MNTIMAGE/dev/tty c 5 0
mknod $MNTIMAGE/dev/console c 5 1
mknod $MNTIMAGE/dev/ptmx c 5 2
if [ -n "$raiddevices" ]; then
inst /sbin/mdadm "$MNTIMAGE"
if [ -f /etc/mdadm.conf ]; then
inst /etc/mdadm.conf "$MNTIMAGE"
fi
fi
# FIXME -- this can really go poorly with clvm or duplicate vg names.
# nash should do lvm probing for us and write its own configs.
if [ -z "$nolvm" -a -n "$vg_list" ]; then
inst /sbin/lvm "$MNTIMAGE" /bin/lvm
if [ -f /etc/lvm/lvm.conf ]; then
cp $verbose --parents /etc/lvm/lvm.conf $MNTIMAGE/
fi
fi
findkeymap () {
local MAP=$1
if [ ! -f "$MAP" ]; then
MAP=$(find /lib/kbd/keymaps -type f -name $MAP -o -name $MAP.\* | head -n1)
fi
case " $KEYMAPS " in
*" $MAP "*)
return
esac
KEYMAPS="$KEYMAPS $MAP"
case $MAP in
*.gz)
cmd=zgrep
;;
*.bz2)
cmd=bzgrep
;;
*)
cmd=grep
;;
esac
for INCL in $($cmd "^include " $MAP | cut -d' ' -f2 | tr -d '"'); do
for FN in $(find /lib/kbd/keymaps -type f -name $INCL\*); do
findkeymap $FN
done
done
}
if [ $ncryptodevs -ne 0 -o $nlatecryptodevs -ne 0 ]; then
inst /sbin/cryptsetup "$MNTIMAGE"
KEYTABLE=
KEYMAP=
if [ -f /etc/sysconfig/console/default.kmap ]; then
KEYMAP=/etc/sysconfig/console/default.kmap
else
if [ -f /etc/sysconfig/keyboard ]; then
. /etc/sysconfig/keyboard
fi
if [ -n "$KEYTABLE" -a -d "/lib/kbd/keymaps" ]; then
KEYMAP="$KEYTABLE.map"
fi
fi
if [ -n "$KEYMAP" ]; then
LOADKEYS=loadkeys
if [ -f /etc/sysconfig/i18n ]; then
. /etc/sysconfig/i18n
fi
if [ "${LANG}" != "${LANG%%.UTF-8}" -o "${LANG}" != "${LANG%%.utf8}" ]; then
LOADKEYS="loadkeys -u"
fi
inst /bin/loadkeys "$MNTIMAGE"
findkeymap $KEYMAP
for FN in $KEYMAPS; do
inst $FN "$MNTIMAGE"
case "$FN" in
*.gz)
gzip -d "$MNTIMAGE$FN"
;;
*.bz2)
bzip2 -d "$MNTIMAGE$FN"
;;
esac
done
fi
fi
echo -n >| $RCFILE
cemit << EOF
#!/bin/nash
mount -t proc /proc /proc
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
EOF
# XXX really we need to openvt too, in case someting changes the
# color palette and then changes vts on fbcon before gettys start.
# (yay, fbcon bugs!)
if ! echo "$(uname -m)" | grep -q "s390"; then
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 ; do
emit "mknod /dev/tty$i c 4 $i"
done
fi
for i in 0 1 2 3 ; do
emit "mknod /dev/ttyS$i c 4 $(($i + 64))"
done
emit "echo Setting up hotplug."
emit "hotplug"
emit "echo Creating block device nodes."
emit "mkblkdevs"
if [ "$scsi_wait_scan" == "yes" ]; then
vecho "Adding module scsi_wait_scan"
installmodule scsi_wait_scan
fi
/sbin/depmod -F /boot/System.map-$kernel -a -b $MNTIMAGE $kernel
usb_mounted="prep"
for MODULE in $MODULES; do
text=""
module=`echo $MODULE | sed -e "s|.*/||" -e "s/\.k\?o$//"`
fullmodule=`echo $MODULE | sed "s|.*/||"`
options=`sed -n -e ':a' -e '/\\\\$/N; s/\\\\\n//; ta' -e "s/^options[ ][ ]*$module[ ][ ]*//p" $modulefile 2>/dev/null`
if [ -n "$options" ]; then
vecho "Adding module $module$text with options $options"
else
vecho "Adding module $module$text"
fi
# we mount usbfs before the first module *after* the HCDs
if [ "$usb_mounted" == "prep" ]; then
if [[ "$module" =~ ".hci[_-]hcd" ]]; then
usb_mounted="no"
fi
elif [ "$usb_mounted" == "no" ]; then
if [[ ! "$module" =~ ".hci[_-]hcd" ]]; then
usb_mounted=yes
emit "mount -t usbfs /proc/bus/usb /proc/bus/usb"
fi
fi
if [ -n "$options" ]; then
echo "options $module $options" >> $MNTIMAGE/etc/modprobe.conf
fi
emit "echo \"Loading $module module\""
emit "modprobe -q $module"
# Hack - we need a delay after loading usb-storage to give things
# time to settle down before we start looking a block devices
if [ "$module" = "usb-storage" -o "$module" = "ub" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized /proc/bus/usb/devices"
fi
# Firewire likes to change the subsystem name every 3 hours. :/
if [ "$module" = "sbp2" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized /sys/bus/ieee1394/drivers/sbp2"
fi
if [ "$module" = "fw-sbp2" -o "$module" = "firewire-sbp2" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized /sys/bus/firewire/drivers/sbp2"
fi
if [ "$module" = "zfcp" -a -f /etc/zfcp.conf ]; then
emit "echo Waiting 2 seconds for driver initialization."
emit "sleep 2"
cat /etc/zfcp.conf | grep -v "^#" | tr "A-Z" "a-z" | while read DEVICE TWO THREE FOUR FIVE; do
if [ -z "$FIVE" ]; then
WWPN=$TWO
FCPLUN=$THREE
else
WWPN=$THREE
FCPLUN=$FIVE
fi
cemit < /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/port_add
echo -n $FCPLUN > /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/$WWPN/unit_add
echo -n 1 > /sys/bus/ccw/drivers/zfcp/${DEVICE/0x/}/online
EOF
done
fi
if [ "${module::5}" == "pata_" -o "$module" == "ata_piix" -o "$module" == "ahci" -o "${module::5}" == "sata_" -o "$module" == "ibmvscsic" ]; then
emit "echo Waiting for driver initialization."
emit "stabilized --hash --interval 250 /proc/scsi/scsi"
fi
done
unset usb_mounted
if [ -n "$availmodules" ]; then
cemit </etc/fstab"
emit "mkrootdev -t $rootfs -o $rootopts $rootdev"
rootdev=/dev/root
emit "echo Mounting root filesystem."
emit "mount /sysroot"
if [ -n "$loopfs" ]; then
emit "Cleaning up loop mount."
emit "umount /tmpmount"
fi
emit "echo Setting up other filesystems."
emit "setuproot"
if [ -n "$dhclient_leases_cmd" ]; then
emit "echo Copying DHCP lease"
emit "$dhclient_leases_cmd"
fi
emit "loadpolicy"
emit "echo Switching to new root and running init."
emit "switchroot"
emit "echo Booting has failed."
emit "sleep -1"
chmod +x $RCFILE
if [ "$dynamic" == "yes" ]; then
vecho "This initrd uses dynamic shared objects."
vecho "Adding dynamic linker configuration files."
[ -n "$LD_SO_CONF" ] && inst "$LD_SO_CONF" "$MNTIMAGE" /etc/ld.so.conf
mkdir -p $MNTIMAGE/etc/ld.so.conf.d
for x in $(find $LD_SO_CONF_D -type f) ; do
inst "$x" "$MNTIMAGE" "/etc/ld.so.conf.d/$(basename "$x")"
done
vecho "Running ldconfig"
/sbin/ldconfig -r "$MNTIMAGE"
if [ $? -ne 0 ]; then
error tmpdir is $MNTIMAGE
exit 1
fi
fi
(cd $MNTIMAGE; findall . | cpio -H newc --quiet -o) >| $IMAGE || exit 1
if [ -n "$compress" ]; then
gzip -9 < $IMAGE >| $target || rc=1
else
cp -a $IMAGE $target || rc=1
fi
rm -rf $MNTIMAGE $IMAGE
if [ -n "$MNTPOINT" ]; then rm -rf $MNTPOINT ; fi
exit $rc
# vim:ts=8:sw=4:sts=4:et