#!/bin/busybox ash
#
# LiveCD startup (linuxrc) script
#
# Copyright (C) 2002-2004, Jaco Greeff <jaco@puxedo.org>
# Copyright (C) 2003, Buchan Milne <bgmilne@obsidian.co.za>
# Copyright (C) 2004, Tom Kelly  <tom_kelly33@yahoo.com>
#
#    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, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Adapted for mklivecd from the MiniCD (http://www.linuxminicd.org) linuxrc script
# The latest version of this script can be found at http://livecd.berlios.de
#
# $Id: linuxrc.in,v 1.107 2008/04/12 09:31:05 ikerekes Exp $
#

### global variables
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/initrd/bin:/initrd/sbin:/initrd/usr/bin:/initrd/usr/sbin
umask 022
DEBUG=
nocd=
nohd=
silent=
dounionfs=
usblive=
OPT_MODULES="zlib_deflate"
DEP_MODULES="nls_iso8859-1 nls_iso8859-2 nls_cp437 jbd ext3 unionfs reiserfs xfs fat msdos vfat ntfs nls_utf8 isofs cdrom ide-core ide-cd i2c-core i2c-piix4 ff-memless evdev dock crc-t10dif squashfs loop paride parport "
SCSI_MODULES="scsi_mod sr_mod libata sg sd_mod scsi_transport_fc scsi_transport_sas scsi_transport_spi mptbase mptscsih i2o_core megaraid_mm qlogicfas408 ahci ata_generic ata_piix pata_ali pata_amd pata_artop pata_atiixp pata_cmd640 pata_cmd64x pata_cs5520 pata_cs5530 pata_cs5535 pata_cypress pata_efar pata_hpt366 pata_hpt37x pata_hpt3x2n pata_hpt3x3 pata_isapnp pata_it8213 pata_it821x pata_jmicron pata_legacy pata_marvell pata_mpiix pata_netcell pata_ns87410 pata_oldpiix pata_optidma pata_opti pata_pcmcia pata_pdc2027x pata_pdc202xx_old pata_platform pata_qdi pata_radisys pata_rz1000 pata_sc1200 pata_serverworks pata_sil680 pata_sis pata_sl82c105 pata_triflex pata_via pata_winbond pdc_adma sata_inic162x sata_mv sata_nv sata_promise sata_qstor sata_sil24 sata_sil sata_sis sata_svw sata_sx4 sata_uli sata_via sata_vsc 3w-9xxx 3w-xxxx a100u2w aacraid advansys aha152x aha1542 aic79xx aic7xxx aic7xxx_old aic94xx arcmsr atp870u BusLogic ch dc395x dmx3191d dpt_i2o dtc eata fdomain gdth g_NCR5380 g_NCR5380_mmio hptiop ide-scsi imm in2000 initio ipr ips lpfc megaraid megaraid_mbox megaraid_sas NCR53c406a nsp32 osst pas16 ppa psi240i qla1280 qla2xxx qla4xxx qlogicfas raid_class seagate stex st sym53c416 sym53c8xx tmscsim u14-34f ultrastor wd7000 sx8  3w-xxxx" # these are for the SCSI drivers
#SCSI_MODULES="sd_mod sg libata ahci ata_piix ata_generic scsi_transport_fc scsi_transport_iscsi scsi_transport_sas scsi_transport_spi"
USB_MODULES="usbcore"
USB_MODULES_DRV="usbhid uhci-hcd ohci-hcd ehci-hcd usb-storage"

CDROM_LIST=""
LOOPSEXT=".sqfs"
ISOTYPE="iso9660"
MEDIACHECK="isolinux/mediacheck"
DEVICES=""                # list of all ide/scsi cd-type devices
FOUNDMEM=200000           # total memory found on box
TOTALMEM=200000           # total usable memory on box
MINSIZE=2000              # Minimum size of additional ram partitions
MINLEFT=16000             # At least this much memory minus 30% should remain when home and var are full.
MAXSIZE=1000000           # maximum ramdisk size
RAMSIZE=1000000           # default ramdisk size
MINRAMSIZE=15000          # the minimum ramdisk size
KERNELVER="2.6.22.18-server-1mdv"   # this is setup via uname -r in the initialise section
MKLIVECDVER="0.7.1"
NAME_VERSION_STR="@NAME_VERSION_STR@"

