#!/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
#--------------------------------------
mountSystemFilesystems >/dev/null 2>&1
closeKernelConsole

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

#======================================
# 3) run udevd
#--------------------------------------
udevStart

#======================================
# 4) 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

#======================================
# 5) Including required kernel modules
#--------------------------------------
probeDevices
for module in usb_storage sg sd_mod BusLogic;do
	modprobe $module >/dev/null 2>&1
done
sleep 5

#======================================
# 6) 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: | cut -f1 -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

#======================================
# 7) Check for vmx system
#--------------------------------------
if [ -f $VMX_SYSTEM ];then
	#======================================
	# 7.1) import vmx configuration file
	#--------------------------------------
	importFile < $VMX_SYSTEM
	#======================================
	# 7.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
	#======================================
	# 7.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
	#======================================
	# 7.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 bs=32k 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
	#======================================
	# 7.5) Umount the CD/DVD
	#--------------------------------------
	umount /cdrom
	#======================================
	# 7.6) reread partition table
	#--------------------------------------
	blockdev --rereadpt $deviceDisk
	#======================================
	# 7.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
	#======================================
	# 7.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
	#======================================
	# 7.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

#======================================
# 8) 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
#======================================
# 9) repartition the disk device
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	#======================================
	# 9.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
		#======================================
		# 9.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
		#======================================
		# 9.3 Update new device names
		#--------------------------------------
		export deviceRoot="$deviceDisk"2
		export deviceSwap="$deviceDisk"1
		export deviceHome="$deviceDisk"3

		#======================================
		# 9.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
		#======================================
		# 9.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
		#======================================
		# 9.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
		#======================================
		# 9.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
		#======================================
		# 9.4 Update new device names
		#--------------------------------------
		export deviceBoot="$deviceDisk"1
		export deviceRoot="$deviceDisk"2
		export deviceSwap="$deviceDisk"4

		#======================================
		# 9.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

#======================================
# 10) 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 "Resize EXT2 filesystem to full partition space..."
			resize2fs -f -F -p $deviceRoot
			Echo "Checking EXT2 filesystem..."
			e2fsck -y -f $deviceRoot
			INITRD_MODULES="$INITRD_MODULES ext2"
		fi
		if test "$FSTYPE" = "ext3";then
			Echo "Resize EXT3 filesystem to full partition space..."
			resize2fs -f -F -p $deviceRoot
			Echo "Checking EXT3 filesystem..."
			e2fsck -y -f $deviceRoot
			INITRD_MODULES="$INITRD_MODULES ext3"
		fi
	fi
fi

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

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

#======================================
# 13) Create system dependant files
#--------------------------------------
if [ $LOCAL_BOOT = "no" ];then
	setupDefaultFstab /config
	updateSwapDeviceFstab /config $deviceSwap
	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
	setupBootLoaderGrub /mnt /config 1 ${deviceDisk}2 OEM $deviceSwap
	setupKernelModules /config
fi

#======================================
# 14) 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

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

#======================================
# 16) umount system filesystems
#--------------------------------------
umountSystemFilesystems

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

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

#======================================
# 18) Unmount initrd / system init
#--------------------------------------
Echo "Rebooting System to activate setup..."
/sbin/reboot -f -i &>/dev/null
Echo "Failed to reboot system"
/bin/sh
