#!/bin/bash # # Description: universal (distro independent) generator for initial # ramdisks for linux diskless clients # # Author(s): Dirk von Suchodoletz , 03-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="" D_ETCEXCL="" D_BINDMPTS="" D_DIRINBINDMNT="" D_RODIRSINRW="" D_DIRINDXS="" D_BINDMNT="" D_INITDIR="" D_INITBOOTD="" D_RCDIRS="" D_RCDIRSINRW="" D_INITSCRIPTS="" D_XF86CONFFILE="" D_XFONTPATH="" D_DEFAULTCOUNTRY="" ######################################################################### # 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} 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 } # Resolve dynamic library dependencies. Returns a list of symbolic links # to shared objects and shared object files for the binaries in $*. # stolen from SuSE mkinitrd shared_object_files() { local LDD initrd_libs lib_files lib_links lib link LDD=`which ldd` if [ ! -x $LDD ]; then error 2 "I need execution permission on ldd ($LDD)." fi initrd_libs=( $( $LDD "$@" \ | sed -ne 's:\t\(.* => \)\?\(/.*\) (0x[0-9a-f]*):\2:p' ) ) # Evil hack: On some systems we have generic as well as optimized # libraries, but the optimized libraries may not work with all # kernel versions (e.g., the NPTL glibc libraries don't work with # a 2.4 kernel). Use the generic versions of the libraries in the # initrd (and guess the name). local n optimized for ((n=0; $n<${#initrd_libs[@]}; n++)); do lib=${initrd_libs[$n]} optimized="$(echo "$lib" | sed -e 's:.*/\([^/]\+/\)[^/]\+$:\1:')" lib=${lib/$optimized/} if [ "${optimized:0:3}" != "lib" -a -f "$lib" ]; then #echo "[Using $lib instead of ${initrd_libs[$n]}]" >&2 initrd_libs[$n]="${lib/$optimized/}" fi done for lib in "${initrd_libs[@]}"; do case "$lib" in linux-gate*) # This library is mapped into the process by the kernel # for vsyscalls (i.e., syscalls that don't need a user/ # kernel address space transition) in 2.6 kernels. continue ;; /*) lib="${lib:1}" ;; *) # Library could not be found. echo "Dynamic library $lib not found" continue ;; esac while [ -L "/$lib" ]; do echo $lib link="$(readlink "/$lib")" if [ x"${link:0:1}" == x"/" ]; then lib=${link#/} else lib="${lib%/*}/$link" fi done echo $lib done \ | sort -u } # 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 ;; 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 # 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*|*) DISTRO_VER=10.0 ;; 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} #if no klibc for bbins in ash bash 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 pivot_root 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 || 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 `shared_object_files ${INSTDIR}/bin/*` ; do baselib=`basename ${lib}` test -e ${INSTDIR}/lib/${baselib} || \ cp -a /${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 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 ;; 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