#!/usr/bin/python
#
# anaconda: The Red Hat Linux Installation program
#
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# Red Hat, Inc.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Author(s): Brent Fox <bfox@redhat.com>
#            Mike Fulbright <msf@redhat.com>
#            Jakub Jelinek <jakub@redhat.com>
#            Jeremy Katz <katzj@redhat.com>
#            Chris Lumens <clumens@redhat.com>
#            Paul Nasrat <pnasrat@redhat.com>
#            Erik Troan <ewt@rpath.com>
#            Matt Wilson <msw@rpath.com>
#

# This toplevel file is a little messy at the moment...

import sys, os, re, time, subprocess
from optparse import OptionParser
from tempfile import mkstemp

# keep up with process ID of the window manager if we start it
wm_pid = None

# Make sure messages sent through python's warnings module get logged.
def AnacondaShowWarning(message, category, filename, lineno, file=sys.stderr, line=None):
    log.warning("%s" % warnings.formatwarning(message, category, filename, lineno, line))

def startMetacityWM():
    childpid = os.fork()
    if not childpid:
        # after this point the method should never return (or throw an exception
        # outside)
        try:
            args = ['--display', ':1',
                    '--sm-disable']
            iutil.execWithRedirect('metacity', args,
                                   stdout='/dev/null', stderr='/dev/null')
        except BaseException as e:
            # catch all possible exceptions
            log.error("Problems running the window manager: %s" % str(e))
            sys.exit(1)

        log.info("The window manager has terminated.")
        sys.exit(0)
    return childpid

def startAuditDaemon():
    childpid = os.fork()
    if not childpid:
        cmd = '/sbin/auditd'
        try:
            os.execl(cmd, cmd)
        except OSError as e:
            log.error("Error running the audit daemon: %s" % str(e))
        sys.exit(0)
    # auditd will turn into a daemon so catch the immediate child pid now:
    os.waitpid(childpid, 0)

# function to handle X startup special issues for anaconda
def doStartupX11Actions():
    global wm_pid # pid of the anaconda fork where the window manager is running

    setupGraphicalLinks()

    # now start up the window manager
    wm_pid = startMetacityWM()
    log.info("Starting window manager, pid %s." % (wm_pid,))

    if wm_pid is not None:
        from pyanaconda import xutils

        try:
            xutils.setRootResource('Xcursor.size', '24')
            xutils.setRootResource('Xcursor.theme', 'Bluecurve')
            xutils.setRootResource('Xcursor.theme_core', 'true')

            xutils.setRootResource('Xft.antialias', '1')
            xutils.setRootResource('Xft.hinting', '1')
            xutils.setRootResource('Xft.hintstyle', 'hintslight')
            xutils.setRootResource('Xft.rgba', 'none')
        except Exception as e:
            sys.stderr.write("X SERVER STARTED, THEN FAILED");
            raise RuntimeError, "X server failed to start"

def set_x_resolution(runres):
    # cant do this if no window manager is running because otherwise when we
    # open and close an X connection in the xutils calls the X server will exit
    # since this is the first X connection (if no window manager is running)
    if runres and opts.display_mode == 'g' and not flags.usevnc and wm_pid :
        try:
            log.info("Setting the screen resolution to: %s.", runres)
            iutil.execWithRedirect("xrandr", 
                                   ["-d", ":1", "-s", runres],
                                   stdout="/dev/tty5", stderr="/dev/tty5")
        except RuntimeError as e:
            log.error("The X resolution not set")
            iutil.execWithRedirect("xrandr",
                                   ["-d", ":1", "-q"],
                                   stdout="/dev/tty5", stderr="/dev/tty5")

