#!/bin/bash
#
# --------------------------------------------------------------------------
# Copyright notice
# --------------------------------------------------------------------------
# Copyright: Rene Mayrhofer, Mar. 2000
#
# 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, 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; see the file COPYING.  If not, write to
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# On Debian GNU/Linux systems, the complete text of the GNU General
# Public License can be found in `/usr/share/common-licenses/GPL'.
# --------------------------------------------------------------------------
#

# customize here
bytes_per_inode=8096
copy_files_from=/usr/share/mkinitrd-cd
reserve_kbytes=100
cdboot_required_modules="cdrom scsi_mod sr_mod ide-mod ide-probe ide-probe-mod ide-cd"
#hdboot_additional_modules="sd_mod ide-disk ext3 reiserfs xfs xfs_support pagebuf"
hdboot_additional_modules="sd_mod ide-disk ext3 reiserfs"

# do not edit below this line
# =================================================

if [ $# -ne 3 ] || ( [ "$3" != "min" ] && [ "$3" != "full" ] ) ; then
  echo "Usage: $0 <path to modules> <created initrd image> <size>"
  echo
  echo "Where <size> can be either 'min' or 'full'. 'min' copies only the "
  echo "modules needed for booting from CD-ROM drives, 'full' additionally "
  echo "copies all modules needed to boot from harddisk partitions."
  exit 1
fi

if [ `id -u` -ne 0 ]; then
  echo "This script must be run as root."
  exit 2
fi

if [ ! -d $1 ]; then
  echo "$1 is not a directory."
  exit 3
fi

umask 077
set -e

olddir=`pwd`

image=$2
# create temporary name for the image
if [ -x /bin/tempfile ]; then
  tmpimage=`tempfile -p timg -m 0600 `
else
  tmpimage=/tmp/tmp-initrd-img-$$
fi
modulepath=$1
imagesize=$3
# temporary image names can not created with tempfile
mntpoint=/tmp/tmp-initrd-mnt-$$
tmpstructure=/tmp/tmp-initrd-files-$$
# this is a temporary build directory for building busybox binaries
tmpbuilddir=/tmp/tmp-initrd-build-$$

# detect which version of the directory layout we have (2.2.x or 2.4.x)
if [ -d $modulepath/kernel/drivers ]; then
  # 2.4.x layout
  moduledirs="kernel/drivers/scsi kernel/drivers/ide kernel/drivers/cdrom kernel/drivers/block kernel/fs"
else
  # 2.2.x layout
  moduledirs="scsi cdrom block fs"
fi

# first create the structure that the initrd image should contain
echo -n "Creating file structure ... "
mkdir $tmpstructure
mkdir $tmpstructure/bin
mkdir $tmpstructure/dev
mkdir $tmpstructure/etc
mkdir $tmpstructure/lib
mkdir $tmpstructure/mnt
mkdir $tmpstructure/modules
mkdir $tmpstructure/sbin
mkdir $tmpstructure/tmp
mkdir $tmpstructure/proc
echo "done"

# devices
echo -n "Creating device files ... "
cd $tmpstructure/dev
#for n in console null ram ram[01] tty[012345] ttyS[0123] fd stdout stderr \
#  hd[abcd] scd[0123456789] log; do
##  cp -a /dev/$n $tmpstructure/dev
#  echo $n
#  /sbin/MAKEDEV $n
#done
tar -C $tmpstructure/dev --preserve --same-owner --atime-preserve \
    -xzf $copy_files_from/initrd-dev.tar.gz
echo "done"

cd $olddir
echo "Copying modules ... "
# copy the modules listed in scsiprobe.dat as well as common modules
# (in $additional_modules)
for n in $moduledirs; do
  if [ -d $modulepath/$n ] ; then
    for f in `find $modulepath/$n/ -name '*.o'`; do
      # copy only those that are also listed in scsiprobe.dat
      mod=`expr $(basename $f) : '\(.*\).o'`
      echo -ne "    $mod\t"
      # cosmetics (another tab for short file names
      if [ `expr "$mod" : '.*'` -lt 4 ]; then
        echo -ne "\t"
      fi
      echo -n "... "
      # I don't know why this doesn't work - it should....
      #if ( ( echo "$cdboot_required_modules" | grep $mod >/dev/null ) ||
      #     ( [ "$imagesize" = "min" ] &&
      #       ( cat $copy_files_from/scsiprobe-min.dat | grep $mod >/dev/null ) ) ||
      #     ( [ "$imagesize" = "full" ] &&
      #       ( echo "$hdboot_additional_modules" | grep $mod >/dev/null ) ||
      #       ( cat $copy_files_from/scsiprobe.dat | grep $mod >/dev/null ) ) )
      #then
      # so try this instead - it is more complicated, slower and just plain 
      # ugly but it works
      copyit=0
      if echo "$cdboot_required_modules" | grep $mod >/dev/null; then
        copyit=1
      elif [ "$imagesize" = "min" ]; then
        if cat $copy_files_from/scsiprobe-min.dat | grep $mod >/dev/null; then
          copyit=1
        fi
      else
        # $imagesize = "full" here
        if echo "$hdboot_additional_modules" | grep $mod >/dev/null ||
           cat $copy_files_from/scsiprobe.dat | grep $mod >/dev/null; then
          copyit=1
        fi
      fi
      if [ "$copyit" -eq 1 ]; then
        cp -a $f $tmpstructure/modules/
        echo "copied"
      else
        echo "skipped"
      fi
    done
  fi
done
# determine the biggest of the modules. this will have to fit on the initrd
# disk for loading - therefore this much free space has to be left on the image
maxsize=0
for f in $tmpstructure/modules/*; do
  modsize=`ls -l $f | awk '{print $5}'`
  if [ $modsize -gt $maxsize ]; then
    maxsize=$modsize
  fi
done
gzip -9 $tmpstructure/modules/*
echo "done"
echo "The largest module will need $maxsize bytes to be unzipped."
reserve_kbytes=`expr $maxsize / 1024 + $reserve_kbytes`

echo "Creating / copying binaries and libraries (this may take some time) ... "
echo -n "    Extracting busybox source ... "
mkdir $tmpbuilddir
tar -C $tmpbuilddir -xzf $copy_files_from/busybox-*.tar.gz
busybox_builddir="$tmpbuilddir/`basename $tmpbuilddir/busybox-*`"
echo "done"
# this is the list of needed binaries from busybox
echo -n "    Adapting busybox binary to the initrd system needs ... "
busybox_bin="cat chmod chgrp cut dirname dmesg expr find grep gunzip kill ln ls mknod mount mv ps pwd rm rmdir tr umount"
busybox_sbin="chroot insmod syslogd klogd pivot_root"
edit_file="$busybox_builddir/Config.h"
mv $edit_file $edit_file.sav
# build the list of defines for the functions to use
for f in $busybox_bin $busybox_sbin; do
  echo "#define BB_`echo $f | tr [a-z] [A-Z]`" >> $edit_file
done
# additional features for busybox
#echo "#define BB_CHMOD_CHOWN_CHGRP" >> $edit_file
echo "#define BB_FEATURE_USE_PROCFS" >> $edit_file
echo "#define BB_FEATURE_TRIVIAL_HELP" >> $edit_file
echo "#define BB_FEATURE_KLOGD" >> $edit_file
echo "#define BB_FEATURE_INSMOD_NEW_KERNEL" >> $edit_file
echo "#define BB_FEATURE_INSMOD_VERSION_CHECKING" >> $edit_file
echo "#define BB_FEATURE_LS_FOLLOWLINKS" >> $edit_file
echo "#define BB_FEATURE_EXTRA_QUIET" >> $edit_file
echo "#define BB_FEATURE_NEW_MODULE_INTERFACE" >> $edit_file
echo "#define BB_FEATURE_INSMOD_VERSION_CHECKING" >> $edit_file
echo "#define BB_FEATURE_DEVFS" >> $edit_file
echo "done"
echo -n "    Building busybox binary ... "
cd $busybox_builddir
if ! make >/dev/null 2>/dev/null; then
  echo "Error: unable to build busybox !"
  exit 1
fi
echo "done"
echo -n "    Installing binaries in temporary file structure ... "
install $busybox_builddir/busybox $tmpstructure/bin
install /bin/ash $tmpstructure/bin
cd $tmpstructure/bin
ln -s ash sh
install $copy_files_from/chown-wrapper $tmpstructure/bin/chown
# now make the links for busybox
cd $tmpstructure/bin
for f in $busybox_bin; do
  ln -s busybox $f
done


# now /sbin
#install /sbin/insmod $tmpstructure/sbin
install /sbin/MAKEDEV $tmpstructure/sbin
cd $tmpstructure/sbin
for f in $busybox_sbin; do
  ln -s ../bin/busybox $f
done
install $copy_files_from/listpci $tmpstructure/sbin
echo "done"

echo -n "    Creating config files in temporary file structure ... "
# now /etc
touch $tmpstructure/etc/fstab
echo -e "root:x:0:0:root:/:/bin/sh" > $tmpstructure/etc/passwd
echo -e "root:x:0:\ndisk:x:6:" > $tmpstructure/etc/group
# the identifier for checking if the CD is correct
install /etc/gibraltar-bootcd/id.txt $tmpstructure/etc
# the modules autoprobing database and utilities
install $copy_files_from/scsiprobe.dat $tmpstructure/etc
# pci device names and modules
install $copy_files_from/pcitable $tmpstructure/etc
echo "done"

# now /lib - this is the most complicated one, but Marcus Brinkmann already
# did all the work for me with his wonderful mklibs.sh script - thanks Marcus
echo -n "    Creating a minimal set of libaries needed by the binaries ... "
/usr/sbin/mklibs.sh -d $tmpstructure/lib \
	$tmpstructure/bin/* $tmpstructure/sbin/*
echo "done"

echo -n "Copying bootup files ... "
# finally the linuxrc file
install $copy_files_from/linuxrc $tmpstructure/
cp $copy_files_from/initrd-common-definitions.sh $tmpstructure/
cp $copy_files_from/ide-scsi-probe.sh $tmpstructure/
echo "done"

cd $olddir
# determine the size of the filesystem
size=`du -s $tmpstructure | awk '{print $1}'`
size=`expr $size + $reserve_kbytes`
echo "The image will take ${size} kb (including ${reserve_kbytes} kb of free"\
	"space for temp files)."

# now create the image
echo -n "Creating image file ... "
/bin/dd if=/dev/zero of=$tmpimage bs=1024 count=$size 2> /dev/null || {
  echo "failed during creation with dd !"
  exit 2
}
echo y | /sbin/mke2fs -i $bytes_per_inode -m 0 -q $tmpimage \
	> /dev/null 2> /dev/null || {
  echo "failed during creation with mke2fs !"
  exit 2
}
echo "done"
echo -n "Copying structure to image file ... "
mkdir -p $mntpoint
mount -o loop -t ext2 $tmpimage $mntpoint

# copy the structure onto it
cp -a $tmpstructure/* $mntpoint
rm -rf $mntpoint/lost+found

# save and compress the image
umount $mntpoint
cd $olddir
echo "done"
echo -n "Compressing image file ... "
mv $tmpimage $tmpimage.nogz
gzip -9 < $tmpimage.nogz > $image
echo "done"

# clean up
echo -n "Cleaning up ... "
rm -rf $tmpimage.nogz $mntpoint $tmpstructure $tmpbuilddir
echo "done"

exit 0