#common variables 

MNTCDROM=initrd/cdrom
MNTLIVECD=initrd/loopfs
MNTRAMDISK=/ramfs
MODEXT=".ko"

### progress indicator
progress_num=0
progress_full=20
progress_max=32768

### screen colors
RES_COL=65
MOVE_TO_COL="echo -en \\033[${RES_COL}G\\033[K"
SETCOLOR_OK="echo -en \\033[1;32m"
SETCOLOR_FAIL="echo -en \\033[1;31m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"

#common (library) functions

### print a success msg
printok() {
        $MOVE_TO_COL
        echo -n "[  "
        $SETCOLOR_OK
        echo -n "OK"
        $SETCOLOR_NORMAL
        echo "  ]"
        return 0
}

### print a loaded success msg
printloaded() {
        $MOVE_TO_COL
        echo -n "["
        $SETCOLOR_OK
        echo -n "LOADED"
        $SETCOLOR_NORMAL
        echo "]"
        return 0
}

### print a failure msg
printfail() {
        $MOVE_TO_COL
        echo -n "["
        $SETCOLOR_FAIL
        echo -n "DONE"
        $SETCOLOR_NORMAL
        echo "]"
        return 0
}

### print error message and exit to limited shell
printfatal() {
	printfail
	$SETCOLOR_FAIL
	echo ""
	echo "$1"
	shift
	while [ $# -gt 0 ]; do
		echo "$1"
		shift
	done
	echo ""
	echo "       Dropping you to a limited shell."
	$SETCOLOR_NORMAL
	execshell
}

### execute a command/commands printing the success or failure msg on completion
docmd() {
        echo -n "$1: "
        shift
        CMD="($1)"
        shift
        while [ $# -gt 0 ]; do
                CMD="$CMD && ($1)"
                shift
        done
        (eval "$CMD") 2>&1 >/dev/null && printok || printfail
}


### load a module
loadmod() {
        MODULE="/lib/modules/$KERNELVER/kernel/$1$MODEXT"
        [ ! -f $MODULE ] && MODULE="/initrd$MODULE"
        [ ! -f $MODULE ] && return 1
        if [ -n "$DEBUG" ]; then
                RET=0
                echo -n "$MODULE: "
		modprobe $1 $2 && RET=0 || RET=1
                echo "($RET)"
                return $RET
        else
		(modprobe $1 $2 2>&1)>/dev/null && return 0 || return 1
        fi
}


### set progress bar
set_progress() {
        if [ -e /proc/splash ] && [ -n "$silent" ]; then
                progress_num=$(($progress_num+1));
                progress=$(($progress_max*($progress_num+1)/$progress_full));
                echo "show $progress" >/proc/splash
        fi
}

dbg() {
    if [ -n "$DEBUG" ]; then
       	echo
       	$SETCOLOR_FAIL
       	echo -e "DBG: ${@}"
       	$SETCOLOR_NORMAL
       	echo
    fi 
}

### this is if we are to execute a limited shell
execshell() {
        export HOSTNAME="localhost.localdomain"
        export PS1="$ "
        export PS2="> "
        export PS4="+ "
        echo "6" >/proc/sys/kernel/printk

        # find the best shell available to us at this point
        if [ -e /bin/bash ]; then
                echo "  Loading /bin/bash"
                export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
                SHELL="/bin/bash"
        elif [ -e /initrd/bin/ash ]; then
                echo "  Loading /initrd/bin/ash"
                export PATH=/initrd/bin:/initrd/sbin:/initrd/usr/bin:/initrd/usr/sbin
                SHELL="/initrd/bin/ash"
        else
                export PATH=/bin:/sbin:/usr/bin:/usr/sbin
                if [ -e /bin/ash ]; then
                        echo "  Loading /bin/ash"
                        SHELL="/bin/ash"
                else
                        echo "  Loading /bin/busybox ash"
                        SHELL="/bin/busybox ash && <dev/tty >dev/console 2>&1"
                fi
        fi
        exec $SHELL
}

mountit(){
# Usage: mountit src dst "options"
    	BUILTIN_FS="iso9660 vfat ext3 ext2 msdos reiserfs ntfs"
    	for fs in $BUILTIN_FS; do
        	test -b $1 && mount -t $fs $3 $1 $2 >/dev/null 2>&1 && return 0
    	done
    	return 1
}

# ===========================================================
# discovery functions
# ===========================================================

# List all CD-ROMs
# by using /proc entries
#
list_cdrom_devices()
{
   if [ -n "$nocd" ]; then return 1; fi
   for CDDEVICE in `cat /proc/sys/dev/cdrom/info | head -n 3 | tail -n 1 | cut -d ":" -f 2`; do
      echo "/dev/$CDDEVICE"
   done
}

# List all partition devices
# take list of all partitions and output unique disks.
# Return empty result when nohd parameter was given.
#
list_partition_devices()
{
   if [ -n "$nohd" ]; then return 1; fi
   for part in `cat /proc/partitions|tail  +3|awk '{print $4}'`
   do
     echo "/dev/$part"
   done
}

# List all disk devices
#
list_disk_devices()
{
   list_partition_devices | grep  "[0-9]"
}

# List all block devices
#
list_block_devices()
{
   list_cdrom_devices
   list_disk_devices
}

#--------------------------------------------------------------------#
# Linuxrc subroutines                                                #
# Display debugging info if debug is on. Allow extended echo chars.  #
#--------------------------------------------------------------------#

### initialise
initialise() {
        busybox mount -n -t proc none /proc
        busybox --install
        #Not sure why this is next line is necessary but it
        #doesn't happen automatically after busybox --install
        ln /bin/busybox /bin/awk

        echo "--- MKLIVECD LINUXRC ---------------"
        rm -rf /sbin/init
        mv /sbin/init.dynamic /sbin/init

        docmd   "  Setting up kernel parameters" \
                "echo '0' >/proc/sys/kernel/printk" \
                "echo '/sbin/modprobe' >/proc/sys/kernel/modprobe" \
                "exec >/dev/console </dev/console 2>&1"

        # some kernel specifics
        KERNELVER=`uname -r`

        # Unhide the udev files
        docmd "  Restoring udev files" \
        "mv /sbin/tmp/* /sbin" \
        "rm -f /bin/mknod" \
        "mv /bin/tmp/* /bin"   

        # parameter parsing
        for x in $(cat /proc/cmdline); do
                case $x in
                        debug) DEBUG=y; ;;
                        md5sum) domd5=y; ;;
                        splash=silent) silent=y; ;;
                        unionfs=no) dounionfs=n; ;;
                        copy2ram) toram=y; ;;
                        nocd) nocd=y; ;;
                        nohd) nohd=y; ;;
			fromusb) usblive=y; ;;
                        livecd=*) BASEIMG="${x#livecd=}"; [ -z "$BASEIMG" ] &&  BASEIMG="livecd"; ;;
                        bootfromiso=*) ISO_PATH="${x#bootfromiso=}"; ;;
                esac
        done
        set_progress
}