def setupPythonUpdates():
    from distutils.sysconfig import get_python_lib

    if not os.path.exists("/tmp/updates"):
        return

    for pkg in os.listdir("/tmp/updates"):
        d = "/tmp/updates/%s" % pkg

        if not os.path.isdir(d):
            continue

        # See if the package exists in /usr/lib{64,}/python/?.?/site-packages.
        # If it does, we can set it up as an update.  If not, the pkg is
        # likely a completely new directory and should not be looked at.
        dest = "%s/%s" % (get_python_lib(), pkg)
        if not os.access(dest, os.R_OK):
            dest = "%s/%s" % (get_python_lib(1), pkg)
            if not os.access(dest, os.R_OK):
                continue
        # Symlink over everything that's in the python libdir but not in
        # the updates directory.
        symlink_updates(dest, d)

    import glob
    import shutil
    for rule in glob.glob("/tmp/updates/*.rules"):
        target = "/etc/udev/rules.d/" + rule.split('/')[-1]
        shutil.copyfile(rule, target)

def symlink_updates(dest_dir, update_dir):    
    contents = os.listdir(update_dir)

    for f in os.listdir(dest_dir):
        dest_path = os.path.join(dest_dir, f)
        update_path = os.path.join(update_dir, f)
        if f in contents:
            # recurse into directories, there might be files missing in updates
            if os.path.isdir(dest_path) and os.path.isdir(update_path):
                symlink_updates(dest_path, update_path)
        else:
            if f.endswith(".pyc") or f.endswith(".pyo"):
                continue
            os.symlink(dest_path, update_path)

def parseOptions(argv = None):
    # Using _isys here so we don't drag in the logging stuff, which is always
    # complicated.
    from pyanaconda import _isys
    op = OptionParser(version="%prog " + _isys.getAnacondaVersion())

    # Interface
    op.add_option("-C", "--cmdline", dest="display_mode", action="store_const", const="c",
                  default="g")
    op.add_option("-G", "--graphical", dest="display_mode", action="store_const", const="g")
    op.add_option("-T", "--text", dest="display_mode", action="store_const", const="t")

    # Network
    op.add_option("--noipv4", action="store_true", default=False)
    op.add_option("--noipv6", action="store_true", default=False)
    op.add_option("--proxy")
    op.add_option("--proxyAuth")

    # Method of operation
    op.add_option("--autostep", action="store_true", default=False)
    op.add_option("-d", "--debug", dest="debug", action="store_true", default=False)
    op.add_option("--kickstart", dest="ksfile")
    op.add_option("--rescue", dest="rescue", action="store_true", default=False)
    op.add_option("--targetarch", dest="targetArch", nargs=1, type="string")

    op.add_option("-m", "--method", dest="method", default=None)
    op.add_option("--repo", dest="method", default=None)
    op.add_option("--stage2", dest="stage2", default=None)
    op.add_option("--noverifyssl", action="store_true", default=False)

    op.add_option("--liveinst", action="store_true", default=False)

    # Display
    op.add_option("--headless", dest="isHeadless", action="store_true", default=False)
    op.add_option("--nofb")
    op.add_option("--resolution", dest="runres", default=None)
    op.add_option("--serial", action="store_true", default=False)
    op.add_option("--usefbx", dest="xdriver", action="store_const", const="fbdev")
    op.add_option("--virtpconsole")
    op.add_option("--vnc", action="store_true", default=False)
    op.add_option("--vncconnect")
    op.add_option("--xdriver", dest="xdriver", action="store", type="string", default=None)

    # Language
    op.add_option("--keymap")
    op.add_option("--kbdtype")
    op.add_option("--lang")

    # Obvious
    op.add_option("--loglevel")
    op.add_option("--syslog")

    op.add_option("--noselinux", dest="selinux", action="store_false", default=True)
    op.add_option("--selinux", action="store_true")

    op.add_option("--nompath", dest="mpath", action="store_false", default=True)
    op.add_option("--mpath", action="store_true")

    op.add_option("--nodmraid", dest="dmraid", action="store_false", default=True)
    op.add_option("--dmraid", action="store_true")

    op.add_option("--noibft", dest="ibft", action="store_false", default=True)
    op.add_option("--ibft", action="store_true")
    op.add_option("--noiscsi", dest="iscsi", action="store_false", default=False)
    op.add_option("--iscsi", action="store_true")

    # Miscellaneous
    op.add_option("--module", action="append", default=[])
    op.add_option("--nomount", dest="rescue_nomount", action="store_true", default=False)
    op.add_option("--updates", dest="updateSrc", action="store", type="string")
    op.add_option("--dogtail", dest="dogtail",   action="store", type="string")
    op.add_option("--dlabel", action="store_true", default=False)
    op.add_option("--image", action="append", dest="images", default=[])

    # Deprecated, unloved, unused
    op.add_option("-r", "--rootPath", dest="unsupportedMode",
                  action="store_const", const="root path")
    op.add_option("-t", "--test", dest="unsupportedMode",
                  action="store_const", const="test")

    return op.parse_args(argv)

