#!/bin/sh
#
# --------------------------------------------------------------------------
# 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'.
# --------------------------------------------------------------------------
#

PATH=.:/bin:/sbin
export PATH

MNTPOINT=/mnt
ROOTDEVVAR=/proc/sys/kernel/real-root-dev
#CDROMDEVVAR=/proc/sys/dev/cdrom/info
HDBOOT_FILESYSTEMS="ext3 reiserfs xfs"

FOUND_ROOT=0

# initial setup
mount -t proc proc /proc 2> /dev/null || \
  echo "Error: mounting proc filesystem failed"

# some definitions
if [ $TERM = "linux" ] && ! grep "console=ttyS" /proc/cmdline >/dev/null; then
  COLOR_NORMAL="\033[0m"
  COLOR_BLUE="\033[1;34m"
  COLOR_GREEN="\033[1;32m"
  COLOR_RED="\033[1;31m"
else
  COLOR_NORMAL=""
  COLOR_BLUE=""
  COLOR_GREEN=""
  COLOR_RED=""
fi

. /initrd-common-definitions.sh
. /ide-scsi-probe.sh

# get the list of found cdrom drives
get_cdromlist() {
  if [ ! -r $CDROMDEVVAR ] ; then
    cdroms=""
    return 0
  fi

  if [ $devfs_support -eq 0 ]; then
    local cdromline="`cat $CDROMDEVVAR | grep \"drive name\"`"
    set $cdromline
    shift 2
    cdroms=$@
  else
    # a lot easier with devfs support ....
    olddir="`pwd`"
    cd /dev
    cdroms="`find cdroms -name \"cdrom*\" | grep '/' | tr '\n' ' '`"
    cd $olddir
  fi
}

## deep magic to create the number for the kernel's real_root_dev variable,
## pointing to the given device
#calc_rootdev() {
#  local maj=`ls -lL /dev/$1 | cut -c 33-37 | tr -d " "`
#  local min=`ls -lL /dev/$1 | cut -c 39-42 | tr -d " "`
#  rootdev="`expr $maj \* 256 \+ $min`"
#}

# check for a given cdrom drive if the correct cdrom is inserted
# expects the device name (relative to /dev) as parameter an returns
# 0....correct cdrom found
# 1....not found
check_cdrom() {
  local dev=$1
  echo -n "  checking $dev ... "

  # try to mount the device
  if mount -t iso9660 -o ro /dev/$dev $MNTPOINT 2>/dev/null; then
    # check if the ID matches
    if [ ! -r $MNTPOINT/id.txt ]; then
      echo "CD inserted, but no identifier found"
      umount $MNTPOINT
      return 1
    fi
    cd_id="`cat $MNTPOINT/id.txt`"
    if [ ! "$initrd_id" = "$cd_id" ]; then
      echo "CD inserted, but identifier does not match"
      umount $MNTPOINT
      return 1
    fi
    # please go away with that unmount - when will pivot_root work ??
    ##umount $MNTPOINT
    FOUND_ROOT=1
    echo "${COLOR_GREEN}found${COLOR_NORMAL}"

    ##echo -n "Using root device /dev/$dev = "
    ##calc_rootdev $dev
    ##echo "$rootdev"
    ##echo "$rootdev" > $ROOTDEVVAR
    ## yes, no more deep magic needed - calc_rootdev has gone away since it
    ## it a lot easier with the pivot_root call now. we just have to leave the
    ## correct root device mounted and use pivot_root. there is no need to
    ## calculate some special root device number anymore.
    return 0
  else
    echo "no CD inserted"
    return 1
  fi
}

# try to find the cdrom
locate_cdrom() {
  # check every device
  for dev in $cdroms ; do
    if [ $devfs_support -eq 0 ]; then
      # special for scsi cdroms - the kernel reports sr[0-9],
      # but the device files are named scd[0-9]
      if [ `expr $dev : \"sr[0-9]*$\"` -gt 2 ] ; then
        dev="scd`expr $dev : \"sr\([0-9]*\)$\"`"
      fi

      # if the corresponding device file isn't there, create it
      if [ ! -b /dev/$dev ] ; then
        MAKEDEV $dev >/dev/null 2>/dev/null
      fi
    #else
      # with devfs support it is easier - no need to kludge around with SCSI
      # device names
    fi

    if check_cdrom $dev; then
      # found the correct cdrom, no need to search any more
      break
    fi
  done
}

