#!/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.104 2006/04/01 23:11:41 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=
FOUND_ISO=""
OPT_MODULES="zlib_inflate"
DEP_MODULES="nls_iso8859-1 nls_iso8859-2 nls_cp437 jbd ext3 reiserfs fat msdos vfat ntfs nls_utf8 isofs cdrom ide-cd loop scsi_mod sr_mod libata ata_piix sg sd_mod scsi_transport_spi mptbase"
SCSI_MODULES="aha1542 ahci aic7xxx BusLogic dmx3191d dtc eata fdomain gdth g_NCR5380 in2000 NCR53c406a pas16 psi240i qlogicfas qlogicfc sata_nv sata_promise sata_qstor sata_sil sata_sis sata_svw sata_sx4 sata_uli sata_via sata_vsc sym53c416 t128 tmscsim u14-34f wd7000 sx8 mptscsih 3w-xxxx" # these are for the SCSI drivers
USB_MODULES="usbcore"
USB_MODULES_DRV="uhci-hcd ohci-hcd ehci-hcd usb-storage"

FOUND_SCSI=""
FOUND_USB=""
BASEIMG="livecd"          # name of the base cloop image, with a .sqfs (squashfs) extension
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.12-27mdk-i686-up-4GB"   # this is setup via uname -r in the initialise section
MKLIVECDVER="0.6.0-20061103"
NAME_VERSION_STR="@NAME_VERSION_STR@"
CLOOPVER="@CLOOPVER@"

#common variables 

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

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

### 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_WARN="echo -en \\033[1;33m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"
SETCOLOR_CLEAR="echo -en \\033c"
SETCOLOR_CEOL="echo -en \\033[0G\\033[K"

#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 warning msg
printwarn() {
        $MOVE_TO_COL
        echo -n "[ "
        $SETCOLOR_WARN
        echo -n "WARN"
        $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: "
                insmod $MODULE $2 && RET=0 || RET=1
                echo "($RET)"
                return $RET
        else
                (insmod $MODULE $2 2>&1)>/dev/null && return 0 || return 1
        fi
}


### set progress bar
set_progress() {
        silent=`grep -i splash=silent /proc/cmdline`
        if [ -e /proc/splash ] && [ -n "$silent" ] && [ -n "$progress_on" ]; 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"
                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
}

### function to get the value of an option from the kernel command line
getbootoption() {
	option="$1"
	val=`$MNTLIVECD/bin/sed -r -e "s/(.*)${option}=([[:alnum:]-]*)(.*)/\2/i" /proc/cmdline`
	if [ -n "$val" -a "$val" != "`$MNTLIVECD/bin/cat /proc/cmdline`" ]; then
		echo $val
		return 0
	else
		return 1
	fi
}

### function to check for an option from the kernel command line
checkbootoption() {
	if [ `grep -iq $1 /proc/cmdline` ]; then
		return 0
	else
		return 1
	fi
}

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

### initialise
initialise() {
        busybox mount -n -t proc none /proc
        busybox --install

        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"

        # debugging?
	DEBUG=`grep -iq debug /proc/cmdline && echo 1`
        set_progress
}