def setupPythonPath():
    sys.path.append('/usr/share/system-config-date')

def setupEnvironment():
    # Silly GNOME stuff
    if os.environ.has_key('HOME') and not os.environ.has_key("XAUTHORITY"):
        os.environ['XAUTHORITY'] = os.environ['HOME'] + '/.Xauthority'
    os.environ['HOME'] = '/tmp'
    os.environ['LC_NUMERIC'] = 'C'
    os.environ["GCONF_GLOBAL_LOCKS"] = "1"

    # In theory, this gets rid of our LVM file descriptor warnings
    os.environ["LVM_SUPPRESS_FD_WARNINGS"] = "1"

    # make sure we have /sbin and /usr/sbin in our path
    os.environ["PATH"] += ":/sbin:/usr/sbin"

    # we can't let the LD_PRELOAD hang around because it will leak into
    # rpm %post and the like.  ick :/
    if os.environ.has_key("LD_PRELOAD"):
        del os.environ["LD_PRELOAD"]

    os.environ["GLADEPATH"] = "/tmp/updates/:/tmp/updates/data/ui/:ui/:/usr/share/anaconda/ui/:/usr/share/python-meh/"
    os.environ["PIXMAPPATH"] = "/tmp/updates/pixmaps/:/tmp/updates/:/tmp/product/pixmaps/:/tmp/product/:pixmaps/:/usr/share/anaconda/pixmaps/:/usr/share/pixmaps/:/usr/share/anaconda/:/usr/share/python-meh/:/usr/share/icons/Fedora/48x48/apps/"

def setupLoggingFromOpts(opts):
    if opts.loglevel and anaconda_log.logLevelMap.has_key(opts.loglevel):
        level = anaconda_log.logLevelMap[opts.loglevel]
        anaconda_log.logger.tty_loglevel = level
        anaconda_log.setHandlersLevel(log, level)
        storage_log = logging.getLogger("storage")
        anaconda_log.setHandlersLevel(storage_log, level)

    if opts.syslog:
        anaconda_log.logger.remote_syslog = opts.syslog

# ftp installs pass the password via a file in /tmp so
# ps doesn't show it
def expandFTPMethod(str):
    ret = None

    try:
        filename = str[1:]
        ret = open(filename, "r").readline()
        ret = ret[:len(ret) - 1]
        os.unlink(filename)
        return ret
    except:
        return None

def runVNC():
    global vncS
    vncS.startServer()

    child = os.fork()
    if child == 0:
        for p in ('/tmp/updates/pyrc.py', \
                '/usr/share/anaconda/pyrc.py'):
            if os.access(p, os.R_OK|os.X_OK):
                os.environ['PYTHONSTARTUP'] = p
                break

        while True:
            # Not having a virtual terminal or otherwise free console
            # are the only places we /really/ need a shell on tty1,
            # and everywhere else this just gets in the way of pdb.  But we
            # don't want to return, because that'll return try to start X
            # a second time.
            if iutil.isConsoleOnVirtualTerminal() or iutil.isS390():
                    time.sleep(10000)
            else:
                    print _("Press <enter> for a shell")
                    sys.stdin.readline()
                    iutil.execConsole()

def gtk_warning(title, reason):
    import gtk
    dialog = gtk.MessageDialog(type = gtk.MESSAGE_ERROR,
                               buttons = gtk.BUTTONS_CLOSE,
                               message_format=reason)
    dialog.set_title(title)
    dialog.run()
    dialog.destroy()

