#!/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
export DOBACKUP=1

#======================================
# 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="/cdrom/config.isoclient"
export OEM_PARTITION_CONFIG="/config.oempartition"

#======================================
# Functions...
#--------------------------------------
. /include
. /repart
. /dump
initialize

#======================================
# Functions...
#--------------------------------------
function setupInitialDeviceNames {
	#======================================
	# Check for DONT_PARTITION variable
	#--------------------------------------
	if [ ! -z "$DONT_PARTITION" ];then
		return
	fi
	#======================================
	# Check boot device
	#--------------------------------------
	if [ -z "$imageDiskDevice" ];then
		systemException \
			"Couldn't find any boot device... abort" \
		"reboot"
	fi
	#======================================
	# Set default filesystem device names
	#--------------------------------------
	export imageRWDevice=$(ddn $imageDiskDevice 2)
	export imageRODevice=$(ddn $imageDiskDevice 1)
	export imageIOWRDevice=$imageRWDevice
	#======================================
	# Check for LVM or standard boot
	#--------------------------------------
	if searchVolumeGroup; then
		#======================================
		# LVM setup...
		#--------------------------------------
		export haveLVM=yes
		if [ -e /dev/$VGROUP/LVComp ];then
			export imageRootDevice=/dev/$VGROUP/LVComp
		else
			export imageRootDevice=/dev/$VGROUP/LVRoot
		fi
		export imageRWDevice=/dev/$VGROUP/LVRoot
		export imageRODevice=/dev/$VGROUP/LVComp
		export imageIOWRDevice=$imageRWDevice
		export imageBootDevice=$(ddn $imageDiskDevice 2)
		if [ ! -z "$KIWI_RECOVERY" ];then
			export imageRecoveryDevice=$(ddn $imageDiskDevice $KIWI_RECOVERY)
		fi
		probeFileSystem $imageRootDevice
	else
		#======================================
		# Standard setup
		#--------------------------------------
		if [ ! -z "$KIWI_RECOVERY" ];then
			export imageRecoveryDevice=$(ddn $imageDiskDevice $KIWI_RECOVERY)
			export imageRootDevice=$(ddn $imageDiskDevice 1)
		else
			for i in 1 2;do
				export imageRootDevice=$(ddn $imageDiskDevice $i)
				probeFileSystem $imageRootDevice
				if [ ! "$FSTYPE" = "unknown" ];then
					break
				fi
			done
		fi
	fi
	#======================================
	# Check for LUKS extension on root fs
	#--------------------------------------
	if [ "$FSTYPE" = "luks" ];then
		imageRootDevice=$(luksOpen $imageRootDevice)
		probeFileSystem $imageRootDevice
		export haveLuks=yes
	fi
	#======================================
	# Check for LUKS extension on rw fs
	#--------------------------------------
	if isFSTypeReadOnly;then
		FSTYPE_OLD=$FSTYPE
		probeFileSystem $imageRWDevice
		if [ "$FSTYPE" = "luks" ];then
			export haveLuks=yes
		fi
		FSTYPE=$FSTYPE_OLD
	fi
}

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

#======================================
# Update library path
#--------------------------------------
ldconfig

#======================================
# 1) Mounting local file systems
#--------------------------------------
mountSystemFilesystems &>/dev/null
test -e /proc/splash && echo verbose > /proc/splash
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" ] || [ "$COMBINED_IMAGE" = "local" ] ||\
	[ ! -z "$KIWI_RECOVERY" ]
then
	# /.../
	# if the unionfs/combined 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
	# This also applies if we use an oem system with the recovery
	# feature enabled
	# ----
	export LOCAL_BOOT="yes"
fi
#======================================
# 5) start boot shell
#--------------------------------------
startBlogD
startShell
errorLogStart
openKernelConsole

#======================================
# 6) Including required kernel modules
#--------------------------------------
probeDevices

#======================================
# 7) Select language if not in cmdline
#--------------------------------------
selectLanguage

#======================================
# 8) Import OEM partition config
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ] && [ -f $OEM_PARTITION_CONFIG ];then
	Echo "Including oem partition info file"
	importFile < $OEM_PARTITION_CONFIG
fi