# modprobe kernel modules needed for the LiveCD
find_cdroms() {
	## Initialise
	echo -n "  Loading basic cdrom modules for Kernel 2.6"
	## Load basic modules
	for i in $OPT_MODULES; do
		loadmod $i
	done
	set_progress

	ALL_LOADED=1
	for i in $DEP_MODULES; do
		loadmod $i || ALL_LOADED=
	done
	[ -n "$ALL_LOADED" ] && printloaded || printfail
	set_progress

	echo -n  "  Starting USB support"
	printok
	## Probe the USB devices.
	dousb=`grep -iq nousb /proc/cmdline || echo 1`
	if [ -n "$dousb" ]; then
		echo -n "  Probing USB devices: "
        	USB_FOUND=1
		for i in $USB_MODULES; do
			loadmod $i || USB_FOUND=
        	done

        	for i in $USB_MODULES_DRV; do
			loadmod $i
        	done
        	sleep 2
        	[ -n "$USB_FOUND" ] && printloaded || printok
	fi
	set_progress
	sleep 6

	#find_scsi_cdroms
	## Probe the SCSI devices.
	doscsi=`grep -iq noscsi /proc/cmdline || echo 1`
	if [ -n "$doscsi" ]; then
		echo -n "  Probing SCSI devices: "
		SCSI_FOUND=
		for i in $SCSI_MODULES; do
			loadmod $i && SCSI_FOUND=1
		done
		sleep 2
		[ -n "$SCSI_FOUND" ] && printloaded || printok
	fi

	## Kernel 26 udev additions
	## Search for cdrom devices and add them to CDROM_LIST
	## Check for ide channels.
	for ide_channel in /proc/ide/ide[0-9]; do
		## If there are no ide channels found, then skip this
		if [ ! -d "$ide_channel" ]; then
			echo "  No ide channels found"
			break
		fi

		## Try each ide device to see if we can find the cd-rom drive (up to 20 - hdt)
		for ide_device in hda hdb hdc hdd hde hdf hdg hdh hdi hdj hdk hdl hdm hdn hdo hdp hdq hdr hds hdt; do
			device_media_file="$ide_channel/$ide_device/media"
			if [ -e "$device_media_file" ]; then
				grep -i "cdrom" $device_media_file > /dev/null 2>&1
				if [ $? -eq 0 ]; then
					CDROM_LIST="$CDROM_LIST /dev/$ide_device"
				fi
                       fi
		done
	done

	## Check for scsi cds, usb cd, usb flash
        for scsi_cdrom in /dev/scd[0-99] /dev/sr[0-99] /dev/sd[a-b][0-99]; do
		if [ -e "$scsi_cdrom" ]; then
			CDROM_LIST="$CDROM_LIST $scsi_cdrom"
		fi
	done

	printok
	set_progress
}

### check the MD5 sum of the cloop iso image
checkmd5() {
        if [ -f $MNTCDROM/$MEDIACHECK ]; then
                domd5=`grep -iq md5sum /proc/cmdline && echo 1`
                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
                        FOUND_ISO="$i"
                                printok
                                checkmd5 ""

                                if [ -n "$LOOPMOD" ]; then  ## -n (not null string)
                                        echo -n "  Loading compressed loop module: "
                                        loadmod $LOOPMOD && printloaded || printfail
                                fi

                                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"
                                else
                                        ## Yes, we got it!
                                        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 / 3)"
        [ -z "$RAMSIZE" ] && RAMSIZE=$MINRAMSIZE
        [ $RAMSIZE -lt $MINRAMSIZE ] && RAMSIZE=$MINRAMSIZE
        #RAMSIZE=$(expr $RAMSIZE \* 4) # tmpfs/varsize version, can use swap
        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 /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

                        echo -n "  Starting udevstart"
                        ( `/sbin/udevstart >/dev/null 2>/dev/null` & ) && printok || printfail
                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"

# First see if bootfrom= cheatcode is given, Try that one first
bootfrom=`grep -iq bootfrom /proc/cmdline && echo 1`
if [ -n "$bootfrom" ]; then
	SOURCE_DEV=$(cat  /proc/cmdline|awk 'BEGIN {OFS="\n"} {$1=$1; print}'|awk '/bootfrom/ {print}'|awk -F"=" '{print $2}')
	LOOP_DEV=$(echo $SOURCE_DEV|awk -F/ '{print $1 "/" $2 "/" $3}')
	ISO_PATH=$(echo $SOURCE_DEV|sed "s|$LOOP_DEV||g" )
	case "$ISO_PATH" in /*.[iI][sS][oO]) ;; *) ISO_PATH="" ;; esac

	mkdir -p /part
	if [ -n "$ISO_PATH" ]; then #ISO_PATH doesn't work yet
		mount -r -o ro $LOOP_DEV /part
		losetup /dev/loop1 /part$ISO_PATH
		mount -r -t iso9660 /dev/loop/1 $MNTCDROM && printok || printfail
		losetup /dev/loop0 $MNTCDROM/livecd.sqfs
		mount -r -t squashfs /dev/loop0 $MNTLIVECD && LOOPMNT=1
	else
		findcloop "$LOOP_DEV"
	fi
	dbg "I am after bootfrom. The LOOPMNT is: $LOOPMNT\n"
fi

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

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