def check_memory(anaconda, opts, display_mode=None):
    reason_strict = _("%s requires %s MB of memory to install, but you only have "
                      "%s MB on this machine.\n")
    reason_method = _("%s requires %s MB of memory to install using this "
                      "installation method, but you only have %s MB on this "
                      "machine.\n")
    reason_graphical = _("The %s graphical installer requires %s MB of memory, but "
                         "you only have %s MB.")

    reboot_extra = _('\n'
                     'Press <return> to reboot your system.\n')
    livecd_title = _("Not enough RAM")
    livecd_extra =_(" Try the text mode installer by running:\n\n"
                    "'/usr/bin/liveinst -T'\n\n from a root "
                    "terminal.")
    nolivecd_extra = _(" Starting text mode.")

    if not display_mode:
        display_mode = anaconda.displayMode

    extra_ram = 0
    reason = reason_strict
    if opts.stage2 and opts.stage2.startswith(('http', 'ftp', '@')):
        extra_ram += isys.URL_INSTALL_EXTRA_RAM
        reason = reason_method

    total_ram = int(isys.total_memory() / 1024)
    needed_ram = int((isys.MIN_RAM + extra_ram) / 1024)

    if needed_ram > total_ram:
        from snack import SnackScreen, ButtonChoiceWindow
        if opts.liveinst:
            stdoutLog.warning(reason % (product.productName, needed_ram, total_ram))
            gtk_warning(livecd_title, reason % (product.productName, needed_ram, total_ram))
        else:
            reason += reboot_extra
            screen = SnackScreen()
            ButtonChoiceWindow(screen, _('Fatal Error'),
                               reason % (product.productName, needed_ram, total_ram),
                               buttons = (_("OK"),))
            screen.finish()
        sys.exit(1)

    # override display mode if machine cannot nicely run X
    if display_mode not in ('t', 'c') and not flags.usevnc:
        needed_ram += int(isys.GUI_INSTALL_EXTRA_RAM / 1024)
        reason = reason_graphical

        if needed_ram > total_ram:
            if opts.liveinst:
                reason += livecd_extra
                stdoutLog.warning(reason % (product.productName, needed_ram, total_ram))
                title = livecd_title
                gtk_warning(title, reason % (product.productName, needed_ram, total_ram))
                sys.exit(1)
            else:
                reason += nolivecd_extra
                stdoutLog.warning(reason % (product.productName, needed_ram, total_ram))
                anaconda.displayMode = 't'
                time.sleep(2)

def setupGraphicalLinks():
    for i in ( "imrc", "im_palette.pal", "gtk-2.0", "pango", "fonts",
               "fb.modes"):
        try:
            if os.path.exists("/mnt/runtime/etc/%s" %(i,)):
                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
        except:
            pass

def handleSshPw(anaconda):
    if not anaconda.ksdata:
        return

    from pyanaconda import users
    u = users.Users(anaconda)

    userdata = anaconda.ksdata.sshpw.dataList()
    for ud in userdata:
        if u.checkUserExists(ud.username, root="/"):
            u.setUserPassword(username=ud.username, password=ud.password,
                              isCrypted=ud.isCrypted, lock=ud.lock)
        else:
            u.createUser(name=ud.username, password=ud.password,
                         isCrypted=ud.isCrypted, lock=ud.lock,
                         root="/", mkmailspool=False)

    del u

def createSshKey(algorithm, keyfile):
    path = '/etc/ssh/%s' % (keyfile,)
    argv = ['-q','-t',algorithm,'-f',path,'-C','','-N','']
    log.info("running \"%s\"" % (" ".join(['ssh-keygen']+argv),))

    so = "/tmp/ssh-keygen-%s-stdout.log" % (algorithm,)
    se = "/tmp/ssh-keygen-%s-stderr.log" % (algorithm,)
    iutil.execWithRedirect('ssh-keygen', argv, stdout=so, stderr=se)