#======================================
# 9) Search boot device...
#--------------------------------------
if [ -z "$pxe" ];then
	Echo "Searching for boot device..."
	if [ "$LOCAL_BOOT" = "no" ];then
		if ! searchBIOSBootDevice;then
			systemException "$biosBootDevice" "reboot"
		fi
		export imageDiskDevice=$biosBootDevice
	else
		export imageDiskDevice=$(dn $disk)
		if [ ! -z "$KIWI_RECOVERY" ];then
			export imageRecoveryDevice=$(ddn $imageDiskDevice $KIWI_RECOVERY)
		fi
	fi
	Echo "Found boot device: $imageDiskDevice"
fi

#======================================
# 10) Check for installation mode...
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then
	OEMInstall
fi

#======================================
# 11) Setup device names...
#--------------------------------------
setupInitialDeviceNames

#======================================
# 12) Check for read-only filesystem
#--------------------------------------
if isFSTypeReadOnly;then
	setupUnionFS $imageRWDevice $imageRODevice $unionFST
fi

#======================================
# 13) repartition the disk device
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then
	OEMRepart
fi

#======================================
# 14) Resize filesystem to full space
#--------------------------------------
Echo "Filesystem of OEM system is: $FSTYPE -> $imageRootDevice"
if [ "$LOCAL_BOOT" = "no" ];then
	deviceResize=$imageRootDevice
	fstypeRootFS=$FSTYPE
	if [ ! -z $COMBINED_IMAGE ];then
		deviceResize=$imageIOWRDevice
		KIWI_INITRD_PARAMS="COMBINED_IMAGE=local"
		probeFileSystem $deviceResize
		export KIWI_INITRD_PARAMS
	fi
	if isFSTypeReadOnly && [ -z "$COMBINED_IMAGE" ];then
		deviceResize=$imageIOWRDevice
		KIWI_INITRD_PARAMS="UNIONFS_CONFIG=yes"
		probeFileSystem $deviceResize
		export KIWI_INITRD_PARAMS
	fi
	if [ ! -z "$deviceResize" ] && partitionSize $deviceResize &>/dev/null;then
		if [ ! -z "$OEM_RECOVERY" ];then
			KIWI_INITRD_PARAMS="$KIWI_INITRD_PARAMS LOCAL_BOOT=yes"
			export KIWI_INITRD_PARAMS
		fi
		if [ -z "$DONT_PARTITION" ];then
			resizeFilesystem $deviceResize
		fi
	fi
	if [ "$OEM_KIWI_INITRD" = "yes" ];then
		if ! echo $KIWI_INITRD_PARAMS | grep -qi LOCAL_BOOT;then
			KIWI_INITRD_PARAMS="$KIWI_INITRD_PARAMS LOCAL_BOOT=yes"
		fi
	fi
	FSTYPE=$fstypeRootFS
fi

#======================================
# 15) Mount system
#--------------------------------------
if [ -z "$RESTORE" ];then
	if ! mountSystem $imageRootDevice;then
		systemException "Failed to mount root filesystem" "reboot"
	fi
	validateRootTree
fi

