#!/bin/bash
#================
# FILE          : linuxrc
#----------------
# PROJECT       : OpenSuSE KIWI Image System
# COPYRIGHT     : (c) 2006 SUSE LINUX Products GmbH. All rights reserved
#               :
# AUTHOR        : Marcus Schaefer <ms@suse.de>
#               :
# BELONGS TO    : Operating System images
#               :
# DESCRIPTION   : This file is changed to become the real
#               : linuxrc script which is used to prepare the
#               : operating system for the main image
#               :
#               :
# STATUS        : BETA
#----------------
#======================================
# Exports (General)...
#--------------------------------------
export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
export IFS_ORIG=$IFS
export DEBUG=0

#======================================
# Exports (Booting)
#--------------------------------------
export DOMURD_MODULES="xennet xenblk"
export INITRD_MODULES="reiserfs"
export LOCAL_BOOT=no
export systemIntegrity="clean"

#======================================
# Exports (Configuration)
#--------------------------------------
export VMX_SYSTEM="/config.vmxsystem"
export LIVECD_CONFIG=$VMX_SYSTEM

#======================================
# Functions...
#--------------------------------------
. /include

#======================================
# Beautify Startup
#--------------------------------------
clear
echo "Loading KIWI OEM Boot-System..."
echo "-------------------------------"

#======================================
# 1) Mounting local file systems
#--------------------------------------
mount -t proc  proc    /proc
mount -t sysfs sysfs   /sys
mount -t devpts devpts /dev/pts
closeKernelConsole

