#!/bin/bash
#
# This script will create LiveCD based on
# The Synergy Linux distribution
#

prog_name=`basename "$0"`

# check kernel release
function get_src_kernel_rel 
{
	if [[ -n "$kernel_rel" ]]; then
		rel=$(ls -1 $1/lib/modules/)
		[ "$(echo $rel | wc -w )" -ne 1 ] && echo "Can't read kernel release in $1 (found: $rel)" && return 1
		echo $rel
	fi
}
# copy module with depends
function copy_module
{
	for modname in $@
	do
		module_with_deps=$(grep -P "/$modname.ko(.gz)?:" $sys_source/lib/modules/$kernel_rel/modules.dep | sed -e s/:// )
		[ -z  "$module_with_deps" ] && module_with_deps=$modname && echo "No entries found in modules.dep for $modname"
		for modpath in $module_with_deps
		do
			dstdir=$(dirname $tmp_initrd/lib/modules/$kernel_rel/$modpath)
			[ ! -d $dstdir ] && mkdir -p $dstdir
			echo " - module: lib/modules/$kernel_rel/$modpath"
			cp $sys_source/lib/modules/$kernel_rel/$modpath $dstdir
		done
	done
}
# copy directory of modules but not check depends
function copy_modules_dir
{
	for moddirname in $@
	do
		[ ! -d $sys_source/lib/modules/$kernel_rel/$moddirname ] && die "Directory /lib/modules/$kernel_rel/$moddirname not found!"
		dstdir=$(dirname $tmp_initrd/lib/modules/$kernel_rel/$moddirname)
		[ ! -d $dstdir ] && mkdir -p $dstdir
		echo " - modules: lib/modules/$kernel_rel/$moddirname"
		cp -r $sys_source/lib/modules/$kernel_rel/$moddirname $dstdir
	done

}
# find&copy firmware for modules copied into initrd skeleton
function findAndCopyFirmwareFiles
{
	# copy firmware loader script
	# cp $sys_source/lib/firmware/firmware-loader.sh 	$tmp_initrd/lib/firmware || return 1
	# search for all modules
	for modname in $(find $tmp_initrd/lib/modules/$kernel_rel/ -type f)
	do
		# get all firmware file names for this module
		firmwareFiles=$(modinfo $modname | grep '^firmware:\ ' | sed 's/.*\ //') || return 1
		for firmwareFile in $firmwareFiles
		do
			# find file path
			firmwareDirs="lib/firmware lib/firmware/updates"
			unset firmwareDir
			for firmwareDir in $firmwareDirs
			do
				[ -f $sys_source/$firmwareDir/$firmwareFile ] && firmwareDirFound=$firmwareDir && continue
			done
			[ -z $firmwareDirFound ] && echo "No firmware: $firmwareFile found"
			# copy files to initrd skeleton
			dstFirmDir=$(dirname $tmp_initrd/$firmwareDirFound/$firmwareFile)
			[ ! -d $dstFirmDir ] && mkdir -p $dstFirmDir
			echo " - $firmwareDirFound/$firmwareFile"
			cp $sys_source/$firmwareDirFound/$firmwareFile $dstFirmDir
		done
	done
}
# create dev nodes in the directory
function createSpecialDevFiles
{
	[ ! -d "$1" ] && die "$ is not a directory"
	echo "Creating devices in $1"
	mknod $1/console c 5 1
	mknod $1/null c 1 3
	mknod $1/zero c 1 5
	mknod $1/kmsg c 1 11
	mknod $1/fb0 c 29 0
	ln -s /proc/self/fd $1/fd
	ln -s $/fd/0 $1/stdin
	ln -s $/fd/1 $1/stdout
	ln -s $/fd/2 $1/stderr

}

function copy_libs
{

	#Make sure we have input
	[[ $# < 2 ]] && echo "No vaild input: copy_libs \"binary\" \"destination\" "

	#Check if the paths are vaild
	echo "what am I" $tmp_initrd/bin/$(basename $1)
	[[ ! -e $tmp_initrd/bin/$(basename $1) ]] && echo "Not a valid input $1" && return 1 
	[[ -d $2 ]] || echo "No such directory $2 creating..."&& mkdir -p "$2"

	#Get the binary library dependencies
	echo "Collecting the shared library dependencies for $1..."
	deps=$(chroot $sys_source ldd $1 |cut -d'>' -f2 |sed 's/(0x[^[:space:]]*//g' )
	#deps=$(ldd $1 |cut -d'>' -f2 | awk '{print $1}')
	echo "Copying the dependencies for $1 to $2"

	#Copy the libs
	for dep in $deps
	do
            lib_link=$(readlink -m $dep)
            if [[ ! -z $(readlink $dep) ]] && [[ ! -f $tmp_initrd/lib/$(basename $dep) ]] && [[ ! -f $tmp_initrd/lib/$(basename $lib_link) ]]; then
                cp -df $lib_link $tmp_initrd/lib/                                                                                                       
                ln -sf /lib/$(basename $lib_link) $tmp_initrd/lib/$(basename $dep)                          
                echo "found lib link $(basename $dep) $tmp_initrd/lib/$(basename $lib_link)"      
            else
                if [[ ! -f $2$(basename $dep) ]] && [[ ! -f $tmp_initrd/lib/$(basename $lib_link) ]]; then
                    echo "Copying $dep to $2"
                    cp -df "$sys_source$dep" $tmp_initrd/lib/
                else
                    echo "lib $2$(basename $dep) exists"
                fi
            fi
	done
}

function find_copy_bin
{
	#Make sure we have input
	[[ $# < 2 ]] && echo "No vaild input: find_bin \"binary\" \"destination\" "

	#Check if the paths are vaild
	#[[ ! -e $sys_source$1 ]] && echo "Not a vaild input $1" && return 1
	[[ -d $2 ]] || echo "No such directory $2 creating..."&& mkdir -p "$2"
	#Copy binary
	found_bin=$(chroot $sys_source find /*bin/ /usr/*bin/ -type f | grep -w -m1 "$1$")
	echo "copying $found_bin to $2"
	if [[ -f $sys_source$found_bin ]]; then
	   cp -d "$sys_source$found_bin" "$2"
           copy_libs $found_bin $tmp_initrd/lib/
        else
           echo "$found_bin file not found"
        fi

}

function find_copy_busybox
{
        #find and copy busybox
        #if busybox.static and busybox shared is installed it's assumed
        #that busybox static should be default otherwise it wouldn't be installed
        #if static is not found use the shared version and copy the libs as well
                locate_bbox=$(find $sys_source/*bin/ $sys_source/usr/*bin/ -executable -type f -name busybox* -print | tr " " "\n" )
                if [[ $(echo $locate_bbox)  == *"static"* ]]; then
                        bbox_bin=$(echo $locate_bbox |tr " " "\n"|grep -m1 'static')
			ln -sf $(basename $bbox_bin) $tmp_initrd/bin/busybox
                        if [[ $1 == 1 ]]; then
                                echo $(basename $bbox_bin)
                                exit 0
                        fi
                else
                        bbox_bin=$(echo $locate_bbox |tr " " "\n"|grep -m1 'busybox')
                        if [[ $1 == 1 ]]; then
                                echo $(basename $bbox_bin)
                                exit 0
                        fi
			echo "not static copying libs"
                        copy_libs $bbox_bin $tmp_initrd/lib/

                fi
                [[ -d $1 ]] || echo "No such directory $1 creating..."&& mkdir -p "$1"
		if [[ $1 != 1 ]]; then
		echo "copying busybox: $bbox_bin"
                cp -df $bbox_bin $1
		fi

}

function create_initrd
{
	#make root dirs
	mkdir $tmp_initrd/{proc,sys,dev}
	mkdir -p $tmp_initrd/usr/share
	mkdir -p $tmp_initrd/var/udev
	mkdir -p $tmp_initrd/run/udev

	#make mnt dirs
	mkdir -p $tmp_initrd/mnt/{device,liveroot,work,upper,newroot}

	[ -d $sys_source/lib64 ] && libDir=lib64 || libDir=lib # guess 'lib' dir name for x86_64 arch
	initrd_tools_dir=/usr/$libDir/initrd
	
	echo "Creating initrd skeleton: $tmp_initrd"
	#cp -r $mkroot/$templatesDir/initrd/* $tmp_initrd
	echo "Creating Folders"
	mkdir $tmp_initrd/bin
	mkdir $tmp_initrd/dev
	mkdir -p $tmp_initrd/etc/udev
	mkdir -p $tmp_initrd/lib/firmware
	mkdir -p $tmp_initrd/lib/modules
        mkdir -p $tmp_initrd/lib64/firmware
        mkdir -p $tmp_initrd/lib64/modules
	mkdir -p $tmp_initrd/mnt/device
	mkdir -p $tmp_initrd/mnt/liveroot
	mkdir -p $tmp_initrd/mnt/newroot
	mkdir -p $tmp_initrd/mnt/tmpfs
	mkdir $tmp_initrd/proc
	mkdir $tmp_initrd/sys
	mkdir -p $tmp_initrd/usr/share
	echo "Copying files from /usr/share/makelive"
	cp /usr/share/makelive/pcimodules $tmp_initrd/bin/
	cp /usr/share/makelive/ld.so.conf $tmp_initrd/etc/
	cp /usr/share/makelive/udev.conf $tmp_initrd/etc/udev/
	cp /usr/share/makelive/init $tmp_initrd/

	# create devices
	createSpecialDevFiles $tmp_initrd/dev
	# demod in source sys if needed
	[ ! -f $sys_source/lib/modules/$kernel_rel/modules.dep ] && echo "Running depmod..." && chroot $sys_source depmod -a -b / $kernel_rel

	echo "Copying kernel modules to initrd skeleton..."
	copy_module loop overlay ext2 ext3 ext4 lvm xfs squashfs vfat rfkill drm cdrom isofs ahci udf
	copy_module mii p4-clockmod usb-storage atl2 i2c-algo-bit i2c-core
	copy_modules_dir kernel/drivers/scsi kernel/drivers/ata kernel/drivers/cpufreq kernel/drivers/net/ethernet/atheros/ kernel/drivers/i2c
        copy_modules_dir kernel/drivers/gpu/drm kernel/fs/isofs

	[ -d $sys_source/lib/modules/$kernel_rel/kernel/fs/aufs ] && echo "found aufs module" && aufs_module_found=1 && copy_module aufs
	echo "Copying firmware files to initrd skeleton..."
	#findAndCopyFirmwareFiles || exit 1

	# gunzip modules, we will compress whole initrd image
#	find $tmp_initrd/lib/modules/$kernel_rel -type f -name \*.xz -exec xz -d \{\} \;
	depmod -a -b $tmp_initrd $kernel_rel

	# Set Plymouth Theme ** We need a new option for this, hard coding no good **
#	chroot $sys_source /usr/sbin/plymouth-set-default-theme synergy
#        chroot $sys_source /usr/libexec/plymouth/plymouth-generate-initrd

	echo "Adding binaries..."
	find_copy_bin kmod $tmp_initrd/bin/
	find_copy_bin udevadm $tmp_initrd/bin/
	#do not fail on these 2 not all systems have them
	find_copy_bin udevd $tmp_initrd/bin/
	#cp -d $sys_source/lib/systemd/systemd-udevd $tmp_initrd/bin/
	find_copy_bin mount $tmp_initrd/bin/ || return 1
	find_copy_bin umount $tmp_initrd/bin/ || return 1
	find_copy_bin killall $tmp_initrd/bin/
	find_copy_bin mke2fs $tmp_initrd/bin/ || return 1
#        cp -d $sys_source/bin/plymouth $tmp_initrd/bin/ || return 1
#        cp -d $sys_source/sbin/plymouthd $tmp_initrd/bin/ || return 1
        find_copy_busybox $tmp_initrd/bin/ || return 1
	ln -sf kmod $tmp_initrd/bin/depmod
#	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/mount || return 1
#	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/umount || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/awk || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/cut || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/dmesg || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/grep || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/head || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/ln || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/losetup || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/lsmod || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/mdev || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/mkdir || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/mknod || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/rmmod || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/sed || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/sh || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/sleep || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/sort || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/switch_root || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/tail || return 1
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/uname || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/cat || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/cp || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/dd || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/find || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/ls || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/modprobe || return 1
        ln -sf `find_copy_busybox 1` $tmp_initrd/bin/pidof || return 1

	#Purely for Troubleshooting and Awesomeness
	ln -sf `find_copy_busybox 1` $tmp_initrd/bin/vi || return 1 	

	echo "Adding libraries..."
 	cp $sys_source/etc/ld.so.conf $tmp_initrd/etc
#       cp -r $sys_source/etc/plymouth $tmp_initrd/etc/
#       cp -r $sys_source/usr/share/plymouth $tmp_initrd/usr/share/

        if [ $arch = 'x86_64' ]; then
           mkdir -p $tmp_initrd/usr/lib64
#	   cp -r $sys_source/usr/lib64/plymouth $tmp_initrd/usr/lib64/
#           cp -rfd $sys_source/usr/lib64/libply* $tmp_initrd/usr/lib64/
#           cp -rfd $sys_source/usr/lib64/libpng12* $tmp_initrd/usr/lib64/
#           cp -rfd $sys_source/usr/lib64/libpng15* $tmp_initrd/usr/lib64/
        else
           mkdir -p $tmp_initrd/usr/lib
#           cp -r $sys_source/usr/lib/plymouth $tmp_initrd/usr/lib/
#           cp -rfd $sys_source/usr/lib/libply* $tmp_initrd/usr/lib/
#           cp -rfd $sys_source/usr/lib/libpng12* $tmp_initrd/usr/lib/
#           cp -rfd $sys_source/usr/lib/libpng15* $tmp_initrd/usr/lib/
        fi

        ldconfig -r $tmp_initrd
	chown -R root:root $tmp_initrd/*
	echo "Writing $VOLID LABEL into: $volid_file"
	echo "$VOLID" > $volid_file
	make_cleanup $tmp_initrd

	# bootsplash
#	if [ $bootsplash_arg -eq 1 ]; then
#		echo "Creating bootsplash"
#		/bin/splash.bin -s -f $bootsplash > $tmp_initrd/bootsplash
#	fi
	echo "Creating initramfs image: $1"
	cd $tmp_initrd
#	find . | cpio -H newc -o | $compr > $1
	find . | cpio -H newc -o | gzip > $1
	[ $? -eq 0 ] && echo "Image saved as $1 (size: $(stat -c %s $1))" || die "Creating image failed!"
}
# return application related libraries
function get_app_libs
{
	[ ! -x "$1" ] && "Error: $1 is not executable file"
	chroot $sys_source ldd $1 | grep '/lib' | sed -e 's/\ (.*//' -e 's/.*=>\ //' -e "s/[\ \t]//g"
}
function die 
{
	echo "Error: $@"
	exit 1
}
function print_help
{
	echo "$prog_name usage: $prog_name /source_directory /image.iso [OPTIONS]"
	echo "  -h|--help - print this message"
	echo "  --lzma - use lzma compression instead gzip"
	echo "  --gzip - use gzip compression (default)"
	echo -e "  --tpl=tpl-dir - templates dir ("templates" by default)"
	echo "  --bootsplash=config - enable bootsplash (default no)"
	echo ""
	echo "  $prog_name script creates a live cd/dvd system based on Synergy Linux"
	echo "  installed into directory."
	echo " example 1:"
	echo "  # $prog_name /my-sys-dir /my-live.iso"
	echo " example 2:"
	echo "  # $prog_name /my-sys-dir /my-live.iso --tpl=templates-my --lzma"

}
function make_cleanup
{
        echo "Running cleanup of $1..."
        find $1 -name \*~ -exec rm \{\} \;
        find $1 -name .svn -type d -exec rm -rf \{\} \; 2> /dev/null
        rm -rf $1/initrd
}


##### MAIN #####
templatesDir=templates
bootsplash_arg=1
for arg in $@
do
        case $arg in
                --lzma) compr=lzma; squashfscompr=xz  ;;
                --kernel=*) kernel_rel=$(echo $arg | sed 's/.*kernel=//;s/--.*//') ;;
                --label=*) VOLID=$(echo $arg | sed 's/.*VOLID=//;s/--.*//') ;;
                --gzip) compr=gzip; squashfscompr=gzip ;;
		--tpl=*) templatesDir=$(echo $arg | sed 's/.*tpl=//;s/--.*//') ;;
		--bootsplash=*)
			bootsplash_arg=1
			bootsplash=$(echo $arg | sed 's/.*bootsplash=//;s/--.*//')
			;;
		-h|--help)
			print_help
			exit 0
		;;
                -*)
			echo "Invalid option: $arg. Use -h to print help"
			print_help
			exit 1
		;;
                *)
                        [ -z $sys_source ] && sys_source=$arg && continue
                        [ -z $dst_iso ] && [ ! -z $sys_source ] && dst_iso=$arg        
                ;;
        esac
