#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
  "XBMC Live" installer
  V1.007 - 20091023
  Luigi Capriotti @2009

""" 

import tempfile
import os, re, sys, time
import subprocess
import random
import shutil
import statvfs
import optparse

gMinSizeMB = 1500

# For HDD installations
gFixedDiskMinSizeMB = 5000
gBootPartitionSizeMB = 4096
gSwapPartitionSizeMB = 512

gPermStorageFilenameV1 = "ext3fs.img"
gRootFSV1="/rootfs.img"
gPermStorageFilenameV2 = "live-rw"
gRootFSV2="/live/filesystem.squashfs"

gBootPartMountPoint = "/tmp/bootPart"
gLivePartMountPoint = "/tmp/livePart"

gDebugMode = 0
gInstallerLogFileName = "/var/tmp/installXBMC.log"



def runSilent(aCmdline):
	writeLog("Running: " + aCmdline)
	process = subprocess.Popen(aCmdline, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
	stdout_value, stderr_value = process.communicate()
	retCode = process.returncode
	writeLog("Return code= " + str(retCode))
	writeLog("Results: StdOut=" + repr(stdout_value))
	writeLog("Results: StdErr=" + repr(stderr_value))
	return stdout_value, retCode

def diskSizeKB(aVolume):
	diskusage, retCode = runSilent('fdisk -l ' + aVolume + ' | grep "' + aVolume + ':" | cut -f 5 -d " "')
	nBytes = int(diskusage)
	return int(nBytes / 1024)

def freeSpaceMB(aPath):
	stats, retCode = runSilent("df -Pk " + aPath)
	return int(stats.splitlines()[1].split()[3])/1024

def readFile(the_file):
	f = file(the_file, 'r')
	content = f.read()
	f.close()
	return content

def writeFile(the_file, content):
	f = file(the_file, 'w')
	f.write(content)
	f.close

def writeLog(aLine):
	global gInstallerLogFileName
	global gDebugMode

	if gDebugMode > 0:
		time_now = time.strftime("[%H:%M:%S] ", time.localtime())
		f = file(gInstallerLogFileName, 'a')
		f.write(time_now + aLine + '\n')
		f.close

def getKernelParameter(token):
	aParam=None
	l=open('/proc/cmdline').readline().strip()
	for t in l.split():
		if t.startswith(token + '='):
			aParam = t.split('=',1)[1]
		
	return aParam

def findBootVolume(rootFS, lookForRootFS):
	if not lookForRootFS:
		rootPartition = getKernelParameter('root')
		if rootPartition.startswith('UUID='):
			anUUID = rootPartition.split('=',1)[1]
			rootPartition, retCode = runSilent('blkid | grep "' + anUUID + '" | cut -d ":" -f 1')
		return rootPartition

	outString, retCode = runSilent('mount | grep iso9660')
	if len(outString):
		driveList = ["sr0","sr1","sr2","sr3"]
	else:
		driveList = ["sda","sdb","sdc","sdd","sde","sdf","sdg"]

	# Find the drive we booted from
	found = False
	for deviceNode in driveList:
		device = "/dev/" + deviceNode
		print "Checking device " + device + " for installation source..."
		if  os.path.exists(device):
			if  os.path.exists("/sys/block/" + deviceNode + "/removable"):
				if isRemovableDisk(device):
					if deviceNode.startswith("sd"):
						device = device + "1"
						mountDevice(device, "", gBootPartMountPoint)
					else:
						mountDevice(device, "-o ro -t iso9660", gBootPartMountPoint)

					if os.path.exists(gBootPartMountPoint + rootFS):
						print "Found Boot drive on " + device
						found = True

					umountDevice(gBootPartMountPoint)

		if found == True:
			break

		print device + " does not contain a rootfs."

	if found == False:
		device = None

	return device

def isRemovableDisk(aDevice):
	aDeviceNode = aDevice.split("/")[2]

	fName='/sys/block/' + aDeviceNode + '/removable'
	if os.path.exists(fName):
		return int(open(fName).readline().strip())
	return 0


def userChoice(prompt, charsGo, charsStop):
	bGoOn=0
	while 1:
		choice = raw_input(prompt)
		if choice == '':
			continue
		if choice in charsGo:
			bGoOn = choice
			break
		if choice in charsStop:
			break

	return bGoOn

def findDisks(bootDisk):
	availDisk = []
	
	while 1:
		found=0
		for deviceNode in ['sda','sdb','sdc','sdd','sde','sdf','sdg']:
			device = "/dev/" + deviceNode
			if bootDisk.find(device) >=0:
				print "Skipping boot device (" + device + ") ..."
			else:
				print "Checking device " + device +" ..."
	
				if os.path.exists(device):
					aFile = '/sys/block/' + deviceNode + '/size'
					if open(aFile).readline().strip() != "0" :
						availDisk.append(device)

						aString = "Found disk: " + device
						if isRemovableDisk(device):
							aString += " - Removable disk."
						print aString
						found=1

		if found == 1:
			break

		raw_input("No drives detected, connect a disk and press return...")
		print ""
		print "Scanning again disk drives..."
		print ""

	return availDisk

def chooseDisk(availableDrives):
	if len(availableDrives) == 0:
		print
		print "No disks"
		print
		return 0
	print ""
	print "Choose disk to use"
	print ""
	availChoices=""
	nChoice = 0
	for t in availableDrives:
		diskSizeMB = int(diskSizeKB(t))/1000
		nChoice += 1
		availChoices += str(nChoice)
		aString = "   " + str(nChoice) + ": " + t + " (" + str(diskSizeMB) + " MB)"

		if isRemovableDisk(t):
			aString += " - Removable disk"
		else:
			aString += " - FIXED disk"
		print aString

	print ""
	return  userChoice("Type the digit, or 0 to restart the procedure: ", availChoices, "0")

def partitionFormatDisk(device, bIsRemovableDisk, bootPartSize, swapPartSize):
	runSilent("dd if=/dev/zero of=" + device + " bs=512 count=2")
	runSilent("sync")

	if bIsRemovableDisk:
		strFdiskCommands = ["o","n","p","1","","","t","c","a","1","w"]

		stdInFile = tempfile.NamedTemporaryFile()
		for line in strFdiskCommands:
			stdInFile.write(line + "\n")
		stdInFile.flush()

		runSilent("cat " + stdInFile.name + " | fdisk " + device)
		stdInFile.close()

		runSilent("mkfs.vfat -I -F 32 -n XBMCLive_" + str(random.randint(0, 999)) + " " + device + "1")
		return
	
	partEnd = ""
	if bootPartSize > 0:
		partEnd = "+" + str(bootPartSize) + "M"

	strFdiskCommands = ["o","n","p","1","",partEnd,"a","1","w"]
	stdInFile = tempfile.NamedTemporaryFile()
	for line in strFdiskCommands:
		stdInFile.write(line + "\n")
	stdInFile.flush()

	runSilent("cat " + stdInFile.name + " | fdisk " + device)
	stdInFile.close()

	runSilent("mkfs.ext3 " + device + "1")

	if swapPartSize != 0:
		partEnd = "+" + str(swapPartSize) + "M"

		strFdiskCommands = ["n","p","2","",partEnd,"t","2","82","n","p","3","","","w"]
		stdInFile = tempfile.NamedTemporaryFile()
		for line in strFdiskCommands:
			stdInFile.write(line + "\n")
		stdInFile.flush()

		runSilent("cat " + stdInFile.name + " | fdisk " + device)
		stdInFile.close()

		runSilent("mkswap -c " + device +"2")
		runSilent("mkfs.ext3 " + device +"3")
	else:
		strFdiskCommands = ["n","p","2","","","w"]
		stdInFile = tempfile.NamedTemporaryFile()
		for line in strFdiskCommands:
			stdInFile.write(line + "\n")
		stdInFile.flush()

		runSilent("cat " + stdInFile.name + " | fdisk " + device)
		stdInFile.close()

		runSilent("mkfs.ext3 " + device +"2")

	runSilent("sync")
	
	# For debugging purposes only
	runSilent("fdisk -l " + device)
	runSilent("mount")

def mountDevice(aDevice, mountOpts, aDirectory):
	if not os.path.exists(aDirectory):
		os.mkdir(aDirectory)

	outStr, retCode = runSilent("mount " + mountOpts + " " + aDevice + " " + aDirectory)
	if retCode > 0:
		outStr, retCode = runSilent("mount -o remount " + mountOpts + " " + aDevice + " " + aDirectory)
		if retCode > 0:
			print "Error mounting device: " + aDevice + " - Exiting."
			writeLog("Error mounting device: " + aDevice + " - Exiting.")
			runSilent("sleep 5")
			sys.exit(-1)

def umountDevice(aDirectory, removeMountPoint=True):
	outStr, retCode = runSilent("umount " + aDirectory)
	if retCode > 0:
		print "Error unmounting directory: " + aDirectory + " - Exiting."
		writeLog("Error unmounting directory: " + aDirectory + " - Exiting.")
		runSilent("sleep 5")
		sys.exit(-1)

	if removeMountPoint == True:
		os.rmdir(aDirectory)

def copySystemFilesV1(srcDirectory, dstDirectory, bIsRemovableDisk, skipLargeFiles):
	global gDebugMode
	global gPermStorageFilenameV1

	if not os.path.exists(dstDirectory):
		os.mkdir(dstDirectory)

	# For debugging purposes only
	runSilent("mount")
	runSilent("ls -aRl " + srcDirectory)
	runSilent("ls -aRl " + dstDirectory)

	if bIsRemovableDisk: 
		for root, dirs, files in os.walk(srcDirectory):
			for file in files:
				# Do not copy storage file
				if file == gPermStorageFilenameV1:
					continue

				writeLog("Copying file: " + file)
				if skipLargeFiles == True:
					if file.find("img") > 0:
						writeLog("TEST MODE = " + str(gDebugMode) + " : file skipped.")
						continue

				from_ = os.path.join(root, file)
				to_ = from_.replace(srcDirectory, dstDirectory, 1)
				to_directory = os.path.split(to_)[0]
				if not os.path.exists(to_directory):
					os.makedirs(to_directory)
				try:
					shutil.copyfile(from_, to_)
				except:
					writeLog("Error copying file: " + file + " - check your media")
					print "Error copying file: " + file + " - check your media"
					continue

		if not os.path.exists(dstDirectory + "/" + "Config"):
			os.mkdir(dstDirectory + "/" + "Config")
	else:
		tmpMountPoint="/tmp/tmpMntPoint"

		mountDevice(srcDirectory + "/rootfs.img", "-o ro,loop -t squashfs", tmpMountPoint)
		runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
		umountDevice(tmpMountPoint)

		# Defaults to current GPU
		# May fail if more than one GPU is available (nvidia has proprity though)
		hasAMD, retCode = runSilent("lspci -nn | grep 0300 | grep 1002")
		hasNVIDIA, retCode = runSilent("lspci -nn | grep 0300 | grep 10de")

		if len(hasNVIDIA):
			print "Installing NVIDIA restricted drivers..."
			writeLog("Installing NVIDIA restricted drivers...")
			mountDevice(srcDirectory + "/restrictedDrivers.nvidia.img", "-o ro,loop", tmpMountPoint)
			runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
			umountDevice(tmpMountPoint)
		elif len(hasAMD):
			print "Installing ATI/AMD restricted drivers..."
			writeLog("Installing ATI/AMD restricted drivers...")
			mountDevice(srcDirectory + "/restrictedDrivers.amd.img", "-o ro,loop", tmpMountPoint)
			runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
			umountDevice(tmpMountPoint)

		if not os.path.exists(dstDirectory + "/boot"):
			os.mkdir(dstDirectory + "/boot")

		aFileName = os.readlink("/initrd.img")
		# writeLog("Src=" + srcDirectory + "/initrd0.img")
		# writeLog("Dest=" + dstDirectory + "/" + aFileName)
		try:
			writeLog("Copying " + srcDirectory + "/initrd0.img")
			shutil.copyfile(srcDirectory + "/initrd0.img", dstDirectory + "/" + aFileName)
		except:
			writeLog("Error copying file: " + "initrd0.img")
			print "Error copying file: " + "initrd0.img" + " - check your media"

		aFileName = os.readlink("/vmlinuz")
		# writeLog("Src=" + srcDirectory + "/vmlinuz")
		# writeLog("Dest=" + dstDirectory + "/" + aFileName)
		try:
			writeLog("Copying " + srcDirectory + "/vmlinuz")
			shutil.copyfile(srcDirectory + "/vmlinuz", dstDirectory + "/" + aFileName)
		except:
			writeLog("Error copying file: " + "vmlinuz")
			print "Error copying file: " + "vmlinuz" + " - check your media"

		# shutil.copyfile(srcDirectory + "/boot/xbmc.xpm.gz", dstDirectory + "/boot/xbmc.xpm.gz")
		for root, dirs, files in os.walk(srcDirectory + "/boot"):
			for file in files:
				from_ = os.path.join(root, file)
				to_ = from_.replace(srcDirectory, dstDirectory, 1)
				to_directory = os.path.split(to_)[0]
				if not os.path.exists(to_directory):
					os.makedirs(to_directory)
				try:
					# print "Copying from: " + from_ + " to>: " + to_
					shutil.copyfile(from_, to_)
				except:
					print "Error copying file: " + file + " - check your media"
					writeLog("Error copying file: " + file)
					continue

def copySystemFilesV2(srcDirectory, dstDirectory, bIsRemovableDisk, skipLargeFiles):
	global gDebugMode
	global gPermStorageFilenameV2

	if not os.path.exists(dstDirectory):
		os.mkdir(dstDirectory)

	# For debugging purposes only
	runSilent("mount")
	runSilent("ls -aRl " + srcDirectory)
	runSilent("ls -aRl " + dstDirectory)

	if bIsRemovableDisk: 
		for root, dirs, files in os.walk(srcDirectory):
			for file in files:
				# Do not copy storage file
				if file == gPermStorageFilenameV2:
					continue

				writeLog("Copying file: " + file)
				if skipLargeFiles == True:
					if file.find("ext3") > 0:
						writeLog("TEST MODE = " + str(gDebugMode) + " : file skipped.")
						continue
					if file.find("squashfs") > 0:
						writeLog("TEST MODE = " + str(gDebugMode) + " : file skipped.")
						continue

				from_ = os.path.join(root, file)
				to_ = from_.replace(srcDirectory, dstDirectory, 1)
				to_directory = os.path.split(to_)[0]
				if not os.path.exists(to_directory):
					os.makedirs(to_directory)
				try:
					shutil.copyfile(from_, to_)
				except:
					writeLog("Error copying file: " + file + " - check your media")
					print "Error copying file: " + file + " - check your media"
					continue

		if not os.path.exists(dstDirectory + "/" + "Config"):
			os.mkdir(dstDirectory + "/" + "Config")
	else:
		tmpMountPoint="/tmp/tmpMntPoint"

		mountDevice(srcDirectory + "/live/filesystem.squashfs", "-o ro,loop -t squashfs", tmpMountPoint)
		runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
		umountDevice(tmpMountPoint)

		# Defaults to current GPU
		# May fail if more than one GPU is available (nvidia has proprity though)
		hasAMD, retCode = runSilent("lspci -nn | grep 0300 | grep 1002")
		hasNVIDIA, retCode = runSilent("lspci -nn | grep 0300 | grep 10de")

		if len(hasNVIDIA):
			if os.path.exists(srcDirectory + "/live/restrictedDrivers/nvidia.ext3"):
				print "Installing NVIDIA restricted drivers..."
				writeLog("Installing NVIDIA restricted drivers...")
				mountDevice(srcDirectory + "/live/restrictedDrivers/nvidia.ext3", "-o ro,loop", tmpMountPoint)
				runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
				umountDevice(tmpMountPoint)
		elif len(hasAMD):
			if os.path.exists(srcDirectory + "/live/restrictedDrivers/amd.ext3"):
				print "Installing ATI/AMD restricted drivers..."
				writeLog("Installing ATI/AMD restricted drivers...")
				mountDevice(srcDirectory + "/live/restrictedDrivers/amd.ext3", "-o ro,loop", tmpMountPoint)
				runSilent("cp -a " + tmpMountPoint + "/* " + dstDirectory)
				umountDevice(tmpMountPoint)

		if not os.path.exists(dstDirectory + "/boot"):
			os.mkdir(dstDirectory + "/boot")

		aFileName = os.readlink("/initrd.img")
		try:
			writeLog("Copying " + srcDirectory + "/live/initrd.img")
			shutil.copyfile(srcDirectory + "/live/initrd.img", dstDirectory + "/" + aFileName)
		except:
			writeLog("Error copying file: " + "initrd.img")
			print "Error copying file: " + "initrd.img" + " - check your media"

		aFileName = os.readlink("/vmlinuz")
		try:
			writeLog("Copying " + srcDirectory + "/live/vmlinuz")
			shutil.copyfile(srcDirectory + "/live/vmlinuz", dstDirectory + "/" + aFileName)
		except:
			writeLog("Error copying file: " + "vmlinuz")
			print "Error copying file: " + "vmlinuz" + " - check your media"

		for root, dirs, files in os.walk(srcDirectory + "/boot"):
			for file in files:
				from_ = os.path.join(root, file)
				to_ = from_.replace(srcDirectory, dstDirectory, 1)
				to_directory = os.path.split(to_)[0]
				if not os.path.exists(to_directory):
					os.makedirs(to_directory)
				try:
					# print "Copying from: " + from_ + " to>: " + to_
					shutil.copyfile(from_, to_)
				except:
					print "Error copying file: " + file + " - check your media"
					writeLog("Error copying file: " + file)
					continue

def createPermanentStorageFile(aFileFName, aSizeMB):
	aCmdLine = "dd if=/dev/zero of=" + aFileFName + " bs=4M count=" + str(aSizeMB/4)
	runSilent(aCmdLine)
	runSilent("mkfs.ext3 -F " + aFileFName)
	return

def findUUID(aPartition):
	cmdLine = 'blkid -s UUID | grep ' + aPartition + ' | cut -d " " -f 2 | cut -d "=" -f 2 | sed \'s/"//g' + "'"
	anUUID, retCode = runSilent(cmdLine)
	return anUUID.rstrip("\n\r")

def installGrub(bootDevice, dstDirectory):
	runSilent("grub-install --recheck --root-directory=" + dstDirectory + " " + bootDevice)

def modifyGrubMenuV1(useGrubLegacy, basePath, isaRemovableDrive, bootPartition):
	menuFName = basePath + "/boot/grub/menu.lst"
	if not useGrubLegacy:
		menuFName = basePath + "/boot/grub/grub.cfg"

	if isaRemovableDrive:
		content = readFile(menuFName)
		if isaRemovableDrive == 1:
			content = re.sub("boot=[a-z]*", "boot=usb", content)
		else:
			content = re.sub("boot=[a-z]*", "boot=disk", content)
	else:
		content = ("default 0" + "\n")
		content += ("hiddenmenu" + "\n")
		content += ("timeout 5" + "\n")
		content += ("foreground eeeeee" + "\n")
		content += ("background 333333" + "\n")
		content += ("splashimage=/boot/xbmc.xpm.gz" + "\n")
		content += ("\n")
		content += ("title  XBMCLive" + "\n")
		content += ("kernel /vmlinuz root=UUID=" + findUUID(bootPartition) + " quiet splash xbmc=nodiskmount,tempfs,setvolume,noredir loglevel=0" + "\n")
		content += ("initrd /initrd.img" + "\n")
		content += ("boot" + "\n")
		content += ("\n")
		content += ("title  XBMCLive - SAFE MODE" + "\n")
		content += ("kernel /vmlinuz root=UUID=" + findUUID(bootPartition) + " xbmc=nodiskmount,noredir loglevel=0" + "\n")
		content += ("initrd /initrd.img" + "\n")
		content += ("boot" + "\n")
		content += ("\n")

	writeFile(menuFName, content)

def modifyGrubMenuV2(useGrubLegacy, basePath, isaRemovableDrive, bootPartition):
	if not isaRemovableDrive:
		if useGrubLegacy:
			menuFName = basePath + "/boot/grub/menu.lst"

			content = ("default 0" + "\n")
			content += ("hiddenmenu" + "\n")
			content += ("timeout 5" + "\n")
			content += ("foreground eeeeee" + "\n")
			content += ("background 333333" + "\n")
			content += ("splashimage=/boot/grub/splash.xpm.gz" + "\n")
			content += ("\n")
			content += ("title  XBMCLive" + "\n")
			content += ("kernel /vmlinuz root=UUID=" + findUUID(bootPartition) + " quiet splash xbmc=autostart,nodiskmount,setvolume,noredir loglevel=0" + "\n")
			content += ("initrd /initrd.img" + "\n")
			content += ("boot" + "\n")
			content += ("\n")
			content += ("title  XBMCLive - SAFE MODE" + "\n")
			content += ("kernel /vmlinuz root=UUID=" + findUUID(bootPartition) + " xbmc=nodiskmount,noredir loglevel=0" + "\n")
			content += ("initrd /initrd.img" + "\n")
			content += ("boot" + "\n")
			content += ("\n")
		else:
			menuFName = basePath + "/boot/grub/grub.cfg"

			content = ""
			content += ("set default=0" + "\n")
			content += ("\n")
			content += ("insmod video" + "\n")
			content += ("insmod vbe" + "\n")
			content += ("insmod font" + "\n")
			content += ("if loadfont ($root)/boot/grub/unicode.pf2 ; then" + "\n")
			content += (" set gfxmode=800x600" + "\n")
			content += ("# set gfxpayload=keep" + "\n")
			content += (" insmod gfxterm" + "\n")
			content += (" if terminal_output gfxterm ; then true ; else" + "\n")
			content += ("  # For backward compatibility with versions of terminal.mod that don't understand terminal_output" + "\n")
			content += ("  terminal gfxterm" + "\n")
			content += (" fi" + "\n")
			content += ("fi" + "\n")
			content += ("\n")
			content += ("insmod tga" + "\n")
			content += ("if background_image ($root)/boot/grub/xbmc.tga ; then" + "\n")
			content += (" set color_normal=white/black" + "\n")
			content += (" set color_highlight=cyan/black" + "\n")
			content += ("else" + "\n")
			content += (" set menu_color_normal=cyan/blue" + "\n")
			content += (" set menu_color_highlight=white/blue" + "\n")
			content += ("fi" + "\n")
			content += ("\n")
			content += ('echo -n "Press ESC to enter the menu... "' + "\n")
			content += ("if sleep --verbose --interruptible 2 ; then" + "\n")
			content += (" set timeout=0" + "\n")
			content += ("else" + "\n")
			content += (" set timeout=-1" + "\n")
			content += ("fi" + "\n")
			content += ("\n")
			content += ('menuentry "XBMCLive" {' + "\n")
			content += ('set quiet=1' + "\n")
			content += (" linux /vmlinuz root=UUID=" + findUUID(bootPartition) + " quiet splash xbmc=autostart,nodiskmount,setvolume,noredir loglevel=0" + "\n")
			content += (" initrd /initrd.img" + "\n")
			content += ("}" + "\n")
			content += ("\n")
			content += ('menuentry "XBMCLive - SAFE MODE" {' + "\n")
			content += ('set quiet=1' + "\n")
			content += (" linux /vmlinuz root=UUID=" + findUUID(bootPartition) + " xbmc=nodiskmount,noredir loglevel=0" + "\n")
			content += (" initrd /initrd.img" + "\n")
			content += ("}" + "\n")
			content += ("\n")
		writeFile(menuFName, content)

def changePasswords(liveRootDir):
	# Lock root account
	runSilent("passwd -l root")

	print "Please set a new password for user 'xbmc':"
	while 1:
		retcode = subprocess.call(["passwd", "xbmc"])
		if retcode >= 0:
			break

	shutil.copyfile("/etc/shadow", liveRootDir + "/etc/shadow")

def prepareFstab(liveRootDir, bootDevice, swapFileSize):
	# Prepare /etc/fstab
	content =  "unionfs     /               unionfs defaults      0 0\n"
	content += "proc        /proc           proc    defaults      0 0\n"
	
	if swapFileSize == 0:
		content += ("UUID=" + findUUID(bootDevice + "2") + "   /home           ext3    defaults,auto 0 0\n")
	else:
		content += ("UUID=" + findUUID(bootDevice + "2") + "   none            swap    sw,auto       0 0\n")
		content += ("UUID=" + findUUID(bootDevice + "3") + "  /home            ext3    defaults,auto 0 0\n")
	writeFile(liveRootDir + "/etc/fstab", content)


def prepareHomeDirectory(bootDevice, swapFileSize):
	homeMountPoint = "/tmp/homePart"

	if swapFileSize > 0:
		mountDevice(bootDevice + "3", "", homeMountPoint)
	else:
		mountDevice(bootDevice + "2", "", homeMountPoint)

	if not os.path.exists(homeMountPoint + "/xbmc"):
		os.mkdir(homeMountPoint + "/xbmc")

	if not os.path.exists(homeMountPoint + "/xbmc/Videos"):
		os.mkdir(homeMountPoint + "/xbmc/Videos")

	if not os.path.exists(homeMountPoint + "/xbmc/Pictures"):
		os.mkdir(homeMountPoint + "/xbmc/Pictures")

	if not os.path.exists(homeMountPoint + "/xbmc/Music"):
		os.mkdir(homeMountPoint + "/xbmc/Music")

	if not os.path.exists(homeMountPoint + "/xbmc/.xbmc"):
		os.mkdir(homeMountPoint + "/xbmc/.xbmc")

	if not os.path.exists(homeMountPoint + "/xbmc/.xbmc/userdata"):
		os.mkdir(homeMountPoint + "/xbmc/.xbmc/userdata")

	# Create a sources.xml referencing the above created directories
	content  = "<sources>"
	content += "    <video>"
	content += "        <default></default>"
	content += "        <source>"
	content += "            <name>Videos</name>"
	content += "            <path>/home/xbmc/Videos/</path>"
	content += "        </source>"
	content += "    </video>"
	content += "    <music>"
	content += "        <default></default>"
	content += "        <source>"
	content += "            <name>Music</name>"
	content += "            <path>/home/xbmc/Music/</path>"
	content += "        </source>"
	content += "    </music>"
	content += "    <pictures>"
	content += "        <default></default>"
	content += "        <source>"
	content += "            <name>Pictures</name>"
	content += "            <path>/home/xbmc/Pictures/</path>"
	content += "        </source>"
	content += "    </pictures>"
	content += "</sources>"

	writeFile(homeMountPoint + "/xbmc/.xbmc/userdata/sources.xml", content)

	runSilent("chown -R xbmc:xbmc " + homeMountPoint + "/xbmc")
	umountDevice(homeMountPoint)

def main():
	global gMinSizeMB
	global gFixedDiskMinSizeMB
	global gBootPartitionSizeMB
	global gSwapPartitionSizeMB
	global gPermStorageFilenameV1
	global gPermStorageFilenameV2
	global gRootFSV1
	global gRootFSV2
	global gBootPartMountPoint
	global gLivePartMountPoint
	global gInstallerLogFileName
	global gDebugMode

	parser = optparse.OptionParser()
	parser.add_option("-i", dest="isoFileName", help="Use specified ISO file as source for XBMC Live files", default=None)
	parser.add_option("-d", dest="debugMode", action="store_true", help="Creates debug log file: " + gInstallerLogFileName, default=False)
	parser.add_option("-l", dest="debugFileName", help="Use specified file as debug log file", default=None)
	parser.add_option("-s", dest="skipFileCopy", action="store_true", help="Do not copy IMG files (debug helper)", default=False)
	parser.add_option("-c", dest="doNotShutdown", action="store_true", help="Do not perform a shutdown after execution", default=False)
	(cmdLineOptions, args) = parser.parse_args()

	if cmdLineOptions.debugMode == True:
		cmdLineOptions.doNotShutdown = True
		gDebugMode = 1
	
	if not cmdLineOptions.debugFileName == None:
		gInstallerLogFileName = cmdLineOptions.debugFileName
		cmdLineOptions.doNotShutdown = True
		gDebugMode = 1

	if cmdLineOptions.skipFileCopy == True:
		cmdLineOptions.doNotShutdown = True
		gDebugMode = 1

	if not cmdLineOptions.isoFileName == None:
		cmdLineOptions.doNotShutdown = True
		gDebugMode = 1
	
	writeLog("-- Installer Start --")

	if not cmdLineOptions.isoFileName == None:
		if not os.path.exists(cmdLineOptions.isoFileName):
			print "File: " + cmdLineOptions.isoFileName + " does not exist, exiting..."
			sys.exit(-1)

		cmdLine = 'file -b ' + cmdLineOptions.isoFileName
		aType, retCode = runSilent(cmdLine)
		if not aType.find("9660") >=0:
			print "File: " + cmdLineOptions.isoFileName + " is not a valid ISO image, exiting..."
			sys.exit(-1)

	availableDisks = []

	bIsLiveV2 = False
	bUseGrubLegacy = True
	permStorageFilename = gPermStorageFilenameV1
	rootFS = gRootFSV1

	bootMedia = getKernelParameter('boot')
	if bootMedia == 'live':
		bIsLiveV2 = True
		permStorageFilename = gPermStorageFilenameV2
		rootFS = gRootFSV2

	while True:
		os.system('clear')
		print ""
		print "XBMC Live bootable disk creator"
		print "---------------------"
		print ""
		print "The procedure will create a XBMC Live bootable disk"
		print ""
		print "Requirements:"
		print "   for USB flash disks: the disk must have at least " + str(gMinSizeMB) + " MB of capacity!"
		print "   for fixed disks: the disk must have at least " + str(gFixedDiskMinSizeMB) + " MB of capacity!"
		print ""
		print "CAUTION: the process will erase all data on the specified disk drive!"
		print "CAUTION: this is an experimental tool, use at your own risk!"
		print ""
		raw_input("Press a key to continue, or Ctrl-C to exit.")
		
		print ""
		print "Identifying boot disk..."
		print ""
		bootVolume = findBootVolume(rootFS, (cmdLineOptions.isoFileName == None))
		if bootVolume == None:
			if cmdLineOptions.doNotShutdown == True:
				raw_input("Error locating boot media, exiting.")
				sys.exit(-1)

			raw_input("Error locating boot media, press a key to shutdown...")
			runSilent("shutdown -h now")
			runSilent("sleep 10")
			sys.exit(-1)

		print "Enumerating available disks..."
		print ""
		availableDisks = findDisks(bootVolume)

		diskIndex = chooseDisk(availableDisks)
		if diskIndex == 0:
			continue
		diskIndex = int(diskIndex) - 1
		removableDiskSelected = isRemovableDisk(availableDisks[diskIndex])

		diskSizeMB = diskSizeKB(availableDisks[diskIndex])/1024
		minSizeMB = gMinSizeMB
		if not removableDiskSelected:
			print ""
			print ""
			print "The selected disk appears to be a fixed disk."
			print ""

			if userChoice("Do you want the installer to handle it as a removable disk instead (Y/N)? ","Yy","Nn") == 0:
				minSizeMB = gFixedDiskMinSizeMB
			else:
				removableDiskSelected = 10

		if diskSizeMB < minSizeMB:
			print ""
			print ""
			print "The selected disk is too small."
			if removableDiskSelected:
				print "The minimum requirements for removable disks are: " + str(gMinSizeMB) + " MB of disk size"
			else:
				print "The minimum requirements for fixed disks are: " + str(gFixedDiskMinSizeMB) + " MB of disk size"
			print
			print "The selected disk has only " + str(diskSizeMB) + " MB of disk space."
			print ""
			print "Please ignore the selected disk and try again."
			print ""
			raw_input("Press a button to restart the procedure. ")
			continue

		if userChoice("Erasing disk " + availableDisks[diskIndex] + ", proceed (Y/N)? ","Yy","Nn") == 0:
			continue

		print "Partitioning & formatting disk..."

		partitionFormatDisk(availableDisks[diskIndex], removableDiskSelected, gBootPartitionSizeMB, gSwapPartitionSizeMB)

		print "Copying system files - please wait..."

		mountDevice(availableDisks[diskIndex] + "1", "", gLivePartMountPoint)

		if cmdLineOptions.isoFileName == None:
			outString, retCode = runSilent('mount | grep iso9660')
			if len(outString):
				mountOpts = "-o ro -t iso9660"
			else:
				mountOpts = "-t vfat"

			mountDevice(bootVolume, mountOpts, gBootPartMountPoint)
		else:
			mountDevice(cmdLineOptions.isoFileName, "-o loop", gBootPartMountPoint)

		if bIsLiveV2 == False:
			copySystemFilesV1(gBootPartMountPoint, gLivePartMountPoint, removableDiskSelected, cmdLineOptions.skipFileCopy)
		else:
			copySystemFilesV2(gBootPartMountPoint, gLivePartMountPoint, removableDiskSelected, cmdLineOptions.skipFileCopy)

		umountDevice(gBootPartMountPoint)

		print "Installing GRUB..."

		installGrub(availableDisks[diskIndex], gLivePartMountPoint)

		if not gDebugMode > 10:
			if removableDiskSelected:
				print ""
				print " XBMC Live saves all system changes into a file, if available."
				print " If such a file, called 'permanent storage file' does not exist,"
				print " changes to system configuration are lost when rebooting."
				print ""
				if not userChoice("Do you want to create a permanent system storage file (Y/N)? ","Yy","Nn") == 0:
					availSpace = freeSpaceMB(availableDisks[diskIndex] + "1")
					storageSize = (availSpace/10)*7
					if storageSize > 4000:
						storageSize = 4000
					print "Permanent system storage size = " + str(storageSize) + " MB, Please wait..."
					createPermanentStorageFile(gLivePartMountPoint + "/" + permStorageFilename, storageSize)

		if os.path.exists(gLivePartMountPoint + "/boot/grub/grub.cfg"):
			bUseGrubLegacy = False

		if bIsLiveV2 == False:
			modifyGrubMenuV1(bUseGrubLegacy, gLivePartMountPoint, removableDiskSelected, availableDisks[diskIndex] + "1")
		else:
			modifyGrubMenuV2(bUseGrubLegacy, gLivePartMountPoint, removableDiskSelected, availableDisks[diskIndex] + "1")

		if not removableDiskSelected:
			print "Applying system changes..."
			prepareFstab(gLivePartMountPoint, availableDisks[diskIndex], gSwapPartitionSizeMB)
			changePasswords(gLivePartMountPoint)
			prepareHomeDirectory(availableDisks[diskIndex], gSwapPartitionSizeMB)

		umountDevice(gLivePartMountPoint)

		print "All done!"
		print ""

		if cmdLineOptions.doNotShutdown == True:
			print "Exiting..."
			break

		if userChoice("Do you want to create another bootable disk (Y/N)? ","Yy","Nn") == 0:
			print "Shutting down the system in 5 seconds..."
			runSilent("sleep 5")
			runSilent("shutdown -h now")
			sys.exit(-1)


if __name__ == '__main__':
	# Make sure only root can run the script
	if os.getuid() != 0: 
		print "This script must be run as root." 
		sys.exit(-1)

	main()