find_cdroms() {
	# modprobe kernel modules needed for the LiveCD
	## Initialise
        echo -n "  Loading basic cdrom, scsi & usb modules for Kernel: $KERNELVER"
	## Load basic modules
	ALL_LOADED=1
        for i in $OPT_MODULES $DEP_MODULES $SCSI_MODULES $USB_MODULES $USB_MODULES_DRV; do
		loadmod $i || ALL_LOADED=
	done
	[ -n "$ALL_LOADED" ] && printloaded || printfail
	set_progress

	## load probe-modules for detecting chipset and load modules ?
        docmd  "  Loading basic Chipset modules for kernel $KERNELVER" \
               "echo '/bin/probe-modules'"
        sleep 2
        set_progress

	## Load the compressed loop module
        echo -n "  Loading compressed loop module: "
        loadmod squashfs && printloaded || printfail

        ## load unionfs
        if [ -n "$dounionfs" ]; then
        	echo -n  "  Starting UNIONFS support"
        	docmd   "  Loading unionfs modules" \
                        "echo '/sbin/modprobe /lib/modules/$KERNELVER/kernel/unionfs.ko'"
        fi
        set_progress

	## Do we want to boot from USB?
	if [ -n "$usblive" ]; then
		echo -n " Booting from USB "
		rm -rf /initrd/sbin/halt.local
	fi

	## Kernel 26 udev additions
	## Search for cdrom devices and add them to CDROM_LIST
	## Check for ide channels.

        if [ ! -e /sbin/start_udev ]; then
		#echo -n "  Starting mdev: "
		# make needed device
		mknod /dev/console c 5 1
		# Run Busybox mdev to create devices
		# echo "Listing of /dev before running mdev: "; cd /dev; ls -l; cd /
		mdev -s
		# echo "Listing of /dev after running mdev: "; cd /dev; ls -l; cd /
		#echo /sbin/mdev > /proc/sys/kernel/hotplug
	else
                echo -n "  Starting udev: "
                ( `/sbin/start_udev >/dev/null 2>/dev/null` ) && printok || printfail
	fi

        echo -n "  Waiting for udev to do stuff."
        sleep 10 && printok
  
	if [ -n "$usblive" ]; then
		## Check for usb stick
		for usb_device in /dev/sd[a-h][0-2]; do
			if [ -e "$usb_device" ]; then
				CDROM_LIST="$CDROM_LIST $usb_device"
			fi
		done
	else	
		# List of cdroms + all the partition devices
		CDROM_LIST=`list_block_devices`

		## Check for scsi cds and partitions - if exist, add to the list 
		for scsi_cdrom in /dev/scd[0-99] /dev/sr[0-99]; do
			if [ -e "$scsi_cdrom" ]; then
				CDROM_LIST="$CDROM_LIST $scsi_cdrom"
			fi
		done

		printok
		set_progress
	fi
}