done
[ ! $(whoami) = 'root' ] && die "You need superuser privileges, try 'su' or 'sudo'"

[ -z $sys_source ] && die "Missing arg: source directory. Use -h to print help."
[ -z $dst_iso ] && die "Missing arg: iso image. Use -h to print help"
[ -z $compr ] && compr=gzip # gzip is default compression method
[ ! -d $sys_source ] && die "$sys_source is not a directory"
mkroot=$(dirname $0)

# read configuration from ~/.mkliverc
[ -f ~/.mkliverc ] && . ~/.mkliverc

# preparing temp dirs
rm -rf /tmp/$0_tmp_*
# Try and Guess arch
[ -d $sys_source/lib64 ] && arch=x86_64 || arch=i686
# If VOLID is not defined grep version from release rpm
[ -z "$VOLID" ] && VOLID=`chroot $sys_source cat /etc/redhat-release | awk -F" " '{print $1"-"$2"_"$4}'`-$arch # default VOLID
tmp_iso_root=$(mktemp -d /tmp/$(basename $0)_tmp_iso__XXXXXX)
tmp_initrd=$(mktemp -d /tmp/$(basename $0)_tmp_initrd__XXXXXX)
volid_file=$tmp_initrd/DEV_LABEL
live_rootfs_archive=squashfs.img
kernel_rel=$(get_src_kernel_rel $1)
[ $? -ne 0 ] && die "Kernel release not found: "$kernel_rel