#======================================
# 16) Recover system if requested
#--------------------------------------
if [ ! -z "$KIWI_RECOVERY" ];then
	text=$TEXT_REPAIR
	if [ ! -z "$RESTORE" ];then
		text=$TEXT_RESTORE
	fi
	Dialog --defaultno --yesno "\"$text\"" 5 50
	if [ ! $? = 0 ];then
		systemException "System-Recovery not started" "reboot"
	fi
	clear
	Echo "Starting System-Recovery/Restore..."
	#======================================
	# 16.1) mount recovery partition
	#--------------------------------------
	mkdir -p /reco-save
	if ! mount -o ro $imageRecoveryDevice /reco-save >/dev/null;then
		systemException "Failed to mount recovery device" "reboot"
	fi
	#======================================
	# 16.2) restore MBR/LVM in restore mode
	#--------------------------------------
	if [ ! -z "$RESTORE" ];then
		if ! dd if=/reco-save/mbr of=$imageDiskDevice;then
			systemException "Failed to restore MBR" "reboot"
		fi
		umount $imageRecoveryDevice
		blockdev --rereadpt $imageDiskDevice
		waitForStorageDevice $imageRecoveryDevice
		if ! mount -o ro $imageRecoveryDevice /reco-save >/dev/null;then
			systemException "Failed to remount recovery device" "reboot"
		fi
		if [ -f /reco-save/lvm ];then
			restoreLVMPhysicalVolumes /reco-save/lvm
			if ! vgcfgrestore -f /reco-save/lvm $VGROUP;then
				systemException "Failed to restore LVM metadata" "reboot"
			fi
			setupInitialDeviceNames
		fi
	fi
	#======================================
	# 16.3) restore root archive
	#--------------------------------------
	mkfifo /progress && cp /usr/bin/tail /usr/bin/mst
	(
		#======================================
		# recreate filesystem in restore mode
		#--------------------------------------
		if [ ! -z "$RESTORE" ];then
			getText "Clean sweep..." > /progress
			export FSTYPE=$(cat /reco-save/recovery.tar.filesystem)
			createFilesystem $imageRootDevice
			if ! mountSystem $imageRootDevice;then
				systemException "Failed to mount root filesystem" "reboot"
			fi
			for i in dev sys proc;do
				mkdir -p /mnt/$i
			done
		fi
		cd /mnt
		#======================================
		# store files temporary
		#--------------------------------------
		if [ -z "$RESTORE" ];then
			for i in passwd shadow group;do
				if ! cp etc/$i tmp/$i;then
					cd / ; umountSystem; rm -f tmp/passwd tmp/shadow tmp/group
					systemException "Failed to store $i" "reboot"
				fi
			done
			if ! cp -a var/lib/rpm tmp/;then
				rm -rf tmp/rpm; cd / ; umountSystem
				systemException "Failed to store RPM database" "reboot"
			fi
		fi
		#======================================
		# create backup diffs
		#--------------------------------------
		if [ -z "$RESTORE" ] && [ "$DOBACKUP" = 1 ];then
			getText "Clean sweep..." > /progress
			rm -rf tmp/foobar; mkdir -p tmp/foobar
			rm -rf tmp/backup; mkdir -p tmp/backup
			if ! find etc/ home/ -type f 2>/dev/null |\
				xargs tar -cO -f - 2>/dev/null |\
				tar -v -C tmp/foobar -xf -
			then
				rm -rf tmp/foobar; umountSystem
				systemException "Failed to create backup files" "reboot"
			fi
		fi
		#======================================
		# extract root archive
		#--------------------------------------
		rFiles=$(cat /reco-save/recovery.tar.files)
		tar --numeric-owner -xvpf /reco-save/recovery.tar.gz >/tmp/rFiles &
		rPID=$!
		while kill -0 $rPID &>/dev/null;do
			rReady=$(cat /tmp/rFiles | wc -l)
			if [ $rReady -eq 0 ];then
				continue
			fi
			#Echo -e -n "$rReady files from $rFiles restored...\r"
			rFDone=$(echo "scale=4; $rFiles / $rReady" | bc)
			rFDone=$(echo "scale=0; 100 / $rFDone" | bc)
			getText "restoring: %1..." "$rFDone%" > /progress
			#getText "%1 files from %2 restored..." $rReady $rFiles > /progress
			sleep 1
		done
		#======================================
		# create backup diffs
		#--------------------------------------
		if [ -z "$RESTORE" ] && [ "$DOBACKUP" = 1 ];then
			rReady=0
			rCount=0
			getText "backing up: %1..." "0%" > /progress
			cat /tmp/rFiles | grep -E "^(./etc|./home)" > /tmp/bFiles
			rFilesBackup=$(cat /tmp/bFiles | wc -l)
			for file in $(cat /tmp/bFiles);do
				if [ ! -d $file ] && [ -e $file ] && [ -e tmp/foobar/$file ]
				then
					sizeOrig=$(stat $file --printf=%s)
					sizeBack=$(stat tmp/foobar/$file --printf=%s)
					if [ $sizeOrig -ne $sizeBack ];then
						if ! cmp -s -n 20480 $file tmp/foobar/$file;then
							label=$(echo $file | cut -c 2-)
							txdiff=$(diff -u \
								--label $label $file \
								--label $label tmp/foobar/$file 2>/dev/null)
							if [ $? = 1 ];then
								base=$(basename $file)
								printf "%s\n" "$txdiff" \
									> tmp/backup/$base.$rCount.diff
								rCount=$((rCount + 1))
							fi
						fi
					fi
				fi
				rReady=$((rReady + 1))
				rPDone=$(echo "scale=4; $rFilesBackup / $rReady" | bc)
				rPDone=$(echo "scale=0; 100 / $rPDone" | bc)
				getText "backing up: %1..." "$rPDone%" > /progress
			done
			rm -rf tmp/foobar
			rm -rf tmp/backup/bootloader*
			rm -rf tmp/backup/mtab*
			rm -rf tmp/backup/fstab*
			rm -rf tmp/backup/kernel*
			rm -rf tmp/backup/passwd*
			rm -rf tmp/backup/shadow*
			rm -rf tmp/backup/group*
		fi
		dPID=$(pidof mst)
		kill $dPID
	)&
	echo "mst -f /progress | dialog \
		--backtitle \"$TEXT_RECOVERYTITLE\" \
		--progressbox 3 50
	" > /tmp/progress.sh
	if [ -e /dev/fb0 ];then
		fbiterm -m $UFONT -- bash -e /tmp/progress.sh
	else
		bash -e /tmp/progress.sh
	fi
	clear
	#======================================
	# 16.4) restore temporary stored files
	#--------------------------------------
	if [ -z "$RESTORE" ];then
		for i in passwd shadow group;do
			if ! mv /mnt/tmp/$i /mnt/etc/$i;then
				systemException "Failed to restore $i" "reboot"
			fi
		done
		mv /mnt/var/lib/rpm /mnt/var/lib/rpm.backup
		if ! mv /mnt/tmp/rpm /mnt/var/lib/;then
			mv /mnt/var/lib/rpm.backup /mnt/var/lib/rpm
			systemException "Failed to restore RPM database" "reboot"
		fi
		rm -rf /mnt/var/lib/rpm.backup
	fi
	#======================================
	# 16.5) restore boot files 1
	#--------------------------------------
	Echo "Restoring boot configuration archive part (1)..."
	if ! tar -xf /reco-save/boot-1.tgz -C /mnt;then
		systemException "Failed to restore boot configuration" "reboot"
	fi
	#======================================
	# 16.6) restore fstab partitions
	#--------------------------------------
	if [ ! -z "$RESTORE" ];then
		imageSwapDevice=$(cat /mnt/etc/fstab | grep swap | cut -f1 -d " ")
		imageSwapDevice=$(echo $imageSwapDevice)
		if [ -e "$imageSwapDevice" ];then
			if ! mkswap $imageSwapDevice 1>&2;then
				systemException "Failed to restore swap signature" "reboot"
			fi
		fi
		imageHomeDevice=$(cat /mnt/etc/fstab | grep /home | cut -f1 -d " ")
		imageHomeDevice=$(echo $imageHomeDevice)
		if [ -e "$imageHomeDevice" ];then
			probeFileSystem $imageRootDevice
			createFilesystem $imageHomeDevice
		fi
		imageBootDevice=$(
			cat /mnt/etc/fstab|grep /.*boot|grep -v bind | sed -r 's/\s+/:/g')
		if [ ! -z "$imageBootDevice" ];then
			imageBootMountP=$(echo $imageBootDevice | cut -f2 -d:)
			imageBootDevice=$(echo $imageBootDevice | cut -f1 -d:)
			rm -rf /mnt/boot
			mkdir  /mnt/boot
			probeFileSystem $imageRootDevice
			createFilesystem $imageBootDevice
			mkdir -p /mnt/$imageBootMountP
			mount $imageBootDevice /mnt/$imageBootMountP
			mkdir -p /mnt/$imageBootMountP/boot
			mount --bind /mnt/$imageBootMountP/boot /mnt/boot
		fi
	fi
	#======================================
	# 16.7) restore boot files 2
	#--------------------------------------
	Echo "Restoring boot configuration archive part (2)..."
	if ! tar -xf /reco-save/boot-2.tgz -C /mnt/$imageBootMountP;then
		systemException "Failed to restore boot configuration" "reboot"
	fi
	#======================================
	# 16.8) umount recovery 
	#--------------------------------------
	umount $imageRecoveryDevice
	#======================================
	# 16.9) import oem config file
	#--------------------------------------
	importFile < $OEM_PARTITION_CONFIG
	IFS=$IFS_ORIG
	#======================================
	# 16.10) write oem-trigger
	#--------------------------------------
	TDIR=/mnt/var/cache/recovery
	TOEM=oem-trigger
	mkdir -p $TDIR
	echo "OEM_RECOVERY_DEVICE=$imageRecoveryDevice" > $TDIR/$TOEM
	if [ ! -z "$RESTORE" ];then
		echo "OEM_RECOVERY_MODE=restore" >> $TDIR/$TOEM
	else
		echo "OEM_RECOVERY_MODE=recover" >> $TDIR/$TOEM
	fi
