#!/bin/bash
#
# Description: universal (distro independent) generator for initial
# ramdisks for linux diskless clients
#
# Author(s): Dirk von Suchodoletz <dirk@goe.net>, 06-02-2006
# Nico Dietrich
# Blub
#
# Version: 0.3.1a
#
# Copyright: (c) 2003 - 2006 - RZ Universitaet Freiburg
DEBUG=1
COMETCEXCL="XF86Config*\nissue*\nmtab*\nfstab*\n"
COMDIRINDXS="/tmp/scratch /var/lib/nobody"
# distro specific settings read from configuration file
# D_SYSCONFDIR - system wide configuration settings in /etc - sysconfig in
# SuSE and RedHat, default in Debian and Ubuntu, conf.d in Gentoo
# D_ETCEXCL - list of files, wildcards to be excluded from /etc when using
# bind mounts
# D_DIRINBINDMNT - lists of directories to be created in bind mounted rw
# part of the client filesystem
# D_RODIRSINRW - ReadOnly Directories in RW part of filesystem to save on
# TempFS usage
# D_DIRINDXS - directories in client filesystem which should be present
# anyhow
# D_BINDMNT - any code which is specific in bind mount environment
# D_RCDIRS - runlevel directories relative to /etc
D_SYSCONFDIR="<set in ~/distro-config/distro file>"
D_ETCEXCL="<set in ~/distro-config/distro file>"
D_BINDMPTS="<set in ~/distro-config/distro file>"
D_DIRINBINDMNT="<set in ~/distro-config/distro file>"
D_RODIRSINRW="<set in ~/distro-config/distro file>"
D_DIRINDXS="<set in ~/distro-config/distro file>"
D_BINDMNT="<set in ~/distro-config/distro file>"
D_INITDIR="<set in ~/distro-config/distro file>"
D_INITBOOTD="<set in ~/distro-config/distro file>"
D_RCDIRS="<set in ~/distro-config/distro file>"
D_RCDIRSINRW="<set in ~/distro-config/distro file>"
D_INITSCRIPTS="<set in ~/distro-config/distro file>"
D_XF86CONFFILE="<set in ~/distro-config/distro file>"
D_XFONTPATH="<set in ~/distro-config/distro file>"
D_DEFAULTCOUNTRY="<set in ~/distro-config/distro file>"
#########################################################################
# End of global variable declaration, nothing needed to be changed at
# default below that line
# replaces which to find executables inside ROOTDIR
binfinder()
{
local PROGRAM="$1"
local RET=1
for ELEMENT in bin sbin usr/bin usr/sbin usr/local/bin usr/bin/X11; do
if [ -f "${ROOTDIR}/$ELEMENT/$PROGRAM" ] && [ -x "${ROOTDIR}/$ELEMENT/$PROGRAM" ]; then
printf '%s\n' "${ROOTDIR}/$ELEMENT/$PROGRAM"
RET=0
break
fi
done
return "$RET"
}
# copy some binary to given destination. Takes binary in $1 and
# destination in $2
cobi()
{
local DEST=$2
local FPTB=`binfinder $1`
if [ -z ${FPTB} ] ; then
return 1;
elif [ -L ${FPTB} ] ; then
# do not copy the link but the binary the link points to
FPTB=${ROOTDIR}/`ls -la ${FPTB} | sed -e "s,.* ,,"`
cp ${FPTB} ${INSTDIR}/${DEST}
else
cp ${FPTB} ${INSTDIR}/${DEST}
fi
}
# replace copy
repco()
{
local FILENAME=$1
# do not forget to define all variables which should be replaced within
# the start and configuration scripts. All comment lines will be deleted.
if [ -d initrd-stuff/${FILENAME} ] ; then
[ -d ${INSTDIR}/${FILENAME} ] || mkdir -p ${INSTDIR}/${FILENAME}
else
if file initrd-stuff/${FILENAME}| grep "ELF" &>/dev/null ; then
cp initrd-stuff/${FILENAME} ${INSTDIR}/${FILENAME}
elif [ -L initrd-stuff/${FILENAME} ] ; then
cp -a initrd-stuff/${FILENAME} ${INSTDIR}/${FILENAME%/*}
else
sed -e "s,@@@INSTDIR@@@,${INSTDIR},g" \
-e "s,@@@NWMODULES@@@,${NWMODULES},g" \
-e "s,@@@KERNVER@@@,${KERNVER},g" \
-e "s,@@@COMDIRINDXS@@@,${COMDIRINDXS},g" \
-e "s,@@@COMETCEXCL@@@,${COMETCEXCL},g" \
-e "s,@@@DISTRO@@@,${DISTRO},g" \
-e "s,@@@NETIF@@@,${NET_IF},g" \
-e "/^# .*/d" \
initrd-stuff/${FILENAME} >> ${INSTDIR}/${FILENAME}
fi
fi
}
# this function incrementally concats and copies distro-specific functions,
# configuration variables and files
copy_distro_stuff() {
# first insert dependencies
case $1 in
suse)
case $2 in
9.3)
;;
10.0)
copy_distro_stuff suse 9.3
;;
10.1)
copy_distro_stuff suse 10.0
;;
esac
;;
debian)
;;
ubuntu)
;;
gentoo)
;;
esac
# now insert the current stuff
cat distro-specs/$1/config-$2 >>${INSTDIR}/etc/sysconfig/config
cat distro-specs/$1/functions-$2 >>${INSTDIR}/etc/distro-functions
# would be cool not to copy .svn here ...
cp -a distro-specs/$1/files-$2 ${INSTDIR}/etc/sysconfig/files 2>/dev/null
}
#########################################################################
# End of function declaration
while getopts :hgk:i:r:o:s:f:n:Sut:d:I:V:a: a ; do
case $a in
\:|\?) case $OPTARG in
k) echo "-k requires kernel version parameter"
;;
i) echo "-i requires initrd path parameter"
;;
f) echo "-f requires file system module list parameter"
;;
n) echo "-n requires network module list parameter"
;;
r) echo "-r requires root dir parameter"
;;
s) echo "-s requires image size(s)"
;;
t) echo "-t requires tmp dir parameter"
;;
d) echo "-d requires linux distribution name"
;;
I) echo "-I requires network interface parameter"
;;
a) echo "-a requires a DSDT parameter"
;;
V) echo "-V requires an executable to run inside linuxrc"
;;
*) echo "Unknown option: -$OPTARG"
echo "Try mkinitrd -h"
;;
esac
exit 1
;;
g) use_glibc=1
;;
k) KERNVER=$OPTARG
;;
i) INITRD_PATH=$OPTARG
;;
f) FSMODULES=$OPTARG
;;
n) NWMODULES=$OPTARG
;;
r) ROOTDIR=$OPTARG
;;
s) SPLASH=$OPTARG
;;
t) INSTDIR=$OPTARG
;;
d) DISTRO=$OPTARG
;;
I) NET_IF=$OPTARG
;;
a) acpi_dsdt="$OPTARG"
;;
S) use_selinux=1
;;
V) vendor_init_script="$OPTARG"
;;
R) mkinit_type="rd"
;;
u) sysfs_root=1
use_udev=
;;
h) usage
;;
esac
done
shift $(expr $OPTIND - 1)
#########################################################################
# End of parameter, argument interpretation
if [ -z "$INSTDIR" ] ; then
INSTDIR=/tmp/dxs-instrd
fi
rm -rf ${INSTDIR}
mkdir -p ${INSTDIR}/{dev,proc,tmp,mnt,root,bin,sbin,sys,lib}
mkdir -p ${INSTDIR}/usr/share
# needed for KNOPPIX hwsetup not to confuse with ${D_SYSCONFDIR}
mkdir -p ${INSTDIR}/etc/sysconfig
# fixme!! Funktion ermittelt die Distro des Servers NICHT des Clients!!
# if no distro name is set, try to find the correct one via lsb_release
#if [ -z "${DISTRO}" ] ; then
# for i in ${ROOTDIR}/bin/lsb_release ${ROOTDIR}/usr/bin/lsb_release; do
# if [ -e $i ] ; then
# $i > /dev/null 2>&1 || break
# DISTRO=`. $i -i | sed "s/.*\t//"`
# DISTRO_VER=`. $i -r | sed "s/.*\t//"`
# break
# fi
# done
#fi
# if still no distro name set, try to find it using significant files
if [ -z "${DISTRO}" ] ; then
if [ -e ${ROOTDIR}/etc/SuSE-release ] ; then
DISTRO=suse
DISTRO_VER=`grep "VERSION" ${ROOTDIR}/etc/SuSE-release | sed "s/.*= //"`
elif [ -e ${ROOTDIR}/etc/debian_version ] ; then
DISTRO=debian
DISTRO_VER=`cat ${ROOTDIR}/etc/debian_version`
fi
fi
case "${DISTRO}" in
Debian*|debian*|Sarge*|sarge*)
DISTRO=debian
case "${DISTRO_VER}" in
Sarge*|sarge*|3.1*|*)
DISTRO_VER=3.1
;;
esac
;;
Ubuntu*|ubuntu*)
DISTRO=ubuntu
case "${DISTRO_VER}" in
Breezy*|breezy*|*)
DISTRO_VER=5.10
;;
esac
;;
Gentoo*|gentoo*)
DISTRO=gentoo
case "${DISTRO_VER}" in
2005*|*)
DISTRO_VER=2005.1
;;
esac
;;
SuSE*|suse*|Suse*|SuSe*|SUSE*|*)
DISTRO=suse
case "${DISTRO_VER}" in
9*)
DISTRO_VER=9.3
# might be needed for older udev/hotplug
# cp -a ${ROOTDIR}/etc/hotplug* ${INSTDIR}/etc
;;
10.0)
DISTRO_VER=10.0
;;
10*)
DISTRO_VER=10.1
;;
esac
# hotplug/udev style and stuff
cp -a ${ROOTDIR}/etc/udev ${INSTDIR}/etc
#cp -a /etc/sysconfig/{hardware,network} ${INSTDIR}/etc/sysconfig
;;
esac
# an dieser stelle sollte jetzt sichergestellt sein, dass sowohl DISTRO als auch DISTRO_VER eindeutig gesetzt sind!
copy_distro_stuff ${DISTRO} ${DISTRO_VER}
# devices needed rather early (copied from /tmp to /dev in init)
mknod ${INSTDIR}/tmp/console c 5 1 &>/dev/null
mknod ${INSTDIR}/tmp/null c 1 3 &>/dev/null
mknod ${INSTDIR}/tmp/kmsg c 1 11 &>/dev/null
#if no klibc - klibc shell seems not to have enough functionality :-(
for bbins in bash ash sh; do
if cobi ${bbins} bin ; then
ln -fs ${bbins} ${INSTDIR}/bin/sh
[ "${bbins}" != "bash" ] && ln -fs ${bbins} ${INSTDIR}/bin/bash
break
else echo "Binary not found (${bbins})"; fi
done
# if no klibc
for bbins in ip ifconfig; do
if cobi ${bbins} bin ; then
[ "${bbins}" = "ifconfig" ] && cobi route bin
break
else echo "Binary not found"; fi
done
# needed standard binaries
for bbins in \
cat chmod chown chroot cp expr killall ln mkdir modprobe \
mount portmap rmmod sed tar umount
do
cobi ${bbins} bin || echo "Program ${bbins} not found"
done
# one of the dhcp clients
for dhcp in dhclient dhcpcd pump ipconfig ; do
binfinder $dhcp && break;
done
cobi $dhcp bin
mkdir -p ${INSTDIR}/var/{lib,run}
# debug binaries
for bbins in \
date ls lsmod lsof ps rm strace time
do
cobi ${bbins} bin || echo "Program ${bbins} not found"
done
# style of hotplug/udev/dev (for etc directories see above!!)
for bbins in udev udevd udevstart
do
cobi ${bbins} bin &>/dev/null || echo "Program ${bbins} not found"
done
# in suse 9.3 it could be better to use udev.static etc
#for bbins in udev udevd udevstart
#do
# cobi ${bbins}.static bin || echo "Program ${bbins}.static not found"
# ln -s /bin/${bbins}.static ${INSTDIR}/bin/${bbins}
#done
# if nfs
mkdir -p ${INSTDIR}/var/lib/nfs/state
# if nbd
# cobi nbd-client bin
if [ -n "${FSMODULES}" ] ; then
case "${FSMODULES}" in
dnbd*)
cobi dnbd-client bin
;;
nbd*)
cobi nbd-client bin
;;
esac
fi
# distro specific additional stuff
case "${DISTRO}" in
debian*)
cp ${ROOTDIR}/lib/libnss_compat.so.2 ${INSTDIR}/lib;;
esac
# add needed libraries depending on choosen binaries
for lib in `ldd /tmp/dxs-instrd/bin/* 2>/dev/null | sed -e "s,tls,," \
-ne 's:\t\(.* => \)\?\(/.*\) (0x[0-9a-f]*):\2:p' | sort -u` ; do
baselib=`basename ${lib}`
test -e ${INSTDIR}/lib/${baselib} || \
cp /${ROOTDIR}/${lib} ${INSTDIR}/lib
done
# add kernel modules and dependency files
if [ -z "$KERNVER" ] ; then
KERNVER=`ls -l ${ROOTDIR}/boot/vmlinuz | grep vmlinuz | sed "s/.*vmlinuz-//"`
fi
if [ -z "$KERNVER" ] ; then
KERNVER=`ls -l ${ROOTDIR}/vmlinuz | grep vmlinuz | sed "s/.*vmlinuz-//"`
fi
if [ -z "$KERNVER" ] ; then
echo "No kernel version set or detected - please use the -k flag! Exiting..."
exit 1
fi
if [ -z "$NWMODULES" ] ; then
NWMODULES="e100 tg3 via-rhine r8169"
fi
if [ -z "$FSMODULES" ] ; then
FSMODULES="nbd nfs"
fi
if [ -z "$INITRD_PATH" ] ; then
INITRD_PATH="/tmp/dxsinitrd.gz"
fi
# define modules to put into initial ramdisk for debugging
#DEBUGMODULES="uhci_hcd usbhid"
DEBUGMODULES=""
# put all needed modules into initial ramdisk
mkdir -p ${INSTDIR}/lib/modules/${KERNVER}
for module in af_packet ${NWMODULES} ${FSMODULES} ${DEBUGMODULES}; do
mod=`cd /${ROOTDIR}; find "lib/modules/${KERNVER}" -name ${module}.ko \
2>/dev/null`
if [ -n "$mod" ] ; then
mpath=${INSTDIR}/${mod%/*}
mkdir -p ${mpath}
cp ${ROOTDIR}/$mod ${mpath}
# fixmee!! selection of dependent modules could be handled a little bi
# more clever
case "$module" in
e100|8139too|via-rhine|sis900|epic100|sundance|8139cp|eepro100|pcnet32)
cp ${ROOTDIR}/lib/modules/${KERNVER}/kernel/drivers/net/mii.ko \
${INSTDIR}/lib/modules/${KERNVER}/kernel/drivers/net &>/dev/null
;;
nfs)
mkdir -p ${INSTDIR}/lib/modules/${KERNVER}/kernel/net/sunrpc/
mkdir -p ${INSTDIR}/lib/modules/${KERNVER}/kernel/fs/lockd
mkdir -p ${INSTDIR}/lib/modules/${KERNVER}/kernel/fs/nfs_common
cp ${ROOTDIR}/lib/modules/${KERNVER}/kernel/net/sunrpc/sunrpc.ko \
${INSTDIR}/lib/modules/${KERNVER}/kernel/net/sunrpc &>/dev/null
cp ${ROOTDIR}/lib/modules/${KERNVER}/kernel/fs/lockd/lockd.ko \
${INSTDIR}/lib/modules/${KERNVER}/kernel/fs/lockd &>/dev/null
cp ${ROOTDIR}/lib/modules/${KERNVER}/kernel/fs/nfs_common/nfs_acl.ko \
${INSTDIR}/lib/modules/${KERNVER}/kernel/fs/nfs_common &>/dev/null
;;
esac
fi
done
cp ${ROOTDIR}/lib/modules/${KERNVER}/modules.* \
${INSTDIR}/lib/modules/${KERNVER}
# initial ramdisk scripts: init, functions, servconfig, hwautocfg, ...
# copy and replace variable names
for dirs in `find initrd-stuff/* ! -regex ".*/\..*"` ; do
repco ${dirs##initrd-stuff/}
done
chmod 755 ${INSTDIR}/init ${INSTDIR}/bin/servconfig \
${INSTDIR}/bin/hwautocfg ${INSTDIR}/bin/dhcpmkconfig
#########################################################################
# End of file copy procedures
# finally create the compressed initial ramdisk cpio archive
pushd . > /dev/null 2>&1
cd ${INSTDIR}
find . ! -name "*~" | cpio -H newc --create | gzip -9 > $INITRD_PATH
popd > /dev/null 2>&1