#!/usr/bin/env python
# Copyright (c) 2005-2006 XenSource, Inc. All use and distribution of this 
# copyrighted material is governed by and subject to terms and conditions 
# as licensed by XenSource, Inc. All other rights reserved.
# Xen, XenSource and XenEnterprise are either registered trademarks or 
# trademarks of XenSource Inc. in the United States and/or other countries.

###
# XEN CLEAN INSTALLER
# Boot script
#
# written by Mark Nijmeijer and Andrew Peace

import commands
import sys
import os
import os.path
import signal

# user interface:
import tui
import tui.init
import tui.progress
import generalui

import install
import oem
import product
import init_constants
import xelogging
import netutil
import util
import restore
import driver
import p2v
from netinterface import *

from version import *
from constants import EXIT_OK, EXIT_ERROR, EXIT_USER_CANCEL
from variant import *

# Attempt to configure the network:
def configureNetworking(ui, device):
    if ui:
        ui.progress.showMessageDialog(
            "Preparing for installation",
            "Attempting to configure networking..."
            )

    nethw = netutil.scanConfiguration()
    netcfg = {}
    for i in nethw.keys():
        netcfg[i] = NetInterface(NetInterface.DHCP, nethw[i].hwaddr)

    netutil.writeDebStyleInterfaceFile(netcfg, '/etc/network/interfaces')

    if device == 'all':
        for i in nethw.keys():
            netutil.ifup(i)
    elif device.startswith('eth'):
        if nethw.has_key(device):
            netutil.ifup(device)
    else:
        # MAC address
        matching_list = filter(lambda x: x.hwaddr == device, nethw.values())
        if len(matching_list) == 1:
            netutil.ifup(matching_list[0].name)

    if ui:
        ui.progress.clearModelessDialog()

def sig_term(x, y):
    xelogging.log("Killed by another instance, terminating")
    os.system('/usr/bin/clear')
    sys.exit(0)

