#!/bin/bash
#boot-loader-manager
#Helps main.c in its tasks. Some tasks can be completed easier through shell.
#C program will be installed as $prefix/libexec/blm-main which will be started
#inside

#Copyright 2011 Akash Rawal

#This file is part of boot-loader-manager.

#boot-loader-manager 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 3 of the License, or
#(at your option) any later version.

#boot-loader-manager 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 boot-loader-manager.  If not, see <http://www.gnu.org/licenses/>.

###############################################################################
#All functions we need are exported so program can access:
function initialise() { #recieves $0
	mkdir -p /tmp/blm
	mkdir -p /tmp/blm/bin
	mkdir -p /mnt
	mkdir -p /mnt/blm
	mkdir -p /mnt/blm/iso_image
	export envdir="`which "$1"`"
	prefix=${envdir%bin/*}
	export INSTALL_PREFIX="$prefix"
	#copy grldr and stage2_eltorito
	if ! test -f /tmp/blm/grldr; then
		echo "Copying grldr"
		libpaths="${LD_LIBRARY_PATH}:"
		test -z "${LD_LIBRARY_PATH}" && libpaths="${LD_LIBRARY_PATH}:/lib:/usr/lib:/usr/local/lib:"
		echo "$libpaths" |
		while read -d ":" onepath; do
			test -f "${onepath}/grub4dos/grldr" && cp -fT "${onepath}/grub4dos/grldr" "/tmp/blm/grldr"
		done
	fi
	if ! test -f /tmp/blm/grldr; then
		echo "grldr was not found."
		exit 1
	fi
	if ! test -f /tmp/blm/stage2_eltorito; then
		echo "Copying stage2_eltorito"
		libpaths="${LD_LIBRARY_PATH}:"
		test -z "${LD_LIBRARY_PATH}" && libpaths="${LD_LIBRARY_PATH}:/lib:/usr/lib:/usr/local/lib:"
		echo "$libpaths" |
		while read -d ":" onepath; do
			test -f "${onepath}/grub/i386-pc/stage2_eltorito" && cp -fT "${onepath}/grub/i386-pc/stage2_eltorito" "/tmp/blm/stage2_eltorito"
		done
	fi
	if ! test -f /tmp/blm/stage2_eltorito; then
		echo "stage2_eltorito was not found."
		exit 1
	fi
	rm -f /tmp/blm/grub-install.log
	#compatiblity for other shells
	if test -z "`readlink /bin/sh | grep "bash"`"; then
		declare -F | 
		while read a b funcname; do
			echo "#!/bin/bash
$funcname \$@
" > /tmp/blm/bin/\$funcname
			chmod +x /tmp/blm/bin/$funcname
		done
		export PATH="/tmp/blm/bin:$PATH"
	fi
}
function is_installed() {
	calldir="${envdir%/*}"
	if test "${calldir##*/}" = "bin"; then
		return 0
	else 
		return 1
	fi
}
export -f is_installed
function mnt_all_drives() {
	#Do not proceed if umount is running
	while test -n "`pidof umount`"; do
		echo "umount is busy, waiting..."
		sleep 0.5
	done
	fdisk -l | grep -Ev "Disk|heads|Units|Device|Extended|swap`
		mount | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs" |
		while read drive w mntpnt y; do
			echo -n "|${drive}"
			#Create symlinks
			ln -n -f -s -T "$mntpnt" "/tmp/blm/${drive//\//_}" &> /dev/stderr
		done
	`" |
	while read drive xtra; do
		#avoid empty lines
		if test -n "$drive"; then
			rmntpnt="/mnt/blm/${drive//\//_}"
			mkdir -p "$rmntpnt"
			mount "$drive" "$rmntpnt"
			#Create symlinks
			ln -n -f -s -T "$rmntpnt" "/tmp/blm/${drive//\//_}"
		fi
	done
}
export -f mnt_all_drives
function mnt_all_drives_refresh() {
	mnt_all_drives
}
export -f mnt_all_drives_refresh
function umount_all_drives() {
	mount | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs" | grep "/mnt/blm/" |
	while read drive xtra; do
		umount "$drive"
	done
}
export -f umount_all_drives
function getdrvlist() {
	fdisk -l | grep "/dev/" | grep -Ev "Disk|Extended|swap" | tr -d "*" | tr -s " " |
	grep -E "$1" | while read drive p q r s type; do
		echo "PART"
		echo "d$drive"
		echo "t$type"
		echo "END"
	done
}
export -f getdrvlist
function getdrvnames() {
	fdisk -l | grep "/dev/" | grep -Ev "Disk|Extended|swap" | tr -d "*" | tr -s " " |
	grep -E "$1" | while read drive p q r s type; do
		echo "$drive"
	done
}
export -f getdrvnames
function eodadder() {
	cat
	echo "///EOD///"
}
export -f eodadder
function gethddlist() {
	fdisk -l | grep -Eo ".*.hd.|.*.sd." | grep -v "Disk" | eodadder |
	while read line; do
		if test "$line" = "///EOD///"; then echo -ne "$data"
		else data="${data//${line}\\n/}${line}\n"
		fi
	done
}
export -f gethddlist
function gethddid() {
	gethddlist |
	while read hdd; do
		#id="`hdparm -I $hdd | grep "Model="`"
		#id="${id%%,*}"; id="${id#*Model=}"; id="${id% *}"
		echo "$hdd: `cat /sys/block/${hdd##*/}/device/vendor` `cat /sys/block/${hdd##*/}/device/model`"
	done
}
export -f gethddid
	
#Beyond this are functions meant to help c program to detect OSes

function detect_puppy_initrd_c() {
	#Decides whether $1 is puppy linux initrd
	#if true writes result to stdout or writes "null"
	test -d /tmp/blm/pup_initrd && rm -r /tmp/blm/pup_initrd
	mkdir -p /tmp/blm/pup_initrd
	#extract initrd.gz
	ipwd="`pwd`"
	cd /tmp/blm/pup_initrd
	gzip -cd "$1" | cpio -i
	if test -f PUPPYVERSION; then
		pupname="Puppy Linux"
		pupversion="`< /tmp/blm/pup_initrd/PUPPYVERSION`"
	elif test -f DISTRO_SPECS; then
		#precaution against syntax errors
		chmod +x ./DISTRO_SPECS
		if ./DISTRO_SPECS; then
		. ./DISTRO_SPECS
		pupname="$DISTRO_NAME"
		pupversion="$DISTRO_VERSION"
		fi
	else
		pupname=""
		pupversion=""
	fi
	cd "$ipwd"
	
	echo -n "$pupname $pupversion";
}	
export -f detect_puppy_initrd_c
function get_linux_name() {
	#finds name of linux installed in given mountpoint
	#Recieves mountpoint as $1
	if test -f "$1/etc/issue"; then
		OSname="`busybox head -n 1 < "$1/etc/issue"`"
		OSname="${OSname//\\a/}"
		OSname="${OSname//\\b/}"
		OSname="${OSname//\\c/}"
		OSname="${OSname//\\d/}"
		OSname="${OSname//\\e/}"
		OSname="${OSname//\\f/}"
		OSname="${OSname//\\g/}"
		OSname="${OSname//\\h/}"
		OSname="${OSname//\\i/}"
		OSname="${OSname//\\j/}"
		OSname="${OSname//\\k/}"
		OSname="${OSname//\\l/}"
		OSname="${OSname//\\m/}"
		OSname="${OSname//\\n/}"
		OSname="${OSname//\\o/}"
		OSname="${OSname//\\p/}"
		OSname="${OSname//\\q/}"
		OSname="${OSname//\\r/}"
		OSname="${OSname//\\s/}"
		OSname="${OSname//\\t/}"
		OSname="${OSname//\\u/}"
		OSname="${OSname//\\v/}"
		OSname="${OSname//\\w/}"
		OSname="${OSname//\\x/}"
		OSname="${OSname//\\y/}"
		OSname="${OSname//\\z/}"
	else
		OSname="Unknown Linux"
	fi
	echo -n "$OSname"
}
export -f get_linux_name		
function bcdread_c() {
	#Reads Windows vista/7 BCD
	#Recieves BCD file through $1
	#Outputs OS name in it through stdout
	if test "`grep -ao "W.i.n.d.o.w.s. .7" "$1" `" != ""; then echo -n "Windows 7 (BCD)"
	elif test "`grep -ao "W.i.n.d.o.w.s. .V.i.s.t.a" "$1" `" != ""; then echo -n "Windows Vista (BCD)"
	elif test "`grep -ao "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8. .R.2." "$1" `" != ""; then echo -n "Windows Server 2008 R2 (BCD)"
	elif test "`grep -ao "W.i.n.d.o.w.s. .S.e.r.v.e.r. .2.0.0.8" "$1" `" != ""; then echo -n "Windows Server 2008 (BCD)"
	elif test "`grep -ao "W.i.n.d.o.w.s. .R.e.c.o.v.e.r.y. .E.n.v.i.r.o.n.m.e.n.t" "$1" `" != ""; then echo -n "Windows Recovery Environment (BCD)"
	elif test "`grep -ao "W.i.n.d.o.w.s. .S.e.t.u.p" "$1" `" != ""; then echo -n "Windows Setup (BCD)"
	else echo -n "Windows Vista/2008/7 (BCD)"
	fi
}
export -f bcdread_c

###############################################################################

function mount_one_drv() {
	if test -z "`mount | grep "$1" | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs"`"; then
		#Drive not mounted, mount it
		mntpnt="/mnt/blm/${1//\//_}"
		mkdir -p "$mntpnt"
		mount "$1" "$mntpnt"
		ln -n -f -s -T "$mntpnt" "/tmp/blm/${1//\//_}"
	else
		#Drive already mounted, just link to it
		txt="`mount | grep "$1" | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs" | head -n 1`"
		#Precaution if something went wrong
		if test -z "$txt"; then
			mntpnt="/mnt/blm/${1//\//_}"
			mkdir -p "$mntpnt"
			ln -n -f -s -T "$mntpnt" "/tmp/blm/${1//\//_}"
			echo "There is possibly a bug in program.
Drive: \"$\"
> mount
`mount`
> mount | grep \"$1\" | grep -Ev \"none|loop|tmpfs|shmfs|unionfs|rootfs\"
`mount | grep "$1" | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs"`" > /dev/stderr
		fi
		drive="`echo "$txt" | cut -d " " -f 1`"
		mntpnt="`echo "$txt" | cut -d " " -f 3`"
		ln -n -f -s -T "$mntpnt" "/tmp/blm/${drive//\//_}"
	fi
}
export -f mount_one_drv
function umount_one_drv() {
	if test -n "`mount | grep -Ev "none|loop|tmpfs|shmfs|unionfs|rootfs" | grep "$1" | grep "/mnt/blm/"`"
	then
		umount "$1"
	fi
}
export -f umount_one_drv	
function grub_install_splashimg() {
	#Archives a given splash image and copies it to grub folder.
	#Recieves xpm image as $1, mountpoint as $2 and bootloader type as $3
	if test ! -f "$1"; then
		echo "File no longer present: $1"
		exit 1;
	else
		if test "${1##*.}" = "gz"; then
			cp -T "$1" /tmp/splash.xpm.gz
		else
			cp -T "$1" /tmp/splash.xpm
			gzip /tmp/splash.xpm
		fi
		mv -T /tmp/splash.xpm.gz "$2`test "$3" = "grub" && echo "/boot/grub"`/splash.xpm.gz"
	fi
}
export -f grub_install_splashimg
function grub_install_gfxmenu() {
	#Archives a given gfxmenu and copies it to grub folder.
	#Recieves cpio archive as $1, mountpoint as $2 and bootloader type as $3
	if test ! -f "$1"; then
		echo "File no longer present: $1"
		exit 1;
	else
		cp -T "$1" "$2`test "$3" = "grub" && echo "/boot/grub"`/message"
	fi
}
export -f grub_install_gfxmenu
function turn_on_boot_flag() {
	#Turns on boot flag of a given partition if off
	#Recieves partition as $1
	drive="${1%0}"
	drive="${drive%1}"
	drive="${drive%2}"
	drive="${drive%3}"
	drive="${drive%4}"
	drive="${drive%5}"
	drive="${drive%6}"
	drive="${drive%7}"
	drive="${drive%8}"
	drive="${drive%9}"
	drive="${drive%0}"
	drive="${drive%1}"
	drive="${drive%2}"
	drive="${drive%3}"
	drive="${drive%4}"
	drive="${drive%5}"
	drive="${drive%6}"
	drive="${drive%7}"
	drive="${drive%8}"
	drive="${drive%9}"
	partnum="${1#$drive}"
	test -z "`fdisk -l | grep "$1" | grep "*"`" && echo -e "a\n$partnum\nw" | fdisk "$drive" > /dev/null
}
export -f turn_on_boot_flag
function mkdevicemap() {
	#Guesses device map for generating root drive
	#may recieve root hdd as $1
	echo -n > /tmp/blm/udma6
	echo -n > /tmp/blm/other
	if test -z "$1"; then
		gethddlist | while read line; do
			hdparm_out="`hdparm -i "$line" 2> /dev/null`"
			if test -n "`echo "$hdparm_out" | grep "Model="`"; then
				if test -n "`echo "$hdparm_out" | grep "\*udma6"`"; then
					echo "$line" > /tmp/blm/udma6
				else
					echo "$line"
				fi
			else
				echo "$line" > /tmp/blm/other
			fi
		done
		cat /tmp/blm/udma6
		cat /tmp/blm/other
	else
		echo "$1"
		gethddlist | grep -v "$1" | while read line; do
			hdparm_out="`hdparm -i "$line" 2> /dev/null`"
			if test -n "`echo "$hdparm_out" | grep "Model="`"; then
				if test -n "`echo "$hdparm_out" | grep "\*udma6"`"; then
					echo "$line" > /tmp/blm/udma6
				else
					echo "$line"
				fi
			else
				echo "$line" > /tmp/blm/other
			fi
		done
		cat /tmp/blm/udma6
		cat /tmp/blm/other
	fi
}
export -f mkdevicemap
###############################################################################
#Functions to assist reading config file
function is_drv_present() {
	#Determines if the drive is present, if yes then return 0, else 1
	#recieves drive as $1
	#fdisk -l | grep "$1 " | grep -v "Disk"
	if test -n "`fdisk -l | grep "$1 " | grep -v "Disk"`"; then return 0
	else return 1
	fi
}
export -f is_drv_present
###############################################################################
#Functions to open web browser
function launch_browser() {
	if which defaulthtmlviewer; then defaulthtmlviewer "$1" &
	elif which defaultbrowser; then defaultbrowser "$1" &
	elif which xfbrowser; then xfbrowser "$1" &
	elif which xfbrowser4; then xfbrowser4 "$1" &
	elif which gnome-www-browser; then gnome-www-browser "$1" &
	elif which mozilla; then mozilla "$1" &
	else echo "Browser not found."; exit 1
	fi
}
export -f launch_browser
###############################################################################
#Functions to work with CD/DVD drives
function get_cd_info() {
	ls /sys/block | grep "sr" |
	while read line; do
		echo "d/dev/$line"
		echo "n`< /sys/block/$line/device/vendor` `< /sys/block/$line/device/model`"
		
		echo -n "m"
		while true; do
			cddetect="`cddetect -d "/dev/$line" 2> /dev/null`"
			response="$?"
			if test "$cddetect" = "tray open!"; then
				echo "Tray open"
				break
			elif test "$cddetect" = "no disc!"; then
				echo "No media"
				break
			elif test "$cddetect" = "drive not ready!"; then
				sleep 1
				continue
			elif test "$response" = "0"; then
				DVDinfo="`dvd+rw-mediainfo /dev/sr0 2> /dev/stdout | tr -s " "`"
				DVDtype="`echo "$DVDinfo" | grep "Mounted Media" | sed -e "s/ /\n/g" | grep "DVD"`"
				if test -n "$DVDtype"; then echo "$DVDtype"; else
					if test -n "`echo "$DVDinfo" | grep "non-DVD media mounted"`"; then
						echo "Unknown"
					else
						echo "DVD-ROM"
					fi
				fi
			else
				cdrdao="`cdrdao disk-info --device /dev/$line 2> /dev/null | grep "yes"`"
				if test -n "`echo "$cdrdao" | grep "CD-RW"`"; then
					echo "CD-RW"
				else
					echo "CD-R"
				fi
			fi
			echo -n "l"
			evalcmd="`blkid /dev/$line | cut -d " " -f 2- | sed -e "s/ /;/g"`"
			eval "$evalcmd"
			echo "${LABEL//;/ }"
			break
		done
		echo "SEP"
	done
}
export -f get_cd_info
function blank_cdrw() {
	#recieves device through $1, type through $2
	if grep -q "CD" <<< "$2"; then
		cdrecord blank=fast -v  dev=$1 driveropts=burnfree
	else
		dvd+rw-format -force $1
	fi
}
export -f blank_cdrw
function mkisoimg() {
	#Usage: mkisoimg [options] srcdir
	#options:
	#--tmpdir=DIR    Use DIR/img.iso instead of usual /tmp/blm/img.iso
	#--rockridge     Use rockridge extension
	#--joliet        Use joliet extension
	#--grub          Install grub to image
	#--grub4dos      Install grub4dos to image
	
	#option processing
	i=1
	iso_file="/tmp/blm/img.iso"
	srcdir=""
	while true; do
		eval "arg=\"\$$i\""
		test -z "$arg" && break
		case "$arg" in
		--tmpdir=*)
			echo -e "cd \"${arg#*=}\"\n"'echo iso_file=\"$PWD/img.iso\"' | bash
			;;
		--*)
			echo "${arg#--}=\"true\""
			;;
		*)
			echo "srcdir=\"$arg\""
			;;
		esac
		i=$(( $i+1 ))
	done > /tmp/blm/args
	eval "`cat /tmp/blm/args`"
	if test -z "$srcdir"; then
		echo "ERROR: No source provided" > /dev/stderr
		return
	fi
	if test "$grub" = "true"; then
		mkdir -p "$srcdir/boot"
		mkdir -p "$srcdir/boot/grub"
		cp -fT /tmp/blm/stage2_eltorito "$srcdir/boot/grub/stage2_eltorito"
	fi
	if test "$grub4dos" = "true"; then
		cp -fT /tmp/blm/grldr "$srcdir/grldr"
	fi
	mkisofs -f -iso-level 3 \
		`test "$grub4dos" = "true" && echo "-R -b grldr -no-emul-boot -boot-load-size 4"` \
		`test "$grub" = "true" && echo "-R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table"` \
		`test "$rockridge" = "true" && echo "-D -R"` \
		`test "$joliet" = "true" && echo "-J -joliet-long"` \
		-o "$iso_file" "$srcdir"
	test "$iso_file" != "/tmp/blm/img.iso" && ln -f -s -T "$iso_file" "/tmp/blm/img.iso"
	if test -e "$iso_file"; then return 0; else return 1; fi
}
export -f mkisoimg	
function burn_iso_to_cd() {
	#Recieves drive as $1, type through $2 and option --multi
	if grep -q "CD" <<< "$2"; then
		cdrecord `grep -q -- "--multi" <<< "$@" && echo "-multi"` -tao -v  \
			dev="$1"  driveropts=burnfree "/tmp/blm/img.iso"
	else
		growisofs `grep -q -- "--multi" <<< "$@" && echo "-dvd-compat"` \
			-use-the-force-luke=notray -Z "$1"="/tmp/blm/img.iso"
		
	fi
}
export -f burn_iso_to_cd
function is_paired() {
	#Finds whether burner drive $1 contains valid media
	#returns 0 if true, 1 if false
	cd-drive "$1" 2> /dev/null | grep -v "Profile List Feature" |
		tr -s " " | grep "Yes" | grep "write" > /tmp/blm/cddrvft
	#find type of disk
	while true; do
		cddetect="`cddetect -d "$1" 2> /dev/null`"
		response="$?"
		if test "$cddetect" = "tray open!"; then
			echo "Tray open"
			break
		elif test "$cddetect" = "no disc!"; then
			echo "No media"
			break
		elif test "$cddetect" = "drive not ready!"; then
			sleep 1
			continue
		elif test "$response" = "0"; then
			DVDinfo="`dvd+rw-mediainfo $1 2> /dev/stdout | tr -s " "`"
			DVDtype="`echo "$DVDinfo" | grep "Mounted Media" | sed -e "s/ /\n/g" | grep "DVD"`"
			if test -n "$DVDtype"; then echo "$DVDtype"; else
				if test -n "`echo "$DVDinfo" | grep "non-DVD media mounted"`"; then
					echo "Unknown"
				else
					echo "DVD-ROM"
				fi
			fi
		else
			cdrdao="`cdrdao disk-info --device $1 2> /dev/null | grep "yes"`"
			if test -n "`echo "$cdrdao" | grep "CD-RW"`"; then
				echo "CD-RW"
			else
				echo "CD-R"
			fi
		fi
		break
	done | while read line; do
		test "$line" = "Tray open" -o "$line" = "No media" && return 1
		grep -q "$line" /tmp/blm/cddrvft && return 0
	done
}
export -f is_paired
function open_filemgr() {
	#recieves dir as $1
	if busybox which rox > /dev/null; then rox -d "$1" &
	elif busybox which thunar > /dev/null; then thunar "$1" &
	elif busybox which nautilus > /dev/null; then nautilus "$1" &
	elif busybox which pcmanfm > /dev/null; then pcmanfm "$1" &
	else return 1
	fi
}
export -f open_filemgr
###############################################################################
#Launching main program inside this shell so it can access all exported
#functions