killallbyname() {
  if [ $# -lt 1 ]; then
    echo "Usage: killallbyname <process(es) name>"
    return 1
  fi

  (ps | grep $1) |
  while read pid tty time desc; do
    kill $pid
  done
}

trymountrootdev() {
  if mount $cmdlineroot $MNTPOINT 2>/dev/null; then
    local fsprocentry="`grep \"$cmdlineroot\" /proc/mounts`"
    set $fsprocentry
    local filesystem=$3
    echo "The root partition uses the $filesystem filesystem."
    ## the same goes here - no more calc_rootdev
    ##umount $cmdlineroot
    FOUND_ROOT=1
    return 0
  else
    return 1
  fi
}

stopit() {
  while true; do
    read key
  done
}

error() {
  echo "${COLOR_RED}Error:${COLOR_NORMAL} $1"
  exit 1
}



# do not allow the script to be killed
trap '' 2 3 15

initrd_id="`cat /etc/id.txt`"
echo -n "\n${COLOR_BLUE}${initrd_id}${COLOR_NORMAL} loading, "

old_printk="`cat /proc/sys/kernel/printk`"
echo 0 0 0 0 > /proc/sys/kernel/printk

# NEW: beginnings of devfs support
devfs_support=0
if grep "devfs" /proc/filesystems >/dev/null; then
  # ahh, the kernel supports devfs, but is it mounted too ?
  if grep "devfs" /proc/mounts >/dev/null; then
    # The syslogd from busybox can not handle to have its socket on devfs
    # (I have no idea why there is a problem, the standard syslogd works
    # perfectly well with devfs mounted on /dev. It creates the socket without
    # complaining, but the busybox syslogd is unable to do that.).
    ln -s /tmp/syslog.socket /dev/log
    devfs_support=1
  fi
fi

#dmesg -n 1
# syslog is only needed so that the kernel does not print error messages
# to the console during insmod probing
syslogd -O messages

# set the real root filesystem invalid now
if [ ! -w $ROOTDEVVAR ] ; then
  echo "Error: $ROOTDEVVAR is not writeable - kernel problem ?"
  exit 1;
fi
echo "0" > $ROOTDEVVAR

# is this a normal CD boot or a rescue boot of an installed system ?
# (when an installed system should be booted, root=xxx must have been given
# on the kernel command line)
cmdline="`cat /proc/cmdline`"
for option in $cmdline; do
  if [ `expr $option : "boot=/dev/.*"` -gt 0 ]; then
    # found the root option
    cmdlineroot="`expr $option : \"boot=\(/dev/.*\)\"`"
  fi
done

if [ -z $cmdlineroot ]; then
  # no root device given on command line - normal CD boot
  echo "searching for CD .... "
  rootdev=0
  cd /dev

  # first try the IDE/ATAPI cdroms
  install_ide_cd_mods
  echo -n "trying to locate cdrom: "
  get_cdromlist
  if [ "$cdroms" ] ; then
    echo "found: $cdroms"
  else
    echo "no ATAPI CD-ROM drives found"
  fi
  locate_cdrom
  if [ $FOUND_ROOT -eq 0 ] ; then
    install_scsi_cd_mods
    check_scsi
    echo -n "trying to locate cdrom: "
    get_cdromlist
    if [ "$cdroms" ] ; then
      echo "found: $cdroms"
    else
      echo "no CD-ROM drives found on already detected adapters"
    fi
    locate_cdrom
  fi
  if [ $FOUND_ROOT -eq 0 ] ; then
    probe_scsi_mods
    echo -n "trying to locate cdrom: "
    get_cdromlist
    if [ "$cdroms" ] ; then
      echo "found: $cdroms"
    fi
  fi
  if [ ! "$cdroms" ] ; then
    error "no CD-ROM drives found"
  fi

  # do this until the cdrom has been found, because going on without
  # this step is senseless
  while [ $FOUND_ROOT -eq 0 ] ; do
    locate_cdrom
    if [ $FOUND_ROOT -eq 0 ]; then
      echo "${COLOR_RED}Error:${COLOR_NORMAL} CD not found, please insert"\
              "and press Enter to continue"
      read key
    fi
  done
else
  echo "booting an installed system on"\
          "${COLOR_GREEN}${cmdlineroot}${COLOR_NORMAL}"
  if [ $devfs_support -eq 0 ]; then
    # it's a bit compilated to determine which modules should be loaded
    # with the old device naming scheme
    case `expr "$cmdlineroot" : "/dev/\(\w\)\d*"` in
      h) load_support="ide"
      	 ;;
      s) load_support="scsi"
	 ;;
      *) load_support="unknown"
    	 ;;
    esac
  else
    # when there is devfs support, it may happen that people use the old
    # naming scheme for giving the root partition - we don't handle this here
    load_support="`expr \"$cmdlineroot\" : \"/dev/\(\w*\)/.*\"`"
    if [ -z $load_support ]; then
      echo "Unable to parse the given root device name."
      load_support="unkown"
    fi
  fi

  case $load_support in
    ide)  echo "Loading IDE modules if needed."
          install_ide_hd_mods
          ;;
    scsi) echo "Loading SCSI modules if needed."
          install_scsi_hd_mods
          check_scsi
          ;;
    *)    echo "${COLOR_RED}Error:${COLOR_NORMAL} Unkown root device type !"
          ;;
  esac

  if [ $devfs_support -eq 0 ]; then
    # without devfs, we will have to create the device file
    cd /dev
    makedevfile="`expr \"$cmdlineroot\" : \"/dev/\(\w\w\w\)\d*\"`"
    MAKEDEV $makedevfile >/dev/null 2>/dev/null
  else
    # with devfs support the device file must exist now - if not, the kernel
    # will not be able to find the device anyway
    if [ ! -e $cmdlineroot ]; then
      echo "${COLOR_RED}Error:${COLOR_NORMAL} The given root device does not exist !"
      # it's the best to stop here
      stopit
    fi
  fi

  # when will these 3 lines go away ??
  ##cmdlinedev="`expr \"$cmdlineroot\" : \"/dev/\(.*\)\"`"
  ##calc_rootdev $cmdlinedev
  ##echo "$rootdev" > $ROOTDEVVAR

  # at last, check if the filesystem of the partition is supported by this
  # kernel
  for fs in $HDBOOT_FILESYSTEMS; do
    echo -n "Trying to mount root filesystem ... "
    if trymountrootdev; then
      # perfect - the root filesystem could be mounted
      echo "${COLOR_GREEN}done${COLOR_NORMAL}"
      break
    else
      # oops, mounting failed - try the next filesystem
      echo "failed"
      echo -n "Trying to load additional support for filesystem $fs ... "
      if insmod_helper $fs; then
        echo "${COLOR_GREEN}done${COLOR_NORMAL}"
      else
        echo "failed"
      fi
    fi
  done
  
  if [ $FOUND_ROOT -eq 0 ]; then
    echo "${COLOR_RED}Error:${COLOR_NORMAL} Unsupported root filesystem !"
    echo "Please check that you specified the correct root device name" \
         "and that it"
    echo "contains a valid, supported filesystem."
    # it's the best to stop here
    stopit
  fi
fi

# cleanup
killallbyname "klogd"
killallbyname "syslogd"
#dmesg -n 3
echo $old_printk > /proc/sys/kernel/printk
umount /proc 2> /dev/null || error "unmounting proc filesystem failed"

# now the new root change mechanism for kernels >= 2.4.x
cd $MNTPOINT
pivot_root . initrd || error "changing to new root failed"

# also mount devfs on the new root, since pivot_root does not change that
# automatically
mount --bind initrd/dev dev 2> /dev/null || error "remounting devfs filesystem failed"

# initrd doesn't seem to like having PATH already set....
# (no need to unset others, PATH is the only one that is exported)
unset PATH

echo "Initial ram disk setup completed. Initiating normal boot procedure.\n"

# first prepare the environment for init - mainly runlevel.conf
/sbin/prepareroot

exec /usr/sbin/chroot . /sbin/init

exit 0