#======================================
# 2) Prepare module load support 
#--------------------------------------
touch /etc/modules.conf
touch /lib/modules/*/modules.dep

#======================================
# 3) Include proc/cmdline information
#--------------------------------------
includeKernelParameters
if [ ! -z $UNIONFS_CONFIG ];then
	# /.../
	# if the unionfs information is already in place at this stage
	# it comes from the cmdline data which means we are not booting
	# from CD/DVD USB stick but want to boot the local system
	# ----
	export LOCAL_BOOT="yes"   
fi

#======================================
# 4) Including required kernel modules
#--------------------------------------
probeDevices
for module in usb_storage sg sd_mod;do
	modprobe $module
done
sleep 5

#======================================
# 5) Search disks, prefer removable one
#--------------------------------------
if [ ! -f $VMX_SYSTEM ];then
	# /.../
	# installed system: Check for a root device to mount and
	# prefer a USB stick if there is any. Otherwise check for
	# first partition of a disk device. During first boot of
	# the installed system there is only one partition and this
	# initrd is going to be replaced by a later mkinitrd call
	# for unified systems the kiwi initrd is used and the
	# kernel parameters of this initrd defines the missing
	# information. Additionally the partition table is different
	# for unified systems. Therefore we check if the second
	# partition is a squashfs partition and change the root
	# partition name accordingly
	# ----
	if [ $LOCAL_BOOT = "no" ];then
		Echo "Searching for disk and root partition"
		USBStickDevice
		if [ $stickFound = 0 ];then
			deviceFound=0
			for deviceRoot in /dev/sda1 /dev/hda1;do
				if mount $deviceRoot /mnt &>/dev/null;then
					deviceFound=1
					umount /mnt
					break
				fi
			done
			if [ $deviceFound = 0 ];then
				systemException \
					"Couldn't find any disk device... abort" \
				"reboot"
			fi
			export deviceDisk=`echo $deviceRoot | tr -d [0-9]`
			export deviceSwap="$deviceDisk"2
			export deviceHome="$deviceDisk"3
		else
			Echo "USB stick found, prefer root on stick"
			export deviceDisk=$stickRoot
			export deviceSwap="$deviceDisk"2
			export deviceHome="$deviceDisk"3
		fi
		probeFileSystem "$deviceDisk"2
		if test "$FSTYPE" = "squashfs";then
			Echo "Unified system detected, adapting root partition"
			export UNIONFS_CONFIG="$deviceDisk"3,"$deviceDisk"2,aufs
			export deviceRoot="$deviceDisk"2
			export deviceSwap="$deviceDisk"4
		else
			export deviceRoot="$deviceDisk"1
		fi
		Echo "Using root partition $deviceRoot on disk $deviceDisk"
	fi
else
	# /.../
	# installation mode: find a usable disk to install the image
	# on. The image is a virtual disk with one partition
	# ----
	Echo "Searching harddrive for installation"
	hwinfo="/usr/sbin/hwinfo --disk"
	export deviceDisk=`$hwinfo | grep "Device File:" | head -n 1 | cut -f2 -d:`
	export deviceDisk=`echo $deviceDisk`
	if [ -z $deviceDisk ];then
		systemException \
			"No hard disk found... abort" \
		"reboot"
	fi
	Echo "Entering installation mode for disk: $deviceDisk"
fi

#======================================
# 6) Check for vmx system
#--------------------------------------
if [ -f $VMX_SYSTEM ];then
	#======================================
	# 6.1) import vmx configuration file
	#--------------------------------------
	importFile < $VMX_SYSTEM
	#======================================
	# 6.2) check version of installed OS
	#--------------------------------------
	deviceRoot="$deviceDisk"2
	probeFileSystem $deviceRoot
	if test "$FSTYPE" = "unknown";then
		deviceRoot="$deviceDisk"1
		probeFileSystem $deviceRoot
	fi
	if test "$FSTYPE" = "squashfs";then
		export UNIONFS_CONFIG="$deviceDisk"3,"$deviceDisk"2,aufs
	fi
	Echo "Try mounting installed system to check version"
	mountSystem $deviceRoot; updateNeeded
	umountSystem
	if test `getSystemIntegrity 1` = "fine";then
		Echo "Base system is up to date... reboot"
		/sbin/reboot -f -i >/dev/null 2>&1
	fi
	#======================================
	# 6.3) mount CD/DVD/USB stick
	#--------------------------------------
	USBStickDevice
	if [ $stickFound = 0 ];then
		Echo "Search for USB stick failed, checking CD/DVD drive"
		CDMount
	else
		Echo "Found Stick: $stickDevice -> $stickSerial"
		mkdir -p /cdrom && mount $stickDevice /cdrom
	fi
	#======================================
	# 6.4) install disk system
	#--------------------------------------
	# /.../
	# install virtual disk image from the CD/DVD onto the
	# real disk. All data on the disk will be lost
	# ----
	imageZipped="uncompressed"
	imageDevice=$deviceDisk
	field=0
	IFS=";" ; for n in $IMAGE;do
	case $field in
		0) field=1 ;; 
		1) imageName=$n   ; field=2 ;;
		2) imageVersion=$n;
	esac
	done
	imageName="/cdrom/$imageName"
	echo $imageName | grep -qE ".gz$"
	if [ $? = 0 ];then
		imageZipped="compressed"
	fi
	IFS=" "
	if test "$imageZipped" = "compressed"; then
		Echo "Compressed image found"
		test ! -p /dev/compressed_image && mkfifo /dev/compressed_image
		cat /dev/compressed_image | gzip -d > $imageDevice 2>/dev/null &
		imageDevice_orig=$imageDevice
		imageName_orig=$imageName
		imageDevice="/dev/compressed_image"
		imageName="$imageName.gz"
	fi
	Echo "Loading $imageName [$imageDevice]..."
	if ! dd if=$imageName of=$imageDevice >/dev/null 2>&1; then
		systemException \
			"Failed to install image: $imageName -> $imageDevice" \
		"reboot"
	fi
	if test "$imageZipped" = "compressed"; then
		imageDevice=$imageDevice_orig
		imageName=$imageName_orig
		rm -f /dev/compressed_image
	fi
	#======================================
	# 6.5) Umount the CD/DVD
	#--------------------------------------
	umount /cdrom
	#======================================
	# 6.6) reread partition table
	#--------------------------------------
	blockdev --rereadpt $deviceDisk
	#======================================
	# 6.7) find new root partition
	#--------------------------------------
	unset UNIONFS_CONFIG
	deviceRoot="$deviceDisk"2
	probeFileSystem $deviceRoot
	if test "$FSTYPE" = "unknown";then
		deviceRoot="$deviceDisk"1
		probeFileSystem $deviceRoot
	fi
	Echo "Filesystem of root system is: $FSTYPE -> $deviceRoot"
	if test "$FSTYPE" = "squashfs";then
		export UNIONFS_CONFIG="$deviceDisk"3,"$deviceDisk"2,aufs
	fi
	#======================================
	# 6.8) Create md5 version info file
	#--------------------------------------
	if ! mountSystem $deviceRoot;then
		systemException \
			"Couldn't mount installed system... abort" \
		"reboot"
	fi
	updateNeeded initialize
	field=0
	IFS=";" ; for n in $IMAGE;do
	case $field in
		0) field=1 ;;
		1) imageName=$n   ; field=2 ;;
		2) imageVersion=$n
	esac
	done
	atversion="$imageName-$imageVersion"
	versionFile="/mnt/etc/ImageVersion-$atversion"
	md5sum=`getSystemMD5Status 1`
	echo "$atversion $md5sum" > $versionFile
	umountSystem
	#======================================
	# 6.9) reboot system
	#--------------------------------------
	if [ $stickFound = 0 ];then
		Echo "NOTE: Please remove the installation CD before reboot !"
		CDEject
	else
		Echo "NOTE: Please unplug the USB stick before reboot !"
	fi
	systemException \
		"System installation has finished" \
	"reboot"
fi

#======================================
# 7) Probe filesystem of disk device
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	probeFileSystem $deviceRoot
	if [ $FSTYPE = "unknown" ];then
		systemException \
			"Couldn't determine filesystem type... abort" \
		"reboot"
	fi
fi
#======================================
# 8) repartition the disk device
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	#======================================
	# 8.1 calculate amount of swap space
	#--------------------------------------
	mem_size=`grep MemTotal: /proc/meminfo | tr -dc '[0-9]'`
	swapsize=$(( $mem_size *2 / 1024 ))
	Echo "Filesystem of root system is: $FSTYPE -> $deviceRoot"
	if ! test "$FSTYPE" = "squashfs";then
		#======================================
		# 8.2 write new partition table
		#--------------------------------------
		# /.../
		# Explanation of the fdisk commands used within the
		# here document below:
		# ----
		# d              # delete xda partition [ 1 ]
		# n              # create xda partition at same place than xda1
		# p              # primary
		# 2              # [ 2 ]
		# 1              # accept old xda1 start block for xda2
		# +10240M        # accept new root device size of 10GB
		# n              # create xda swap partition
		# p              # primary
		# 1              # [ 1 ]
		#                # accept start block
		# +"$swapsize"M  # accept new swapsize
		# n              # create xda3 home partition
		# p              # primary
		# 3              # [ 3 ]
		#                # accept start block
		#                # accept end block, complete disk
		# t              # change swap system id
		# 1              # [ 1 ]
		# 82             # Linux Swap
		# w              # write partition table
		# ----
		input=/part.input
		rm -f $input
		disk1MBytes=10240
		diskXMBytes=`sfdisk -s $deviceDisk`
		diskXMBytes=`expr $diskXMBytes / 1024`
		if [ $disk1MBytes -gt $diskXMBytes ];then
			# /.../
			# Very small disk, we use half of the size for root and
			# assume the rest is ok for /home and /. Additionally we set
			# the swap space to 50MB. All this could fail if the disk
			# is really small so that / doesn't fit into half of
			# $diskXMBytes
			# ----
			disk1MBytes=`expr $diskXMBytes / 2`
			swapsize=50
		fi
		for cmd in \
			d n p 2 1 +"$disk1MBytes"M \
			n p 1 . +"$swapsize"M \
			n p 3 . . \
			t 1 82 w
		do
			if [ $cmd = "." ];then
				echo >> $input
				continue
			fi
			echo $cmd >> $input
		done
		Echo "Repartition the disk according to current geometry"
		fdisk $deviceDisk < $input >/dev/null 2>&1
		if test $? != 0; then
			systemException "Failed to create partition table" "reboot"
		fi
		#======================================
		# 8.3 Update new device names
		#--------------------------------------
		export deviceRoot="$deviceDisk"2
		export deviceSwap="$deviceDisk"1
		export deviceHome="$deviceDisk"3

		#======================================
		# 8.4 Activate swap space
		#--------------------------------------
		Echo "Activating swap space on $deviceSwap"
		if ! mkswap $deviceSwap >/dev/null 2>&1;then
			systemException "Failed to create swap signature" "reboot"
		fi
		#======================================
		# 8.5 Create home file system
		#--------------------------------------
		Echo "Creating Home filesystem on $deviceHome"
		if ! mke2fs -j -q $deviceHome >/dev/null 2>&1;then
			systemException "Failed to create home filesystem" "reboot"
		fi
	else
		#======================================
		# 8.2 calculate end block - swapspace
		#--------------------------------------
		swapXMBytes=$swapsize
		diskXMBytes=`sfdisk -s $deviceDisk`
		diskXMBytes=`expr $diskXMBytes / 1024`
		disk1MBytes=`sfdisk -s "$deviceDisk"1`
		disk1MBytes=`expr $disk1MBytes / 1024`
		disk2MBytes=`sfdisk -s "$deviceDisk"2`
		disk2MBytes=`expr $disk2MBytes / 1024`
		disk3MBytes=`expr $diskXMBytes - $disk1MBytes - $disk2MBytes`
		disk3MBytes=`expr $disk3MBytes - $swapXMBytes`
		if [ $disk3MBytes -lt 100 ];then
			# /.../
			# Very small disk, we use only 50MB of swap and assume
			# that the rest disk space is big enough to create the
			# RW and swap partition. All this could fail if the disk
			# is not big enough compared to the system image already
			# installed
			# ----
			swapsize=50
			disk3MBytes=`expr $diskXMBytes - $disk1MBytes - $disk2MBytes`
			disk3MBytes=`expr $disk3MBytes - $swapXMBytes`
		fi
		#======================================
		# 8.3 write new partition table
		#--------------------------------------
		# /.../
		# Explanation of the fdisk commands used within the
		# here document below:
		# ----
		# d               # delete xda partition
		# 3               # [ 3 ]
		# n               # create xda partition at same place than xda3
		# p               # primary
		# 3               # [ 3 ]
		#                 # accept old xda3 start block
		# +"disk3MBytes"M # accept new RW device size of disk blocks - swap
		# n               # create xda swap partition
		# p               # primary
		# 4               # [ 4 ]
		#                 # accept start block
		#                 # accept end block
		# t               # change swap system id
		# 4               # [ 4 ]
		# 82              # Linux Swap
		# w               # write partition table
		# ----
		input=/part.input
		rm -f $input
		for cmd in d 3 n p 3 . +"$disk3MBytes"M n p 4 . . t 4 82 w;do
			if [ $cmd = "." ];then
				echo >> $input
				continue
			fi
			echo $cmd >> $input
		done
		fdisk $deviceDisk < $input >/dev/null 2>&1
		if test $? != 0; then
			systemException "Failed to create partition table" "reboot"
		fi
		#======================================
		# 8.4 Update new device names
		#--------------------------------------
		export deviceBoot="$deviceDisk"1
		export deviceRoot="$deviceDisk"2
		export deviceSwap="$deviceDisk"4

		#======================================
		# 8.5 Activate swap space
		#--------------------------------------
		Echo "Activating swap space on $deviceSwap"
		if ! mkswap $deviceSwap >/dev/null 2>&1;then
			systemException "Failed to create swap signature" "reboot"
		fi
	fi
fi

#======================================
# 9) Resize filesystem to full space
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	if test "$FSTYPE" = "squashfs";then
		export UNIONFS_CONFIG="$deviceDisk"3,"$deviceDisk"2,aufs
		KIWI_INITRD_PARAMS="UNIONFS_CONFIG=\"$UNIONFS_CONFIG\""
		KIWI_INITRD_PARAMS="$KIWI_INITRD_PARAMS deviceRoot=\"$deviceRoot\""
		export KIWI_INITRD_PARAMS
	else
		if test "$FSTYPE" = "reiserfs";then
			Echo "Resize Reiser filesystem to full partition space..."
			resize_reiserfs -q $deviceRoot
			INITRD_MODULES="$INITRD_MODULES reiserfs"
		fi
		if test "$FSTYPE" = "ext2";then
			#Echo "Checking EXT2 filesystem..."
			e2fsck -y -f $deviceRoot
			Echo "Resize EXT2 filesystem to full partition space..."
			resize2fs -F -p $deviceRoot
			INITRD_MODULES="$INITRD_MODULES ext2"
		fi
		if test "$FSTYPE" = "ext3";then
			#Echo "Checking EXT3 filesystem..."
			e2fsck -y -f $deviceRoot
			Echo "Resize EXT3 filesystem to full partition space..."
			resize2fs -F -p $deviceRoot
			Echo "Checking EXT3 journal..."
			tune2fs -j $deviceRoot
			INITRD_MODULES="$INITRD_MODULES ext3"
		fi
	fi
fi

#======================================
# 10) Mount system
#--------------------------------------
if ! mountSystem $deviceRoot;then
	systemException "Failed to mount root filesystem" "reboot"
fi

#======================================
# 11) get installed kernels
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	kernelList /mnt
fi

#======================================
# 12) Create system dependant files
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	# a) /etc/fstab...
	#-----------------
	mkdir -p /config/etc
	cat > /config/etc/fstab < /dev/null
	if [ -z "$UNIONFS_CONFIG" ]; then
		echo "$deviceRoot /      $FSTYPE defaults 0 0"     > /config/etc/fstab
		echo "$deviceHome /home  ext3    defaults 0 0"    >> /config/etc/fstab
	else
		mkdir -p /config/kiwiboot
		echo "$deviceBoot /kiwiboot ext2 defaults 0 0"    >> /config/etc/fstab
	fi
	echo "$deviceSwap swap   swap    pri=42  0 0"         >> /config/etc/fstab
	echo "devpts  /dev/pts   devpts  mode=0620,gid=5 0 0" >> /config/etc/fstab
	echo "proc    /proc      proc    defaults 0 0"        >> /config/etc/fstab
	echo "sysfs   /sys       sysfs   noauto 0 0"          >> /config/etc/fstab
	echo "tmpfs   /dev/shm   tmpfs   defaults 0 0"        >> /config/etc/fstab

	# b) /boot/grub/menu.lst
	# ----------------------
	if [ -z "$UNIONFS_CONFIG" ]; then
		console=""
		gdev="(hd0,1)"
		menu=/config/boot/grub/menu.lst
		mkdir -p /config/boot/grub
		echo "timeout 10"                                > $menu
		if [ -f /image/loader/message ];then
			echo "gfxmenu $gdev/boot/message"           >> $menu
		fi
		IFS="," ; for i in $KERNEL_LIST;do
			if test ! -z "$i";then
				kernel=`echo $i | cut -f1 -d:`
				initrd=`echo $i | cut -f2 -d:`
				echo "title SLE/SUSE Linux OEM"         >> $menu
				echo -n " kernel $gdev/boot/$kernel"    >> $menu
				echo -n " root=${deviceDisk}2 $console" >> $menu
				echo " vga=0x314"                       >> $menu
				echo " initrd $gdev/boot/$initrd"       >> $menu
			fi
		done
	fi

	# c) /etc/grub.conf...
	# --------------------
	mkdir -p /config/etc
	gconf=/config/etc/grub.conf
	if [ ! -z "$UNIONFS_CONFIG" ]; then
		gdev="(hd0,0)"
	fi
	echo -en "root $gdev\ninstall"           > $gconf 
	echo -n " --stage2=/boot/grub/stage2"   >> $gconf
	echo -n " /boot/grub/stage1 d (hd0)"    >> $gconf
	echo -n " /boot/grub/stage2 0x8000"     >> $gconf
	echo " $gdev/boot/grub/menu.lst"        >> $gconf
	echo "quit"                             >> $gconf

	# d) /etc/sysconfig/kernel...
	# ---------------------------
	mkdir -p /config/etc/sysconfig
	syskernel=/config/etc/sysconfig/kernel
	echo "INITRD_MODULES=\"$INITRD_MODULES\""       > $syskernel
	echo "DOMU_INITRD_MODULES=\"$DOMURD_MODULES\"" >> $syskernel
fi

#======================================
# 13) copy system dependant files
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	cd /config
	find . -type d | while read d ; do  mkdir -p /mnt/$d ; done
	find . -type f | while read f ; do  cp $f /mnt/$f ; done
	cd /
	rm -rf /config
fi

#======================================
# 14) setup real root device
#--------------------------------------
# echo 256 > /proc/sys/kernel/real-root-dev

#======================================
# 15) umount system filesystems
#--------------------------------------
umount /dev/pts
umount /sys
umount /proc

#======================================
# 16) copy initrd files to image
#--------------------------------------
if [ -f /image/loader/message ];then
	mv /image/loader/message /mnt/boot
fi
cp /preinit /mnt
cp /include /mnt

#======================================
# 17) Start YaST when booting final sys
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	touch /mnt/var/lib/YaST2/runme_at_boot >/dev/null 2>&1
fi

#======================================
# 18) Activate new root
#--------------------------------------
Echo "Activating Image: [$deviceDisk]"
cd /mnt && exec < dev/console >dev/console 2>&1
Echo "Calling preinit phase..."
reopenKernelConsole
/mnt/sbin/pivot_root . mnt >/dev/null 2>&1
if test $? != 0;then
	PIVOT=false
	cleanInitrd && mount --move . / && chroot . ./preinit
	chroot . rm ./preinit
	chroot . rm ./include
else
	PIVOT=true
	./preinit
	rm ./preinit
	rm ./include
fi

#======================================
# 19) Unmount initrd / system init
#--------------------------------------
echo " "
echo "Booting into final System..."
echo "----------------------------"
export IFS=$IFS_ORIG
mount -n -o remount,rw / 2>/dev/null
if [ $PIVOT = "true" ];then
	exec umount -n -l /mnt
else
	exec chroot . /sbin/init $@
fi