#Initialise
initialise "$0"
#Check for missing programs
if ! busybox which cpio gzip cp mv fdisk blkid tr cut hdparm bootlace.com grub-install > /dev/null; then
	echo "One or more of the programs cpio, gzip, cp, mv, fdisk, tr, cut, blkid, 
hdparm, bootlace.com, grub-install and busybox were not found. Exiting" > /dev/stderr
	exit 1
fi
if busybox which cd-drive cddetect dvd+rw-mediainfo cdrdao cdrecord growisofs dvd+rw-format > /dev/null; then
	export IS_CDROM_SUPPORTED="true"
else
	export IS_CDROM_SUPPORTED="false"
fi
#-v or --verbose option handled here
if test -n "`echo "$@" | grep -E -- "-v|--verbose|-h|-g|--help"`"; then
	#Determine whether program is installed
	if is_installed "$0"; then
		eval "$prefix/libexec/blm_main $0 $@"
	else
		#If not installed assume terminal is opened in $projectdir/src
		eval "./blm_main $0 $@"
	fi
else
	#Determine whether program is installed
	if is_installed "$0"; then
		eval "$prefix/libexec/blm_main $0 $@" 1> /tmp/blm/logfile 2> /dev/stderr
	else
		#If not installed assume terminal is opened in $projectdir/src
		eval "./blm_main $0 $@" 1> /tmp/blm/logfile 2> /dev/stderr
	fi
fi

