#!/bin/busybox ash
#
# MyLiveCD startup (linuxrc) script
#
# Copyright (C) 2014, Texstar <texstar@gmail.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 MyLivecd from MkLiveCD
#
#

### global variables
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/initrd/bin:/initrd/sbin:/initrd/usr/bin:/initrd/usr/sbin
umask 022
DEBUG=
fromhdd=
fromcd=
silent=
dounionfs=
OPT_MODULES=
DEP_MODULES=
SCSI_MODULES=
LOW_SCSI_MODULES=
USB_MODULES=
USB_MODULES_DRV=

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.32.8-pclos5.bfs"   # this is setup via uname -r in the initialise section
mylivecdVER="0.9.0"
NAME_VERSION_STR="@NAME_VERSION_STR@"

#common variables 

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

### 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
}



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="udf iso9660 vfat ext3 ext4 f2fs btrfs 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 CD/DVD devices (e.g. sr0) ############
list_cdrom_devices()
{
# If boot code used then no CDs are discovered
   for CDDEVICE in `lsblk -l -o NAME,RM,TYPE |  grep " 1" | grep rom | cut -d ' ' -f1`
   do
    echo /dev/$CDDEVICE
   done
}
 
# ############ List all partitions on removable media ############
list_usb_partitions()
{
   for usb in `lsblk -l -o NAME,HOTPLUG,TYPE |  grep " 1" | grep part | cut -d ' ' -f1`
   do
    echo /dev/$usb
   done
}

# ############ List all partitions on fixed drives ############
list_fixed_partitions()
{
  for part in `lsblk -l -o NAME,HOTPLUG,TYPE |  grep " 0" | grep part | cut -d ' ' -f1`
  do
 echo /dev/$part
done
}

# ############ Discover block devices depending on boot code used. ############

list_block_devices()
{
###### if 'fromhdd' boot code is present use this discovery sequence ######
 if [ -n "$fromhdd" ]
 then
   list_fixed_partitions
   list_usb_partitions
   list_cdrom_devices

 else
###### If 'fromcd' boot code is present use this discovery sequence ######
 if [ -n "$fromcd" ]
 then 
   list_cdrom_devices     
   list_fixed_partitions
   list_usb_partitions

 else
###### By default (absence of boot codes) search all attached devices ######
   list_usb_partitions
   list_fixed_partitions
   list_cdrom_devices

 fi
 fi
}
# ===========================================================
# end of discovery functions
# ===========================================================


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

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

        busybox --install
	ln /bin/busybox /bin/awk
	
        rm -rf /sbin/init
        mv /sbin/init.dynamic /sbin/init
        echo
        docmd   "  Setting up kernel parameters" \
                "echo '0' >/proc/sys/kernel/printk" \
                "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"

        # 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; ;;
                        fromhdd) fromhdd=y; ;;
                        fromcd) fromcd=y; ;;
                        livecd=*) BASEIMG="${x#livecd=}"; [ -z "$BASEIMG" ] &&  BASEIMG="livecd"; ;;
                        bootfromiso=*) ISO_PATH="${x#bootfromiso=}"; ;;
                esac
        done
}

### Make media devices available so we can locate loop image
find_cdroms() {
# fix /dev/null - be a character device NOT a regular file
# don't wait udev to fix /dev/null because udev starts later and..
# bad things sure can happen..

rm -f /dev/null
mknod /dev/null c 1 3

mdev -s
mknod /dev/fb c 29 0

if [ -n "$silent" ]; then
docmd "  plymouth start" \
"plymouthd --tty=tty7" \
"console_init tty0" \
"plymouth --show-splash"
fi
# first detect all media/storage devices
probe-modules
# now load other useful modules
probe-modules cdrom
probe-modules scsi_mod
probe-modules sr_mod
probe-modules nls_iso8859_1
probe-modules nls_iso8859_2
probe-modules nls_iso8859_3
probe-modules nls_iso8859_4
probe-modules nls_iso8859_5
probe-modules nls_iso8859_6
probe-modules nls_iso8859_7
probe-modules nls_iso8859_8
probe-modules nls_iso8859_9
probe-modules nls_iso8859_13
probe-modules nls_iso8859_14
probe-modules nls_iso8859_15
probe-modules nls_utf8
probe-modules nls_cp437
probe-modules isofs
probe-modules udf
probe-modules fat
probe-modules ntfs
probe-modules vfat
probe-modules exfat
probe-modules ext4
probe-modules f2fs
probe-modules btrfs
probe-modules crc_t10dif
probe-modules sd_mod
probe-modules usbcore
probe-modules usb_common
probe-modules usb_storage
probe-modules uhci_hcd
probe-modules ohci_hcd
probe-modules ehci_hcd
probe-modules xhci_hcd
probe-modules ehci_pci
probe-modules loop max_loop=64
probe-modules overlay
probe-modules fuse
probe-modules squashfs
probe-modules vfio
probe-modules tun
probe-modules dm_mod
probe-modules snd_seq


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

	if [ ! -e /sbin/udevstart ]; then
		#echo -n "  Starting mdev: "
		# make needed device
		# 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
		echo -n "   Waiting for udev detection."
		sleep 10 && printok
	fi
	
		# List of cdroms + all the partition devices
		CDROM_LIST=`list_block_devices`

		#printok
                echo
}

### 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"
                if [ -n "$DEBUG" ]; then
                $MOVE_TO_COL
                $SETCOLOR_OK
                echo "$i"
                $SETCOLOR_NORMAL
                fi
                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/$BASEIMG$LOOPTYPE | 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/$BASEIMG$LOOPTYPE $RAMDIR
                                                        if [ "$?" -eq 0 ]; then
                                                                printok
                                                                # free the boot device
                                                                umount $MNTLIVECD
                                                                # and use our new directory as the new MNTLIVECD
                                                                `losetup -d $DEVLOOP 2>&1 >/dev/null`
                                                                losetup $DEVLOOP $RAMDIR/$BASEIMG$LOOPTYPE
                                                                mount -r -t squashfs $DEVLOOP $MNTLIVECD
                                                                rm -rf /initrd/sbin/halt.local
								                               umount $MNTCDROM
                                                        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 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 devtmpfs 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/lib64" \
                        "ln -s /initrd/usr" \
                        "ln -s /initrd/dev" \
                        "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

        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 udf,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 -e "\n"
exec /etc/rc.d/rc.sysinit <dev/console >dev/console 2>&1
exit 0