echo "::: $prog_name :::"	 
echo "found kernel:         $kernel_rel"	 
echo "compression method:   $compr"	 
echo "initrd temporary dir: $tmp_initrd"	 
echo "iso temporary dir:    $tmp_iso_root"	 
echo "templates directory:  $mkroot/$templatesDir"
echo "application:          $APPLICATION"
echo "preparer:             $PREPARER"
echo "volid:                $VOLID"
echo ""

# does templates exist
#[ ! -d $mkroot/$templatesDir ] && die "templates dir: $mkroot/$templatesDir does not exist."
# does bootsplash configuration exist
if [ $bootsplash_arg -eq 1 ]; then
	[ ! -f $bootsplash ] && die "bootsplash configuration: $bootsplash does not exist."
fi
# is destination exists
if [ -a $dst_iso ]
then
	echo "Warning: $dst_iso file already exists."
	echo "Do you wish to overwrite? [N/y]"
	read anykey
	[ ! "$anykey" = 'y' ] && die "Interrupted." || rm -f $dst_iso
fi

# creating initrd: temp live root
echo "Copying kernel and basic tools..."
#cp -r $mkroot/$templatesDir/isolinux $tmp_iso_root
mkdir -p $tmp_iso_root/isolinux
cp /usr/*/syslinux/ldlinux.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/libcom32.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/libutil.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/chain.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/hdt.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/isolinux.bin $tmp_iso_root/isolinux/
cp /usr/*/syslinux/reboot.c32 $tmp_iso_root/isolinux/
cp /usr/*/syslinux/vesamenu.c32 $tmp_iso_root/isolinux/
cp /usr/share/makelive/isolinux.cfg $tmp_iso_root/isolinux/
cp /usr/share/makelive/splash.jpg $tmp_iso_root/isolinux/
cp /usr/share/makelive/help.msg $tmp_iso_root/isolinux/
cp /usr/share/makelive/memtest86 $tmp_iso_root/isolinux/
cp /usr/share/hwdata/pci.ids $tmp_iso_root/isolinux


if [ -f $sys_source/boot/vmlinuz-$(echo $kernel_rel) ]; then
       	cp $sys_source/boot/vmlinuz-$(echo $kernel_rel) $tmp_iso_root/isolinux/vmlinuz
else
     die "No Suitable vmlinuz found for kernel: "$kernel_rel
fi
make_cleanup $tmp_iso_root
# create image
create_initrd $tmp_iso_root/isolinux/initrd.img || die "Creating initrd image failed."
cp $tmp_iso_root/isolinux/initrd.img /tmp/
# create live
echo "Creating squashfs filesystem: $tmp_iso_root/$live_rootfs_archive..."
mkdir -p $tmp_iso_root/LiveOS/

# Test cli installer, so copy over
#cp -f $mkroot/$templatesDir/synergy-install-cli $sys_source/usr/sbin/
#cp -f $mkroot/$templatesDir/synergy-install-gui $sys_source/usr/sbin/
#cp -f $mkroot/$templatesDir/auto-part $sys_source/usr/sbin/

mksquashfs  $sys_source $tmp_iso_root/LiveOS/$live_rootfs_archive -comp $squashfscompr -e /tmp -e /root/rpms -e /root/rpmbuild -e /root/packages -e /root/building -e /proc/ -e /sys/ -e /dev/ -e /run/ > /dev/null || die "Creating live rootfs failed"
echo "Creating ISO image: $dst_iso ($VOLID)..."
mkisofs -o $dst_iso --publisher "Unity Linux" -b isolinux/isolinux.bin -c isolinux/boot.cat \
	-no-emul-boot -boot-load-size 4 -boot-info-table -l -R \
	-A "$APPLICATION" -V "$VOLID" -p "$PREPARER" \
       	-r $tmp_iso_root \
	|| die "Creating iso image failed."
rm -rf $tmp_iso_root
rm -rf $tmp_initrd
echo "Image $dst_iso seems to be ready"