def fork_orphan():
    """Forks an orphan.
    
    Returns 1 in the parent and 0 in the orphaned child.
    """
    intermediate = os.fork()
    if not intermediate:
        if os.fork():
            # the intermediate child dies
            os._exit(0)
        return 0;
    # the original process waits for the intermediate child
    os.waitpid(intermediate, 0)
    return 1

def startSsh():
    if iutil.isS390():
        return

    if not fork_orphan():
        os.open("/var/log/lastlog", os.O_RDWR | os.O_CREAT, 0644)
        ssh_keys = {
            'rsa1':'ssh_host_key',
            'rsa':'ssh_host_rsa_key',
            'dsa':'ssh_host_dsa_key',
            }
        for (algorithm, keyfile) in ssh_keys.items():
            createSshKey(algorithm, keyfile)
        sshd = iutil.find_program_in_path("sshd")
        args = [sshd, "-f", "/etc/ssh/sshd_config.anaconda"]
        os.execv(sshd, args)
        sys.exit(1)

def startDebugger(signum, frame):
    import epdb
    epdb.serve(skip=1)

def runRescueMode(anaconda, opts):
    anaconda.rescue = True

    from pyanaconda import rescue

    if anaconda.ksdata:
        anaconda.instClass.configure(anaconda)

        # We need an interface before running kickstart execute methods for
        # storage.
        from snack import SnackScreen
        screen = SnackScreen()
        anaconda.intf = rescue.RescueInterface(screen)

        anaconda.ksdata.execute()

        anaconda.intf = None
        screen.finish()

        # command line 'nomount' overrides kickstart /same for vnc/
        anaconda.rescue_mount = not (opts.rescue_nomount or
                                     anaconda.ksdata.rescue.nomount)

    rescue.runRescue(anaconda)

    # shouldn't get back here
    sys.exit(1)