fi

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

#======================================
# 18) setup ird/kernel links for union
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then 
	if [ "$OEM_KIWI_INITRD" = "yes" ] || isFSTypeReadOnly;then
		# /.../
		# we are using a special root setup with aufs. In this case
		# we can't use the SuSE Linux initrd but must stick to the
		# kiwi boot system.
		# ----
		mountCalled=no
		if [ -e "$imageRWDevice" ];then
			kiwiMount $imageRWDevice "/mnt"
			mountCalled=yes
		fi
		pushd /mnt/boot >/dev/null
		IFS="," ; for i in $KERNEL_LIST;do
			if test -z "$i";then
				continue
			fi
			kernel=`echo $i | cut -f1 -d:`
			initrd=`echo $i | cut -f2 -d:`
			rm -f $initrd && ln -s initrd.vmx $initrd
			rm -f $kernel && ln -s linux.vmx  $kernel
			break
		done
		IFS=$IFS_ORIG
		popd >/dev/null
		if [ "$mountCalled" = "yes" ];then
			umount /mnt
		fi
	fi
fi

#======================================
# 19) Create system dependant files
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then
	#======================================
	# setup: /etc/fstab
	#--------------------------------------
	setupDefaultFstab /config
	updateRootDeviceFstab /config $imageRootDevice
	if [ "$haveLVM" = "yes" ];then
		updateLVMBootDeviceFstab /config $imageBootDevice
	elif [ "$haveClicFS" = "yes" ];then
		updateClicBootDeviceFstab /config $imageBootDevice
	elif [ "$haveBtrFS" = "yes" ];then
		updateBtrBootDeviceFstab /config $imageBootDevice
	elif [ "$loader" = "syslinux" ] || [ "$loader" = "extlinux" ];then
		updateSyslinuxBootDeviceFstab /config $imageBootDevice
	elif [ "$haveLuks" = "yes" ];then
		updateLuksBootDeviceFstab /config $imageBootDevice
	fi
	if partitionSize $imageSwapDevice &>/dev/null;then
		updateSwapDeviceFstab /config $imageSwapDevice
	else
		unset $imageSwapDevice
	fi
	if [ -z "$OEM_WITHOUTHOME" ] && [ -z "$DONT_PARTITION" ];then
		if [ `ls /mnt/home/ | wc -l` != 0 ]; then
			Echo "Found non empty home/ directory !"
			Echo "Moving home/ data to home partition $imageHomeDevice"
			mount $imageHomeDevice /mnt/mnt
			mv /mnt/home/*  /mnt/mnt
			mv /mnt/home/.* /mnt/mnt
			umount /mnt/mnt
		fi
		FSTYPE_SAVE=$FSTYPE
		probeFileSystem $imageHomeDevice
		Echo "Activate home partition $imageHomeDevice in fstab"
		echo "$(getDiskID $imageHomeDevice) /home $FSTYPE defaults 0 0" \
			>> /config/etc/fstab
		FSTYPE=$FSTYPE_SAVE
	fi
	#======================================
	# setup: bootloader files
	#--------------------------------------
	Echo "Creating boot loader configuration"
	if [ -z "$OEM_BOOT_TITLE" ];then
		export OEM_BOOT_TITLE="OEM"
	fi
	if [ ! -z $OEM_RECOVERY ];then
		OEM_RECOVERY=$imageRootDevice
	fi
	setupBootLoader \
		/mnt /config $(($bootid - 1)) $imageRootDevice \
		"$OEM_BOOT_TITLE" $imageSwapDevice
	setupKernelModules /config
fi

#======================================
# 20) copy system dependant files
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then
	setupConfigFiles
fi

#======================================
# 21) update system dependant files
#--------------------------------------
setupInittab /mnt

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

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

#======================================
# 24) copy initrd files to image
#--------------------------------------
if [ "$LOCAL_BOOT" = "no" ];then
	importBranding
fi
cp /preinit /mnt
cp /include /mnt

#======================================
# 25) kill boot shell
#--------------------------------------
killShell
killBlogD

#======================================
# 26) Activate new root
#--------------------------------------
activateImage

#======================================
# 27 Unmount initrd / system init
#--------------------------------------
bootImage $@