def main(args):
    # switch to ISO 8859-1 mode so line drawing characters work as expected on 
    # vt100 terminals.
    print "\033%@"

    # log to tty3
    xelogging.openLog('/dev/tty3')

    tty = None
    signal.signal(signal.SIGTERM, sig_term)
    try:
        tty = os.path.basename(os.readlink('/proc/self/fd/0'))
        pidfile = open('/var/run/installer-%s.pid' % tty, 'w')
        print >>pidfile, os.getpid()
        pidfile.close()
    except:
        pass

    operation = None
    ui = tui
    interactive = True
    answer_device = 'all'
    driver_answers = {}
    driver_repos = []
    init_network = False
    reboot = False
    oem_edition = False
    oem_manufacturer = "OEM Manufacturer not found"
    oem_verify = False
    answerfile_address = None
    flash_and_or_hdd = "all"
    custom = 'default'
    
    for (opt, val) in args.items():
        if opt == "--install":
            operation = init_constants.OPERATION_INSTALL
        elif opt == "--oem_edition":
            oem_edition = True
        elif opt == "--OEM_VERIFY":
            oem_verify = (val == "on")
        elif opt == "--OEM_MANUFACTURER":
            oem_manufacturer = val
        elif opt == "--install_oem_to_flash":
            operation = init_constants.OPERATION_INSTALL_OEM_TO_FLASH
        elif opt == "--install_oem_to_disk":
            operation = init_constants.OPERATION_INSTALL_OEM_TO_DISK
        elif opt == "--p2v":
            operation = init_constants.OPERATION_P2V
        elif opt == "--answerfile":
            answerfile_address = val
            interactive = False
            init_network = True
        elif opt == "--rt_answerfile":
            answerfile_address = val
            interactive = False
            init_network = True
            ui = None
            xelogging.openLog(sys.stdout)
        elif opt == '--answerfile_device':
            answer_device = val.lower()
        elif opt == "--reboot":
            reboot = True
        elif opt == "--rootmedia":
            flash_and_or_hdd = val
        elif opt == "--custom":
            custom = val

    # Set up the variant object
    if oem_edition:
        Variant.setInstance(VariantOEM())
    else:
        Variant.setInstance(VariantRetail())

    # check that an answerfile was specified if we're being non-interactive:
    if not interactive and not operation:
        xelogging.log("No operation specified for answerfile - dropping back to interactive mode.")
        interactive = True
        ui = tui

    # start the user interface:
    if ui:
        xelogging.log("Starting 'init' user interface on %s" % tty)
        ui.init_ui()

    # if oem_manufacturer=$md5sum appears on cmdline then this
    # CD is only to be run on machines built by a that manufacturer
    if oem_verify:
        is_oem_machine = oem.OemManufacturerTest(ui, oem_manufacturer)
        if not is_oem_machine:
            xelogging.log("OemManufacturerTest failed.  This installation is not licenced for this machine.")
            return reboot

    # let the user choose what they would like to do:
    if interactive:
        # choose keymap
        kmap = ui.init.get_keymap()

        if tty:
            try:
                # terminate any additional instances of the installer
                for p in os.listdir('/var/run'):
                    if p != 'installer-%s.pid' % tty:
                        f = open('/var/run/'+p)
                        pid = int(f.readline())
                        f.close()
                        xelogging.log("Killing installer with pid %d" % pid)
                        os.kill(pid, signal.SIGTERM)
            except:
                pass
                    
        args['--keymap'] = kmap
        xelogging.log("Loading keymap %s" % kmap)
        util.runCmd2(["/bin/loadkeys", kmap])

        xelogging.writeLog("/tmp/startup-log")

    if init_network:
        configureNetworking(ui, answer_device)

    if not oem_edition:
        backups = product.findXenSourceBackups()

    try:
        while True:
            # if interactive, set the operation:
            if interactive and not operation:
                if oem_edition:
                    operation = ui.init_oem.choose_operation(flash_and_or_hdd, custom)
                else:
                    operation = ui.init.choose_operation(len(backups) > 0)
                    

            if operation == init_constants.OPERATION_REBOOT:
                break

            # install/upgrade:
            elif operation == init_constants.OPERATION_INSTALL:
                xelogging.log("Starting installation/upgrade")

                args['--extrarepo'] = driver_repos
                rc = install.go(ui, args, answerfile_address)

            elif operation == init_constants.OPERATION_INSTALL_OEM_TO_FLASH:
                xelogging.log("Starting default installation of OEM to flash")

                rc = oem.go_flash(ui, args, answerfile_address, 'default')

            elif operation == init_constants.OPERATION_INSTALL_OEM_TO_FLASH_CUSTOM:
                xelogging.log("Starting custom installation of OEM to flash")

                rc = oem.go_flash(ui, args, answerfile_address, 'custom')
                
            elif operation == init_constants.OPERATION_INSTALL_OEM_TO_DISK:
                xelogging.log("Starting default installation of OEM to disk")

                rc = oem.go_disk(ui, args, answerfile_address, 'default')

            elif operation == init_constants.OPERATION_INSTALL_OEM_TO_DISK_CUSTOM:
                xelogging.log("Starting custom installation of OEM to disk")

                rc = oem.go_disk(ui, args, answerfile_address, 'custom')

            # load a driver:
            elif operation == init_constants.OPERATION_LOAD_DRIVER:
                driver_repos.extend(driver.doInteractiveLoadDriver(ui, driver_answers))
                rc = None

            # restore:
            elif operation == init_constants.OPERATION_RESTORE:
                xelogging.log("Starting restore")
                rc = restore.go(ui)

            # P2V:
            elif operation == init_constants.OPERATION_P2V:
                xelogging.log("Starting P2V")
                rc = p2v.go(args, ui)

            # reset password
            elif operation == init_constants.OPERATION_RESET_PASSWORD:
                xelogging.log("Resetting password")
                rc = oem.reset_password(ui, args, answerfile_address)

            # reset OEM state partition
            elif operation == init_constants.OPERATION_RESET_STATE_PARTITION:
                xelogging.log("Resetting password")
                rc = oem.reset_state_partition(ui, args, answerfile_address)

            operation = None
            # if we're non-interactive, or weren't canceled, force us to exit:
            if rc == EXIT_OK or rc == EXIT_ERROR or not interactive:
                break

    finally:
        if ui:
            ui.end_ui()

        # stop logging to tty3:
        xelogging.closeLogs()

    return reboot


if __name__ == "__main__":
    reboot = main(util.splitArgs(sys.argv[1:], ('--console')))
    if reboot:
        os.system("reboot")