def setupDisplay(anaconda, opts):
    graphical_failed = 0
    vncS = vnc.VncServer()          # The vnc Server object.
    vncS.anaconda = anaconda

    anaconda.displayMode = opts.display_mode
    anaconda.isHeadless = opts.isHeadless

    if opts.vnc:
        flags.usevnc = 1
        anaconda.displayMode = 'g'
        vncS.recoverVNCPassword()

        # Only consider vncconnect when vnc is a param
        if opts.vncconnect:
            cargs = string.split(opts.vncconnect, ":")
            vncS.vncconnecthost = cargs[0]
            if len(cargs) > 1 and len(cargs[1]) > 0:
                if len(cargs[1]) > 0:
                    vncS.vncconnectport = cargs[1]

    if opts.serial:
        flags.serial = True
    if opts.virtpconsole:
        flags.virtpconsole = opts.virtpconsole

    if opts.xdriver:
        anaconda.xdriver = opts.xdriver
        anaconda.writeXdriver(root="/")

    if not opts.rescue:
        if anaconda.ksdata:
            if anaconda.ksdata.vnc.enabled:
                flags.usevnc = 1
                anaconda.displayMode = 'g'

                if vncS.password == "":
                    vncS.password = anaconda.ksdata.vnc.password

                if vncS.vncconnecthost == "":
                    vncS.vncconnecthost = anaconda.ksdata.vnc.host

                if vncS.vncconnectport == "":
                    vncS.vncconnectport = anaconda.ksdata.vnc.port

            flags.vncquestion = False

        # disable VNC over text question when not enough memory is available
        if iutil.memInstalled() < isys.MIN_GUI_RAM:
            flags.vncquestion = False

        if os.environ.has_key('DISPLAY'):
            flags.preexisting_x11 = True

        if anaconda.displayMode == 't' and flags.vncquestion:
            #we prefer vnc over text mode, so ask about that
            title = _("Would you like to use VNC?")
            message = _("Text mode provides a limited set of installation "
                        "options. It does not allow you to specify your "
                        "own partitioning layout or package selections. "
                        "Would you like to use VNC mode instead?")

            ret = vnc.askVncWindow(title, message)
            if ret != -1:
                anaconda.displayMode = 'g'
                flags.usevnc = 1
                if ret is not None:
                    vncS.password = ret

        log.info("Display mode = %s" % anaconda.displayMode)
        check_memory(anaconda, opts)

        #
        # now determine if we're going to run in GUI or TUI mode
        #
        # if no X server, we have to use text mode
        if not flags.livecdInstall and not iutil.isS390() and \
           not os.access("/usr/bin/Xorg", os.X_OK):
             stdoutLog.warning(_("Graphical installation is not available. "
                                 "Starting text mode."))
             time.sleep(2)
             anaconda.displayMode = 't'

        # s390/iSeries checks
        if anaconda.isHeadless and anaconda.displayMode == "g" and not \
           (flags.preexisting_x11 or flags.usevnc):
            stdoutLog.warning(_("DISPLAY variable not set. Starting text mode."))
            anaconda.displayMode = 't'
            graphical_failed = 1
            time.sleep(2)

        # if DISPLAY not set either vnc server failed to start or we're not
        # running on a redirected X display, so start local X server
        if anaconda.displayMode == 'g' and not flags.preexisting_x11 and \
           not flags.usevnc:
            # The following code depends on no SIGCHLD being delivered,
            # possibly only except the one from a failing X.org. Thus
            # make sure before entering this section that all the other
            # children of anaconda have terminated or were forked into
            # an orphan (which won't deliver a SIGCHLD to mess up the
            # fragile signaling below). start X with its USR1 handler
            # set to ignore.  this will make it send us SIGUSR1 if it
            # succeeds.  if it fails, catch SIGCHLD and bomb out.
            def sigchld_handler(num, frame):
                raise OSError(0, "SIGCHLD caught when trying to start the X server.")

            def sigusr1_handler(num, frame):
                log.debug("X server has signalled a successful start.")

            def preexec_fn():
                signal.signal(signal.SIGUSR1, signal.SIG_IGN)

            old_sigusr1 = signal.signal(signal.SIGUSR1, sigusr1_handler)
            old_sigchld = signal.signal(signal.SIGCHLD, sigchld_handler)
            xout = open("/dev/tty5", "w")
            try:
                proc = subprocess.Popen(["Xorg", "-br",
                                         "-logfile", "/tmp/X.log",
                                         ":1", "vt6", "-s", "1440", "-ac",
                                         "-nolisten", "tcp", "-dpi", "96",
                                         "-noreset"],
                                         close_fds=True,
                                         stdout=xout, stderr=xout,
                                         preexec_fn=preexec_fn)

                signal.pause()
                os.environ["DISPLAY"] = ":1"
                doStartupX11Actions()
            except (OSError, RuntimeError):
                stdoutLog.warning("X startup failed, falling back to text mode")
                anaconda.displayMode = 't'
                graphical_failed = 1
                time.sleep(2)
            finally:
                signal.signal(signal.SIGUSR1, old_sigusr1)
                signal.signal(signal.SIGCHLD, old_sigchld)

        set_x_resolution(opts.runres)

        if anaconda.displayMode == 't' and graphical_failed and \
             not anaconda.ksdata:
            ret = vnc.askVncWindow()
            if ret != -1:
                anaconda.displayMode = 'g'
                flags.usevnc = 1
                if ret is not None:
                    vncS.password = ret

        # if they want us to use VNC do that now
        if anaconda.displayMode == 'g' and flags.usevnc:
            runVNC()
            doStartupX11Actions()

        # with X running we can initialize the UI interface
        anaconda.initInterface()
        anaconda.instClass.configure(anaconda)

def runDogtail(opts):
    import urlgrabber

    try:
        fr = urlgrabber.urlopen(opts.dogtail)
    except urlgrabber.grabber.URLGrabError as e:
        log.error("Could not retrieve Dogtail script from %s.\nError "
                  "was\n%s" % (opts.dogtail, e))
        return

    (fw, testcase) = mkstemp(prefix='testcase.py.', dir='/tmp')
    os.write(fw, fr.read())
    fr.close()
    os.close(fw)

    try:
        # download completed, run the test
        if not os.fork():
            # we are in the child
            os.chmod(testcase, 0755)
            os.execv(testcase, [testcase])
            sys.exit(0)
        else:
            # we are in the parent, sleep to give time for the testcase
            # to initialize
            # todo: is this needed, how to avoid possible race conditions
            time.sleep(1)
    except OSError as e:
        log.error("Exception %s while running Dogtail testcase" % e)