### check the MD5 sum of the cloop iso image
checkmd5() {
        if [ -f $MNTCDROM/$MEDIACHECK ]; then
                if [ -n "$domd5" ]; then
                        echo -n "  Verifying MD5 checksum of iso image: "
                        $MNTCDROM/$MEDIACHECK $CDDEV && printok || printfail
                fi
        fi
}


findcloop() {
        ## Now try to find and mount the boot CD (we use ID as identification)
        echo -n "  Searching for the loop image: "
        PRINTK=`cat /proc/sys/kernel/printk`
        echo "0" >/proc/sys/kernel/printk
        for i in $1; do
                CDDEV="$i"
                $MOVE_TO_COL
                $SETCOLOR_OK
                echo "$i"
                $SETCOLOR_NORMAL
                if mountit $CDDEV $MNTCDROM ; then
                        dbg "Mounted $CDDEV\n"
                        # try to find either the .sqfs loop image
                        LOOPTYPE=""
                        if [ -f $MNTCDROM/$BASEIMG$LOOPSEXT ]; then
                                LOOPTYPE="$LOOPSEXT"
                                DEVLOOP="/dev/loop0"
                                LOOPMOD="squashfs"
                                ISOTYPE="squashfs"
                        fi

                        # if it exists, load the correct module and mount
                        if [ -n "$LOOPTYPE" ]; then
                                printok
                                checkmd5 ""

                                echo -n "  Mounting loop image on /$MNTLIVECD: "
                                if [ -e "$DEVLOOP" ]; then
                                        losetup $DEVLOOP $MNTCDROM/$BASEIMG$LOOPTYPE 
                                        mount -r -t $ISOTYPE $DEVLOOP $MNTLIVECD && LOOPMNT=1
                                fi

                                ## Did we get it?
                                if [ -z "$LOOPMNT" ]; then ## -z (null because mount failed)
                                        printfatal "ERROR: Unable to mount loop filesystem," \
                                        "  Commands were:" \
                                        "  losetup $DEVLOOP $MNTCDROM/$BASEIMG$LOOPTYPE" \
                                        "  mount -r -t $ISOTYPE $DEVLOOP $MNTLIVECD" \
                                        "  Most likely cause is bad burn or bad download" \
                                        "  Please run mediacheck on livecd" 
                                else
                                        ## Yes, we got it!
                                        # do we want copy2ram?
                                        toram=`grep -iq copy2ram /proc/cmdline && echo 1`
                                        if [ -n "$toram" ]; then
                                                RAMDIR="/initrd/livecd.ram"
                                                mkdir -p $RAMDIR
                                                # make sure we have enough room for the image
                                                IMAGESIZE=`ls -l $MNTCDROM/livecd.sqfs | awk '{print $5+1000000}'`
                                                mount -t tmpfs -o "size=$IMAGESIZE" tmpfs $RAMDIR
                                                if [ "$?" -eq 0 ]; then
                                                        # copy the livecd.sqfs image to a tmpfs directory to be used as the new MNTCDROM
                                                        echo -n 
                                                        echo -n " Copying to memory, please stand by..."
                                                        cp -R $MNTCDROM/livecd.sqfs $RAMDIR
                                                        if [ "$?" -eq 0 ]; then
                                                                printok
                                                                # free the boot device
                                                                umount $MNTLIVECD
                                                                umount $MNTCDROM
                                                                # and use our new directory as the new MNTLIVECD
                                                                `losetup -d $DEVLOOP 2>&1 >/dev/null`
                                                                losetup $DEVLOOP $RAMDIR/livecd.sqfs
                                                                mount -r -t squashfs $DEVLOOP $MNTLIVECD
                                                                rm -rf /initrd/sbin/halt.local
                                                        else
                                                                `umount $RAMDIR 2>&1 >/dev/null`
                                                                echo -n "copy 2 ram was unsuccesfull"
                                                                printfail
                                                        fi
                                                else
                                                        `umount $RAMDIR 2>&1 >/dev/null`
                                                        echo -n "the iso is larger than the available ram"
                                                        printfail
                                                fi
                                        fi
                                        printok
                                        break
                                fi
                        fi
                        `umount $MNTCDROM 2>&1 >/dev/null`
                fi
        done
        echo "$PRINTK" >/proc/sys/kernel/printk
}

### create /initrd/ramfs
createramdisk() {
        # how much memory do we have?
        echo -n "  Creating ramdisk -  usable memory"
        FOUNDMEM="$(awk '/MemTotal/{print $2}' /proc/meminfo)"
        TOTALMEM="$(awk 'BEGIN{m=0};/MemFree|Cached/{m+=$2};END{print m}' /proc/meminfo)"
        MAXSIZE="$(expr $TOTALMEM - $MINLEFT)"
        RAMSIZE="$(expr $TOTALMEM / 2)"
        [ -z "$RAMSIZE" ] && RAMSIZE=$MINRAMSIZE
        [ $RAMSIZE -lt $MINRAMSIZE ] && RAMSIZE=$MINRAMSIZE
        echo -n " (${RAMSIZE}/${TOTALMEM}/${FOUNDMEM}kB)"
        printok

        # Check for sufficient memory to mount extra ramdisk for /etc, /home, /root, /var
        if test -n "$TOTALMEM" -a "$TOTALMEM" -gt "$MINLEFT"; then
                docmd   "  Creating 2.6 root filesystem (${RAMSIZE}/${FOUNDMEM}kB) on /dev/shm" \
                        "mkdir -p $MNTRAMDISK" \
                        "mount -t tmpfs -o 'size=${RAMSIZE}k' /dev/shm $MNTRAMDISK" \
                        "mkdir -p $MNTRAMDISK/initrd" \
                        "echo '0x0100' >/proc/sys/kernel/real-root-dev" \
                        "pivot_root $MNTRAMDISK $MNTRAMDISK/initrd" \
                        "mkdir -p /proc && mount -n -t proc none /proc" \
                        "mkdir -p /sys && mount -n -t sysfs none /sys" \
                        "mkdir -p /tmp && chmod 1777 /tmp" \
                        "mkdir -p /media && chmod 755 /media" \
                        "mkdir -p /dev && mount -n -t tmpfs none /dev" \
                        "mkdir -p /dev/pts" \
                        "cd /" \
                        "ln -s /initrd/bin" \
                        "ln -s /initrd/boot" \
                        "ln -s /initrd/etc" \
                        "ln -s /initrd/opt" \
                        "ln -s /initrd/lib" \
                        "ln -s /initrd/sbin" 

                docmd   "  Making extra nodes" \
                        "ln -s /proc/self/fd /dev/fd" \
                        "ln -s /proc/self/fd/0 /dev/stdin" \
                        "ln -s /proc/self/fd/1 /dev/stdout" \
                        "ln -s /proc/self/fd/2 /dev/stderr" \
                        "ln -s /proc/kcore /dev/core" 

                        if [ ! -x /sbin/hotplug ]; then
                                echo /sbin/udev > /proc/sys/kernel/hotplug
                        fi

                set_progress
        else
                printfatal "ERROR: Insufficient memory to create ramdisk."
        fi
}