if __name__ == "__main__":
    setupPythonPath()

    # Allow a file to be loaded as early as possible
    try:
        import updates_disk_hook
    except ImportError:
        pass

    # this handles setting up updates for pypackages to minimize the set needed
    setupPythonUpdates()

    # do this early so we can set flags before initializing logging
    (opts, args) = parseOptions()
    from pyanaconda.flags import flags
    if opts.images:
        flags.imageInstall = True

    # Set up logging as early as possible.
    import logging
    from pyanaconda import anaconda_log
    anaconda_log.init()

    log = logging.getLogger("anaconda")
    stdoutLog = logging.getLogger("anaconda.stdout")

    if os.geteuid() != 0:
        stdoutLog.error("anaconda must be run as root.")
        sys.exit(0)

    # pull this in to get product name and versioning
    from pyanaconda import product

    from pyanaconda import isys
    isys.initLog()

    import signal, string, time
    import warnings

    from pyanaconda import iutil
    from pyanaconda import vnc
    from pyanaconda import users
    from pyanaconda import kickstart

    import gettext
    _ = lambda x: gettext.ldgettext("anaconda", x)

    from pyanaconda import Anaconda
    anaconda = Anaconda()
    warnings.showwarning = AnacondaShowWarning
    iutil.setup_translations(gettext)

    # reset python's default SIGINT handler
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    signal.signal(signal.SIGSEGV, isys.handleSegv)

    setupEnvironment()
    # make sure we have /var/log soon, some programs fail to start without it
    iutil.mkdirChain("/var/log")

    pidfile = open("/var/run/anaconda.pid", "w")
    pidfile.write("%s\n" % (os.getpid(),))
    del pidfile
    # add our own additional signal handlers
    signal.signal(signal.SIGHUP, startDebugger)

    anaconda.opts = opts

    # check memory, just the text mode for now:
    check_memory(anaconda, opts, 't')

    if opts.unsupportedMode:
        stdoutLog.error("Running anaconda in %s mode is no longer supported." % opts.unsupportedMode)
        sys.exit(0)

    # Now that we've got arguments, do some extra processing.
    setupLoggingFromOpts(opts)

    # Default is to prompt to mount the installed system.
    anaconda.rescue_mount = not opts.rescue_nomount

    if opts.dlabel: #autodetected driverdisc in use
        flags.dlabel = True

    if opts.noipv4:
        flags.useIPv4 = False

    if opts.noipv6:
        flags.useIPv6 = False

    if opts.proxy:
        anaconda.proxy = opts.proxy

        if opts.proxyAuth:
            filename = opts.proxyAuth
            ret = open(filename, "r").readlines()
            os.unlink(filename)

            anaconda.proxyUsername = ret[0].rstrip()
            if len(ret) == 2:
                anaconda.proxyPassword = ret[1].rstrip()

    if opts.updateSrc:
        anaconda.updateSrc = opts.updateSrc

    if opts.method:
        if opts.method[0] == '@':
            opts.method = expandFTPMethod(opts.method)

        anaconda.setMethodstr(opts.method)
    else:
        anaconda.methodstr = None

    if opts.stage2:
        if opts.stage2[0] == '@':
            opts.stage2 = expandFTPMethod(opts.stage2)

        anaconda.stage2 = opts.stage2

    if opts.noverifyssl:
        flags.noverifyssl = True

    if opts.liveinst:
        flags.livecdInstall = True

    if opts.module:
        for mod in opts.module:
            (path, name) = string.split(mod, ":")
            anaconda.extraModules.append((path, name))

    if opts.ibft:
        flags.ibft = 1

    if opts.iscsi:
        flags.iscsi = 1

    if opts.targetArch:
        flags.targetarch = opts.targetArch

    # set flags 
    flags.dmraid = opts.dmraid
    flags.mpath = opts.mpath
    flags.selinux = opts.selinux

    if not flags.livecdInstall and not flags.imageInstall:
        startAuditDaemon()

    # setup links required for all install types
    for i in ( "services", "protocols", "nsswitch.conf", "joe", "selinux",
               "mke2fs.conf" ):
        try:
            if os.path.exists("/mnt/runtime/etc/" + i):
                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
        except:
            pass

    if opts.debug:
        flags.debug = True

    log.info("anaconda called with cmdline = %s" %(sys.argv,))
    log.info("Default encoding = %s " % sys.getdefaultencoding())
    setupDisplay(anaconda, opts)

    image_count = 0
    for image in opts.images:
        image_spec = image.rsplit(":", 1)
        path = image_spec[0]
        if len(image_spec) == 2 and image_spec[1].strip():
            name = image_spec[1].strip()
        else:
            name = os.path.splitext(os.path.basename(path))[0]

        if "/" in name or name in anaconda.storage.config.diskImages.keys():
            name = "diskimg%d" % image_count

        log.info("naming disk image '%s' '%s'" % (path, name))
        anaconda.storage.config.diskImages[name] = path
        image_count += 1
        flags.imageInstall = True

    if image_count:
        anaconda.storage.setupDiskImages()

    # This is the one place we do all kickstart file parsing.
    if opts.ksfile:
        kickstart.preScriptPass(anaconda, opts.ksfile)
        anaconda.ksdata = kickstart.parseKickstart(anaconda, opts.ksfile)
        opts.rescue = opts.rescue or anaconda.ksdata.rescue.rescue

    if flags.sshd:
        # we need to have a libuser.conf that points to the installer root for
        # sshpw, but after that we start sshd, we need one that points to the
        # install target.
        luserConf = users.createLuserConf(instPath="")
        handleSshPw(anaconda)
        startSsh()
        del(os.environ["LIBUSER_CONF"])

    users.createLuserConf(anaconda.rootPath)

    if opts.rescue:
        runRescueMode(anaconda, opts)

    # comment out the next line to make exceptions non-fatal
    from pyanaconda.exception import initExceptionHandling
    anaconda.mehConfig = initExceptionHandling(anaconda)

    # add our own additional signal handlers
    signal.signal(signal.SIGUSR2, lambda signum, frame: anaconda.dumpState())

    # download and run Dogtail script
    if opts.dogtail:
        runDogtail(opts)

    if opts.lang:
        # this is lame, but make things match what we expect (#443408)
        opts.lang = opts.lang.replace(".utf8", ".UTF-8")
        anaconda.dispatch.skipStep("language", permanent = 1)
        anaconda.instLanguage.instLang = opts.lang
        anaconda.instLanguage.systemLang = opts.lang
        anaconda.timezone.setTimezoneInfo(anaconda.instLanguage.getDefaultTimeZone(anaconda.rootPath))

    if opts.keymap:
        anaconda.dispatch.skipStep("keyboard", permanent = 1)
        anaconda.keyboard.set(opts.keymap)
        anaconda.keyboard.activate()

    if anaconda.ksdata:
        from pyanaconda import storage
        storage.storageInitialize(anaconda)

        # Now having initialized storage, we can apply all the other kickstart
        # commands.  This gives us the ability to check that storage commands
        # are correctly formed and refer to actual devices.
        anaconda.ksdata.execute()

    # set up the headless case
    if anaconda.isHeadless:
        anaconda.dispatch.skipStep("keyboard", permanent = 1)

    if not anaconda.ksdata:
        anaconda.instClass.setSteps(anaconda)
    else:
        kickstart.setSteps(anaconda)

    try:
        anaconda.dispatch.run()
    except SystemExit, code:
        anaconda.intf.shutdown()

    if anaconda.ksdata and anaconda.ksdata.reboot.eject:
        for drive in anaconda.storage.devicetree.devices:
            if drive.type != "cdrom":
                continue

            log.info("attempting to eject %s" % drive.path)
            drive.eject()

    del anaconda.intf

# vim:tw=78:ts=4:et:sw=4