### main script entry point

initialise    ""
$SETCOLOR_NORMAL
createramdisk ""

# try to find all the cdrom and partitions

find_cdroms ""

dbg "Devices to check: $CDROM_LIST\n"

if [ "$CDROM_LIST" = "" ]; then
	printfatal "Error: No suitable media for the livecd content found." \
	"Workaround: Copy the content of the livecd from your boot device to an IDE/SATA disk," \ 
	"eg. to /mnt/hda1/livecd.sqfs or C:\\livecd.sqfs Then try to boot again."
fi

# First see if bootfrom= cheatcode is given, Try that one first

case "$ISO_PATH" in *.[iI][sS][oO]) ;; *) ISO_PATH="" ;; esac

if [ -n "$ISO_PATH" ]; then
         mkdir -p /part 
         #try to find the iso
         for i in $CDROM_LIST; do
                  CDDEV="$i"
                  $MOVE_TO_COL
                  $SETCOLOR_OK
                  echo "$i"
                  $SETCOLOR_NORMAL
                  if mountit $CDDEV $MNTCDROM ; then
                           dbg "Mounted $CDDEV\n"
                           # try to find the iso image
                           LOOP_DEV=""
                           if [ -f $MNTCDROM/$ISO_PATH ]; then
                                   LOOP_DEV=$CDDEV
                                   `umount $MNTCDROM 2>&1 >/dev/null`
				   break
                           fi
                          `umount $MNTCDROM 2>&1 >/dev/null`
		  else
			  dbg "Could not mount $CDDEV on $MNTCDROM. The ISO_PATH is $ISO_PATH\n" 	
                  fi
         done
         if [ -z $LOOP_DEV ]; then
                  echo -n "couldn't find the $ISO_PATH iso image in your computer"
                  printfail
         else
                  mount -r -o ro $LOOP_DEV /part || echo "could't mount the $LOOP_DEV partition"
                  losetup /dev/loop1 /part$ISO_PATH
                  mount -r -t iso9660 /dev/loop1 $MNTCDROM && printok || printfail
                  if [ -e "$MNTCDROM/$BASEIMG$LOOPSEXT" ]; then
                           losetup /dev/loop2 $MNTCDROM/$BASEIMG$LOOPSEXT
                           mount -r -t squashfs /dev/loop2 $MNTLIVECD && LOOPMNT=1
                           rm -rf /initrd/sbin/halt.local
                  else
                           printfatal "couldn't find the $BASEIMG$LOOPSEXT in the $ISO_PATH" 
                  fi
        fi
fi
dbg "I am after bootfrom. The LOOPMNT is: $LOOPMNT\n"

# no bootfrom -lets try all the mountable devices

if [ -z "$LOOPMNT" ]; then
	findcloop "$CDROM_LIST"
	dbg "I am after find_cloop The LOOPMNT is: $LOOPMNT\n"
fi

# Did we find _any_ livecd.sqfs?

if [ -z "$LOOPMNT" ]; then
	printfatal "ERROR: Unable to mount the livecd"
fi

echo "--- Exiting LINUXRC ----------------"
exec /etc/rc.d/rc.sysinit <dev/console >dev/console 2>&1
exit 0
