7004610 Update Text Installer to use CUD
authorKaren Tung <karen.tung@oracle.com>
Wed, 11 May 2011 15:30:11 -0700
changeset 1121 670325895b19
parent 1120 5512a4039f2e
child 1122 d30415c63b07
7004610 Update Text Installer to use CUD 7039676 TransferCPIO checkpoint sometimes won't calculate install size correctly 7043391 Wrong definition for VFSTAB_FILE variable in target controller
usr/src/Makefile.master
usr/src/Targetdirs
usr/src/cmd/Makefile.targ
usr/src/cmd/distro_const/checkpoints/Makefile
usr/src/cmd/distro_const/checkpoints/boot_archive_configure.py
usr/src/cmd/distro_const/checkpoints/pkg_img_mod.py
usr/src/cmd/distro_const/checkpoints/xslt/Makefile
usr/src/cmd/distro_const/checkpoints/xslt/doc2_media_transfer.xslt
usr/src/cmd/slim-install/svc/net-assembly
usr/src/cmd/system-config/xslt/doc2sc_profile.xslt
usr/src/cmd/text-install/Makefile
usr/src/cmd/text-install/__init__.py
usr/src/cmd/text-install/disk_selection.py
usr/src/cmd/text-install/disk_window.py
usr/src/cmd/text-install/fdisk_partitions.py
usr/src/cmd/text-install/install_progress.py
usr/src/cmd/text-install/install_status.py
usr/src/cmd/text-install/log_viewer.py
usr/src/cmd/text-install/osol_install/__init__.py
usr/src/cmd/text-install/osol_install/profile/Makefile
usr/src/cmd/text-install/osol_install/profile/__init__.py
usr/src/cmd/text-install/osol_install/profile/disk_info.py
usr/src/cmd/text-install/osol_install/profile/disk_space.py
usr/src/cmd/text-install/osol_install/profile/install_profile.py
usr/src/cmd/text-install/osol_install/profile/partition_info.py
usr/src/cmd/text-install/osol_install/profile/slice_info.py
usr/src/cmd/text-install/osol_install/text_install/Makefile
usr/src/cmd/text-install/osol_install/text_install/__init__.py
usr/src/cmd/text-install/osol_install/text_install/disk_selection.py
usr/src/cmd/text-install/osol_install/text_install/disk_window.py
usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py
usr/src/cmd/text-install/osol_install/text_install/install_progress.py
usr/src/cmd/text-install/osol_install/text_install/install_status.py
usr/src/cmd/text-install/osol_install/text_install/log_viewer.py
usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py
usr/src/cmd/text-install/osol_install/text_install/summary.py
usr/src/cmd/text-install/osol_install/text_install/test/test_disk_select.py
usr/src/cmd/text-install/osol_install/text_install/test/test_disk_window.py
usr/src/cmd/text-install/osol_install/text_install/test/test_text_install.py
usr/src/cmd/text-install/osol_install/text_install/text-install
usr/src/cmd/text-install/osol_install/text_install/ti_install.py
usr/src/cmd/text-install/osol_install/text_install/ti_install_utils.py
usr/src/cmd/text-install/osol_install/text_install/welcome.py
usr/src/cmd/text-install/partition_edit_screen.py
usr/src/cmd/text-install/progress.py
usr/src/cmd/text-install/summary.py
usr/src/cmd/text-install/test/test_disk_select.py
usr/src/cmd/text-install/test/test_disk_window.py
usr/src/cmd/text-install/test/test_text_install.py
usr/src/cmd/text-install/text-install
usr/src/cmd/text-install/ti_install.py
usr/src/cmd/text-install/ti_install_utils.py
usr/src/cmd/text-install/ti_target_utils.py
usr/src/cmd/text-install/welcome.py
usr/src/lib/install_engine/__init__.py
usr/src/lib/install_manifest/dtd/Makefile
usr/src/lib/install_manifest/dtd/media-transfer.dtd
usr/src/lib/install_target/controller.py
usr/src/lib/install_transfer/Makefile
usr/src/lib/install_transfer/cpio.py
usr/src/lib/install_transfer/media_transfer.py
usr/src/pkg/manifests/install-distribution-constructor.mf
usr/src/pkg/manifests/system-install-text-install.mf
usr/src/pkg/manifests/system-library-install.mf
usr/src/tools/tests/tests.nose
--- a/usr/src/Makefile.master	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/Makefile.master	Wed May 11 15:30:11 2011 -0700
@@ -98,7 +98,6 @@
 ROOTPYTHONVENDORINSTALL=	$(ROOTPYTHONVENDOR)/osol_install
 ROOTPYTHONVENDORINSTALLAI=	$(ROOTPYTHONVENDORINSTALL)/auto_install
 ROOTPYTHONVENDORINSTALLPROF=    $(ROOTPYTHONVENDORINSTALL)/profile
-ROOTPYTHONVENDORINSTALLTI=	$(ROOTPYTHONVENDORINSTALL)/text_install
 ROOTPYTHONVENDORSOLINSTALL=	$(ROOTPYTHONVENDOR)/solaris_install
 ROOTPYTHONVENDORSOLINSTALLBOOT =	$(ROOTPYTHONVENDORSOLINSTALL)/boot
 ROOTPYTHONVENDORSOLINSTALLDATACACHE= $(ROOTPYTHONVENDORSOLINSTALL)/data_object
@@ -125,6 +124,7 @@
 ROOTPYTHONVENDORSOLINSTALLTARGETLIBDISKMGT = $(ROOTPYTHONVENDORSOLINSTALLTARGET)/libdiskmgt
 ROOTPYTHONVENDORSOLINSTALLTARGETLIBNVPAIR = $(ROOTPYTHONVENDORSOLINSTALLTARGET)/libnvpair
 ROOTPYTHONVENDORSOLINSTALLTARGETSHADOW = $(ROOTPYTHONVENDORSOLINSTALLTARGET)/shadow
+ROOTPYTHONVENDORSOLINSTALLTI=	$(ROOTPYTHONVENDORSOLINSTALL)/text_install
 ROOTPYTHONVENDORINSTALLTRANSFER =       $(ROOTPYTHONVENDORSOLINSTALL)/transfer
 ROOTPYTHONVENDORBOOTMGMT=	$(ROOTPYTHONVENDOR)/bootmgmt
 ROOTPYTHONVENDORBOOTMGMTBKND=	$(ROOTPYTHONVENDORBOOTMGMT)/backend
--- a/usr/src/Targetdirs	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/Targetdirs	Wed May 11 15:30:11 2011 -0700
@@ -65,7 +65,6 @@
 	/usr/lib/python2.6/vendor-packages/osol_install \
 	/usr/lib/python2.6/vendor-packages/osol_install/auto_install \
 	/usr/lib/python2.6/vendor-packages/osol_install/profile \
-	/usr/lib/python2.6/vendor-packages/osol_install/text_install \
 	/usr/lib/python2.6/vendor-packages/solaris_install/auto_install \
 	/usr/lib/python2.6/vendor-packages/solaris_install/auto_install/checkpoints \
 	/usr/lib/python2.6/vendor-packages/solaris_install/distro_const \
@@ -89,6 +88,7 @@
 	/usr/lib/python2.6/vendor-packages/solaris_install/target/libdiskmgt \
 	/usr/lib/python2.6/vendor-packages/solaris_install/target/libnvpair \
 	/usr/lib/python2.6/vendor-packages/solaris_install/target/shadow \
+	/usr/lib/python2.6/vendor-packages/solaris_install/text_install \
 	/usr/lib/python2.6/vendor-packages/solaris_install/transfer \
 	/usr/lib/python2.6/vendor-packages/terminalui \
 	/usr/sbin \
--- a/usr/src/cmd/Makefile.targ	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/Makefile.targ	Wed May 11 15:30:11 2011 -0700
@@ -92,7 +92,7 @@
 $(ROOTPYTHONVENDORINSTALLPROF):
 	$(INS.dir)
 
-$(ROOTPYTHONVENDORINSTALLTI):
+$(ROOTPYTHONVENDORSOLINSTALLTI):
 	$(INS.dir)
 
 $(ROOTPYTHONVENDORSOLINSTALLJS2AI):
@@ -126,7 +126,7 @@
 $(ROOTPYTHONVENDORINSTALLAI)/%: %
 	$(CP_P.file)
 
-$(ROOTPYTHONVENDORINSTALLTI)/%: %
+$(ROOTPYTHONVENDORSOLINSTALLTI)/%: %
 	$(CP_P.file)
 
 $(ROOTPYTHONVENDORSCI)/%: %
--- a/usr/src/cmd/distro_const/checkpoints/Makefile	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/distro_const/checkpoints/Makefile	Wed May 11 15:30:11 2011 -0700
@@ -30,7 +30,7 @@
 clobber:=	TARGET=	clobber
 install:=	TARGET=	install
 
-SUBDIRS=	defaultfiles
+SUBDIRS=	defaultfiles xslt
 
 PYMODULES=	__init__.py \
 		ai_publish_pkg.py \
--- a/usr/src/cmd/distro_const/checkpoints/boot_archive_configure.py	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/distro_const/checkpoints/boot_archive_configure.py	Wed May 11 15:30:11 2011 -0700
@@ -34,6 +34,10 @@
 
 from pkg.cfgfiles import UserattrFile
 from solaris_install.data_object.data_dict import DataObjectDict
+from solaris_install.transfer.info import Software, Source, Destination, \
+    CPIOSpec, Dir
+from solaris_install.transfer.media_transfer import TRANSFER_ROOT, \
+    TRANSFER_MISC, INSTALL_TARGET_VAR
 from solaris_install.distro_const import DC_LABEL
 from solaris_install.engine import InstallEngine
 from solaris_install.engine.checkpoint import AbstractCheckpoint as Checkpoint
@@ -164,6 +168,16 @@
         if not os.path.islink("opt"):
             os.symlink("mnt/misc/opt", "opt")
 
+        tr_uninstall = CPIOSpec()
+        tr_uninstall.action = CPIOSpec.UNINSTALL
+        tr_uninstall.contents = ["opt"]
+
+        root_tr_software_node = self.doc.persistent.get_descendants(\
+                            name=TRANSFER_ROOT, class_type=Software,
+                            not_found_is_err=True)[0]
+
+        root_tr_software_node.insert_children(tr_uninstall)
+
         # copy the SMF repository from pkg_image_path to ba_build
         pkg_img_path_repo = os.path.join(self.pkg_img_path,
                                          "etc/svc/repository.db")
@@ -235,6 +249,7 @@
         # change to the pkg_img_path directory
         os.chdir(self.pkg_img_path)
 
+        misc_symlinks = [] #keep track of all the symlinks created
         for rootdir in ["etc", "var"]:
             for root, dirs, files in os.walk(rootdir):
                 for f in files:
@@ -261,6 +276,42 @@
 
                         os.chdir(cwd)
 
+                        misc_symlinks.append(os.path.join(root, f))
+
+        tr_uninstall = CPIOSpec()
+        tr_uninstall.action = CPIOSpec.UNINSTALL
+        tr_uninstall.contents = misc_symlinks
+
+        # Add that into the software transfer list.  The list of files
+        # to uninstall MUST go before the contents to be installed
+        # from /mnt/misc
+        root_tr_software_node = self.doc.persistent.get_descendants( \
+            name=TRANSFER_ROOT, class_type=Software, not_found_is_err=True)[0]
+
+        root_tr_software_node.insert_children(tr_uninstall)
+
+        #add Software node to install items from /mnt/misc
+
+        src_path = Dir("/mnt/misc")
+        src = Source()
+        src.insert_children(src_path)
+
+        dst_path = Dir(INSTALL_TARGET_VAR)
+        dst = Destination()
+        dst.insert_children(dst_path)
+
+        tr_install_misc = CPIOSpec()
+        tr_install_misc.action = CPIOSpec.INSTALL
+        tr_install_misc.contents = ["."]
+        # must use the following cpio option instead of the default "-pdum"
+        tr_install_misc.cpio_args = "-pdm"
+
+        misc_software_node = Software(TRANSFER_MISC, type="CPIO")
+        misc_software_node.insert_children([src, dst, tr_install_misc])
+        self.doc.persistent.insert_children(misc_software_node)
+
+        self.logger.debug(str(self.doc.persistent))
+
     def parse_doc(self):
         """ class method for parsing data object cache (DOC) objects for use by
         the checkpoint.
@@ -275,6 +326,40 @@
         except KeyError:
             raise RuntimeError("Error retrieving a value from the DOC")
 
+    def add_root_transfer_to_doc(self):
+        """ Adds the list of files of directories to be transferred
+            to the DOC 
+        """
+        if self.doc is None:
+            self.doc = InstallEngine.get_instance().data_object_cache
+
+        src_path = Dir("/")
+        src = Source()
+        src.insert_children(src_path)
+
+        dst_path = Dir(INSTALL_TARGET_VAR)
+        dst = Destination()
+        dst.insert_children(dst_path)
+
+        dot_node = CPIOSpec()
+        dot_node.action = CPIOSpec.INSTALL
+        dot_node.contents = ["."]
+
+        usr_node = CPIOSpec()
+        usr_node.action = CPIOSpec.INSTALL
+        usr_node.contents = ["usr"]
+
+        dev_node = CPIOSpec()
+        dev_node.action = CPIOSpec.INSTALL
+        dev_node.contents = ["dev"]
+
+        software_node = Software(TRANSFER_ROOT, type="CPIO")
+        software_node.insert_children([src, dst, dot_node, usr_node, dev_node])
+
+        self.doc.persistent.insert_children(software_node)
+
+        self.logger.debug(str(self.doc.persistent))
+
     def execute(self, dry_run=False):
         """ Primary execution method used by the Checkpoint parent class.
         dry_run is not used in DC
@@ -284,6 +369,8 @@
 
         self.parse_doc()
 
+        self.add_root_transfer_to_doc()
+
         # configure various boot archive files
         self.configure_system()
 
@@ -314,6 +401,8 @@
 
         self.parse_doc()
 
+        self.add_root_transfer_to_doc()
+
         # configure various boot archive files
         self.configure_system()
 
@@ -420,6 +509,8 @@
 
         self.parse_doc()
 
+        self.add_root_transfer_to_doc()
+
         # configure various boot archive files
         self.configure_system()
 
--- a/usr/src/cmd/distro_const/checkpoints/pkg_img_mod.py	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/distro_const/checkpoints/pkg_img_mod.py	Wed May 11 15:30:11 2011 -0700
@@ -39,6 +39,11 @@
 from solaris_install.distro_const import DC_LABEL
 from solaris_install.engine import InstallEngine
 from solaris_install.engine.checkpoint import AbstractCheckpoint as Checkpoint
+from solaris_install.transfer.info import Software, Source, Destination, \
+    CPIOSpec, Dir
+from solaris_install.transfer.media_transfer import TRANSFER_MEDIA, \
+    INSTALL_TARGET_VAR, MEDIA_DIR_VAR, TRANSFER_MANIFEST_NAME
+from solaris_install.manifest.writer import ManifestWriter
 
 # load a table of common unix cli calls
 import solaris_install.distro_const.cli as cli
@@ -258,8 +263,36 @@
         shutil.rmtree(os.path.join(self.pkg_img_path, "usr"),
                       ignore_errors=True)
 
-    def create_livecd_content_file(self):
-        """ class method to create the .livecd-cdrom-content file
+    def add_content_list_to_doc(self, content_list):
+        src_path = Dir(MEDIA_DIR_VAR)
+        src = Source()
+        src.insert_children(src_path)
+
+        dst_path = Dir(INSTALL_TARGET_VAR)
+        dst = Destination()
+        dst.insert_children(dst_path)
+
+        media_install = CPIOSpec()
+        media_install.action = CPIOSpec.INSTALL
+        media_install.contents = content_list
+
+        media_soft_node = Software(TRANSFER_MEDIA, type="CPIO")
+        media_soft_node.insert_children([src, dst, media_install])
+
+        # Add that into the software transfer list.  
+        self.doc.persistent.insert_children(media_soft_node)
+
+        # call manifest writer to write out the content of
+        # the transfer manifest
+        manifest_out = os.path.join(self.pkg_img_path, TRANSFER_MANIFEST_NAME)
+        xslt_name = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                 "xslt", "doc2_media_transfer.xslt")
+        manifest_writer = ManifestWriter("manifest-writer",
+                                         manifest_out, xslt_file=xslt_name)
+        manifest_writer.write(self.doc)
+
+    def populate_livecd_content(self):
+        """ class method to populate content of live media's root into DOC
         """
         # save the current working directory
         cwd = os.getcwd()
@@ -272,22 +305,20 @@
             for f in files:
                 if not f.endswith(".zlib") and not f.endswith(".image_info") \
                     and not f.endswith("boot_archive") and not \
-                    f.endswith(".livecd-cdrom-content"):
+                    f.endswith(".media-transfer.xml"):
                     content_list.append(os.path.join(root, f))
             for d in dirs:
                 content_list.append(os.path.join(root, d))
 
-        with open(".livecd-cdrom-content", "w") as fh:
-            for entry in content_list:
-                fh.write(entry + "\n")
+        self.add_content_list_to_doc(content_list)
 
         os.chdir(cwd)
-
-    def create_save_list(self):
+    
+    def populate_save_list(self):
         '''Store a list of files under the 'save' directory. Net-booted
         text installer uses this list to determine what files it needs from
         the boot server
-
+        
         '''
         save_files = []
         save_dir = os.path.join(self.pkg_img_path, "save")
@@ -297,11 +328,8 @@
                                           start=self.pkg_img_path)
                 save_files.append(relpath)
 
-        save_list = os.path.join(self.pkg_img_path, "save_list")
-        with open(save_list, "w") as save_fh:
-            for entry in save_files:
-                save_fh.write(entry + "\n")
-
+        self.add_content_list_to_doc(save_files)
+        
     def execute(self, dry_run=False):
         """Customize the pkg_image area. Assumes that a populated pkg_image
            area exists and that the boot_archive has been built
@@ -319,9 +347,7 @@
 
         # create the /mnt/misc archive
         self.create_misc_archive()
-
-        self.create_save_list()
-
+        
 
 class LiveCDPkgImgMod(PkgImgMod, Checkpoint):
     """ LiveCDPkgImgMod - class to modify the pkg_image directory after the
@@ -380,8 +406,8 @@
         # strip the /platform directory
         self.strip_platform()
 
-        # create the .livecd-cdrom-content file
-        self.create_livecd_content_file()
+        # populate live cd's content into DOC
+        self.populate_livecd_content()
 
 
 class TextPkgImgMod(PkgImgMod, Checkpoint):
@@ -422,23 +448,56 @@
                 self.strip_x86_platform()
             else:
                 self.strip_sparc_platform()
-
-            # create the .livecd-cdrom-content file
-            self.create_livecd_content_file()
+    
+            # populate live cd's content into DOC
+            self.populate_livecd_content()
         finally:
             # return to the initial directory
             os.chdir(cwd)
 
-        self.create_save_list()
-
-# Currently, no difference between AIPkgImgMod and TextPkgImgMod.
-# Defined as an empty subclass here so that manifests can
-# reference AIPkgImgMod now, and if the classes diverge,
-# old manifests won't need updating
-
 
 class AIPkgImgMod(TextPkgImgMod):
     """ AIPkgImgMod - class to modify the pkg_image directory after the boot
     archive is built for AI distributions
     """
-    pass
+
+    DEFAULT_ARG = {"compression_type": "gzip"}
+
+    def __init__(self, name, arg=DEFAULT_ARG):
+        super(AIPkgImgMod, self).__init__(name, arg)
+
+    def execute(self, dry_run=False):
+        """ Customize the pkg_image area. Assumes that a populated pkg_image
+        area exists and that the boot_archive has been built
+        """
+        self.logger.info("=== Executing Pkg Image Modification Checkpoint ===")
+
+        self.parse_doc()
+
+        # clean up the root of the package image path
+        self.strip_root()
+
+        # create the /usr archive
+        self.create_usr_archive()
+
+        # create the /mnt/misc archive
+        self.create_misc_archive()
+
+        # get the platform of the system
+        arch = platform.processor()
+
+        # save the current working directory
+        cwd = os.getcwd()
+        try:
+            # clean up the package image path based on the platform
+            if arch == "i386":
+                self.strip_x86_platform()
+            else:
+                self.strip_sparc_platform()
+    
+            # populate the value from the save directory into the DOC
+            self.populate_save_list()
+
+        finally:
+            # return to the initial directory
+            os.chdir(cwd)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/checkpoints/xslt/Makefile	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,53 @@
+# 
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+include ../../../Makefile.cmd
+
+all:=		TARGET=	all
+clean:=		TARGET=	clean
+clobber:=	TARGET=	clobber
+install:=	TARGET=	install
+
+XSLT_FILES=	doc2_media_transfer.xslt
+
+ROOTXSLT_DIR = $(ROOTPYTHONVENDORINSTALLDCCHKPT)/xslt
+ROOTXSLT_FILES= $(XSLT_FILES:%=$(ROOTXSLT_DIR)/%)
+
+all:		
+
+clean:	
+
+clobber: clean
+
+$(ROOTXSLT_DIR):
+	$(INS.dir)
+
+$(ROOTXSLT_DIR)/%: %
+	$(INS.file)
+
+install: $(ROOTXSLT_DIR) .WAIT $(ROOTXSLT_FILES)
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/distro_const/checkpoints/xslt/doc2_media_transfer.xslt	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+-->
+
+<!-- Extract the Software nodes we constructed from the varies -->
+<!-- checkpoints into a XML file to be stored in the image. -->
+<!-- The software node names we specified here must match the ones -->
+<!-- used during the image construction process -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+    <xsl:output method="xml" indent="yes" encoding="UTF-8" doctype-system="file:///usr/share/install/media-transfer.dtd"/>
+
+    <xsl:template match="/">
+        <media_transfer>
+            <xsl:copy-of select="//software[@name='transfer-root']"/>
+            <xsl:copy-of select="//software[@name='transfer-misc']"/>
+            <xsl:copy-of select="//software[@name='transfer-media']"/>
+        </media_transfer>
+    </xsl:template>
+</xsl:stylesheet>
--- a/usr/src/cmd/slim-install/svc/net-assembly	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/slim-install/svc/net-assembly	Wed May 11 15:30:11 2011 -0700
@@ -60,10 +60,6 @@
 # Image Info file (needed for x86 AI, and both for Text Installs)
 IMAGE_INFO=".image_info"
 
-# Save folder information (needed for Text Installs)
-SAVE="save"
-SAVE_LIST="save_list"
-
 # Sparc installation configuration
 INSTALL_CONF_FILE="install.conf"
 INSTALL_CONF_SPEC="/tmp/$INSTALL_CONF_FILE"
@@ -251,11 +247,11 @@
 for file in $SOLARIS_ZLIB $SOLARISMISC_ZLIB $IMAGE_INFO $config_file; do
 
 	print "Downloading $file" > /dev/msglog
-	$WGET --continue --tries=$TRIES --waitretry=$WAITRETRY \
-	    --timeout=$TIMEOUT ${url}/$file -O /tmp/$file >/dev/msglog 2>&1
+        $WGET --continue --tries=$TRIES --waitretry=$WAITRETRY \
+            --timeout=$TIMEOUT ${url}/$file -O /tmp/$file >/dev/msglog 2>&1
 
-	# if wget exits with failure, then exit 
-	if [ $? -ne 0 ]; then
+        # if wget exits with failure, then exit
+        if [ $? -ne 0 ]; then
 		print "Could not obtain $url/$file from install server" \
 		    > /dev/msglog
 		print "Please verify that the install server is correctly" \
@@ -337,29 +333,6 @@
 #
 if [ "$TEXT_FLAG" == "true" ]; then
 	
-	# Retrieve the 'save' files (needed by remove_livecd_environment ICT)
-	cd /tmp
-	$WGET -x -i $url/$SAVE_LIST > /dev/msglog 2>&1
-	if [ "$?" != "0" ]; then
-		echo "ERROR: Failed to download save folder contents" > /dev/msglog
-		exit $SMF_EXIT_ERR_FATAL
-	fi
-	save_folder=$(print $url | $SED 's#.*//##')/$SAVE
-	cd -
-
-	# When net-booted, only the contents of /.cdrom/save
-	# (catalogued in the save_list)
-	# are relevant to the '.livecd-cdrom-content' file
-	$WGET $url/$SAVE_LIST -O /tmp/.livecd-cdrom-content
-	
-
-	# Link all of the downloaded files to where they should be in order to mimic CD
-	ln -s /tmp/solarismisc.zlib /.cdrom/solarismisc.zlib
-	ln -s /.volsetid /.cdrom/.volsetid 
-	ln -s /tmp/.image_info /.cdrom/.image_info
-	ln -s /tmp/.livecd-cdrom-content /.cdrom/.livecd-cdrom-content
-	ln -s /tmp/$save_folder /.cdrom/save
-
 	$SVCADM disable -s $CLI_LOGIN 
 	if [ "$?" != "0" ]; then
 		echo "svcadm failed to disable client login" > /dev/msglog
--- a/usr/src/cmd/system-config/xslt/doc2sc_profile.xslt	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/system-config/xslt/doc2sc_profile.xslt	Wed May 11 15:30:11 2011 -0700
@@ -33,8 +33,7 @@
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:output method="xml" indent="yes" encoding="UTF-8" doctype-system="/usr/share/lib/xml/dtd/service_bundle.dtd.1"/>
 
-    <xsl:template match="//service_bundle">
-    	<xsl:copy-of select="."/>
-    </xsl:template>
-
+    <xsl:template match="/">
+        <xsl:copy-of select="//service_bundle[@name='sysconfig']"/>
+    </xsl:template> 
 </xsl:stylesheet>
--- a/usr/src/cmd/text-install/Makefile	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/cmd/text-install/Makefile	Wed May 11 15:30:11 2011 -0700
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 
 include ../Makefile.cmd
@@ -30,17 +29,65 @@
 clobber:=	TARGET= clobber
 install:=	TARGET= install
 
-SUBDIRS=	osol_install/text_install osol_install/profile svc helpfiles
+SUBDIRS=        svc helpfiles
+
+MSG_DOMAIN =	textinstall
+
+PROGS=		text-install
+
+PYMODULES=	__init__.py \
+		disk_selection.py \
+		disk_window.py \
+		fdisk_partitions.py \
+		install_progress.py \
+		install_status.py \
+		log_viewer.py \
+		partition_edit_screen.py \
+                progress.py \
+		summary.py \
+		ti_install.py \
+		ti_install_utils.py \
+                ti_target_utils.py \
+		welcome.py
+
+PYCMODULES=     $(PYMODULES:%.py=%.pyc)
+
+ROOTPROGS=      $(PROGS:%=$(ROOTUSRBIN)/%)
+
+ROOTPYMODULES=  $(PYMODULES:%=$(ROOTPYTHONVENDORSOLINSTALLTI)/%)
+
+ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORSOLINSTALLTI)/%)
+
+MSGFILES =	$(PYMODULES)
+
+.PARALLEL:	$(SUBDIRS)
 
 .KEEP_STATE:
 
-all:	$(SUBDIRS)
+all:	python $(PROGS) $(SUBDIRS)
 
-clean:	$(SUBDIRS)
+clean: $(SUBDIRS)
+	rm -f *.pyc  $(MSG_DOMAIN).po*
 
 clobber: clean
 
-install: all $(SUBDIRS)
+install: all .WAIT $(SUBDIRS) .WAIT $(ROOTPROGS) \
+	$(ROOTPYTHONVENDOR) \
+	$(ROOTPYTHONVENDORSOLINSTALL) \
+	$(ROOTPYTHONVENDORSOLINSTALLTI) \
+	$(ROOTPYMODULES) \
+	$(ROOTPYCMODULES) \
+	.WAIT msgs
+
+python:
+	$(PYTHON) -m compileall -l $(@D)
+
+msgs:	$(MSG_DOMAIN).po
+
+$(MSG_DOMAIN).po: $(PYMODULES)
+	@echo "Making messages file $(MSG_DOMAIN).po"
+	$(GNUXGETTEXT) $(GNUXGETFLAGS) -d $(MSG_DOMAIN) \
+		$(MSGFILES)
 
 $(SUBDIRS): FRC
 	cd $@; pwd; echo $(TARGET); $(MAKE) $(TARGET)
@@ -48,4 +95,3 @@
 FRC:
 
 include ../Makefile.targ
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/__init__.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,410 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Text / (n)Curses based UI for installing Oracle Solaris
+'''
+
+import gettext
+
+# Variables used by modules this module imports
+# Defined here to avoid circular import errors
+_ = gettext.translation("textinstall", "/usr/share/locale",
+                        fallback=True).ugettext
+RELEASE = {"release": _("Oracle Solaris")}
+TUI_HELP = "/usr/share/text-install/help"
+
+# Names of registered checkpoints.
+TARGET_DISCOVERY = "TargetDiscovery"
+TARGET_INIT = "TargetInitialization"
+TRANSFER_PREP = "PrepareTransfer"
+CLEANUP_CPIO_INSTALL = "cleanup-cpio-install"
+INIT_SMF = "initialize-smf"
+BOOT_CONFIG = "boot-configuration"
+DUMP_ADMIN = "update-dump-admin"
+FLUSH_IPS = "flush-ips-content"
+DEVICE_CONFIG = "device-config"
+APPLY_SYSCONFIG = "apply-sysconfig"
+BOOT_ARCHIVE = "boot-archive"
+CREATE_SNAPSHOT = "create-snapshot"
+
+import curses
+import locale
+import logging
+import os
+import platform
+import signal
+import subprocess
+import sys
+import traceback
+
+from optparse import OptionParser
+
+import solaris_install.sysconfig as sysconfig
+
+from solaris_install import Popen, CalledProcessError
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME, FileHandler
+from solaris_install.target.controller import TargetController
+from solaris_install.target.libbe.be import be_list
+from solaris_install.target.size import Size
+from solaris_install.text_install.disk_selection import DiskScreen
+from solaris_install.text_install.fdisk_partitions import FDiskPart
+from solaris_install.text_install.install_progress import InstallProgress
+from solaris_install.text_install.install_status import InstallStatus, \
+                                                     RebootException
+from solaris_install.text_install.log_viewer import LogViewer
+from solaris_install.text_install.partition_edit_screen import PartEditScreen
+from solaris_install.text_install.summary import SummaryScreen
+from solaris_install.text_install.ti_install_utils import InstallData
+from solaris_install.text_install.welcome import WelcomeScreen
+from solaris_install.transfer.media_transfer import TRANSFER_ROOT, \
+    TRANSFER_MISC, TRANSFER_MEDIA
+import terminalui
+from terminalui import LOG_LEVEL_INPUT, LOG_NAME_INPUT
+from terminalui.action import Action
+from terminalui.base_screen import BaseScreen
+from terminalui.help_screen import HelpScreen
+from terminalui.i18n import get_encoding, set_wrap_on_whitespace
+from terminalui.main_window import MainWindow
+from terminalui.screen_list import ScreenList
+
+
+LOG_LOCATION_FINAL = "/var/sadm/system/logs/install_log"
+DEFAULT_LOG_LOCATION = "/tmp/install_log"
+DEFAULT_LOG_LEVEL = "info"
+DEBUG_LOG_LEVEL = "debug"
+REBOOT = "/usr/sbin/reboot"
+
+LOGGER = None
+
+
+def exit_text_installer(logname=None, errcode=0):
+    '''Close out the logger and exit with errcode'''
+    LOGGER.info("**** END ****")
+    LOGGER.close()
+    if logname is not None:
+        print _("Exiting Text Installer. Log is available at:\n%s") % logname
+    if isinstance(errcode, unicode):
+        errcode = errcode.encode(get_encoding())
+    sys.exit(errcode)
+
+
+def setup_logging(logname, log_level):
+    '''setup the logger, logging to logname at log_level'''
+
+    global LOGGER
+    LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+    log_level = log_level.upper()
+    if hasattr(logging, log_level):
+        log_level = getattr(logging, log_level.upper())
+    elif log_level == LOG_NAME_INPUT:
+        log_level = LOG_LEVEL_INPUT
+    else:
+        raise IOError(2, "Invalid --log-level parameter", log_level.lower())
+
+    LOGGER.setLevel(log_level)
+    LOGGER.transfer_log(destination=logname)
+
+    LOGGER.info("**** START ****")
+
+
+def make_screen_list(main_win, target_controller, install_data):
+    '''Initialize the screen list. On x86, add screens for editing slices
+    within a partition. Also, trigger the target discovery thread.
+    
+    '''
+    
+    result = []
+    result.append(WelcomeScreen(main_win, install_data))
+    disk_screen = DiskScreen(main_win, target_controller)
+    disk_screen.start_discovery()
+    result.append(disk_screen)
+    result.append(FDiskPart(main_win, target_controller))
+    result.append(PartEditScreen(main_win, target_controller))
+    if platform.processor() == "i386":
+        result.append(FDiskPart(main_win, target_controller,
+                                x86_slice_mode=True))
+        result.append(PartEditScreen(main_win, target_controller,
+                                     x86_slice_mode=True))
+    result.extend(sysconfig.get_all_screens(main_win))
+    
+    result.append(SummaryScreen(main_win))
+    result.append(InstallProgress(main_win, install_data, target_controller))
+    result.append(InstallStatus(main_win, install_data))
+    result.append(LogViewer(main_win, install_data))
+    return result
+
+
+def _reboot_cmds(is_x86):
+    '''Generate list of cmds to try fast rebooting'''
+    cmds = list()
+    
+    all_be = be_list()
+
+    for be_name, be_pool, root_ds, is_active in all_be:
+        if is_active:
+            if is_x86:
+                cmds.append([REBOOT, "-f", "--", root_ds])
+            else:
+                # SPARC requires "-Z" before the root dataset
+                cmds.append([REBOOT, "-f", "--", "-Z", root_ds])
+
+    # Fallback reboot. If the subprocess.call(..) command above fails,
+    # simply do a standard reboot.
+    cmds.append([REBOOT])
+    return cmds
+
+
+def reboot(is_x86):
+    '''Reboot the machine, attempting fast reboot first if available'''
+    cmds = _reboot_cmds(is_x86)
+    for cmd in cmds:
+        try:
+            Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                             logger=LOGGER)
+        except (CalledProcessError):
+            LOGGER.warn("Reboot failed:\n\t'%s'", " ".join(cmd))
+        else:
+            LOGGER.warn("Reboot failed:\n\t'%s'.\nWill attempt"
+                        " standard reboot", " ".join(cmd))
+
+
+def prepare_engine(options):
+    ''' Instantiate the engine, setup logging, and register all
+        the checkpoints to be used for doing the install.
+    '''
+
+    eng = InstallEngine(debug=options.debug)
+    
+    # setup_logging() must be called after the engine is initialized.
+    setup_logging(options.logname, options.log_level)
+
+    terminalui.init_logging(INSTALL_LOGGER_NAME)
+
+    # Information regarding checkpoints used for the Text Installer.
+    # The values specified are used as arguments for registering the
+    # checkpoint.  If function signature for any of the checkpoints are
+    # is modified, these values need to be modified as well.
+
+    eng.register_checkpoint(TARGET_DISCOVERY,
+                            "solaris_install/target/discovery",
+                            "TargetDiscovery")
+
+    eng.register_checkpoint(TRANSFER_PREP,
+                           "solaris_install/transfer/media_transfer",
+                           "init_prepare_media_transfer")
+
+    eng.register_checkpoint(TARGET_INIT,
+                            "solaris_install/target/instantiation",
+                            "TargetInstantiation")
+
+    # The following 3 are transfer checkpoints
+    eng.register_checkpoint(TRANSFER_ROOT,
+                           "solaris_install/transfer/cpio",
+                           "TransferCPIO")
+
+    eng.register_checkpoint(TRANSFER_MISC,
+                           "solaris_install/transfer/cpio",
+                           "TransferCPIO")
+
+    eng.register_checkpoint(TRANSFER_MEDIA,
+                            "solaris_install/transfer/cpio",
+                            "TransferCPIO")
+
+    # sys config checkpoint must be registered after transfer checkpoints
+    sysconfig.register_checkpoint()
+
+    # rest of the checkpoints are for finishing up the install process
+    eng.register_checkpoint(CLEANUP_CPIO_INSTALL,
+                            "solaris_install/ict/cleanup_cpio_install",
+                            "CleanupCPIOInstall")
+
+    eng.register_checkpoint(INIT_SMF,
+                            "solaris_install/ict/initialize_smf",
+                            "InitializeSMF")
+
+    eng.register_checkpoint(BOOT_CONFIG,
+                            "solaris_install/boot/boot",
+                            "SystemBootMenu")
+
+    eng.register_checkpoint(DUMP_ADMIN,
+                            "solaris_install/ict/update_dumpadm",
+                            "UpdateDumpAdm")
+
+    eng.register_checkpoint(FLUSH_IPS,
+                            "solaris_install/ict/ips",
+                            "SetFlushContentCache")
+
+    eng.register_checkpoint(DEVICE_CONFIG,
+                            "solaris_install/ict/device_config",
+                            "DeviceConfig")
+
+    eng.register_checkpoint(APPLY_SYSCONFIG,
+                            "solaris_install/ict/apply_sysconfig",
+                            "ApplySysConfig")
+
+    eng.register_checkpoint(BOOT_ARCHIVE,
+                            "solaris_install/ict/boot_archive",
+                            "BootArchive")
+
+    eng.register_checkpoint(CREATE_SNAPSHOT,
+                            "solaris_install/ict/create_snapshot",
+                            "CreateSnapshot")
+    
+
+def init_locale():
+
+    locale.setlocale(locale.LC_ALL, "")
+    gettext.install("textinstall", "/usr/share/locale", unicode=True)
+    set_wrap_on_whitespace(_("DONT_TRANSLATE_BUT_REPLACE_msgstr_WITH_True_"
+                             "OR_False: Should wrap text on whitespace in"
+                             " this language"))
+    BaseScreen.set_default_quit_text(_("Confirm: Quit the Installer?"),
+                                     _("Do you want to quit the Installer?"),
+                                     _("Cancel"),
+                                     _("Quit"))
+
+
+def main():
+    init_locale()
+    
+    if os.getuid() != 0:
+        sys.exit(_("The %(release)s Text Installer must be run with "
+                   "root privileges") % RELEASE)
+    usage = "usage: %prog [-l FILE] [-v LEVEL] [-d] [-n]"
+    parser = OptionParser(usage=usage, version="%prog 1.1")
+    parser.add_option("-l", "--log-location", dest="logname",
+                      help=_("Set log location to FILE (default: %default)"),
+                      metavar="FILE", default=DEFAULT_LOG_LOCATION)
+    parser.add_option("-v", "--log-level", dest="log_level",
+                      default=None,
+                      help=_("Set log verbosity to LEVEL. In order of "
+                             "increasing verbosity, valid values are 'error' "
+                             "'warn' 'info' 'debug' or 'input'\n[default:"
+                             " %default]"),
+                      choices=["error", "warn", "info", "debug", "input"],
+                      metavar="LEVEL")
+    parser.add_option("-d", "--debug", action="store_true", dest="debug",
+                      default=False, help=_("Enable debug mode. Sets " 
+                      "logging level to 'input' and enables CTRL-C for " 
+                      "killing the program\n"))
+    parser.add_option("-b", "--no-color", action="store_true", dest="force_bw",
+                      default=False, help=_("Force the installer to run in "
+                      "black and white. This may be useful on some SPARC "
+                      "machines with unsupported frame buffers\n"))
+    parser.add_option("-n", "--no-install", action="store_true",
+                      dest="no_install", default=False,
+                      help=_("Runs in 'no installation' mode. When run"
+                      " in 'no installation' mode, no persistent changes are"
+                      " made to the disks and booted environment\n"))
+    options, args = parser.parse_args()
+    if options.log_level is None:
+        if options.debug:
+            options.log_level = DEBUG_LOG_LEVEL
+        else:
+            options.log_level = DEFAULT_LOG_LEVEL
+    try:
+        prepare_engine(options)
+    except IOError, err:
+        parser.error("%s '%s'" % (err.strerror, err.filename))
+    LOGGER.debug("CLI options: log location = %s, verbosity = %s, debug "
+                 "mode = %s, no install = %s, force_bw = %s",
+                 options.logname, options.log_level, options.debug,
+                 options.no_install, options.force_bw)
+
+    install_data = InstallData()
+    install_data.log_location = options.logname
+    install_data.log_final = LOG_LOCATION_FINAL
+    install_data.no_install_mode = options.no_install
+
+    try:
+        with terminalui as initscr:
+            win_size_y, win_size_x = initscr.getmaxyx()
+            if win_size_y < 24 or win_size_x < 80:
+                msg = _("     Terminal too small. Min size is 80x24."
+                        " Current size is %(x)ix%(y)i.") % \
+                        {'x': win_size_x, 'y': win_size_y}
+                exit_text_installer(errcode=msg)
+            
+            screen_list = ScreenList()
+            actions = [Action(curses.KEY_F2, _("Continue"),
+                              screen_list.get_next),
+                       Action(curses.KEY_F3, _("Back"),
+                              screen_list.previous_screen),
+                       Action(curses.KEY_F6, _("Help"), screen_list.show_help),
+                       Action(curses.KEY_F9, _("Quit"), screen_list.quit)]
+            
+            main_win = MainWindow(initscr, screen_list, actions,
+                                  force_bw=options.force_bw)
+            screen_list.help = HelpScreen(main_win, _("Help Topics"),
+                                          _("Help Index"),
+                                          _("Select a topic and press "
+                                          "Continue."))
+            doc = InstallEngine.get_instance().doc
+
+            debug_tc = False
+            if options.debug:
+                debug_tc = True
+            target_controller = TargetController(doc, debug=debug_tc)
+
+            win_list = make_screen_list(main_win, target_controller,
+                                        install_data)
+            screen_list.help.setup_help_data(win_list)
+            screen_list.screen_list = win_list
+            screen = screen_list.get_next()
+            ctrl_c = None
+            while screen is not None:
+                LOGGER.debug("Displaying screen: %s", type(screen))
+                screen = screen.show()
+                if not options.debug and ctrl_c is None:
+                    # This prevents the user from accidentally hitting
+                    # ctrl-c halfway through the install. Ctrl-C is left
+                    # available through the first screen in case terminal
+                    # display issues make it impossible for the user to
+                    # quit gracefully
+                    ctrl_c = signal.signal(signal.SIGINT, signal.SIG_IGN)
+            errcode = 0
+    except RebootException:
+        reboot(platform.processor() == "i386")
+    except SystemExit:
+        raise
+    except:
+        LOGGER.info(str(InstallEngine.get_instance().doc))
+        LOGGER.info(str(install_data))
+        LOGGER.exception("Install failed")
+        exc_type, exc_value = sys.exc_info()[:2]
+        print _("An unhandled exception occurred.")
+        if str(exc_value):
+            print '\t%s: "%s"' % (exc_type.__name__, str(exc_value))
+        else:
+            print "\t%s" % exc_type.__name__
+        print _("Full traceback data is in the installation log")
+        print _("Please file a bug at http://defect.opensolaris.org")
+        errcode = 1
+    exit_text_installer(options.logname, errcode)
+
+if __name__ == '__main__':
+    main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/disk_selection.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,451 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Screens and functions to display a list of disks to the user.
+'''
+
+import curses
+import logging
+import platform
+
+import osol_install.errsvc as errsvc
+import osol_install.liberrsvc as liberrsvc
+from solaris_install.text_install import _, RELEASE, TUI_HELP, \
+    TARGET_DISCOVERY, TRANSFER_PREP
+from solaris_install.text_install.disk_window import DiskWindow, \
+    get_minimum_size, get_recommended_size
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.target import Target
+from solaris_install.target.controller import FALLBACK_IMAGE_SIZE
+from solaris_install.target.physical import Disk, Partition, Slice
+from solaris_install.target.size import Size
+from solaris_install.text_install.ti_target_utils import MAX_VTOC
+from solaris_install.transfer.media_transfer import get_image_size
+from terminalui.base_screen import BaseScreen, QuitException, UIMessage
+from terminalui.i18n import fit_text_truncate, textwidth, ljust_columns
+from terminalui.list_item import ListItem
+from terminalui.scroll_window import ScrollWindow
+from terminalui.window_area import WindowArea
+
+LOGGER = None
+
+
+class TargetDiscoveryError(StandardError):
+    '''Class for target discovery related errors'''
+    pass
+
+
+class DiskScreen(BaseScreen):
+    '''
+    Allow the user to select a (valid) disk target for installation
+    Display the partition/slice table for the highlighted disk
+    
+    '''
+    
+    HEADER_TEXT = _("Disks")
+    PARAGRAPH = _("Where should %(release)s be installed?") % RELEASE
+    SIZE_TEXT = _("Recommended size:  %(recommend).1fGB      "
+                  "Minimum size: %(min).1fGB")
+    DISK_SEEK_TEXT = _("Seeking disks on system")
+    FOUND_x86 = _("The following partitions were found on the disk.")
+    FOUND_SPARC = _("The following slices were found on the disk.")
+    PROPOSED_x86 = _("A partition table was not found. The following is "
+                     "proposed.")
+    PROPOSED_SPARC = _("A VTOC label was not found. The following "
+                       "is proposed.")
+    PROPOSED_GPT = _("A GPT labeled disk was found. The following is "
+                     "proposed.")
+    TOO_SMALL = _("Too small")
+    TOO_BIG_WARN = _("Limited to %.1f TB")
+    GPT_LABELED = _("GPT labeled disk")
+    NO_DISKS = _("No disks found. Additional device drivers may "
+                 "be needed.")
+    NO_TARGETS = _("%(release)s cannot be installed on any disk") % RELEASE
+    TGT_ERROR = _("An error occurred while searching for installation"
+                  " targets. Please check the install log and file a bug"
+                  " at defect.opensolaris.org.")
+    
+    DISK_HEADERS = [(8, _("Type")),
+                    (10, _("Size(GB)")),
+                    (6, _("Boot")),
+                    (9, _("Device")),
+                    (15, _("Manufacturer")),
+                    (22, _("Notes"))]
+    SPINNER = ["\\", "|", "/", "-"]
+    
+    DISK_WARNING_HEADER = _("Warning")
+    DISK_WARNING_TOOBIG = _("Only the first %.1fTB can be used.")
+    DISK_WARNING_GPT = _("You have chosen a GPT labeled disk. Installing "
+                         "onto a GPT labeled disk will cause the loss "
+                         "of all existing data and the disk will be "
+                         "relabeled as SMI.")
+
+    CANCEL_BUTTON = _("Cancel")
+    CONTINUE_BUTTON = _("Continue")
+    
+    HELP_DATA = (TUI_HELP + "/%s/disks.txt", _("Disks"))
+    
+    def __init__(self, main_win, target_controller):
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        super(DiskScreen, self).__init__(main_win)
+        if platform.processor() == "i386":
+            self.found_text = DiskScreen.FOUND_x86
+            self.proposed_text = DiskScreen.PROPOSED_x86
+        else:
+            self.found_text = DiskScreen.FOUND_SPARC
+            self.proposed_text = DiskScreen.PROPOSED_SPARC
+        
+        disk_header_text = []
+        for header in DiskScreen.DISK_HEADERS:
+            header_str = fit_text_truncate(header[1], header[0] - 1,
+                                           just="left")
+            disk_header_text.append(header_str)
+        self.disk_header_text = " ".join(disk_header_text)
+        max_note_size = DiskScreen.DISK_HEADERS[5][0]
+        self.too_small_text = DiskScreen.TOO_SMALL[:max_note_size]
+        max_disk_size = (Size(MAX_VTOC)).get(Size.tb_units)
+        too_big_warn = DiskScreen.TOO_BIG_WARN % max_disk_size
+        self.too_big_warn = too_big_warn[:max_note_size]
+        self.disk_warning_too_big = \
+            DiskScreen.DISK_WARNING_TOOBIG % max_disk_size
+        
+        self.disks = []
+        self.existing_pools = []
+        self.disk_win = None
+        self.disk_detail = None
+        self.num_targets = 0
+        self.td_handle = None
+        self._size_line = None
+        self.selected_disk_index = 0
+        self._minimum_size = None
+        self._recommended_size = None
+
+        self.engine = InstallEngine.get_instance()
+        self.doc = self.engine.data_object_cache
+        self.tc = target_controller
+        self._target_discovery_completed = False
+        self._target_discovery_status = InstallEngine.EXEC_SUCCESS
+    
+    def determine_minimum(self):
+        '''Returns minimum install size, fetching first if needed'''
+        self.determine_size_data()
+        return self._minimum_size
+    
+    minimum_size = property(determine_minimum)
+    
+    def determine_recommended(self):
+        '''Returns recommended install size, fetching first if needed'''
+        self.determine_size_data()
+        return self._recommended_size
+    
+    recommended_size = property(determine_recommended)
+    
+    def determine_size_data(self):
+        '''Retrieve the minimum and recommended sizes and generate the string
+        to present that information.
+        
+        '''
+        if self._minimum_size is None or self._recommended_size is None:
+            self._recommended_size = get_recommended_size(self.tc)
+            self._minimum_size = get_minimum_size(self.tc)
+    
+    def get_size_line(self):
+        '''Returns the line of text displaying the min/recommended sizes'''
+        if self._size_line is None:
+            rec_size = self.recommended_size.get(Size.gb_units)
+            min_size = self.minimum_size.get(Size.gb_units)
+            size_dict = {"recommend": rec_size, "min": min_size}
+            self._size_line = DiskScreen.SIZE_TEXT % size_dict
+        return self._size_line
+    
+    size_line = property(get_size_line)
+    
+    def wait_for_disks(self):
+        '''Block while waiting for libtd to finish. Catch F9 and quit
+        if needed
+        
+        '''
+        self.main_win.actions.pop(curses.KEY_F2, None)
+        self.main_win.actions.pop(curses.KEY_F6, None)
+        self.main_win.actions.pop(curses.KEY_F3, None)
+        self.main_win.show_actions()
+
+        self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1,
+                                 self.win_size_x - 3)
+        self.main_win.do_update()
+        offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2
+        spin_index = 0
+        self.center_win.window.timeout(250)
+
+        while not self._target_discovery_completed:
+            input_key = self.main_win.getch()
+            if input_key == curses.KEY_F9:
+                if self.confirm_quit():
+                    raise QuitException
+            self.center_win.add_text(DiskScreen.SPINNER[spin_index], 5, offset)
+            self.center_win.no_ut_refresh()
+            self.main_win.do_update()
+            spin_index = (spin_index + 1) % len(DiskScreen.SPINNER)
+
+        self.center_win.window.timeout(-1)
+        self.center_win.clear()
+
+        # check the result of target discovery
+        if self._target_discovery_status is not InstallEngine.EXEC_SUCCESS:
+            err_data = (errsvc.get_errors_by_mod_id(TARGET_DISCOVERY))[0]
+            LOGGER.error("Target discovery failed")
+            err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION]
+            LOGGER.error(err)
+            raise TargetDiscoveryError(("Unexpected error (%s) during target "
+                "discovery. See log for details.") % err)
+
+    def _td_callback(self, status, errsvc):
+        '''Callback function for Target Discovery checkpoint execution.
+           If there's no error from executing the checkpoint,
+           this will call the _display_disks() function to display disk
+           information.
+ 
+        '''
+
+        try:
+            image_size = Size(str(get_image_size(LOGGER)) + Size.mb_units)
+            LOGGER.debug("Image_size: %s", image_size)
+        except:
+            # Unable to get the image size for some reason, allow
+            # the target controller to use it's default size.
+            LOGGER.debug("Unable to get image size") 
+            image_size = FALLBACK_IMAGE_SIZE
+
+        self.tc.initialize(image_size=image_size)
+        self._target_discovery_status = status
+        self._target_discovery_completed = True
+
+    def _show(self):
+        '''Create a list of disks to choose from and create the window
+        for displaying the partition/slice information from the selected
+        disk
+        
+        '''
+
+        self.wait_for_disks()
+
+        discovered_target = self.doc.persistent.get_first_child( \
+            name=Target.DISCOVERED)
+
+        LOGGER.debug(discovered_target)
+        if discovered_target is None:
+            self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1,
+                                          max_x=(self.win_size_x - 1))
+            return
+
+        self.disks = discovered_target.get_children(class_type=Disk)
+        if not self.disks:
+            self.center_win.add_paragraph(DiskScreen.NO_TARGETS, 1, 1,
+                                          max_x=(self.win_size_x - 1))
+            return
+         
+        # Go through all the disks found and find ones that have
+        # enough space for installation.  At the same time, see if any
+        # existing disk is the boot disk.  If a boot disk is found, move
+        # it to the front of the list
+        num_usable_disks = 0
+        boot_disk = None
+        for disk in self.disks:
+            LOGGER.debug("size: %s, min: %s" % \
+                         (disk.disk_prop.dev_size, self.minimum_size))
+            if disk.disk_prop.dev_size >= self.minimum_size:
+                if disk.is_boot_disk():
+                    boot_disk = disk
+                num_usable_disks += 1
+        if boot_disk is not None:
+            self.disks.remove(boot_disk)
+            self.disks.insert(0, boot_disk)
+
+        if num_usable_disks == 0:
+            self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1,
+                                          max_x=(self.win_size_x - 1))
+            return
+
+        self.main_win.reset_actions()
+        self.main_win.show_actions()
+        
+        y_loc = 1
+        self.center_win.add_text(DiskScreen.PARAGRAPH, y_loc, 1)
+        
+        y_loc += 1
+        self.center_win.add_text(self.size_line, y_loc, 1)
+        
+        y_loc += 2
+        self.center_win.add_text(self.disk_header_text, y_loc, 1)
+        
+        y_loc += 1
+        self.center_win.window.hline(y_loc, self.center_win.border_size[1] + 1,
+                                     curses.ACS_HLINE,
+                                     textwidth(self.disk_header_text))
+        
+        y_loc += 1
+        disk_win_area = WindowArea(4, textwidth(self.disk_header_text) + 2,
+                                   y_loc, 0)
+        disk_win_area.scrollable_lines = len(self.disks) + 1
+        self.disk_win = ScrollWindow(disk_win_area,
+                                     window=self.center_win)
+        
+        disk_item_area = WindowArea(1, disk_win_area.columns - 2, 0, 1)
+        disk_index = 0
+        len_type = DiskScreen.DISK_HEADERS[0][0] - 1
+        len_size = DiskScreen.DISK_HEADERS[1][0] - 1
+        len_boot = DiskScreen.DISK_HEADERS[2][0] - 1
+        len_dev = DiskScreen.DISK_HEADERS[3][0] - 1
+        len_mftr = DiskScreen.DISK_HEADERS[4][0] - 1
+        for disk in self.disks:
+            disk_text_fields = []
+            type_field = disk.disk_prop.dev_type[:len_type]
+            type_field = ljust_columns(type_field, len_type)
+            disk_text_fields.append(type_field)
+            disk_size = disk.disk_prop.dev_size.get(Size.gb_units)
+            size_field = "%*.1f" % (len_size, disk_size)
+            disk_text_fields.append(size_field)
+            if disk.is_boot_disk():
+                bootable_field = "+".center(len_boot)
+            else:
+                bootable_field = " " * (len_boot)
+            disk_text_fields.append(bootable_field)
+            device_field = disk.ctd[:len_dev]
+            device_field = ljust_columns(device_field, len_dev)
+            disk_text_fields.append(device_field)
+            vendor = disk.disk_prop.dev_vendor
+            if vendor is not None:
+                mftr_field = vendor[:len_mftr]
+                mftr_field = ljust_columns(mftr_field, len_mftr)
+            else:
+                mftr_field = " " * len_mftr
+            disk_text_fields.append(mftr_field)
+            selectable = True
+            if disk.disk_prop.dev_size < self.minimum_size:
+                note_field = self.too_small_text
+                selectable = False
+            elif disk_size > Size(MAX_VTOC).get(Size.gb_units):
+                note_field = self.too_big_warn
+            else:
+                note_field = ""
+            disk_text_fields.append(note_field)
+            disk_text = " ".join(disk_text_fields)
+            disk_item_area.y_loc = disk_index
+            disk_list_item = ListItem(disk_item_area, window=self.disk_win,
+                                      text=disk_text, add_obj=selectable)
+            disk_list_item.on_make_active = on_activate
+            disk_list_item.on_make_active_kwargs["disk"] = disk
+            disk_list_item.on_make_active_kwargs["disk_select"] = self
+            disk_index += 1
+
+        self.disk_win.no_ut_refresh()
+        
+        y_loc += 7
+        disk_detail_area = WindowArea(6, 70, y_loc, 1)
+
+        self.disk_detail = DiskWindow(disk_detail_area, self.disks[0],
+                                      target_controller=self.tc,
+                                      window=self.center_win)
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(self.disk_win)
+        self.disk_win.activate_object(self.selected_disk_index)
+    
+    def on_change_screen(self):
+        ''' Save the index of the current selected object
+        in case the user returns to this screen later
+        
+        '''
+
+        # Save the index of the selected object
+        self.selected_disk_index = self.disk_win.active_object
+
+        LOGGER.debug("disk_selection.on_change_screen, saved_index: %s",
+                     self.selected_disk_index)
+        LOGGER.debug(self.doc.persistent)
+    
+    def start_discovery(self):
+
+        # start target discovery
+        if not self._target_discovery_completed:
+            errsvc.clear_error_list()
+
+            self.engine.execute_checkpoints(pause_before=TRANSFER_PREP,
+                                            callback=self._td_callback)
+
+    def validate(self):
+        '''Validate the size of the disk.'''
+
+        warning_txt = []
+
+        disk = self.disk_detail.ui_obj.doc_obj
+        disk_size_gb = disk.disk_prop.dev_size.get(Size.gb_units)
+        max_size_gb = Size(MAX_VTOC).get(Size.gb_units)
+        if disk_size_gb > max_size_gb:
+            warning_txt.append(self.disk_warning_too_big)
+        warning_txt = " ".join(warning_txt)
+        
+        if warning_txt:
+            # warn the user and give user a chance to change
+            result = self.main_win.pop_up(DiskScreen.DISK_WARNING_HEADER,
+                                          warning_txt,
+                                          DiskScreen.CANCEL_BUTTON,
+                                          DiskScreen.CONTINUE_BUTTON)
+            
+            if not result:
+                raise UIMessage() # let user select different disk
+            
+            # if user didn't quit it is always OK to ignore disk size,
+            # that will be forced less than the maximum in partitioning.
+        
+
+def on_activate(disk=None, disk_select=None):
+    '''When a disk is selected, pass its data to the disk_select_screen'''
+    max_x = disk_select.win_size_x - 1
+
+    LOGGER.debug("on activate..disk=%s", disk)
+
+    # See whether the disk is blank
+    if platform.processor() == "i386":
+        parts = disk.get_children(class_type=Partition)
+    else:
+        parts = disk.get_children(class_type=Slice)
+
+    if not parts:
+        display_text = disk_select.proposed_text
+    else:
+        display_text = disk_select.found_text
+
+    # Add the selected disk to the target controller so appropriate defaults
+    # can be filled in, if necessary
+    selected_disk = (disk_select.tc.select_disk(disk))[0]
+    selected_disk.whole_disk = False # assume we don't want to use whole disk
+
+    disk_select.center_win.add_paragraph(display_text, 11, 1, max_x=max_x)
+    disk_select.disk_detail.set_disk_info(disk_info=selected_disk)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/disk_window.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,864 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+'''
+UI component for displaying (and editing) partition & slice data
+'''
+
+
+import curses
+import logging
+import platform
+
+from copy import deepcopy
+
+from solaris_install.engine import InstallEngine
+from solaris_install.text_install import _
+from solaris_install.text_install.ti_target_utils import UIDisk, UIPartition, \
+    dump_doc, get_desired_target_disk, get_solaris_partition, ROOT_POOL, \
+    UI_PRECISION 
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.target.libadm.const import FD_NUMPART as MAX_PRIMARY_PARTS
+from solaris_install.target.libadm.const import MAX_EXT_PARTS
+from solaris_install.target.physical import Disk, Partition, Slice
+from solaris_install.target.size import Size
+from solaris_install.target.libadm.const import V_ROOT
+
+from terminalui.base_screen import UIMessage
+from terminalui.edit_field import EditField
+from terminalui.i18n import fit_text_truncate, textwidth
+from terminalui.inner_window import InnerWindow, no_action
+from terminalui.list_item import ListItem
+from terminalui.scroll_window import ScrollWindow
+from terminalui.window_area import WindowArea
+
+LOGGER = None
+
+
+class DiskWindow(InnerWindow):
+    '''Display and edit disk information, including partitions and slices'''
+    
+    STATIC_PARTITION_HEADERS = [(12, _("Primary"), _("Logical")),
+                                (9, _("Size(GB)"), _("Size(GB)"))]
+    
+    EDIT_PARTITION_HEADERS = [(13, _("Primary"), _("Logical")),
+                              (9, _("Size(GB)"), _("Size(GB)")),
+                              (7, _(" Avail"), _(" Avail"))]
+    
+    STATIC_SLICE_HEADERS = [(13, _("Slice"), _("Slice")),
+                            (2, "#", "#"),
+                            (9, _("Size(GB)"), _("Size(GB)"))]
+    
+    EDIT_SLICE_HEADERS = [(13, _("Slice"), _("Slice")),
+                          (2, "#", "#"),
+                          (9, _("Size(GB)"), _("Size(GB)")),
+                          (7, _(" Avail"), _(" Avail"))]
+    
+    ADD_KEYS = {curses.KEY_LEFT: no_action,
+                curses.KEY_RIGHT: no_action}
+    
+    DEAD_ZONE = 3
+    SCROLL_PAD = 2
+    
+    MIN_SIZE = None
+    REC_SIZE = None
+    
+    SIZE_PRECISION = Size(UI_PRECISION).get(Size.gb_units)
+
+    DESTROYED_MARK = EditField.ASTERISK_CHAR
+    
+    def __init__(self, area, disk_info, editable=False,
+                 error_win=None, target_controller=None, **kwargs):
+        '''See also InnerWindow.__init__
+        
+        disk_info (required) - Either a Disk or Partition object
+        containing the data to be represented. If a Partition objects is
+        provided, it will be used for displaying slice
+        data within that partition. If Disk has partition(s), those are
+        displayed. If not, but it has slices, then those are displayed. If
+        neither partition data nor slice data are available, a ValueError is
+        raised. 
+        
+        headers (required) - List of tuples to populate the header of this
+        window with. The first item in each tuple should be the width of the
+        header, the second item should be the left side header.
+        
+        editable (optional) - If True, the window will be created such that
+        data is editable.
+
+        target_controller(optional) - Target controller
+        
+        '''
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        self.headers = None
+        self.orig_ext_part_field = None
+        self.orig_logicals_active = False
+        self.ext_part_field = None
+        self.error_win = error_win
+        self.editable = editable
+        self.win_width = None
+        self.left_win = None
+        self.right_win = None
+        self.list_area = None
+        self.edit_area = None
+        super(DiskWindow, self).__init__(area, add_obj=editable, **kwargs)
+        self.left_header_string = None
+        self.right_header_string = None
+        self._orig_data = None
+        self.disk_info = None
+        self.has_partition_data = False
+        self.key_dict[curses.KEY_LEFT] = self.on_arrow_key
+        self.key_dict[curses.KEY_RIGHT] = self.on_arrow_key
+        if self.editable:
+            self.key_dict[curses.KEY_F5] = self.change_type
+
+        self.tc = target_controller
+        self._ui_obj = None
+        self.ui_obj = disk_info
+
+        self.set_disk_info(ui_obj=self.ui_obj)
+
+        LOGGER.debug(self.ui_obj)
+        
+        if platform.processor() == "sparc":
+            self.is_x86 = False
+        else:
+            self.is_x86 = True
+
+    @property
+    def ui_obj(self):
+        return self._ui_obj
+
+    @ui_obj.setter
+    def ui_obj(self, part):
+        ''' create and set the value for ui_obj depending on type '''
+        if isinstance(part, Disk):
+            self._ui_obj = UIDisk(self.tc, parent=None, doc_obj=part)
+        elif isinstance(part, Partition):
+            self._ui_obj = UIPartition(self.tc, parent=None, doc_obj=part)
+        else:
+            # Must be a either a Disk or Partition.  It's an error to be here
+            raise RuntimeError("disk_info object is invalid")
+    
+    def _init_win(self, window):
+        '''Require at least 70 columns and 6 lines to fit current needs for
+        display of partitions and slices. Builds two inner ScrollWindows for
+        displaying/editing the data.
+        
+        '''
+        if self.area.columns < 70:
+            raise ValueError("Insufficient space - area.columns < 70")
+        if self.area.lines < 6:
+            raise ValueError("Insufficient space - area.lines < 6")
+        self.win_width = (self.area.columns - DiskWindow.DEAD_ZONE
+                          + DiskWindow.SCROLL_PAD) / 2
+        
+        super(DiskWindow, self)._init_win(window)
+        
+        win_area = WindowArea(self.area.lines - 1, self.win_width, 2, 0)
+        win_area.scrollable_lines = self.area.lines - 2
+        self.left_win = ScrollWindow(win_area, window=self, add_obj=False)
+        self.left_win.color = None
+        self.left_win.highlight_color = None
+        win_area.x_loc = self.win_width + DiskWindow.DEAD_ZONE
+        win_area.scrollable_lines = 2 * MAX_EXT_PARTS
+        self.right_win = ScrollWindow(win_area, window=self, add_obj=False)
+        self.right_win.color = None
+        self.right_win.highlight_color = None
+    
+    def set_disk_info(self, ui_obj=None, disk_info=None, no_part_ok=False):
+        '''Set up this DiskWindow to represent disk_info'''
+
+        if ui_obj is not None:
+            disk_info = ui_obj.doc_obj
+        elif disk_info is not None:
+            self.ui_obj = disk_info
+        else:
+            # Should never be this case
+            raise RuntimeError("Unable to find ui_obj or disk_info")
+
+        part_list = disk_info.get_children(class_type=Partition)
+        if part_list:
+            self.has_partition_data = True
+        else:
+            slice_list = disk_info.get_children(class_type=Slice)
+            if slice_list:
+                self.has_partition_data = False
+            else:
+                # No partitions and no slices
+                if no_part_ok:
+                    if self.is_x86:
+                        self.has_partition_data = True
+                    else:
+                        self.has_partition_data = False
+                else:
+                    return
+        
+        if self.has_partition_data:
+            if self.editable:
+                self.headers = DiskWindow.EDIT_PARTITION_HEADERS
+                self.list_area = WindowArea(1, self.headers[0][0] + 
+                                            self.headers[1][0],
+                                            0, DiskWindow.SCROLL_PAD)
+                self.edit_area = WindowArea(1, self.headers[1][0], 0,
+                                            self.headers[0][0])
+            else:
+                self.headers = DiskWindow.STATIC_PARTITION_HEADERS
+        else:
+            if self.editable:
+                self.headers = DiskWindow.EDIT_SLICE_HEADERS
+                self.list_area = WindowArea(1, self.headers[0][0] +
+                                            self.headers[1][0] +
+                                            self.headers[2][0],
+                                            0, DiskWindow.SCROLL_PAD)
+                self.edit_area = WindowArea(1, self.headers[2][0], 0,
+                                            self.headers[0][0] +
+                                            self.headers[1][0])
+            else:
+                self.headers = DiskWindow.STATIC_SLICE_HEADERS
+        
+        LOGGER.debug("have_partition: %s", self.has_partition_data)
+        LOGGER.debug(self.ui_obj)
+
+        self.ui_obj.add_unused_parts(no_part_ok=no_part_ok)
+
+        self.left_win.clear()
+        self.right_win.clear()
+        self.window.erase()
+        self.print_headers()
+        
+        if self.editable:
+            self.active_object = None
+            self.build_edit_fields()
+            self.right_win.bottom = max(0, len(self.right_win.all_objects) -
+                                        self.right_win.area.lines)
+            if self.has_partition_data:
+                self.orig_ext_part_field = None
+                for obj in self.left_win.objects:
+                    if (obj.data_obj.is_extended()):
+                        self.orig_ext_part_field = obj
+                        self.orig_logicals_active = True
+                        break
+        else:
+            self.print_data()
+
+    def print_headers(self):
+        '''Print the headers for the displayed data.
+        
+        header[0] - The width of this column. header[1] and header[2] are
+                    trimmed to this size
+        header[1] - The internationalized text for the left window
+        header[2] - The internationalized text for the right window
+        
+        '''
+        self.left_header_string = []
+        self.right_header_string = []
+        for header in self.headers:
+            left_header_str = header[1]
+            right_header_str = header[2]
+            # Trim the header to fit in the column width,
+            # splitting columns with at least 1 space
+            # Pad with extra space(s) to align the columns
+            left_header_str = fit_text_truncate(left_header_str,
+                                                header[0] - 1, just="left")
+            self.left_header_string.append(left_header_str)
+            right_header_str = fit_text_truncate(right_header_str,
+                                                header[0] - 1, just="left")
+            self.right_header_string.append(right_header_str)
+        self.left_header_string = " ".join(self.left_header_string)
+        self.right_header_string = " ".join(self.right_header_string)
+        LOGGER.debug(self.left_header_string)
+        self.add_text(self.left_header_string, 0, DiskWindow.SCROLL_PAD)
+        right_win_offset = (self.win_width + DiskWindow.DEAD_ZONE +
+                            DiskWindow.SCROLL_PAD)
+        self.add_text(self.right_header_string, 0, right_win_offset)
+        self.window.hline(1, DiskWindow.SCROLL_PAD, curses.ACS_HLINE,
+                          textwidth(self.left_header_string))
+        self.window.hline(1, right_win_offset, curses.ACS_HLINE,
+                          textwidth(self.right_header_string))
+        self.no_ut_refresh()
+    
+    def print_data(self):
+        '''Print static (non-editable) data.
+        
+        Slices - fill the left side, then remaining slices on the right side.
+        If for some reason not all slices fit, indicate how many more slices
+        there area
+        
+        Partitions - Put standard partitions on the left, logical partitions
+        on the right
+        
+        '''
+
+        part_index = 0
+        data = self.ui_obj.get_parts_in_use()
+
+        if len(data) == 0:
+            return   # should never be this case
+
+        if self.has_partition_data:
+            max_parts = MAX_PRIMARY_PARTS
+        else:
+            max_parts = min(len(data), self.left_win.area.lines)
+
+        win = self.left_win
+        y_loc = 0
+        for next_data in data:
+            LOGGER.debug("next_data: %s", next_data)
+            if y_loc >= max_parts:
+                if win is self.left_win:
+                    win = self.right_win
+                    y_loc = 0
+                    max_parts = win.area.lines
+                else:
+                    num_extra = len(data) - part_index
+                    if self.has_partition_data:
+                        more_parts_txt = _("%d more partitions") % num_extra
+                    else:
+                        more_parts_txt = _("%d more slices") % num_extra
+                    win.add_text(more_parts_txt, win.area.lines, 3)
+                    break
+            x_loc = DiskWindow.SCROLL_PAD
+            field = 0
+            win.add_text(next_data.get_description(), y_loc, x_loc,
+                         self.headers[field][0] - 1)
+            x_loc += self.headers[field][0]
+            field += 1
+            if not self.has_partition_data:
+                win.add_text(str(next_data.name), y_loc, x_loc,
+                             self.headers[field][0] - 1)
+                x_loc += self.headers[field][0]
+                field += 1
+            win.add_text("%*.1f" % (self.headers[field][0] - 1,
+                                    next_data.size.get(Size.gb_units)),
+                                    y_loc, x_loc,
+                                    self.headers[field][0] - 1)
+            x_loc += self.headers[field][0]
+            y_loc += 1
+            field += 1
+            part_index += 1
+        self.right_win.use_vert_scroll_bar = False
+        self.no_ut_refresh()
+    
+    def build_edit_fields(self):
+        '''Build subwindows for editing partition sizes
+        
+        For slices, fill the left side, then the right (right side scrolling as
+        needed, though this shouldn't happen unless the number of slices on
+        disk exceeds 8 for some reason)
+        
+        For partitions, fill the left side up to MAX_PRIMARY_PARTS,
+        and place all logical partitions on the right.
+        
+        '''
+
+        data = self.ui_obj.get_parts_in_use()
+
+        if self.has_partition_data:
+            max_left_parts = MAX_PRIMARY_PARTS
+        else:
+            if len(data) == 0:
+                return   # should never be this case
+            max_left_parts = min(len(data), self.left_win.area.lines)
+
+        part_iter = iter(data)
+        try:
+            next_part = part_iter.next()
+            self.objects.append(self.left_win)
+            for y_loc in range(max_left_parts):
+                self.list_area.y_loc = y_loc
+                self.create_list_item(next_part, self.left_win, self.list_area)
+                next_part = part_iter.next()
+            self.objects.append(self.right_win)
+            for y_loc in range(self.right_win.area.scrollable_lines):
+                self.list_area.y_loc = y_loc
+                self.create_list_item(next_part, self.right_win,
+                                      self.list_area)
+                next_part = part_iter.next()
+            if len(data) > max_left_parts:
+                self.right_win.use_vert_scroll_bar = True
+        except StopIteration:
+            if len(self.right_win.all_objects) <= self.right_win.area.lines:
+                self.right_win.use_vert_scroll_bar = False
+            self.right_win.no_ut_refresh()
+        else:
+            raise ValueError("Could not fit all partitions in DiskWindow")
+        self.no_ut_refresh()
+    
+    def create_list_item(self, next_part, win, list_area):
+        '''Add an entry for next_part (a Partition or Slice) to
+        the DiskWindow
+        
+        '''
+        list_item = ListItem(list_area, window=win, data_obj=next_part)
+        list_item.key_dict.update(DiskWindow.ADD_KEYS)
+        edit_field = EditField(self.edit_area, window=list_item,
+                               numeric_pad=" ",
+                               validate=decimal_valid,
+                               on_exit=on_exit_edit,
+                               error_win=self.error_win,
+                               add_obj=False,
+                               data_obj=next_part)
+        edit_field.right_justify = True
+        edit_field.validate_kwargs["disk_win"] = self
+        edit_field.on_exit_kwargs["disk_win"] = self
+        edit_field.key_dict.update(DiskWindow.ADD_KEYS)
+        self.update_part(part_field=list_item)
+        return list_item
+    
+    def update_part(self, part_info=None, part_field=None):
+        '''Sync changed partition data to the screen.'''
+        if part_field is None:
+            if part_info is None:
+                raise ValueError("Must supply either part_info or part_field")
+            part_field = self.find_part_field(part_info)[1]
+        elif part_info is None:
+            part_info = part_field.data_obj
+        elif part_field.data_obj is not part_info:
+            raise ValueError("part_field must be a ListItem associated with "
+                             "part_info")
+        if not isinstance(part_field, ListItem):
+            raise TypeError("part_field must be a ListItem associated with "
+                            "part_info")
+        if self.has_partition_data:
+            desc_text = part_info.get_description()
+        else:
+            desc_length = self.headers[0][0] - 1
+            desc_text = "%-*.*s %s" % (desc_length, desc_length,
+                                       part_info.get_description(),
+                                       part_info.name)
+        part_field.set_text(desc_text)
+        edit_field = part_field.all_objects[0]
+        edit_field.set_text("%.1f" % part_info.size.get(Size.gb_units))
+        self.mark_if_destroyed(part_field)
+        self._update_edit_field(part_info, part_field, edit_field)
+
+        self.update_avail_space(part_info=part_info)
+        if self.has_partition_data:
+            if part_info.is_extended():
+                self.ext_part_field = part_field
+    
+    def _update_edit_field(self, part_info, part_field, edit_field):
+        '''If the partition/slice is editable, add it to the .objects list.
+        If it's also the part_field that's currently selected, then activate
+        the edit field.
+        
+        '''
+        if part_info.editable():
+            part_field.objects = [edit_field]
+            active_win = self.get_active_object()
+            if active_win is not None:
+                if active_win.get_active_object() is part_field:
+                    part_field.activate_object(edit_field)
+        else:
+            edit_field.make_inactive()
+            part_field.objects = []
+            part_field.active_object = None
+
+    def mark_if_destroyed(self, part_field):
+        '''Determine if the partition/slice represented by part_field has
+        changed such that its contents will be destroyed.
+        
+        '''
+        part_info = part_field.data_obj
+        destroyed = part_info.modified()
+        self.mark_destroyed(part_field, destroyed)
+    
+    def mark_destroyed(self, part_field, destroyed):
+        '''If destroyed is True, add an asterisk indicating that the
+        partition or slice's content will be destroyed during installation.
+        Otherwise, clear the asterisk
+        
+        '''
+        y_loc = part_field.area.y_loc
+        x_loc = part_field.area.x_loc - 1
+        if part_field in self.right_win.objects:
+            win = self.right_win
+        else:
+            win = self.left_win
+        if destroyed:
+            win.window.addch(y_loc, x_loc, DiskWindow.DESTROYED_MARK,
+                             win.color_theme.inactive)
+        else:
+            win.window.addch(y_loc, x_loc, InnerWindow.BKGD_CHAR)
+    
+    def update_avail_space(self, part_number=None, part_info=None):
+        '''Update the 'Avail' column for the specified slice or partition.
+        If no number is given, all avail columns are updated
+        
+        '''
+        if part_number is None and part_info is None:
+            self._update_all_avail_space()
+        else:
+            self._update_avail_space(part_number, part_info)
+
+    def _update_all_avail_space(self):
+        '''Update the 'Avail' column for all slices or partitions.'''
+        idx = 0
+        for item in self.left_win.objects:
+            self.update_avail_space(idx)
+            idx += 1
+        for item in self.right_win.objects:
+            self.update_avail_space(idx)
+            idx += 1
+        y_loc = idx - len(self.left_win.objects)
+        if self.has_partition_data:
+            x_loc = self.headers[0][0] + self.headers[1][0] + 1
+            field = 2
+        else:
+            x_loc = (self.headers[0][0] + self.headers[1][0] +
+                     self.headers[2][0] + 1)
+            field = 3
+        if y_loc > 0:
+            self.right_win.add_text(" " * self.headers[field][0],
+                                    y_loc, x_loc)
+
+    def _update_avail_space(self, part_number=None, part_info=None):
+        '''Update the 'Avail' column for the specified slice or partition.'''
+        if part_number is None:
+            win, item = self.find_part_field(part_info)
+        elif part_number < len(self.left_win.objects):
+            win = self.left_win
+            item = win.objects[part_number]
+        else:
+            win = self.right_win
+            item = win.objects[part_number - len(self.left_win.objects)]
+        if self.has_partition_data:
+            x_loc = self.headers[0][0] + self.headers[1][0] + 1
+            field = 2
+        else:
+            x_loc = (self.headers[0][0] + self.headers[1][0] +
+                     self.headers[2][0] + 1)
+            field = 3
+        y_loc = item.area.y_loc
+        part = item.data_obj
+        max_space = part.get_max_size()
+        max_space = "%*.1f" % (self.headers[field][0],
+                               max_space.get(Size.gb_units))
+        win.add_text(max_space, y_loc, x_loc)
+    
+    def find_part_field(self, part_info):
+        '''Given a PartitionInfo or SliceInfo object, find the associated
+        ListItem. This search compares by reference, and will only succeed
+        if you have a handle to the exact object referenced by the ListItem
+        
+        '''
+        for win in [self.left_win, self.right_win]:
+            for item in win.objects:
+                if item.data_obj is part_info:
+                    return win, item
+        raise ValueError("Part field not found")
+    
+    def reset(self, dummy=None):
+        '''Reset ui_obj to value found from Target Discovery.
+        Meaningful only for editable DiskWindows
+        
+        '''
+        if not self.editable:
+            return
+        doc = InstallEngine.get_instance().doc
+
+        # "reset" the desired target
+        reset_obj = None
+        if isinstance(self.ui_obj, UIDisk):
+            reset_obj = (self.tc.reset_layout(disk=self.ui_obj.doc_obj))[0]
+        else:
+            # reset the partition by removing the modified Partition, and
+            # resetting it with the partition found during target discovery.
+
+            discovered_obj = self.ui_obj.discovered_doc_obj
+
+            desired_disk = get_desired_target_disk(doc)
+            desired_part = get_solaris_partition(doc)
+
+            desired_disk.delete_partition(desired_part)
+            part_copy = deepcopy(discovered_obj)
+            desired_disk.insert_children(part_copy)
+
+            # get the updated reference
+            reset_obj = get_solaris_partition(doc)
+
+        dump_doc("After doing reset")
+
+        self.set_disk_info(disk_info=reset_obj)
+        self.activate_solaris_data()
+    
+    def activate_solaris_data(self):
+        '''Find the Solaris Partition / ZFS Root Pool Slice and activate it.
+        
+        '''
+
+        if self.editable:
+            solaris_part = self.ui_obj.get_solaris_data()
+            if solaris_part is None:
+                LOGGER.debug("No Solaris data, activating default")
+                self.activate_object()
+                self.right_win.scroll(scroll_to_line=0)
+                return
+            disk_order = self.ui_obj.get_parts_in_use().index(solaris_part)
+            LOGGER.debug("solaris disk at disk_order = %s", disk_order)
+            self.activate_index(disk_order)
+    
+    def make_active(self):
+        '''On activate, select the solaris partition or ZFS root pool,
+        instead of defaulting to 0
+        
+        '''
+        self.set_color(self.highlight_color)
+        self.activate_solaris_data()
+    
+    def on_arrow_key(self, input_key):
+        '''
+        On curses.KEY_LEFT: Move from the right win to the left win
+        On curses.KEY_RIGHT: Move from the left to the right
+        
+        '''
+        if (input_key == curses.KEY_LEFT and
+            self.get_active_object() is self.right_win and
+            len(self.left_win.objects) > 0):
+            
+            active_object = self.right_win.get_active_object().area.y_loc
+            if (active_object >= len(self.left_win.objects)):
+                active_object = len(self.left_win.objects) - 1
+            self.activate_object(self.left_win)
+            self.left_win.activate_object(active_object)
+            return None
+        elif (input_key == curses.KEY_RIGHT and
+              self.get_active_object() is self.left_win and
+              len(self.right_win.objects) > 0):
+            active_line = (self.left_win.active_object + 
+                             self.right_win.current_line[0])
+            active_object = None
+            force_to_top = False
+            for obj in self.right_win.objects:
+                if obj.area.y_loc >= active_line:
+                    active_object = obj
+                    off_screen = (self.right_win.current_line[0] +
+                                  self.right_win.area.lines)
+                    if active_object.area.y_loc > off_screen:
+                        force_to_top = True
+                    break
+            if active_object is None:
+                active_object = 0
+            self.left_win.activate_object(-1, loop=True)
+            self.activate_object(self.right_win)
+            self.right_win.activate_object_force(active_object,
+                                                 force_to_top=force_to_top)
+            return None
+        return input_key
+    
+    def no_ut_refresh(self, abs_y=None, abs_x=None):
+        '''Refresh self, left win and right win explicitly'''
+        super(DiskWindow, self).no_ut_refresh()
+        self.left_win.no_ut_refresh(abs_y, abs_x)
+        self.right_win.no_ut_refresh(abs_y, abs_x)
+    
+    def change_type(self, dummy):
+        '''Cycle the type for the currently active object, and
+        update its field
+        
+        '''
+        LOGGER.debug("changing type")
+
+        part_field = self.get_active_object().get_active_object()
+        part_info = part_field.data_obj
+
+        part_order = self.ui_obj.get_parts_in_use().index(part_info)
+
+        old_obj = part_info.discovered_doc_obj
+        old_type = list()
+        if old_obj is not None:
+            if self.has_partition_data:
+                old_type.append(old_obj.part_type)
+            else:
+                if old_obj.in_zpool is not None:
+                    old_type.append(old_obj.in_zpool)
+                else:
+                    in_use = part_info.doc_obj.in_use
+                    if in_use is not None:
+                        if in_use['used_name']:
+                            old_type.append((in_use['used_name'])[0])
+
+        LOGGER.debug("extra type to cycle: %s", old_type)
+        part_info.cycle_type(extra_type=old_type)
+        self.set_disk_info(ui_obj=self.ui_obj, no_part_ok=True)
+        self.activate_index(part_order)
+
+        return None
+    
+    def create_extended(self, ext_part_field):
+        '''If this is the original extended partition, restore the original
+        logical partitions. Otherwise, create a single unused logical
+        partition.
+        
+        '''
+        if not ext_part_field.data_obj.modified():
+            self.right_win.clear()
+            self.orig_logicals_active = True
+            logicals = deepcopy(self._orig_data.get_logicals())
+            self.disk_info.partitions.extend(logicals)
+            for idx, logical in enumerate(logicals):
+                self.list_area.y_loc = idx
+                self.create_list_item(logical, self.right_win, self.list_area)
+            if self.right_win not in self.objects:
+                self.objects.append(self.right_win)
+            self.right_win.activate_object_force(0, force_to_top=True)
+            self.right_win.make_inactive()
+            self.right_win.no_ut_refresh()
+        else:
+            # Leave old data be, create new Unused logical partition
+            if self.right_win not in self.objects:
+                self.objects.append(self.right_win)
+            self.append_unused_logical()
+
+    def activate_index(self, obj_index):
+        '''Activate the object at the specified index '''
+
+        if obj_index < len(self.left_win.objects):
+            LOGGER.debug("activating in left_win")
+            self.left_win.activate_object(obj_index)
+            self.activate_object(self.left_win)
+            self.right_win.scroll(scroll_to_line=0)
+        else:
+            activate = obj_index - len(self.left_win.objects)
+            LOGGER.debug('activating in right win')
+            self.right_win.activate_object_force(activate, force_to_top=True)
+            self.activate_object(self.right_win)
+            left_active = self.left_win.get_active_object()
+            if left_active is not None:
+                left_active.make_inactive()
+    
+    def append_unused_logical(self):
+        '''Adds a single Unused logical partition to the right window'''
+        new_part = self.disk_info.append_unused_logical()
+        self.list_area.y_loc = len(self.right_win.all_objects)
+        bottom = self.list_area.y_loc - self.right_win.area.lines + 1
+        self.right_win.bottom = max(0, bottom)
+        self.create_list_item(new_part, self.right_win, self.list_area)
+        scroll = len(self.right_win.all_objects) > self.right_win.area.lines
+        self.right_win.use_vert_scroll_bar = scroll
+        self.right_win.no_ut_refresh()
+
+
+def decimal_valid(edit_field, disk_win=None):
+    '''Check text to see if it is a decimal number of precision no
+    greater than the tenths place.
+
+    '''
+    text = edit_field.get_text().lstrip()
+    if text.endswith(" "):
+        raise UIMessage(_('Only the digits 0-9 and "." are valid.'))
+    vals = text.split(".")
+    if len(vals) > 2:
+        raise UIMessage(_('A number can only have one "."'))
+    try:
+        if len(vals[0]) > 0:
+            int(vals[0])
+        if len(vals) > 1 and len(vals[1]) > 0:
+            int(vals[1])
+    except ValueError:
+        raise UIMessage(_('Only the digits 0-9 and "." are valid.'))
+    if len(vals) > 1 and len(vals[1]) > 1:
+        raise UIMessage(_("Size can be specified to only one decimal place."))
+    if disk_win is not None:
+        text = text.rstrip(".")
+        if not text:
+            text = "0"
+
+        new_size = Size(text + Size.gb_units)
+        max_size = edit_field.data_obj.get_max_size()
+        
+        # When comparing sizes, check only to the first decimal place,
+        # as that is all the user sees. (Rounding errors that could
+        # cause the partition/slice layout to be invalid get cleaned up
+        # prior to target instantiation)
+        new_size_rounded = round(new_size.get(Size.gb_units), 1)
+        max_size_rounded = round(max_size.get(Size.gb_units), 1)
+        if new_size_rounded > max_size_rounded:
+            raise UIMessage(_("The new size (%(size).1f) is greater than "
+                              "the available space (%(avail).1f)") %
+                              {"size": new_size_rounded,
+                               "avail": max_size_rounded})
+    return True
+
+
+def on_exit_edit(edit_field, disk_win=None):
+    '''On exit, if the user has left the field blank, set the size to 0'''
+
+    text = edit_field.get_text()
+    if not text.strip():
+        text = "0"
+    edit_field.set_text("%.1f" % float(text))
+
+    part_order = disk_win.ui_obj.get_parts_in_use().index(edit_field.data_obj)
+    LOGGER.debug("Part being resized is at index: %s", part_order)
+
+    new_size_text = text.strip()
+
+    LOGGER.debug("Resizing text=%s", new_size_text)
+    new_size = Size(new_size_text + Size.gb_units)
+    old_size = edit_field.data_obj.size
+
+    new_size_byte = new_size.get(Size.byte_units)
+    old_size_byte = old_size.get(Size.byte_units)
+
+    precision = Size(UI_PRECISION).get(Size.byte_units)
+
+    if abs(new_size_byte - old_size_byte) > precision:
+        resized_obj = edit_field.data_obj.doc_obj.resize(float(new_size_text),
+                                           size_units=Size.gb_units)
+
+        if isinstance(resized_obj, Partition):
+            resized_obj.in_zpool = ROOT_POOL 
+        else:
+            if resized_obj.in_zpool == ROOT_POOL:
+                resized_obj.tag = V_ROOT
+
+        if disk_win is not None:
+            disk_win.set_disk_info(ui_obj=disk_win.ui_obj)
+            disk_win.activate_index(part_order)
+
+    dump_doc("After resize")
+
+
+def get_recommended_size(target_controller):
+    '''Returns the recommended size for the installation, as a Size object '''
+    if DiskWindow.REC_SIZE is None:
+        DiskWindow.REC_SIZE = target_controller.recommended_target_size 
+    return DiskWindow.REC_SIZE
+
+
+def get_minimum_size(target_controller):
+    '''Returns the minimum disk space needed for installation, 
+       as a Size object
+    
+    '''
+
+    if DiskWindow.MIN_SIZE is None:
+        DiskWindow.MIN_SIZE = target_controller.minimum_target_size
+    return DiskWindow.MIN_SIZE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/fdisk_partitions.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Screen for selecting to use whole disk, or a partition/slice on the disk
+'''
+
+import logging
+import platform
+
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.target.physical import Disk, Partition, Slice
+from solaris_install.target.size import Size
+from solaris_install.text_install import _, RELEASE, TUI_HELP
+from solaris_install.text_install.disk_window import DiskWindow
+from solaris_install.text_install.ti_target_utils import \
+    get_desired_target_disk, get_solaris_partition, dump_doc, ROOT_POOL
+from terminalui.base_screen import BaseScreen, SkipException
+from terminalui.i18n import textwidth
+from terminalui.list_item import ListItem
+from terminalui.window_area import WindowArea
+
+
+LOGGER = None
+
+
+class FDiskPart(BaseScreen):
+    '''Allow user to choose to use the whole disk, or move to the
+    partition/slice edit screen.
+    
+    '''
+    
+    BOOT_TEXT = _("Boot")
+    HEADER_FDISK = _("Fdisk Partitions: %(size).1fGB %(type)s %(bootable)s")
+    HEADER_PART_SLICE = _("Solaris Partition Slices")
+    HEADER_SLICE = _("Solaris Slices: %(size).1fGB %(type)s %(bootable)s")
+    PARAGRAPH_FDISK = _("%(release)s can be installed on the whole "
+                        "disk or a partition on the disk.") % RELEASE
+    PARAGRAPH_PART_SLICE = _("%(release)s can be installed in the "
+                             "whole fdisk partition or within a "
+                             "slice in the partition") % RELEASE
+    PARAGRAPH_SLICE = _("%(release)s can be installed on the whole"
+                        " disk or a slice on the disk.") % RELEASE
+    FOUND_PART = _("The following partitions were found on the disk.")
+    PROPOSED_PART = _("A partition table was not found. The following is"
+                      " proposed.")
+    FOUND_SLICE = _("The following slices were found on the disk.")
+    PROPOSED_SLICE = _("A VTOC label was not found. The following is "
+                       "proposed.")
+    USE_WHOLE_DISK = _("Use the whole disk")
+    USE_WHOLE_PARTITION = _("Use the whole partition")
+    USE_SLICE_IN_PART = _("Use a slice in the partition")
+    USE_PART_IN_DISK = _("Use a partition of the disk")
+    USE_SLICE_IN_DISK = _("Use a slice on the disk")
+    
+    SPARC_HELP = (TUI_HELP + "/%s/sparc_solaris_slices.txt",
+                  _("Solaris Slices"))
+    X86_PART_HELP = (TUI_HELP + "/%s/"
+                     "x86_fdisk_partitions.txt",
+                     _("Fdisk Partitions"))
+    X86_SLICE_HELP = (TUI_HELP + "/%s/x86_fdisk_slices.txt",
+                      _("Solaris Partition Slices"))
+    
+    def __init__(self, main_win, target_controller, x86_slice_mode=False):
+        '''If x86_slice_mode == True, this screen presents options for using a
+        whole partition, or a slice within the partition.
+        Otherwise, it presents options for using the whole disk, or using a
+        partition (x86) or slice (SPARC) within the disk
+        
+        '''
+        super(FDiskPart, self).__init__(main_win)
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+        self.x86_slice_mode = x86_slice_mode
+        self.is_x86 = True
+        self.help_format = "  %s"
+        if platform.processor() == "sparc": # SPARC, slices on a disk
+            self.is_x86 = False
+            self.header_text = FDiskPart.HEADER_SLICE
+            self.paragraph = FDiskPart.PARAGRAPH_SLICE
+            self.found = FDiskPart.FOUND_SLICE
+            self.proposed = FDiskPart.PROPOSED_SLICE
+            self.use_whole = FDiskPart.USE_WHOLE_DISK
+            self.use_part = FDiskPart.USE_SLICE_IN_DISK
+            self.help_data = FDiskPart.SPARC_HELP
+        elif self.x86_slice_mode: # x86, slices within a partition
+            self.instance = ".slice"
+            self.header_text = FDiskPart.HEADER_PART_SLICE
+            self.paragraph = FDiskPart.PARAGRAPH_PART_SLICE
+            self.found = FDiskPart.FOUND_SLICE
+            self.proposed = FDiskPart.PROPOSED_SLICE
+            self.use_whole = FDiskPart.USE_WHOLE_PARTITION
+            self.use_part = FDiskPart.USE_SLICE_IN_PART
+            self.help_data = FDiskPart.X86_SLICE_HELP
+            self.help_format = "    %s"
+        else: # x86, partitions on a disk
+            self.header_text = FDiskPart.HEADER_FDISK
+            self.paragraph = FDiskPart.PARAGRAPH_FDISK
+            self.found = FDiskPart.FOUND_PART
+            self.proposed = FDiskPart.PROPOSED_PART
+            self.use_whole = FDiskPart.USE_WHOLE_DISK
+            self.use_part = FDiskPart.USE_PART_IN_DISK
+            self.help_data = FDiskPart.X86_PART_HELP
+        self.disk_win = None
+        self.partial_disk_item = None
+        self.whole_disk_item = None
+        self.disk = None 
+        self.tc = target_controller
+        self.use_whole_segment = True
+    
+    def _show(self):
+        '''Display partition data for selected disk, and present the two
+        choices
+        
+        '''
+        doc = InstallEngine.get_instance().doc
+        
+        if self.x86_slice_mode:
+
+            disk = get_desired_target_disk(doc)
+            if disk.whole_disk:
+                raise SkipException
+
+            sol_partition = get_solaris_partition(doc)
+
+            LOGGER.debug("Working with the following partition:")
+            LOGGER.debug(str(sol_partition))
+
+            if sol_partition is None:
+                # Must have a Solaris partition
+                err_msg = "Critical error - no Solaris partition found"
+                LOGGER.error(err_msg)
+                raise ValueError(err_msg)
+
+            # See if there are any slices in the partition
+            all_slices = sol_partition.get_children(class_type=Slice)
+
+            if not all_slices:
+                LOGGER.info("No previous slices found")
+
+                # Setting the in_zpool flag to indicate the whole
+                # partition should be used.  The needed underlying
+                # slices will be created in the next step when
+                # the in_zpool flag is detected.
+                sol_partition.in_zpool = ROOT_POOL
+
+                raise SkipException
+                    
+            LOGGER.debug("Preserved partition with existing slices, "
+                         "presenting option to install into a slice")
+
+            self.disk = sol_partition
+
+        else:
+
+            self.disk = get_desired_target_disk(doc)
+
+            LOGGER.debug("Working with the following disk:")
+            LOGGER.debug(str(self.disk))
+
+            if self.disk.whole_disk:
+                LOGGER.debug("disk.whole_disk=True, skip editting")
+                raise SkipException
+
+            if self.disk.is_boot_disk():
+                bootable = FDiskPart.BOOT_TEXT
+            else:
+                bootable = u""
+            disk_size_gb = self.disk.disk_prop.dev_size.get(Size.gb_units)
+            header_text = self.header_text % \
+                            {"size": disk_size_gb,
+                             "type": self.disk.disk_prop.dev_type,
+                             "bootable": bootable}
+            self.main_win.set_header_text(header_text)
+
+        y_loc = 1
+        y_loc += self.center_win.add_paragraph(self.paragraph, start_y=y_loc)
+        
+        y_loc += 1
+        if self.is_x86 and not self.x86_slice_mode:
+            all_parts = self.disk.get_children(class_type=Partition)
+        else:
+            all_parts = self.disk.get_children(class_type=Slice)
+
+        found_parts = bool(all_parts)
+
+        if found_parts:
+            next_line = self.found
+        else:
+            next_line = self.proposed
+        y_loc += self.center_win.add_paragraph(next_line, start_y=y_loc)
+        
+        y_loc += 1
+        disk_win_area = WindowArea(6, 70, y_loc, 0)
+        self.disk_win = DiskWindow(disk_win_area, self.disk,
+                                   target_controller=self.tc,
+                                   window=self.center_win)
+        y_loc += disk_win_area.lines
+        
+        y_loc += 3
+        whole_disk_width = textwidth(self.use_whole) + 3
+        cols = (self.win_size_x - whole_disk_width) / 2
+        whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols)
+        self.whole_disk_item = ListItem(whole_disk_item_area,
+                                        window=self.center_win,
+                                        text=self.use_whole,
+                                        centered=True)
+        
+        y_loc += 1
+        partial_width = textwidth(self.use_part) + 3
+        cols = (self.win_size_x - partial_width) / 2
+        partial_item_area = WindowArea(1, partial_width, y_loc, cols)
+        self.partial_disk_item = ListItem(partial_item_area,
+                                          window=self.center_win,
+                                          text=self.use_part,
+                                          centered=True)
+        
+        self.main_win.do_update()
+        if self.use_whole_segment:
+            self.center_win.activate_object(self.whole_disk_item)
+        else:
+            self.center_win.activate_object(self.partial_disk_item)
+    
+    def on_continue(self):
+        '''Set the user's selection in the install target. If they chose
+        to use the entire disk (or entire partition), define a single
+        partition (or slice) to consume the whole disk (or partition)
+        
+        '''
+
+        if self.center_win.get_active_object() is self.whole_disk_item:
+            self.use_whole_segment = True
+            if isinstance(self.disk, Disk):
+                LOGGER.debug("Setting whole_disk and creating default"
+                             " layout for %s", self.disk)
+                disk = self.tc.select_disk(self.disk, use_whole_disk=True)[0]
+                disk.whole_disk = True
+            else: 
+                # it's a partition, set the in_zpool attribute in
+                # the object for now.  The next screen will
+                # fill in needed slices
+                self.disk.in_zpool = ROOT_POOL
+        else:
+            self.use_whole_segment = False
+            if isinstance(self.disk, Disk):
+                LOGGER.debug("Setting whole_disk to false")
+                self.disk.whole_disk = False
+            else:
+                self.disk.in_zpool = None
+
+        dump_doc("At the end of fdisk_partitions.continue")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/install_progress.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Start the installation, provide functions for updating the install progress
+'''
+
+import curses
+import math
+
+from solaris_install.text_install import _, RELEASE
+from solaris_install.text_install.ti_install import perform_ti_install
+from terminalui.base_screen import BaseScreen
+from terminalui.i18n import ljust_columns
+from terminalui.inner_window import InnerWindow
+from terminalui.window_area import WindowArea
+
+
+class InstallProgress(BaseScreen):
+    '''Present a progress bar, and callback hooks for an installation
+    Thread to update this screen with percent complete and status.
+    
+    '''
+    
+    HEADER_TEXT = _("Installing %(release)s") % RELEASE
+    PROG_BAR_ENDS = (ord('['), ord(']'))
+    
+    QUIT_DISK_MODIFIED = _("Do you want to quit the Installer?\n\n"
+                           "Any changes made to the disk by the "
+                           "Installer will be left \"as is.\"")
+    
+    def __init__(self, main_win, install_data, target_controller):
+        super(InstallProgress, self).__init__(main_win)
+        
+        # Location on screen where the status messages should get printed
+        # Format: (y, x, max-width)
+        self.status_msg_loc = (4, 12, 50)
+        
+        # Location on screen where the progress bar should be displayed
+        # Format: (y, x, width)
+        self.status_bar_loc = (6, 10, 50)
+        
+        self.status_bar = None
+        self.status_bar_width = None
+        self.install_data = install_data
+        self.progress_color = None
+        self.update_to = None
+        self.tc = target_controller
+    
+    def set_actions(self):
+        '''Remove all actions except F9_Quit.'''
+        self.main_win.actions.pop(curses.KEY_F2) # Remove F2_Continue
+        self.main_win.actions.pop(curses.KEY_F3) # Remove F3_Back
+        self.main_win.actions.pop(curses.KEY_F6) # Remove F6_Help
+
+    def _show(self):
+        '''Set an initial status message, and initialize the progress bar'''
+        self.set_status_message(InstallProgress.HEADER_TEXT)
+        self.init_status_bar(*self.status_bar_loc)
+        self.main_win.redrawwin()
+        self.main_win.do_update()
+
+    def validate_loop(self):
+        ''' Do the actual installation '''
+        self.center_win.window.timeout(100) # Make getch() non-blocking
+        perform_ti_install(self.install_data, self, self.update_status)
+        self.center_win.window.timeout(-1) # Restore getch() to be blocking
+        return self.main_win.screen_list.get_next(self)
+
+    def update_status(self, percent, message):
+        '''Update this screen to display message and set the status
+        bar to 'percent'. 
+
+        '''
+
+        self.set_status_message(message)
+        self.set_status_percent(percent)
+        self.main_win.redrawwin()
+        self.main_win.do_update()
+    
+    def set_status_message(self, message):
+        '''Set the status message on the screen, completely overwriting
+        the previous message'''
+        self.center_win.add_text(ljust_columns(\
+            message, self.status_msg_loc[2]), self.status_msg_loc[0],\
+            self.status_msg_loc[1], max_chars=self.status_msg_loc[2])
+    
+    def set_status_percent(self, percent):
+        '''Set the completion percentage by updating the progress bar.
+        Note that this is implemented as a 'one-way' change (updating to
+        a percent that is lower than previously set will not work)
+        
+        '''
+        width = self.status_bar_width
+        complete = int(math.ceil(float(percent) / 100.0 * width))
+        self.status_bar.add_text(" " * complete, start_y=0, start_x=1,
+                                 max_chars=width)
+        percent_text = "(%i%%)" % percent
+        percent_bar = percent_text.center(width)
+        left_half = percent_bar[:complete]
+        right_half = percent_bar[complete:]
+        self.status_bar.window.addstr(0, 1, left_half, self.progress_color)
+        self.status_bar.window.addstr(0, complete + 1, right_half)
+        self.status_bar.no_ut_refresh()
+    
+    def init_status_bar(self, y_loc, x_loc, width):
+        '''Initialize the progress bar window and set to 0%'''
+        self.status_bar_width = width
+        status_bar_area = WindowArea(1, width + 3, y_loc, x_loc + 1)
+        self.status_bar = InnerWindow(status_bar_area,
+                                      window=self.center_win)
+        self.status_bar.window.addch(0, 0, InstallProgress.PROG_BAR_ENDS[0])
+        self.status_bar.window.addch(0, width + 1,
+                                     InstallProgress.PROG_BAR_ENDS[1])
+        self.progress_color = self.center_win.color_theme.progress_bar
+        self.set_status_percent(0)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/install_status.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Report the status of an installation to the user
+'''
+
+import curses
+
+from solaris_install.text_install import _, RELEASE
+from terminalui.action import Action
+from terminalui.base_screen import BaseScreen
+
+
+class RebootException(SystemExit):
+    '''Raised when user requests reboot'''
+    pass
+
+
+class InstallStatus(BaseScreen):
+    '''
+    Display text to the user indicating success or failure of the installation.
+    Also provide option for viewing the install log
+    
+    '''
+    
+    SUCCESS_HEADER = _("Installation Complete")
+    FAILED_HEADER = _("Installation Failed")
+    
+    SUCCESS_TEXT = _("The installation of %(release)s has completed "
+                     "successfully.\n\n"
+                     "Reboot to start the newly installed software "
+                     "or Quit if you wish to perform additional "
+                     "tasks before rebooting.\n\n"
+                     "The installation log is available at "
+                     "%(log_tmp)s. After reboot it can be found"
+                     " at %(log_final)s.")
+    
+    FAILED_TEXT = _("The installation did not complete normally.\n\n"
+                    "For more information you can review the"
+                    " installation log.\n"
+                    "The installation log is available at %(log_tmp)s")
+    
+    def __init__(self, main_win, install_data):
+        super(InstallStatus, self).__init__(main_win)
+        self.log_locations = {}
+        self.install_data = install_data
+    
+    def set_actions(self):
+        '''Remove all actions except Quit, and add actions for rebooting
+        and viewing the log.
+        
+        '''
+        self.main_win.actions.pop(curses.KEY_F2) # Remove F2_Continue
+        self.main_win.actions.pop(curses.KEY_F3) # Remove F3_Back
+        self.main_win.actions.pop(curses.KEY_F6) # Remove F6_Help
+        
+        if self.install_data.install_succeeded:
+            reboot_action = Action(curses.KEY_F8, _("Reboot"), reboot_system)
+            self.main_win.actions[reboot_action.key] = reboot_action
+        
+        log_action = Action(curses.KEY_F4, _("View Log"),
+                            self.main_win.screen_list.get_next)
+        self.main_win.actions[log_action.key] = log_action
+        
+    def _show(self):
+        '''Display the correct text based on whether the installation
+        succeeded or failed.
+        
+        '''
+
+        self.log_locations["log_tmp"] = self.install_data.log_location
+        self.log_locations["log_final"] = self.install_data.log_final
+        if self.install_data.install_succeeded:
+            self.header_text = InstallStatus.SUCCESS_HEADER
+            paragraph_text = InstallStatus.SUCCESS_TEXT
+        else:
+            self.header_text = InstallStatus.FAILED_HEADER
+            paragraph_text = InstallStatus.FAILED_TEXT
+        self.main_win.set_header_text(self.header_text)
+        
+        fmt = {}
+        fmt.update(self.log_locations)
+        fmt.update(RELEASE)
+        self.center_win.add_paragraph(paragraph_text % fmt, 2)
+    
+    def confirm_quit(self):
+        '''No need to confirm after installation is complete'''
+        return True
+
+
+def reboot_system(screen=None):
+    '''Attempts to reboot the system (unless running with the '-n' command
+    line flag)
+    
+    '''
+    if screen and screen.install_data.no_install_mode:
+        raise SystemExit("REBOOT")
+    else:
+        raise RebootException
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/log_viewer.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Read in and display the install log to the user
+'''
+
+import curses
+
+from solaris_install.text_install import _
+from terminalui.base_screen import BaseScreen
+from terminalui.i18n import convert_paragraph
+from terminalui.scroll_window import ScrollWindow
+from terminalui.window_area import WindowArea
+
+
+class LogViewer(BaseScreen):
+    '''Screen for reading and displaying the install log'''
+    
+    HEADER_TEXT = _("Installation Log")
+    
+    def __init__(self, main_win, install_data):
+        super(LogViewer, self).__init__(main_win)
+        self.log_data = None
+        self.scroll_area = None
+        self.install_data = install_data
+    
+    def set_actions(self):
+        '''Remove all actions except F3_Back'''
+        self.main_win.actions.pop(curses.KEY_F2)
+        self.main_win.actions.pop(curses.KEY_F6)
+        self.main_win.actions.pop(curses.KEY_F9)
+    
+    def _show(self):
+        '''Create a scrollable region and fill it with the install log'''
+        
+        self.center_win.border_size = (0, 0)
+        self.scroll_area = WindowArea(self.win_size_y,
+                                      self.win_size_x,
+                                      0, 0, len(self.get_log_data()))
+        log = ScrollWindow(self.scroll_area, window=self.center_win)
+        log.add_paragraph(self.get_log_data(), 0, 2)
+        self.center_win.activate_object(log)
+    
+    def get_log_data(self):
+        '''Attempt to read in the install log file. If an error occurs,
+        the log_data is set to a string explaining the cause, if possible.
+        
+        '''
+        if self.log_data is None:
+            try:
+                with open(self.install_data.log_location) as log_file:
+                    log_data = log_file.read()
+            except (OSError, IOError) as error:
+                self.log_data = _("Could not read log file:\n\t%s") % \
+                                  error.strerror
+            max_chars = self.win_size_x - 4
+            self.log_data = convert_paragraph(log_data, max_chars)
+        return self.log_data
--- a/usr/src/cmd/text-install/osol_install/__init__.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#!/usr/bin/python
-'''This file SHOULD NOT be built into the package
-It is included solely to provide the ability to run/debug
-osol_install.text_install.* directly from the workspace
-(so that Python recognizes the osol_install folder as a
-module). osol_install/__init__.py is normally delivered by
-pkg:/system/install
-'''
--- a/usr/src/cmd/text-install/osol_install/profile/Makefile	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-include ../../../Makefile.cmd
-
-all:=		TARGET= all
-clean:=		TARGET= clean
-clobber:=	TARGET= clobber
-install:=	TARGET= install
-
-PYMODULES=	__init__.py \
-		disk_info.py \
-		disk_space.py \
-		install_profile.py \
-		partition_info.py \
-		slice_info.py
-
-PYCMODULES=     $(PYMODULES:%.py=%.pyc)
-
-ROOTPROGS=      $(PROGS:%=$(ROOTUSRBIN)/%)
-
-ROOTPYMODULES=  $(PYMODULES:%=$(ROOTPYTHONVENDORINSTALLPROF)/%)
-
-ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORINSTALLPROF)/%)
-
-MSGFILES =	$(PYMODULES)
-
-.KEEP_STATE:
-
-all:		python
-
-clean:
-	rm -f $(PROGS) *.pyc
-
-clobber: clean
-
-
-install: all .WAIT $(ROOTPROGS) \
-	$(ROOTPYTHONVENDOR) \
-	$(ROOTPYTHONVENDORINSTALL) \
-	$(ROOTPYTHONVENDORINSTALLPROF) \
-	$(ROOTPYMODULES) \
-	$(ROOTPYCMODULES)
-
-python:
-	$(PYTHON) -m compileall -l $(@D)
-
-
-FRC:
-
-include ../../../Makefile.targ
-
--- a/usr/src/cmd/text-install/osol_install/profile/disk_info.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,629 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Object to represent Disks
-'''
-
-from copy import copy, deepcopy
-import logging
-import platform
-
-import osol_install.tgt as tgt
-from osol_install.profile.disk_space import DiskSpace, round_to_multiple, \
-                                            round_down
-from osol_install.profile.partition_info import PartitionInfo, MIN_GAP_SIZE, \
-                                            MIN_LOGICAL_GAP_SIZE
-from osol_install.profile.slice_info import SliceInfo
-from osol_install.text_install.ti_install_utils import InstallationError
-
-
-def adjust_tgt_parts(tgt_objs, tgt_parent=None, ext_part=None):
-    '''Modify a list of tgt.Partitions or tgt.Slices in place. For each item
-    in the list, ensure that its offset is *past* the previous tgt object, and
-    ensure that its size + offset doesn't cause it to overlap with the
-    subsequent partition/slice.
-    
-    tgt.Partitions/Slices whose 'modified' flag is false are ignored. These
-    are assumed to already exist on the disk (and assumed to not overlap);
-    new Partitions/Slices are adjusted around the existing ones.
-    
-    tgt_objs: A list of tgt.Partitions or tgt.Slices. Logical partitions
-                should NOT be mixed with standard partitions.
-    tgt_parent: The tgt.Disk or tgt.Partition on which the tgt_objs are
-                supposed to fit
-    ext_part: The extended partition on which the tgt_objs are supposed to fit
-    
-    It is invalid to specify both tgt_parent and ext_part (ext_part will be
-    ignored and the resulting disk layout could be indeterminate)
-    
-    '''
-    
-    if not tgt_objs:
-        return
-    
-    if tgt_parent is not None:
-        cylsz = tgt_parent.geometry.cylsz
-        if isinstance(tgt_objs[0], tgt.Slice):
-            # Checking slices on a partition/disk
-            # Can start at 0
-            min_offset = 0
-            
-            if isinstance(tgt_parent, tgt.Slice):
-                # Using S2 to determine max. All blocks usable
-                abs_max_end = tgt_parent.blocks
-            else:
-                # Using a disk or partition to determine max
-                # Must leave 2 cylinders worth of space available
-                abs_max_end = tgt_parent.blocks - 2 * cylsz
-            
-        else:
-            # Checking partitions on a disk
-            # Use the minimum partition offset as starting point
-            # Don't exceed the end of the disk
-            min_offset = PartitionInfo.MIN_OFFSET
-            abs_max_end = tgt_parent.blocks
-    elif ext_part is not None:
-        # Logicals on an extended partition
-        # Should have an offset past the start of the extended partition
-        # Should not go past the end of the extended partition
-        min_offset = ext_part.offset
-        abs_max_end = ext_part.offset + ext_part.blocks
-        cylsz = ext_part.geometry.cylsz
-    else:
-        raise TypeError("Must specify ext_part or tgt_parent keyword arg")
-    
-    for idx, tgt_obj in enumerate(tgt_objs):
-        
-        if tgt_obj.modified and tgt_obj.offset < min_offset:
-            tgt_obj.offset = round_to_multiple(min_offset, cylsz)
-        
-        if tgt_obj is tgt_objs[-1]:
-            # Last item in the list - don't let this obj slide past the end
-            # of the disk/partition
-            max_end = abs_max_end
-        else:
-            # More items in the list - don't let this obj overlap with the
-            # next item
-            max_end = tgt_objs[idx+1].offset - 1
-        
-        if tgt_obj.modified and tgt_obj.offset + tgt_obj.blocks > max_end:
-            shift = (tgt_obj.offset + tgt_obj.blocks) - max_end
-            new_blocks = tgt_obj.blocks - shift
-            tgt_obj.blocks = round_down(new_blocks, cylsz)
-        
-        # Minimum offset for next obj should be past the end of this obj.
-        # Preserve the current value of min_offset if it happens to be greater
-        # than the end of this obj (for example, if this slice overlaps with,
-        # and lies completely within, a prior slice)
-        min_offset = max(min_offset, tgt_obj.offset + tgt_obj.blocks + 1)
-
-
-# Pylint gets confused and thinks DiskInfo.size is a string but it's
-# actually a DiskSpace object
-# pylint: disable-msg=E1103
-class DiskInfo(object):
-    '''Represents a single disk on the system.'''
-    
-    FDISK = "fdisk"
-    GPT = "gpt"
-    VTOC = "vtoc"
-    
-    def __init__(self, blocksz=512, cylsz=None, boot=False, partitions=None,
-                 slices=None, controller=None, label=None, name=None,
-                 removable=False, serialno=None, size=None, vendor=None,
-                 tgt_disk=None):
-        '''Constructor takes either a tgt_disk, which should be a tgt.Disk
-        object, or a set of parameters. If tgt_disk is supplied, all other
-        parameters are ignored.
-        
-        '''
-        self._size = None
-        self._tgt_disk = tgt_disk
-        self._ext_part_idx = 0
-        self._sol_part_idx = 0
-        self._unused_parts_added = False
-        if tgt_disk:
-            self.blocksz = tgt_disk.geometry.blocksz
-            self.cylsz = tgt_disk.geometry.cylsz
-            self.boot = tgt_disk.boot
-            self.partitions = []
-            self.slices = []
-            if tgt_disk.children:
-                if isinstance(tgt_disk.children[0], tgt.Slice):
-                    for child in tgt_disk.children:
-                        self.slices.append(SliceInfo(tgt_slice=child))
-                else:
-                    for child in tgt_disk.children:
-                        self.partitions.append(PartitionInfo(tgt_part=child))
-            self.controller = tgt_disk.controller
-            self.label = set()
-            if tgt_disk.gpt:
-                self.label.add(DiskInfo.GPT)
-            if tgt_disk.vtoc:
-                self.label.add(DiskInfo.VTOC)
-            if tgt_disk.fdisk:
-                self.label.add(DiskInfo.FDISK)
-            self.name = tgt_disk.name
-            self.removable = tgt_disk.removable
-            self.serialno = tgt_disk.serialno
-            size = str(tgt_disk.blocks * self.blocksz) + "b"
-            self.size = size
-            self.vendor = tgt_disk.vendor
-        else:
-            self.blocksz = blocksz
-            self.cylsz = cylsz
-            self.boot = boot
-            if partitions and slices:
-                raise ValueError("A disk cannot have both partitions and"
-                                 " slices")
-            if partitions is None:
-                partitions = []
-            self.partitions = partitions
-            if slices is None:
-                slices = []
-            self.slices = slices
-            self.controller = controller
-            self.label = label
-            self.name = name
-            self.removable = removable
-            self.serialno = serialno
-            self.size = size
-            self.vendor = vendor
-        self.use_whole_segment = False
-        
-        if platform.processor() == "i386":
-            self.was_blank = not bool(self.partitions)
-        else:
-            self.was_blank = not bool(self.slices)
-    
-    def __str__(self):
-        result = ["Disk Info (%s):" % self.name]
-        result.append("Size: %s" % self.size)
-        for part in self.partitions:
-            result.append(str(part))
-        for slice_info in self.slices:
-            result.append(str(slice_info))
-        return "\n".join(result)
-    
-    def get_type(self):
-        '''Return this disk's 'type' (controller) as a string'''
-        if self.controller is None:
-            return ""
-        else:
-            return self.controller.upper()
-    
-    type = property(get_type)
-    
-    def get_size(self):
-        '''Returns this disk's size as a DiskSpace object'''
-        return self._size
-    
-    def set_size(self, size):
-        '''Set this disk's size. size must be either a DiskSpace or a string
-        that will be accepted by DiskSpace.__init__
-        
-        '''
-        if isinstance(size, DiskSpace):
-            self._size = deepcopy(size)
-        else:
-            self._size = DiskSpace(size)
-    
-    size = property(get_size, set_size)
-    
-    def get_blocks(self):
-        '''Return the number of blocks on this disk'''
-        return int(self.size.size_as("b") / self.blocksz)
-    
-    blocks = property(get_blocks)
-    
-    def get_solaris_data(self, check_multiples=False):
-        '''Find and return the solaris partition (x86) or install target
-        slice (sparc) on this disk.
-        
-        Returns None if one does not exist.
-        
-        '''
-        if platform.processor() == "i386":
-            parts = self.partitions
-        else:
-            parts = self.slices
-        
-        if (not check_multiples and self._sol_part_idx < len(parts) and
-            parts[self._sol_part_idx].is_solaris_data()):
-            return parts[self._sol_part_idx]
-        
-        solaris_data = None
-        for part in parts:
-            if part.is_solaris_data():
-                if solaris_data is None:
-                    self._sol_part_idx = parts.index(part)
-                    solaris_data = part
-                    if not check_multiples:
-                        break
-                elif check_multiples:
-                    raise ValueError("Found multiple children with "
-                                     "solaris data")
-        
-        return solaris_data
-    
-    def get_extended_partition(self):
-        '''Find and return the Extended partition on this disk.
-        Returns None if this disk has no extended partition.
-        
-        '''
-        if (self._ext_part_idx < len(self.partitions) and
-            self.partitions[self._ext_part_idx].is_extended()):
-            return self.partitions[self._ext_part_idx]
-        
-        for part in self.partitions:
-            if part.is_extended():
-                self._ext_part_idx = part
-                return part
-        
-        return None
-    
-    def get_logicals(self):
-        '''Retrieve all the logicals on this disk'''
-        logicals = []
-        for part in self.partitions:
-            if part.is_logical():
-                logicals.append(part)
-        return logicals
-    
-    def get_standards(self):
-        '''Return all non-logical partitions'''
-        standards = []
-        for part in self.partitions:
-            if not part.is_logical():
-                standards.append(part)
-        return standards
-    
-    def remove_logicals(self):
-        '''Delete the logicals from this disk'''
-        remove_all = []
-        for part in self.partitions:
-            if part.is_logical():
-                remove_all.append(part)
-        for part in remove_all:
-            self.partitions.remove(part)
-    
-    def collapse_unused_logicals(self):
-        '''Collapse adjacent unused logical partitions'''
-        logicals = self.get_logicals()
-        removal_count = 0
-        for idx, logical in enumerate(logicals[:-1]):
-            next_log = logicals[idx+1]
-            if (logical.id == PartitionInfo.UNUSED and
-                next_log.id == PartitionInfo.UNUSED):
-                self.partitions.remove(next_log)
-                removal_count += 1
-        return removal_count
-    
-    def add_unused_parts(self):
-        '''On x86: Sort through the logical and non-logical partitions and
-        find the largest gaps. For non-logical partitions, create additional 
-        Unused partitions such that the number of 
-        non-logical partitions == MAX_STANDARD_PARTITIONS. For logical
-        partitions, create additional Unused partitions such that the number of
-        logical partitions == MAX_LOGICAL_PARTITIONS
-        
-        On SPARC: Create Unused slices in the largest gaps of empty space,
-        so that there are exactly 8 slices
-        
-        For non-logical partitions, gaps smaller than 1 GB are ignored.
-        For logical partitions, gaps smaller than 0.1 GB are ignored.
-        
-        This method adds unused parts exactly once.
-
-        '''
-        if self._unused_parts_added:
-            return
-
-        if self.partitions:
-            use_partitions = True
-            parts = self.get_standards()
-            parts.sort(cmp=PartitionInfo.compare)
-            numbers = range(1, PartitionInfo.MAX_STANDARD_PARTITIONS + 1)
-            start_pt = 0
-        elif self.slices:
-            use_partitions = False
-            parts = copy(self.slices)
-            parts.sort(cmp=SliceInfo.compare)
-            numbers = range(SliceInfo.MAX_SLICES)
-            numbers.remove(SliceInfo.BACKUP_SLICE)
-            start_pt = 0
-        else:
-            raise ValueError("Cannot determine if this disk has partitions"
-                             " or slices")
-        backup_part = None
-        if not use_partitions:
-            for part in parts:
-                if part.number == SliceInfo.BACKUP_SLICE:
-                    backup_part = part
-            if backup_part is not None:
-                parts.remove(backup_part)
-        
-        min_gap_size = MIN_GAP_SIZE.size_as("b")
-        gaps = []
-        end_pt = 0
-        for part in parts:
-            if part.number in numbers:
-                numbers.remove(part.number)
-            start_pt = part.offset.size_as("b")
-            gap_size = start_pt - end_pt
-            if gap_size > min_gap_size:
-                gaps.append((gap_size, end_pt))
-            end_pt = part.get_endblock().size_as("b")
-        end_disk = self.size.size_as("b")
-        gap_size = end_disk - end_pt
-        if gap_size > min_gap_size:
-            gaps.append((gap_size, end_pt))
-        # Sorting a list of tuples will sort by the first item in the tuple,
-        # In this case, gap_size, such that the smallest gap is first.
-        # Then, the largest gaps can be popped off the end of the list
-        gaps.sort()
-        for part_num in numbers:
-            if gaps:
-                gap = gaps.pop()
-                offset = str(gap[1]) + "b"
-            else:
-                offset = str(end_pt) + "b"
-            if use_partitions:
-                new_part = PartitionInfo(part_num=part_num, offset=offset)
-                self.partitions.append(new_part)
-            else:
-                new_part = SliceInfo(slice_num=part_num, offset=offset)
-                self.slices.append(new_part)
-        if not use_partitions and backup_part is None:
-            new_part = SliceInfo(slice_num=SliceInfo.BACKUP_SLICE,
-                                 size=self.size)
-            self.slices.append(new_part)
-        self.sort_disk_order()
-        
-        # now process the logical partitions
-        if use_partitions:
-            logicals = self.get_logicals()
-            ext_part = self.get_extended_partition()
-            if ext_part is not None:
-                min_logical_gap_size = MIN_LOGICAL_GAP_SIZE.size_as("b")
-                logical_gaps = []
-                end_pt = ext_part.offset.size_as("b")
-                                 	
-                numbers = range(PartitionInfo.FIRST_LOGICAL, 
-                    PartitionInfo.FIRST_LOGICAL + 
-                    PartitionInfo.MAX_LOGICAL_PARTITIONS)
-                for logical in logicals:
-                    numbers.remove(logical.number)
-                    start_pt = logical.offset.size_as("b") 
-                    logical_gap_size = start_pt - end_pt
-                    if logical_gap_size > min_logical_gap_size:
-                        logical_gaps.append((logical_gap_size, end_pt))
-                    end_pt = logical.get_endblock().size_as("b")
-               
-                end_disk = ext_part.get_endblock().size_as("b")
-                logical_gap_size = end_disk - end_pt
-                if logical_gap_size > min_logical_gap_size:
-                    logical_gaps.append((logical_gap_size, end_pt))
-
-                # Sorting a list of tuples will sort by the first item
-                # in the tuple, in this case, logical_gap_size, such that
-                # the smallest gap is first.
-                logical_gaps.sort()    
-                for number in numbers:
-                    if logical_gaps:
-                        logical_gap = logical_gaps.pop()
-                        offset = str(logical_gap[1]) + "b"
-                    else:
-                        break
-                    new_part = PartitionInfo(part_num=number, offset=offset)
-                    self.partitions.append(new_part)
-
-                self.sort_disk_order()
-
-        self._unused_parts_added = True
-
-    def append_unused_logical(self):
-        '''Append a single unused logical partition to the disk.
-        The last logical partition is assumed to be something *other*
-        than an 'unused' partition
-        
-        '''
-        ext_part = self.get_extended_partition()
-        if ext_part is None:
-            return None
-        logicals = self.get_logicals()
-        
-        if len(logicals) > 0:
-            last_log = logicals[-1]
-            offset = last_log.get_endblock()
-            part_num = last_log.number + 1
-        else: # First logical on this disk
-            offset = ext_part.offset
-            part_num = PartitionInfo.FIRST_LOGICAL
-        new_part = PartitionInfo(part_num=part_num, offset=offset)
-        self.partitions.append(new_part)
-        return new_part
-    
-    def sort_disk_order(self):
-        '''Sort partitions/slices in disk order'''
-        self.partitions.sort(cmp=PartitionInfo.compare)
-        self.slices.sort(cmp=SliceInfo.compare)
-    
-    def get_parts(self):
-        '''Return the list of partitions or slices, depending on what
-        this disk has on it
-        
-        '''
-        if self.partitions:
-            return self.partitions
-        else:
-            return self.slices
-    
-    def to_tgt(self):
-        '''Transfer the install profile information to tgt format
-
-        ''' 
-        if self._tgt_disk is not None:
-            tgt_disk = self._tgt_disk
-        else:
-            name = self.name
-            blocks = round_to_multiple(self.get_blocks(), self.cylsz)
-            controller = self.controller
-            boot = self.boot
-            removable = self.removable
-            vendor = self.vendor
-            serialno = self.serialno
-            geo = tgt.Geometry(cylsz=self.cylsz, blocksz=self.blocksz)
-            tgt_disk = tgt.Disk(geo, name, blocks, controller=controller,
-                                boot=boot, removable=removable,
-                                vendor=vendor, serialno=serialno)
-        
-        backup_slice = None
-        if self.partitions:
-            sl_iter = iter(self.get_solaris_data().slices)
-        else:
-            sl_iter = iter(self.slices)
-        for slice_ in sl_iter:
-            if slice_.number == SliceInfo.BACKUP_SLICE:
-                backup_slice = slice_._tgt_slice
-                break
-        
-        tgt_disk.use_whole = self.use_whole_segment
-        
-        child_list = ()
-        if not tgt_disk.use_whole:
-            for partition in self.partitions:
-                part = partition.to_tgt(self)
-                if part is not None:
-                    child_list += (part,)
-                    tgt_disk.fdisk = True
-            if not child_list:
-                for slice_info in self.slices:
-                    sl = slice_info.to_tgt(self)
-                    if sl is not None:
-                        child_list += (sl,)
-                        tgt_disk.vtoc = True
-        
-        tgt_disk.children = child_list
-        slice_parent = tgt_disk
-        if child_list and isinstance(child_list[0], tgt.Partition):
-            standards = []
-            logicals = []
-            ext_part = None
-            for child in child_list:
-                if child.id == PartitionInfo.DELETED:
-                    continue
-                if child.number > PartitionInfo.MAX_STANDARD_PARTITIONS:
-                    logicals.append(child)
-                else:
-                    standards.append(child)
-                    if child.id in PartitionInfo.EXTENDED:
-                        ext_part = child
-                if child.id == PartitionInfo.SOLARIS:
-                    slice_parent = child
-            adjust_tgt_parts(standards, tgt_parent=tgt_disk)
-            if logicals:
-                adjust_tgt_parts(logicals, ext_part=ext_part)
-        
-        slices = []
-        for child in slice_parent.children:
-            if child.number == SliceInfo.BACKUP_SLICE:
-                continue
-            slices.append(child)
-        if backup_slice is not None:
-            slice_parent = backup_slice
-        adjust_tgt_parts(slices, tgt_parent=slice_parent)
-        
-        # print out the tgt_disk object for debugging
-        logging.debug("%s", tgt_disk)
-        
-        return tgt_disk
-    
-    def create_default_layout(self):
-        '''Create a reasonable default layout consisting of a single slice
-        or partition that consumes the whole disk. In the slice case, also
-        add the traditional backup slice.
-        
-        '''
-        # do not allow size to exceed MAX_VTOC
-        maxsz = min(self.get_size(), SliceInfo.MAX_VTOC)
-        
-        if platform.processor() == "sparc":
-            whole_part = SliceInfo(slice_num=0, size=self.size,
-                                   slice_type=SliceInfo.ROOT_POOL)
-            backup_part = SliceInfo(slice_num=SliceInfo.BACKUP_SLICE,
-                                    size=self.size)
-            self.slices = [whole_part, backup_part]
-            self.label.add(DiskInfo.VTOC)
-        else:
-            whole_part = PartitionInfo(part_num=1, size=maxsz,
-                                       partition_id=PartitionInfo.SOLARIS)
-            whole_part.create_default_layout()
-            self.partitions = [whole_part]
-            self.label.add(DiskInfo.FDISK)
-    
-    def get_install_dev_name_and_size(self):
-        '''Returns the installation device name string and the size of the
-        install device in MB.
-        
-        '''
-        install_target = self.get_install_target()
-        if install_target is None:
-            logging.error("Failed to find device to install onto")
-            raise InstallationError
-        name = self.name + "s" + str(install_target.number)
-        size = (int)(install_target.size.size_as("mb"))
-        return (name, size)
-    
-    def get_install_device_size(self):
-        '''Returns the size of the install device in MB. '''
-        # Size is the second item in the tuple
-        return self.get_install_dev_name_and_size()[1]
-    
-    def get_install_device(self):
-        '''Returns the install device name string. '''
-        # Install device is the first item in the tuple
-        return self.get_install_dev_name_and_size()[0]
-    
-    def get_install_target(self):
-        '''Returns the slice target of this installation'''
-        try:
-            install_target = self
-            if install_target.partitions:
-                install_target = install_target.get_solaris_data()
-            install_target = install_target.get_solaris_data()
-            return install_target
-        except AttributeError:
-            logging.debug("Install target not yet defined")
-            return None
-    
-    def get_install_root_pool(self):
-        ''' Returns name of the pool to be used for installation '''
-        install_slice = self.get_install_target()
-        if install_slice is None:
-            logging.error("Failed to find device to install onto")
-            raise InstallationError
-        slice_type = install_slice.get_type()
-        return (str(slice_type[1]))
--- a/usr/src/cmd/text-install/osol_install/profile/disk_space.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Object representing space on a disk (for example, a file, partition or slice)
-'''
-
-
-def round_to_multiple(num, mult):
-    ''' Round the given number (num) up to a given multiple (mult) '''
-    remainder = num % mult
-    if (remainder == 0):
-        return (num)	# num is already of the given multiple
-    return (num + (mult - remainder))
-
-
-def round_down(num, mult):
-    ''' Round the given number (num) down to a given multiple (mult) '''
-    return (num - (num % mult))
-
-
-class DiskSpace(object):
-    '''Represent a disk, partition or file's size in
-    bytes, kb, mb, gb or tb
-    
-    '''
-    SIZES = {"b" : 1,
-             "kb" : 1024,
-             "mb" : 1024**2,
-             "gb" : 1024**3,
-             "tb" : 1024**4}
-    
-    def __init__(self, size=None):
-        '''size must be a string with a suffix of b, kb, mb, gb or tb'''
-        self._size = 0
-        self.size = size
-    
-    def __str__(self):
-        return self.size_as_string()
-    
-    def set_size(self, size):
-        '''Set the size to the string specified'''
-        if size is None:
-            self._size = 0
-        else:
-            self._size = DiskSpace.check_format(size)
-    
-    def size_as_string(self, unit_str="gb"):
-        '''Return a string representing this object's size in the indicated
-        units
-        
-        '''
-        return str(self.size_as(unit_str)) + unit_str
-    
-    def size_as(self, unit_str="gb"):
-        '''Return the size of this DiskSpace converted in scale to unit_str.
-        unit_str defaults to gigabytes
-        
-        unit_str must be in DiskSpace.SIZES
-        '''
-        unit_str = unit_str.lower()
-        if unit_str in DiskSpace.SIZES:
-            return (self._size / DiskSpace.SIZES[unit_str])
-        else:
-            raise ValueError("%s not a recognized suffix" % unit_str)
-    
-    size = property(size_as, set_size)
-    
-    @staticmethod
-    def check_format(input_str):
-        '''Analyze a string to determine if it could represent a DiskSpace
-        
-        input_str must be a string object, or a TypeError will be raised
-        
-        Returns the object's size in bytes if input_str could represent
-        a DiskSpace, and raises ValueError otherwise
-        
-        '''
-        if not isinstance(input_str, basestring):
-            raise TypeError("input_str must be a string")
-        input_str = input_str.strip()
-        # Determine whether the units are represented by a single character
-        # (bytes, b), or two characters (kb, mb, gb, tb)
-        if input_str[-2:-1].isdigit():
-            units = input_str[-1:].lower()
-            value = input_str[:-1]
-        else:
-            units = input_str[-2:].lower()
-            value = input_str[:-2]
-        if units in DiskSpace.SIZES:
-            if value:
-                # Raises a ValueError if value isn't a parseable float
-                return float(value) * DiskSpace.SIZES[units]
-            else:
-                raise TypeError("Invalid value (%s)" % input_str)
-        else:
-            raise ValueError("Invalid units (%s)" % units)
-    
-    def __cmp__(self, other):
-        if self._size > other._size:
-            return 1
-        if self._size < other._size:
-            return -1
-        return 0
--- a/usr/src/cmd/text-install/osol_install/profile/install_profile.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Represent all details of an installation in a single Python object,
-including the disk target, netwrok configuration, system details (such as
-timezone and locale), users, and zpool / zfs datasets.
-'''
-
-
-from solaris_install.data_object import DataObject
-
-
-INSTALL_PROF_LABEL = "install_profile"
-
-
-class InstallProfile(DataObject):
-    '''
-    Represents an entire installation profile
-    '''
-    
-    LABEL = INSTALL_PROF_LABEL
-
-    # pylint: disable-msg=E1003
-    def __init__(self, disk=None, zpool=None):
-        super(DataObject, self).__init__(InstallProfile.LABEL)
-        self.disk = disk
-        self.zpool = zpool
-        self.install_succeeded = False
-    
-    def __str__(self):
-        result = ["Install Profile:"]
-        result.append("Install Completed - %s" % self.install_succeeded)
-        result.append(str(self.disk))
-        result.append(str(self.zpool))
-        return "\n".join(result)
-    
-    ## InstallProfile not intended for long term use as a DataObject
-    ## It's expected that this will be replaced with formal DataObject
-    ## structures as the Text Installer transitions to use the InstallEngine
-    ## and DOC more completely.
-    def to_xml(self):
-        return None
-    
-    @classmethod
-    def from_xml(cls, xml_node):
-        return None
-    
-    @classmethod
-    def can_handle(cls, xml_node):
-        return False
-    
-    def __getstate__(self):
-        '''Do not 'pickle' InstallProfiles'''
-        return None
--- a/usr/src/cmd/text-install/osol_install/profile/partition_info.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,648 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Object to represent Partitions
-'''
-
-from copy import copy, deepcopy
-import logging
-
-import osol_install.tgt as tgt
-from osol_install.profile.disk_space import DiskSpace, round_to_multiple, \
-                                            round_down
-from osol_install.profile.slice_info import SliceInfo, UI_PRECISION
-
-# Minimum space between partitions before presenting it as 'unused' space
-# Used by PartitionInfo.add_unused_parts()
-MIN_GAP_SIZE = DiskSpace("1gb")
-
-# Minimum space between logical partitions before presenting it as
-# 'unused' space. Used by DiskInfo.add_unused_parts()
-MIN_LOGICAL_GAP_SIZE = DiskSpace("100mb")
-
-# Pylint gets confused and thinks PartitionInfo.size and PartitionInfo.offset
-# are strings, but they are actually DiskSpace objects
-# pylint: disable-msg=E1103
-class PartitionInfo(object):
-    '''Represents a single partition on a disk on the system.
-    
-    EDITABLE_PART_TYPES is a list of primary partition types for which
-    modifying the size is supported.
-    
-    KNOWN_PART_TYPES is a list of primary partition types which can be
-    created out of a previously unused block of space
-    
-    *_LOGIC_TYPES represent the same concepts applied to logical partitions'''
-    
-    UNUSED = None
-    UNUSED_TEXT = "Unused"
-    SOLARIS = 0xBF
-    SOLARIS_ONE = 0x82
-    EXT_DOS = 0x05
-    FDISK_EXTLBA = 0x0f
-    DELETED = 0
-    
-    LOGICAL_BLOCK_PAD = 63
-    
-    EXTENDED = [EXT_DOS, FDISK_EXTLBA]
-    EXTENDED_TEXT = "Extended"
-    
-    EDITABLE_PART_TYPES = [SOLARIS,
-                           EXT_DOS,
-                           FDISK_EXTLBA]
-    
-    EDITABLE_LOGIC_TYPES = [SOLARIS]
-    
-    KNOWN_PART_TYPES = [UNUSED,
-                        SOLARIS,
-                        EXT_DOS]
-    
-    KNOWN_LOGIC_TYPES = [UNUSED]
-    KNOWN_LOGIC_TYPES.extend(EDITABLE_LOGIC_TYPES)
-    
-    MIN_OFFSET = 1
-    
-    MAX_STANDARD_PARTITIONS = 4
-    MAX_LOGICAL_PARTITIONS = 32
-    FIRST_LOGICAL = 5
-    
-    def __init__(self, part_num=None, offset="0gb", size="0gb", slices=None,
-                 blocksz=512, partition_id=UNUSED, tgt_part=None):
-        '''Constructor takes either a tgt_part, which should be a tgt.Partition
-        object, or a set of parameters. If tgt_part is supplied, all other
-        parameters are ignored.
-        
-        '''
-        self._sol_slice_idx = 0
-        self._offset = None
-        self._size = None
-        self._tgt_part = tgt_part
-        self.original_type = None
-        self.previous_size = None
-        if tgt_part:
-            self.slices = []
-            for child in tgt_part.children:
-                self.slices.append(SliceInfo(tgt_slice=child))
-            self.number = tgt_part.number
-            offset = str(tgt_part.offset * tgt_part.geometry.blocksz) + "b"
-            self.offset = offset
-            size = str(tgt_part.blocks * tgt_part.geometry.blocksz) + "b"
-            self.blocksz = tgt_part.geometry.blocksz
-            self.size = size
-            self.id = tgt_part.id
-        else:
-            if slices is None:
-                slices = []
-            self.slices = slices
-            self.number = part_num
-            self.offset = offset
-            self.blocksz = blocksz
-            self.size = size
-            self.id = partition_id
-        self.use_whole_segment = False
-        self.boot_slice = None
-        self.alt_slice = None
-        self.orig_slices = copy(self.slices)
-    
-    def __str__(self):
-        result = ["Partition Info (%s):" % self.number]
-        result.append("Type: %s" % self.type)
-        result.append("Offset: %s" % self.offset)
-        result.append("Size: %s" % self.size)
-        for slice_info in self.slices:
-            result.append(str(slice_info))
-        return "\n".join(result)
-    
-    @staticmethod
-    def compare(left, right):
-        '''Compare 2 tgt.Partition or PartitionInfo's in such a way that
-        passing this method to list.sort() results in a list sorted by disk
-        order.
-        
-        '''
-        if isinstance(left, tgt.Partition):
-            left = PartitionInfo(left)
-        if not isinstance(left, PartitionInfo):
-            return NotImplemented
-        
-        if isinstance(right, tgt.Partition):
-            right = PartitionInfo(right)
-        if not isinstance(right, PartitionInfo):
-            return NotImplemented
-        
-        if left.is_logical() == right.is_logical():
-            left_off = left.offset.size_as("b")
-            right_off = right.offset.size_as("b")
-            if left_off < right_off:
-                return -1
-            elif left_off > right_off:
-                return 1
-            else:
-                return 0
-        elif left.is_logical():
-            return 1
-        else:
-            return -1
-    
-    def get_offset(self):
-        '''Return this partition's offset as a DiskSpace object'''
-        return self._offset
-    
-    def set_offset(self, offset):
-        '''Set this partition's offset. Must be either a DiskSpace object
-        or a string that will be accepted by DiskSpace.__init__
-        
-        '''
-        if isinstance(offset, DiskSpace):
-            self._offset = deepcopy(offset)
-        else:
-            self._offset = DiskSpace(offset)
-    
-    def get_size(self):
-        '''Returns this partition's size as a DiskSpace object'''
-        return self._size
-    
-    def set_size(self, size):
-        '''Set this partition's size. size must be either a DiskSpace or a
-        string that will be accepted by DiskSpace.__init__
-        
-        '''
-        if isinstance(size, DiskSpace):
-            self._size = deepcopy(size)
-        else:
-            self._size = DiskSpace(size)
-    
-    def get_type(self):
-        '''Return this object's partition type'''
-        return self.id
-    
-    def get_blocks(self):
-        '''Return the number of blocks on this partition'''
-        return int(self.size.size_as("b") / self.blocksz)
-    
-    blocks = property(get_blocks)
-    offset = property(get_offset, set_offset)
-    size = property(get_size, set_size)
-    type = property(get_type)
-    
-    def is_logical(self):
-        '''Returns true if this is a logical partition'''
-        if self.number is not None:
-            return (self.number > PartitionInfo.MAX_STANDARD_PARTITIONS)
-        else:
-            return False
-    
-    def is_extended(self):
-        '''Returns True if this is an Extended Partition, False otherwise'''
-        return (self.id in PartitionInfo.EXTENDED)
-    
-    def cycle_type(self, disk, extra_types=None):
-        '''Cycle this partition's type. Potential types are based on
-        whether or not another Solaris partition exists, whether an extended
-        partition exists, and whether or not this is a logical partition.
-        
-        If extra_types is passed in, it should be a list of other potential
-        types. These types will also be considered when cycling.
-        
-        '''
-        if extra_types is None:
-            extra_types = []
-        types = set()
-        sol2_part = disk.get_solaris_data()
-        has_solaris_part = (sol2_part is not None)
-        
-        ext_part = disk.get_extended_partition()
-        has_extended = (ext_part is not None)
-        
-        # If this is the extended partition, and the Solaris2 partition
-        # is a logical partition, allow for cycling from Extended to Solaris2
-        if (has_extended and ext_part is self and
-            has_solaris_part and sol2_part.is_logical()):
-            has_solaris_part = False
-        
-        if self.is_logical():
-            types.update(PartitionInfo.KNOWN_LOGIC_TYPES)
-        else:
-            types.update(PartitionInfo.KNOWN_PART_TYPES)
-        types.update(extra_types)
-        types = list(types)
-        types.sort()
-        if self.id in types:
-            logging.debug("type in types, cycling next")
-            type_index = types.index(self.id)
-            type_index = (type_index + 1) % len(types)
-            self.id = types[type_index]
-            logging.debug("now %s", self.id)
-        else:
-            logging.debug("type NOT in types, setting to types[0]")
-            self.original_type = self.id
-            self.id = types[0]
-        if self.id == PartitionInfo.UNUSED:
-            self.previous_size = self.size
-            self.size = "0GB"
-        elif has_solaris_part and self.id == PartitionInfo.SOLARIS:
-            self.cycle_type(disk, extra_types)
-        elif has_extended and self.is_extended():
-            self.cycle_type(disk, extra_types)
-    
-    def get_description(self):
-        '''
-        Return a string suitable for representing this partition in a UI
-        '''
-        description = None
-        if self.id == PartitionInfo.UNUSED:
-            description = PartitionInfo.UNUSED_TEXT
-        elif self.is_extended():
-            description = PartitionInfo.EXTENDED_TEXT
-        else:
-            description = tgt.Partition.ID[self.id]
-        return str(description)
-    
-    def get_max_size(self, disk):
-        '''Analyze nearby partitions and determine the total unused, available
-        space that this partition could consume without affecting other
-        partitions.
-        
-        Result is in gigabytes
-        
-        '''
-        if self.is_logical():
-            parts = disk.get_logicals()
-            ext_part = disk.get_extended_partition()
-        else:
-            parts = disk.get_standards()
-        if self not in parts:
-            raise ValueError("This partition was not found on the "
-                             "supplied disk")
-        self_idx = parts.index(self)
-        prev_part = None
-        next_part = None
-        for part in reversed(parts[:self_idx]):
-            if part.id != PartitionInfo.UNUSED:
-                prev_part = part
-                break
-        for part in parts[self_idx+1:]:
-            if part.id != PartitionInfo.UNUSED:
-                next_part = part
-                break
-        msg_str = self.get_description() + ":"
-        if prev_part is None:
-            msg_str += "No prev part:"
-            if self.is_logical():
-                begin_avail_space = ext_part.offset.size_as("gb")
-            else:
-                begin_avail_space = 0
-        else:
-            try:
-                begin_avail_space = prev_part.get_endblock().size_as("gb")
-                msg_str += ("prev_part(%s).endblock=%s:" %
-                            (prev_part.type, begin_avail_space))
-            except Exception:
-                logging.error("%s", prev_part)
-                raise
-        if next_part is None:
-            if self.is_logical():
-                msg_str += ("no next_part (ext_part size=%s):" %
-                            ext_part.size.size_as("gb"))
-                end_avail_space = ext_part.get_endblock().size_as("gb")
-            else:
-                msg_str += ("no next_part (disk_size=%s):" % 
-                            disk.size.size_as("gb"))
-                end_avail_space = disk.size.size_as("gb")
-        else:
-            end_avail_space = next_part.offset.size_as("gb")
-            msg_str += ("next_part(%s).offset=%s:" %
-                        (next_part.type, end_avail_space))
-        logging.debug(msg_str)
-        avail = min(end_avail_space - begin_avail_space,
-                    SliceInfo.MAX_VTOC.size_as("gb"))
-        if avail < 0:
-            avail = 0
-        return avail
-    
-    def get_endblock(self):
-        '''Returns the ending 'offset' of this partition, as a DiskSpace'''
-        try:
-            start_pt = self.offset.size_as("b")
-            end_pt = self.size.size_as("b")
-            return DiskSpace(str(start_pt + end_pt) + "b")
-        except AttributeError:
-            raise AttributeError("%s does not have valid size data" %
-                                 self.__class__.__name__)
-    
-    def get_solaris_data(self, check_multiples=False):
-        '''Returns the slice within this partition that has the Solaris root
-        pool.
-        
-        Raises AttributeError if there is no such slice
-        
-        '''
-        if (not check_multiples and self._sol_slice_idx < len(self.slices) and
-            self.slices[self._sol_slice_idx].is_solaris_data()):
-            return self.slices[self._sol_slice_idx]
-        
-        solaris_data = None
-        for slice_info in self.slices:
-            if slice_info.is_solaris_data():
-                if solaris_data is None:
-                    self._sol_slice_idx = self.slices.index(slice_info)
-                    solaris_data = slice_info
-                    if not check_multiples:
-                        break
-                elif check_multiples:
-                    raise ValueError("Found multiple slices with 'solaris'"
-                                     "data on them")
-        
-        return solaris_data
-    
-    def editable(self, disk):
-        '''Returns True if it is possible to edit this partition's size'''
-        if self.is_extended():
-            for logical in disk.get_logicals():
-                if logical.id != PartitionInfo.UNUSED:
-                    return False
-        if self.id in PartitionInfo.EDITABLE_PART_TYPES:
-            return True
-        else:
-            return False
-    
-    def sort_disk_order(self):
-        '''Sort slices by disk order'''
-        self.slices.sort(cmp=SliceInfo.compare)
-    
-    def get_parts(self):
-        '''Return the slices on this partition. Provided for interface
-        compatibility with DiskInfo.get_parts()
-        
-        '''
-        return self.slices
-    
-    def add_unused_parts(self):
-        '''Sort through the non-logical partitions, find the largest gaps,
-        and create additional Unused partitions such that the number of
-        non-logical partitions == MAX_STANDARD_PARTITIONS.
-        
-        Gaps smaller than 1 GB are ignored.
-        
-        Also note that the x86 boot slice (8) and x86 alt slice (9) are 
-        hidden from view after calling this method. They're stored for 
-        later retrieval in self.boot_slice and self.alt_slice respectively
-        
-        '''
-        boot_slice = None
-        for part in self.slices:
-            if part.number == SliceInfo.x86_BOOT_SLICE:
-                boot_slice = part
-        if boot_slice is not None:
-            self.boot_slice = boot_slice
-            self.slices.remove(boot_slice)
-
-        alt_slice = None
-        for part in self.slices:
-            if part.number == SliceInfo.x86_ALT_SLICE:
-                alt_slice = part
-        if alt_slice is not None:
-            self.alt_slice = alt_slice
-            self.slices.remove(alt_slice)
-        
-        parts = copy(self.slices)
-        parts.sort(cmp=SliceInfo.compare)
-        numbers = range(SliceInfo.MAX_SLICES)
-        numbers.remove(SliceInfo.BACKUP_SLICE)
-        backup_part = None
-        for part in parts:
-            if part.number == SliceInfo.BACKUP_SLICE:
-                backup_part = part
-                break
-        if backup_part is not None:
-            parts.remove(backup_part)
-        start_pt = 0
-        
-        min_gap_size = MIN_GAP_SIZE.size_as("b")
-        gaps = []
-        end_pt = 0
-        for part in parts:
-            if part.number == SliceInfo.BACKUP_SLICE:
-                continue
-            if part.number in numbers:
-                numbers.remove(part.number)
-            start_pt = part.offset.size_as("b")
-            gap_size = start_pt - end_pt
-            if gap_size > min_gap_size:
-                gaps.append((gap_size, end_pt))
-            end_pt = part.get_endblock().size_as("b")
-        end_disk = self.size.size_as("b")
-        gap_size = end_disk - end_pt
-        if gap_size > min_gap_size:
-            gaps.append((gap_size, end_pt))
-        # Sorting a list of tuples will sort by the first item in the tuple,
-        # In this case, gap_size, such that the smallest gap is first.
-        # Then, the largest gaps can be popped off the end of the list
-        gaps.sort()
-        for part_num in numbers:
-            if gaps:
-                gap = gaps.pop()
-                offset = str(gap[1]) + "b"
-            else:
-                offset = str(end_pt) + "b"
-            new_part = SliceInfo(slice_num=part_num, offset=offset)
-            self.slices.append(new_part)
-            if len(self.slices) >= SliceInfo.MAX_SLICES:
-                break
-        if backup_part is None:
-            new_part = SliceInfo(slice_num=SliceInfo.BACKUP_SLICE,
-                                 size=self.size)
-            self.slices.append(new_part)
-        self.sort_disk_order()
-    
-    def adjust_offset(self, parent):
-        '''Adjust this partition's offset such that it no longer overlaps
-        with subsequent partitions, by comparing this partition's trailing
-        edge with the next used partition's offset.
-        
-        Additionally, any unused partitions found are shifted to align
-        with this partition's trailing edge, if needed
-        
-        '''
-        if self.is_logical():
-            parts = parent.get_logicals()
-            ext_part = parent.get_extended_partition()
-        else:
-            parts = parent.get_standards()
-        
-        self_idx = parts.index(self)
-        endblock = self.get_endblock()
-        endblock_bytes = endblock.size_as("gb")
-        unused_parts = []
-        shift = None
-        for part in parts[self_idx+1:]:
-            if part.offset.size_as("gb") < endblock_bytes:
-                if part.id == PartitionInfo.UNUSED:
-                    unused_parts.append(part)
-                else:
-                    shift = endblock_bytes - part.offset.size_as("gb")
-                    break
-            else:
-                break
-        else:
-            # Check to ensure we don't slip past the end of the disk
-            # (or extended partition, if this is a logical partition)
-            if self.is_logical():
-                max_endblock = ext_part.get_endblock().size_as("gb")
-            else:
-                max_endblock = parent.size.size_as("gb")
-            if endblock_bytes > max_endblock:
-                shift = endblock_bytes - max_endblock
-        
-        if shift is not None:
-            new_offset = max(0, self.offset.size_as("gb") - shift)
-            self.offset = str(new_offset) + "gb"
-        
-        new_endblock = self.get_endblock()
-        for part in unused_parts:
-            part.offset = new_endblock
-    
-    def to_tgt(self, parent):
-        '''Transfer the install profile information to tgt format'''
-        
-        if not self.modified():
-            part = deepcopy(self._tgt_part)
-        else:
-            # Something changed, need to create a new one
-            geo = tgt.Geometry(parent.cylsz, self.blocksz)
-            
-            if self.type == PartitionInfo.UNUSED:
-                # Partition was deleted. Return an empty partition,
-                # which will indicate to target instantiation to
-                # delete this partition
-                return tgt.Partition(geo, self.number, PartitionInfo.DELETED,
-                                     0, 0, modified=True)
-            
-            offset = int(self.offset.size_as("b") / self.blocksz)
-            offset = max(PartitionInfo.MIN_OFFSET, offset)
-            blocks = self.get_blocks()
-            
-            if self.is_logical() or self.is_extended():
-                # Ensure that the required minimum amount of empty space
-                # precedes and follows this logical partition
-                offset += PartitionInfo.LOGICAL_BLOCK_PAD
-                blocks -= 2 * PartitionInfo.LOGICAL_BLOCK_PAD
-            
-            # offset must be a multiple of tgt.Geometry.cylsz
-            offset = round_to_multiple(offset, geo.cylsz)
-            blocks = round_down(blocks, geo.cylsz)
-            
-            part = tgt.Partition(geo, self.number, self.id, offset, blocks,
-                                 modified=True)
-        
-        part.use_whole = self.use_whole_segment
-        
-        child_list = ()
-        if not part.use_whole:
-            slices = []
-            if self.boot_slice is not None:
-                slices.append(self.boot_slice)
-            if self.alt_slice is not None:
-                slices.append(self.alt_slice)
-            slices.extend(self.slices)
-            for slice_info in slices:
-                sl = slice_info.to_tgt(parent)
-                if sl is not None:
-                    child_list += (sl,)
-        
-        part.children = child_list
-        return (part)
-         
-    def modified(self, off_by=UI_PRECISION):
-        '''Returns False if and only if this PartitionInfo was instantiated
-        from a tgt.Partition, and this PartitionInfo does not differ in
-        substance from the tgt.Partition from which it was instantiated.
-        
-        Size, offset, id and number are compared to determine whether this
-        partition has been modified. Slices within this partition are not
-        considered.
-        
-        off_by - A string or DiskSpace indicating a rounding factor. Any size
-        data (offset, size) that differs by less than the given amount is
-        assumed to be unchanged. e.g., if the tgt.Partition indicates a size
-        of 10.05GB and this PartitionInfo has a size of 10.1GB, and off_by
-        is the default of 0.1GB, then it is assumed that the represented
-        partition has not changed. (The original tgt.Partition size should be
-        used, for accuracy)
-        
-        '''
-        if self._tgt_part is None:
-            return True
-        
-        if not isinstance(off_by, DiskSpace):
-            off_by = DiskSpace(off_by)
-        off_by_bytes = off_by.size_as("b")
-        
-        if self.number != self._tgt_part.number:
-            return True
-        
-        if self.id != self._tgt_part.id:
-            return True
-        
-        tgt_size = self._tgt_part.blocks * self._tgt_part.geometry.blocksz
-        if abs(tgt_size - self.size.size_as("b")) > off_by_bytes:
-            return True
-        
-        tgt_offset = self._tgt_part.offset * self._tgt_part.geometry.blocksz
-        if abs(tgt_offset - self.offset.size_as("b")) > off_by_bytes:
-            return True
-        
-        return False
-    
-    def destroyed(self, off_by=UI_PRECISION):
-        '''Returns True if this partition previously had data, and has also
-        been modified. Also returns True if this is the Solaris2 partition,
-        but the partition originally had no slices - the slice editing screen
-        is skipped in such a case, so the user needs to be informed that the
-        entire contents of the Solaris2 partition will be destroyed (as the
-        entire partition will be used as the install target)
-        
-        '''
-        if self._tgt_part is None:
-            return False
-        modified = self.modified(off_by)
-        return modified or (self.is_solaris_data() and not self.orig_slices)
-    
-    def create_default_layout(self):
-        '''Create a reasonable default layout, consisting of a single
-        slice that consumes the entire partition (as well as defining the
-        traditional backup slice)
-        
-        '''
-        whole_part = SliceInfo(slice_num=0, size=self.size,
-                               slice_type=SliceInfo.ROOT_POOL)
-        backup_part = SliceInfo(slice_num=SliceInfo.BACKUP_SLICE,
-                                size=self.size)
-        self.slices = [whole_part, backup_part]
-    
-    def is_solaris_data(self):
-        '''Returns True if this PartitionInfo would be the install target'''
-        return self.id == PartitionInfo.SOLARIS
-
--- a/usr/src/cmd/text-install/osol_install/profile/slice_info.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,467 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Object to represent Slices
-'''
-
-from copy import deepcopy
-from UserString import UserString
-import logging
-
-import osol_install.tgt as tgt
-from osol_install.profile.disk_space import DiskSpace, round_to_multiple
-
-UI_PRECISION = DiskSpace("0.05gb")
-
-
-# Pylint gets confused and thinks SliceInfo.size and SliceInfo.offset
-# are strings, but they are actually DiskSpace objects
-# pylint: disable-msg=E1103
-class SliceInfo(object):
-    '''Represents a single slice on a partition or slice.'''
-    MAX_SLICES = 8
-    MAX_VTOC = DiskSpace("2tb")
-    
-    BACKUP_SLICE = 2
-    x86_BOOT_SLICE = 8
-    x86_ALT_SLICE = 9
-    UNUSED = (None, None)
-    UNUSED_TEXT = "Unused"
-    DEFAULT_POOL = UserString("")
-    ZPOOL = tgt.Slice.AZPOOL
-    ZPOOL_TYPES = [tgt.Slice.AZPOOL, tgt.Slice.EZPOOL, tgt.Slice.SZPOOL,
-                   tgt.Slice.CZPOOL]
-    ROOT_POOL = (ZPOOL, DEFAULT_POOL)
-    LEGACY = "legacy"
-    UFS = tgt.Slice.FS
-    UFS_TEXT = "UFS"
-    UNKNOWN = "???"
-    
-    TYPES = [UNUSED,
-             ROOT_POOL]
-    
-    def __init__(self, slice_num=0, size=None, offset=None, blocksz=512,
-                 slice_type=None, readonly=False, unmountable=True,
-                 tag=None, tgt_slice=None):
-        '''Constructor takes either a tgt_slice, which should be a tgt.Slice
-        object, or a set of parameters. If tgt_slice is supplied, all other
-        parameters are ignored.
-        
-        '''
-        self._tgt_slice = tgt_slice
-        self._size = None
-        self._offset = None
-        self.previous_size = None
-        if tgt_slice:
-            size = str(tgt_slice.blocks * tgt_slice.geometry.blocksz) + "b"
-            self.size = size
-            offset = str(tgt_slice.offset * tgt_slice.geometry.blocksz) + "b"
-            self.blocksz = tgt_slice.geometry.blocksz
-            self.offset = offset
-            self.number = tgt_slice.number
-            self.readonly = tgt_slice.readonly
-            self.type = (tgt_slice.type, tgt_slice.user)
-            self.last_mount = tgt_slice.last_mount
-            self.unmountable = tgt_slice.unmountable
-            self.tag = tgt_slice.tag
-        else:
-            self.readonly = readonly
-            if slice_type is None:
-                slice_type = SliceInfo.UNUSED
-            if len(slice_type) != 2:
-                raise TypeError("slice_type must be tuple of length 2")
-            self.type = slice_type
-            self.unmountable = unmountable
-            self.size = size
-            self.blocksz = blocksz
-            self.offset = offset
-            self.number = slice_num
-            self.last_mount = None
-            self.tag = tag
-        self.original_type = self.type
-    
-    def __str__(self):
-        result = ["Slice Info (%s):" % self.number]
-        result.append("Type: %s:%s" % self.type)
-        result.append("Offset: %s" % self.offset)
-        result.append("Size: %s" % self.size)
-        return "\n".join(result)
-    
-    @staticmethod
-    def compare(left, right):
-        '''Returns an integer such that this method can be passed to
-        list.sort() and the list will be sorted in disk layout order.
-        
-        The backup slice is always listed last
-        
-        '''
-        if isinstance(left, tgt.Slice):
-            left = SliceInfo(left)
-        if not isinstance(left, SliceInfo):
-            return NotImplemented
-        
-        if isinstance(right, tgt.Slice):
-            right = SliceInfo(right)
-        if not isinstance(right, SliceInfo):
-            return NotImplemented
-        
-        if left.number == SliceInfo.BACKUP_SLICE:
-            return 1
-        elif right.number == SliceInfo.BACKUP_SLICE:
-            return -1
-        
-        left_off = left.offset.size_as("b")
-        right_off = right.offset.size_as("b")
-        if left_off < right_off:
-            return -1
-        elif left_off > right_off:
-            return 1
-        else:
-            return 0
-    
-    def get_offset(self):
-        '''Return this slice's offset as a DiskSpace object'''
-        return self._offset
-    
-    def set_offset(self, offset):
-        '''Set this slice's offset. Must be either a DiskSpace object
-        or a string that will be accepted by DiskSpace.__init__
-        
-        '''
-        if isinstance(offset, DiskSpace):
-            self._offset = deepcopy(offset)
-        else:
-            self._offset = DiskSpace(offset)
-    
-    def get_size(self):
-        '''Returns this slice's size as a DiskSpace object'''
-        return self._size
-    
-    def set_size(self, size):
-        '''Set this slice's size. size must be either a DiskSpace or a
-        string that will be accepted by DiskSpace.__init__
-        
-        '''
-        if isinstance(size, DiskSpace):
-            self._size = deepcopy(size)
-        else:
-            self._size = DiskSpace(size)
-    
-    def get_type(self):
-        '''Returns this SliceInfo's 'type'
-        Here for interface compatibility with PartitionInfo.get_type()'''
-        return self.type
-    
-    def get_blocks(self):
-        '''Return the number of blocks on this slice'''
-        return int(self.size.size_as("b") / self.blocksz)
-    
-    size = property(get_size, set_size)
-    offset = property(get_offset, set_offset)
-    
-    def get_description(self):
-        '''Return a string suitable for representing this slice in a UI'''
-        description = None
-        if self.number == SliceInfo.BACKUP_SLICE:
-            description = tgt.Slice.BACKUP
-        elif self.type == SliceInfo.UNUSED:
-            description = SliceInfo.UNUSED_TEXT
-        elif self.type[0] == SliceInfo.UFS:
-            if self.last_mount:
-                description = self.last_mount
-            else:
-                description = SliceInfo.UFS_TEXT
-        elif self.type[0] == tgt.Slice.UNKNOWN:
-            if self.tag == tgt.Slice.UNKNOWN:
-                description = SliceInfo.UNKNOWN
-            else:
-                description = self.tag
-        elif self.type[1] and self.type[1] != tgt.Slice.UNKNOWN:
-            description = self.type[1]
-        else:
-            description = self.type[0]
-        return str(description)
-    
-    def cycle_type(self, parent, extra_types=None):
-        '''Cycle this partition's type. If extra_types is given, it should
-        be a list of additional types - these will be considered when cycling
-        to the next type
-        
-        '''
-        if extra_types is None:
-            extra_types = []
-        if self.number == SliceInfo.BACKUP_SLICE:
-            return
-        
-        has_solaris_data = (parent.get_solaris_data() is not None)
-        types = set()
-        types.update(SliceInfo.TYPES)
-        types.update(extra_types)
-        types = list(types)
-        types.sort()
-        if self.type in types:
-            logging.debug("type in types, cycling next")
-            type_index = types.index(self.type)
-            type_index = (type_index + 1) % len(types)
-            self.type = types[type_index]
-            logging.debug("now %s-%s", *self.type)
-        else:
-            logging.debug("type NOT in types, setting to types[0]")
-            self.original_type = self.type
-            self.type = types[0]
-        if self.type == SliceInfo.UNUSED:
-            self.previous_size = self.size
-            self.size = "0GB"
-        elif self.is_rpool():
-            if has_solaris_data:
-                self.cycle_type(parent, extra_types)
-    
-    def get_endblock(self):
-        '''Returns the ending 'offset' of this slice, as a DiskSpace'''
-        try:
-            start_pt = self.offset.size_as("b")
-            end_pt = self.size.size_as("b")
-            return DiskSpace(str(start_pt + end_pt) + "b")
-        except AttributeError:
-            raise AttributeError("%s does not have valid size data" %
-                                 self.__class__.__name__)
-    
-    def get_max_size(self, parent):
-        '''Return the maximum possible size this slice could consume,
-        in gigabytes, based on adjacent unused space
-        
-        '''
-        if self.number == SliceInfo.BACKUP_SLICE:
-            return self.size.size_as("gb")
-        msg_str = "get_max_size:%s:" % self.number
-        slices = parent.slices
-        if self not in slices:
-            raise ValueError("This slice not in the parent!")
-        self_idx = slices.index(self)
-        prev_slice = None
-        next_slice = None
-        
-        # Search for the slice prior to this one with the largest "endblock"
-        # Since existing slices may overlap, this could be any slice prior
-        # to the current one.
-        for slice_info in reversed(slices[:self_idx]):
-            if (slice_info.type != SliceInfo.UNUSED and
-                slice_info.number != SliceInfo.BACKUP_SLICE):
-                if (prev_slice is None or
-                    slice_info.get_endblock() > prev_slice.get_endblock()):
-                    prev_slice = slice_info
-        for slice_info in slices[self_idx+1:]:
-            if (slice_info.type != SliceInfo.UNUSED and
-                slice_info.number != SliceInfo.BACKUP_SLICE):
-                next_slice = slice_info
-                break
-        if prev_slice is None:
-            msg_str += "prev_part=None:start_pt=0:"
-            start_pt = 0
-        else:
-            msg_str += "prev_part=%s:" % prev_slice.number
-            start_pt = prev_slice.get_endblock().size_as("gb")
-            msg_str += "start_pt=" + str(start_pt) + ":"
-        
-        if next_slice is None:
-            msg_str += "next_part=None:end_pt="
-            for slice_info in reversed(slices):
-                # Use the backup slice to define the absolute max size
-                # any given slice can be. (This is usually the last slice,
-                # hence the use of a reversed iterator)
-                if slice_info.number == SliceInfo.BACKUP_SLICE:
-                    end_pt = slice_info.size.size_as("gb")
-                    break
-            else:
-                # Default to the parent's size if there happens to be no S2
-                end_pt = parent.size.size_as("gb")
-            msg_str += str(end_pt) + ":"
-        else:
-            msg_str += "next_part=%s:" % next_slice.number
-            end_pt = next_slice.offset.size_as("gb")
-            msg_str += "end_pt=%s:" % end_pt
-        max_space = end_pt - start_pt
-        if max_space < 0:
-            max_space = 0
-        msg_str += "max_size=%s" % max_space
-        logging.debug(msg_str)
-        return max_space
-    
-    def editable(self, dummy):
-        '''Returns True if the installer is capable of resizing this Slice'''
-        return self.is_rpool()
-    
-    def adjust_offset(self, parent):
-        '''Adjust this slice's offset such that it no longer overlaps
-        with prior or subsequent slices, by comparing this slice's 
-        offset with prior slices, and its endblock with subsequent ones.
-        
-        Additionally, any unused slices found are shifted to align
-        with this slice's trailing edge, if needed.
-        
-        This function should only be called after ensuring that this slice's
-        size is less than or equal its max_size (as given by get_max_size);
-        the behavior of this function when attempting to adjust in both
-        directions is undefined. Additionally, the slices on the parent
-        should already be sorted in disk order.
-        
-        '''
-        if self.number == SliceInfo.BACKUP_SLICE:
-            return
-        parts = parent.get_parts()
-        self_idx = parts.index(self)
-        endblock = self.get_endblock()
-        endblock_bytes = endblock.size_as("gb")
-        unused_parts = []
-        
-        pre_shift = 0
-        for part in parts[:self_idx]:
-            if (part.type == SliceInfo.UNUSED or
-                part.number == SliceInfo.BACKUP_SLICE):
-                continue
-            overlap = (part.get_endblock().size_as("gb") -
-                       self.offset.size_as("gb"))
-            pre_shift = max(pre_shift, overlap)
-        
-        if pre_shift > 0:
-            new_offset = self.offset.size_as("gb") + pre_shift
-            self.offset = str(new_offset) + "gb"
-        
-        post_shift = None
-        for part in parts[self_idx+1:]:
-            if part.offset.size_as("gb") < endblock_bytes:
-                if part.type == SliceInfo.UNUSED:
-                    unused_parts.append(part)
-                elif part.number != SliceInfo.BACKUP_SLICE:
-                    post_shift = endblock_bytes - part.offset.size_as("gb")
-                    break
-            else:
-                break
-        else:
-            # Check to ensure we don't slip past the end of the disk/partition
-            max_endblock = parent.size.size_as("gb")
-            if endblock_bytes > max_endblock:
-                post_shift = endblock_bytes - max_endblock
-        
-        if post_shift is not None:
-            new_offset = max(0, self.offset.size_as("gb") - post_shift)
-            self.offset = str(new_offset) + "gb"
-        new_endblock = self.get_endblock()
-        for part in unused_parts:
-            part.offset = new_endblock
-    
-    def to_tgt(self, parent):
-        '''Transfer the install profile information to tgt format'''
-        # Create tgt.Slice object
-
-        if self.get_type() == SliceInfo.UNUSED:
-            return None
-
-        if not self.modified():
-            return self._tgt_slice
-
-        # Don't need to include the 'backup' slice, libti will
-        # automatically create one appropriately
-        if self.number == SliceInfo.BACKUP_SLICE:
-            return None
-
-        # Something changed, need to create a new one
-        geo = tgt.Geometry(parent.cylsz, self.blocksz)
-
-        # offset must be a multiple of tgt.Geometry.cylsz
-        off = int(self.offset.size_as("b") / self.blocksz)
-        offset = round_to_multiple(off, geo.cylsz)
-
-        blocks = round_to_multiple(self.get_blocks(), geo.cylsz)
-
-        tag = tgt.Slice.UNASSIGNED
-        slice_type = self.type[0]
-        user = self.type[1]
-        sl = tgt.Slice(geo, self.number, tag, slice_type, offset, blocks,
-                      modified=True, user=str(user), 
-                      unmountable=self.unmountable, readonly=self.readonly)
-        return (sl)
-    
-    def modified(self, off_by=UI_PRECISION):
-        '''Returns False if and only if this SliceInfo was instantiated from
-        a tgt.Slice, and this SliceInfo does not differ in substance
-        from the tgt.Slice from which it was instantiated.
-        
-        Size, offset, type and number are compared to determine
-        whether this slice has been modified.
-        
-        off_by - A string or DiskSpace indicating a rounding factor. Any size
-        data (offset, size) that differs by less than the given amount is
-        assumed to be unchanged. e.g., if the tgt.Slice indicates a size
-        of 10.05GB and this SliceInfo has a size of 10.1GB, and off_by
-        is the default of 0.1GB, then it is assumed that the represented
-        slice has not changed. (The original tgt.Slice size should be
-        used, for accuracy)
-        
-        '''
-        if self._tgt_slice is None:
-            return True
-        
-        if not isinstance(off_by, DiskSpace):
-            off_by = DiskSpace(off_by)
-        off_by_bytes = off_by.size_as("b")
-        
-        if self.number != self._tgt_slice.number:
-            return True
-        
-        if self.type[0] != self._tgt_slice.type:
-            return True
-        
-        if self.type[1] != self._tgt_slice.user:
-            return True
-        
-        tgt_size = self._tgt_slice.blocks * self._tgt_slice.geometry.blocksz
-        if abs(tgt_size - self.size.size_as("b")) > off_by_bytes:
-            return True
-        
-        tgt_offset = self._tgt_slice.offset * self._tgt_slice.geometry.blocksz
-        if abs(tgt_offset - self.offset.size_as("b")) > off_by_bytes:
-            return True
-        
-        return False
-    
-    def destroyed(self, off_by=UI_PRECISION):
-        '''Returns True if this slice previously had data, and has also
-        been modified.
-        
-        '''
-        if self.is_rpool():
-            return True
-        return (self._tgt_slice is not None and self.modified(off_by))
-    
-    def is_rpool(self):
-        '''Returns True this slice is the default pool
-        
-        '''
-        return (self.type[0] in SliceInfo.ZPOOL_TYPES and 
-            self.type[1] == SliceInfo.DEFAULT_POOL)
-    
-    def is_solaris_data(self):
-        return self.is_rpool()
--- a/usr/src/cmd/text-install/osol_install/text_install/Makefile	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-include ../../../Makefile.cmd
-
-all:=		TARGET= all
-clean:=		TARGET= clean
-clobber:=	TARGET= clobber
-install:=	TARGET= install
-
-MSG_DOMAIN =	textinstall
-
-PROGS=		text-install
-
-PYMODULES=	__init__.py \
-		disk_selection.py \
-		disk_window.py \
-		fdisk_partitions.py \
-		install_progress.py \
-		install_status.py \
-		log_viewer.py \
-		partition_edit_screen.py \
-		summary.py \
-		ti_install.py \
-		ti_install_utils.py \
-		welcome.py
-
-PYCMODULES=     $(PYMODULES:%.py=%.pyc)
-
-ROOTPROGS=      $(PROGS:%=$(ROOTUSRBIN)/%)
-
-ROOTPYMODULES=  $(PYMODULES:%=$(ROOTPYTHONVENDORINSTALLTI)/%)
-
-ROOTPYCMODULES= $(PYCMODULES:%=$(ROOTPYTHONVENDORINSTALLTI)/%)
-
-MSGFILES =	$(PYMODULES)
-
-.KEEP_STATE:
-
-all:	python $(PROGS)
-
-clean:
-	rm -f *.pyc  $(MSG_DOMAIN).po*
-
-clobber: clean
-
-
-install: all .WAIT $(ROOTPROGS) \
-	$(ROOTPYTHONVENDOR) \
-	$(ROOTPYTHONVENDORINSTALL) \
-	$(ROOTPYTHONVENDORINSTALLTI) \
-	$(ROOTPYMODULES) \
-	$(ROOTPYCMODULES) \
-	.WAIT msgs
-
-python:
-	$(PYTHON) -m compileall -l $(@D)
-
-msgs:	$(MSG_DOMAIN).po
-
-$(MSG_DOMAIN).po: $(PYMODULES)
-	@echo "Making messages file $(MSG_DOMAIN).po"
-	$(GNUXGETTEXT) $(GNUXGETFLAGS) -d $(MSG_DOMAIN) \
-		$(MSGFILES)
-
-FRC:
-
-include ../../../Makefile.targ
--- a/usr/src/cmd/text-install/osol_install/text_install/__init__.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Text / (n)Curses based UI for installing Oracle Solaris
-'''
-
-import gettext
-
-# Variables used by modules this module imports
-# Defined here to avoid circular import errors
-_ = gettext.translation("textinstall", "/usr/share/locale",
-                        fallback=True).ugettext
-RELEASE = {"release" : _("Oracle Solaris")}
-TUI_HELP = "/usr/share/text-install/help"
-
-
-import curses
-import locale
-import logging
-from optparse import OptionParser
-import os
-import platform
-import signal
-import subprocess
-import sys
-import traceback
-
-import libbe_py
-from osol_install.liblogsvc import init_log
-from osol_install.profile.install_profile import InstallProfile, \
-                                                 INSTALL_PROF_LABEL
-from osol_install.text_install.disk_selection import DiskScreen
-from osol_install.text_install.fdisk_partitions import FDiskPart
-from osol_install.text_install.install_progress import InstallProgress
-from osol_install.text_install.install_status import InstallStatus, \
-                                                     RebootException
-from osol_install.text_install.log_viewer import LogViewer
-from osol_install.text_install.partition_edit_screen import PartEditScreen
-from osol_install.text_install.summary import SummaryScreen
-from osol_install.text_install.welcome import WelcomeScreen
-from solaris_install.engine import InstallEngine
-from solaris_install.logger import INSTALL_LOGGER_NAME
-import solaris_install.sysconfig as sysconfig
-import terminalui
-from terminalui import LOG_LEVEL_INPUT, LOG_NAME_INPUT
-from terminalui.action import Action
-from terminalui.base_screen import BaseScreen
-from terminalui.help_screen import HelpScreen
-from terminalui.i18n import get_encoding, set_wrap_on_whitespace
-from terminalui.main_window import MainWindow
-from terminalui.screen_list import ScreenList
-
-
-LOG_LOCATION_FINAL = "/var/sadm/system/logs/install_log"
-DEFAULT_LOG_LOCATION = "/tmp/install_log"
-DEFAULT_LOG_LEVEL = "info"
-DEBUG_LOG_LEVEL = "debug"
-LOG_FORMAT = ("%(asctime)-25s %(name)-10s "
-              "%(levelname)-10s %(message)-50s")
-REBOOT = "/usr/sbin/reboot"
-
-
-def exit_text_installer(logname=None, errcode=0):
-    '''Close out the logger and exit with errcode'''
-    logging.info("**** END ****")
-    logging.shutdown()
-    if logname is not None:
-        print _("Exiting Text Installer. Log is available at:\n%s") % logname
-    if isinstance(errcode, unicode):
-        errcode = errcode.encode(get_encoding())
-    sys.exit(errcode)
-
-
-def setup_logging(logname, log_level):
-    '''Initialize the logger, logging to logname at log_level'''
-    log_level = log_level.upper()
-    if hasattr(logging, log_level):
-        log_level = getattr(logging, log_level.upper())
-    elif log_level == LOG_NAME_INPUT:
-        log_level = LOG_LEVEL_INPUT
-    else:
-        raise IOError(2, "Invalid --log-level parameter", log_level.lower())
-    logging.basicConfig(filename=logname, level=log_level,
-                        filemode='w', format=LOG_FORMAT)
-    logging.info("**** START ****")
-    return log_level
-
-
-def make_screen_list(main_win):
-    '''Initialize the screen list. On x86, add screens for editing slices
-    within a partition. Also, trigger the target discovery thread.
-    
-    '''
-    
-    result = []
-    result.append(WelcomeScreen(main_win))
-    disk_screen = DiskScreen(main_win)
-    disk_screen.start_discovery()
-    result.append(disk_screen)
-    result.append(FDiskPart(main_win))
-    result.append(PartEditScreen(main_win))
-    if platform.processor() == "i386":
-        result.append(FDiskPart(main_win, x86_slice_mode=True))
-        result.append(PartEditScreen(main_win, x86_slice_mode=True))
-    
-    result.extend(sysconfig.get_all_screens(main_win))
-    
-    result.append(SummaryScreen(main_win))
-    result.append(InstallProgress(main_win))
-    result.append(InstallStatus(main_win))
-    result.append(LogViewer(main_win))
-    return result
-
-
-def _reboot_cmds(is_x86):
-    '''Generate list of cmds to try fast rebooting'''
-    cmds = []
-    
-    ret_val, be_list = libbe_py.beList()
-    if ret_val == 0:
-        for be in be_list:
-            if be.get("active_boot", False):
-                root_ds = "%s" % be['root_ds']
-                if is_x86:
-                    cmds.append([REBOOT, "-f", "--", root_ds])
-                else:
-                    # SPARC requires "-Z" before the root dataset
-                    cmds.append([REBOOT, "-f", "--", "-Z", root_ds])
-                break
-        
-    # Fallback reboot. If the subprocess.call(..) command above fails,
-    # simply do a standard reboot.
-    cmds.append([REBOOT])
-    return cmds
-
-
-def reboot(is_x86):
-    '''Reboot the machine, attempting fast reboot first if available'''
-    cmds = _reboot_cmds(is_x86)
-    for cmd in cmds:
-        try:
-            subprocess.call(cmd)
-        except OSError, err:
-            logging.warn("Reboot failed:\n\t'%s'\n%s",
-                         " ".join(cmd), err)
-        else:
-            logging.warn("Reboot failed:\n\t'%s'.\nWill attempt"
-                         " standard reboot", " ".join(cmd))
-
-
-def prepare_engine(options):
-    eng = InstallEngine(loglevel=options.log_level, debug=options.debug)
-    terminalui.init_logging(INSTALL_LOGGER_NAME)
-    
-    install_profile = InstallProfile()
-    install_profile.log_location = options.logname
-    install_profile.log_final = LOG_LOCATION_FINAL
-    install_profile.no_install_mode = options.no_install
-    
-    eng.doc.persistent.insert_children([install_profile])
-
-    sysconfig.register_checkpoint()
-
-
-def init_locale():
-    locale.setlocale(locale.LC_ALL, "")
-    gettext.install("textinstall", "/usr/share/locale", unicode=True)
-    set_wrap_on_whitespace(_("DONT_TRANSLATE_BUT_REPLACE_msgstr_WITH_True_"
-                             "OR_False: Should wrap text on whitespace in"
-                             " this language"))
-    BaseScreen.set_default_quit_text(_("Confirm: Quit the Installer?"),
-                                     _("Do you want to quit the Installer?"),
-                                     _("Cancel"),
-                                     _("Quit"))
-
-
-def main():
-    init_locale()
-    
-    if os.getuid() != 0:
-        sys.exit(_("The %(release)s Text Installer must be run with "
-                   "root privileges") % RELEASE)
-    usage = "usage: %prog [-l FILE] [-v LEVEL] [-d] [-n]"
-    parser = OptionParser(usage=usage, version="%prog 1.1")
-    parser.add_option("-l", "--log-location", dest="logname",
-                      help=_("Set log location to FILE (default: %default)"),
-                      metavar="FILE", default=DEFAULT_LOG_LOCATION)
-    parser.add_option("-v", "--log-level", dest="log_level",
-                      default=None,
-                      help=_("Set log verbosity to LEVEL. In order of "
-                             "increasing verbosity, valid values are 'error' "
-                             "'warn' 'info' 'debug' or 'input'\n[default:"
-                             " %default]"),
-                      choices=["error", "warn", "info", "debug", "input"],
-                      metavar="LEVEL")
-    parser.add_option("-d", "--debug", action="store_true", dest="debug",
-                      default=False, help=_("Enable debug mode. Sets " 
-                      "logging level to 'input' and enables CTRL-C for " 
-                      "killing the program\n"))
-    parser.add_option("-b", "--no-color", action="store_true", dest="force_bw",
-                      default=False, help=_("Force the installer to run in "
-                      "black and white. This may be useful on some SPARC "
-                      "machines with unsupported frame buffers\n"))
-    parser.add_option("-n", "--no-install", action="store_true",
-                      dest="no_install", default=False,
-                      help=_("Runs in 'no installation' mode. When run"
-                      " in 'no installation' mode, no persistent changes are"
-                      " made to the disks and booted environment\n"))
-    options, args = parser.parse_args()
-    if options.log_level is None:
-        if options.debug:
-            options.log_level = DEBUG_LOG_LEVEL
-        else:
-            options.log_level = DEFAULT_LOG_LEVEL
-    try:
-        options.log_level = setup_logging(options.logname, options.log_level)
-    except IOError, err:
-        parser.error("%s '%s'" % (err.strerror, err.filename))
-    logging.debug("CLI options: log location = %s, verbosity = %s, debug "
-                  "mode = %s, no install = %s, force_bw = %s",
-                  options.logname, options.log_level, options.debug,
-                  options.no_install, options.force_bw)
-    init_log(0) # initialize old logging service
-    profile = None
-    try:
-        with terminalui as initscr:
-            win_size_y, win_size_x = initscr.getmaxyx()
-            if win_size_y < 24 or win_size_x < 80:
-                msg = _("     Terminal too small. Min size is 80x24."
-                        " Current size is %(x)ix%(y)i.") % \
-                        {'x': win_size_x, 'y': win_size_y}
-                exit_text_installer(errcode=msg)
-            prepare_engine(options)
-            
-            screen_list = ScreenList()
-            actions = [Action(curses.KEY_F2, _("Continue"),
-                              screen_list.get_next),
-                       Action(curses.KEY_F3, _("Back"),
-                              screen_list.previous_screen),
-                       Action(curses.KEY_F6, _("Help"), screen_list.show_help),
-                       Action(curses.KEY_F9, _("Quit"), screen_list.quit)]
-            
-            main_win = MainWindow(initscr, screen_list, actions,
-                                  force_bw=options.force_bw)
-            screen_list.help = HelpScreen(main_win, _("Help Topics"),
-                                          _("Help Index"),
-                                          _("Select a topic and press "
-                                            "Continue."))
-            win_list = make_screen_list(main_win)
-            screen_list.help.setup_help_data(win_list)
-            screen_list.screen_list = win_list
-            screen = screen_list.get_next()
-            ctrl_c = None
-            doc = InstallEngine.get_instance().doc
-            while screen is not None:
-                profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                              not_found_is_err=True)
-                logging.debug("Install profile:\n%s", profile)
-                logging.debug("Displaying screen: %s", type(screen))
-                screen = screen.show()
-                if not options.debug and ctrl_c is None:
-                    # This prevents the user from accidentally hitting
-                    # ctrl-c halfway through the install. Ctrl-C is left
-                    # available through the first screen in case terminal
-                    # display issues make it impossible for the user to
-                    # quit gracefully
-                    ctrl_c = signal.signal(signal.SIGINT, signal.SIG_IGN)
-            errcode = 0
-    except RebootException:
-        reboot(platform.processor() == "i386")
-    except SystemExit:
-        raise
-    except:
-        logging.exception(str(profile))
-        exc_type, exc_value = sys.exc_info()[:2]
-        print _("An unhandled exception occurred.")
-        if str(exc_value):
-            print '\t%s: "%s"' % (exc_type.__name__, str(exc_value))
-        else:
-            print "\t%s" % exc_type.__name__
-        print _("Full traceback data is in the installation log")
-        print _("Please file a bug at http://defect.opensolaris.org")
-        errcode = 1
-    exit_text_installer(options.logname, errcode)
-
-if __name__ == '__main__':
-    main()
--- a/usr/src/cmd/text-install/osol_install/text_install/disk_selection.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,433 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Screens and functions to display a list of disks to the user.
-'''
-
-from copy import deepcopy
-import curses
-import logging
-import platform
-import threading
-import traceback
-
-from osol_install.profile.disk_info import DiskInfo, SliceInfo
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from osol_install.text_install.disk_window import DiskWindow, \
-                                                  get_minimum_size, \
-                                                  get_recommended_size
-from osol_install.text_install.ti_install_utils import get_zpool_list
-import osol_install.tgt as tgt
-from solaris_install.engine import InstallEngine
-from terminalui.base_screen import BaseScreen, QuitException, UIMessage
-from terminalui.i18n import fit_text_truncate, textwidth, ljust_columns
-from terminalui.list_item import ListItem
-from terminalui.scroll_window import ScrollWindow
-from terminalui.window_area import WindowArea
-
-
-class DiskScreen(BaseScreen):
-    '''
-    Allow the user to select a (valid) disk target for installation
-    Display the partition/slice table for the highlighted disk
-    
-    '''
-    
-    HEADER_TEXT = _("Disks")
-    PARAGRAPH = _("Where should %(release)s be installed?") % RELEASE
-    SIZE_TEXT = _("Recommended size:  %(recommend).1fGB      "
-                  "Minimum size: %(min).1fGB")
-    DISK_SEEK_TEXT = _("Seeking disks on system")
-    FOUND_x86 = _("The following partitions were found on the disk.")
-    FOUND_SPARC = _("The following slices were found on the disk.")
-    PROPOSED_x86 = _("A partition table was not found. The following is "
-                     "proposed.")
-    PROPOSED_SPARC = _("A VTOC label was not found. The following "
-                       "is proposed.")
-    PROPOSED_GPT = _("A GPT labeled disk was found. The following is "
-                     "proposed.")
-    TOO_SMALL = _("Too small")
-    TOO_BIG_WARN = _("Limited to %.1f TB")
-    GPT_LABELED = _("GPT labeled disk")
-    NO_DISKS = _("No disks found. Additional device drivers may "
-                 "be needed.")
-    NO_TARGETS = _("%(release)s cannot be installed on any disk") % RELEASE
-    TGT_ERROR = _("An error occurred while searching for installation"
-                  " targets. Please check the install log and file a bug"
-                  " at defect.opensolaris.org.")
-    
-    DISK_HEADERS = [(8, _("Type")),
-                    (10, _("Size(GB)")),
-                    (6, _("Boot")),
-                    (9, _("Device")),
-                    (15, _("Manufacturer")),
-                    (22, _("Notes"))]
-    SPINNER = ["\\", "|", "/", "-"]
-    
-    DISK_WARNING_HEADER = _("Warning")
-    DISK_WARNING_TOOBIG = _("Only the first %.1fTB can be used.")
-    DISK_WARNING_GPT = _("You have chosen a GPT labeled disk. Installing "
-                         "onto a GPT labeled disk will cause the loss "
-                         "of all existing data and the disk will be "
-                         "relabeled as SMI.")
-
-    CANCEL_BUTTON = _("Cancel")
-    CONTINUE_BUTTON = _("Continue")
-    
-    HELP_DATA = (TUI_HELP + "/%s/disks.txt", _("Disks"))
-    
-    def __init__(self, main_win):
-        super(DiskScreen, self).__init__(main_win)
-        if platform.processor() == "i386":
-            self.found_text = DiskScreen.FOUND_x86
-            self.proposed_text = DiskScreen.PROPOSED_x86
-        else:
-            self.found_text = DiskScreen.FOUND_SPARC
-            self.proposed_text = DiskScreen.PROPOSED_SPARC
-        
-        disk_header_text = []
-        for header in DiskScreen.DISK_HEADERS:
-            header_str = fit_text_truncate(header[1], header[0]-1, just="left")
-            disk_header_text.append(header_str)
-        self.disk_header_text = " ".join(disk_header_text)
-        max_note_size = DiskScreen.DISK_HEADERS[5][0]
-        self.too_small_text = DiskScreen.TOO_SMALL[:max_note_size]
-        max_disk_size = SliceInfo.MAX_VTOC.size_as("tb")
-        too_big_warn = DiskScreen.TOO_BIG_WARN % max_disk_size
-        self.too_big_warn = too_big_warn[:max_note_size]
-        self.disk_warning_too_big = \
-            DiskScreen.DISK_WARNING_TOOBIG % max_disk_size
-        
-        self.disks = []
-        self.existing_pools = []
-        self.disk_win = None
-        self.disk_detail = None
-        self.num_targets = 0
-        self.td_handle = None
-        self._size_line = None
-        self.selected_disk = 0
-        self._minimum_size = None
-        self._recommended_size = None
-        self.do_copy = False # Flag indicating if install_profile.disk
-                             # should be copied
-    
-    def determine_minimum(self):
-        '''Returns minimum install size, fetching first if needed'''
-        self.determine_size_data()
-        return self._minimum_size
-    
-    minimum_size = property(determine_minimum)
-    
-    def determine_recommended(self):
-        '''Returns recommended install size, fetching first if needed'''
-        self.determine_size_data()
-        return self._recommended_size
-    
-    recommended_size = property(determine_recommended)
-    
-    def determine_size_data(self):
-        '''Retrieve the minimum and recommended sizes and generate the string
-        to present that information.
-        
-        '''
-        if self._minimum_size is None or self._recommended_size is None:
-            self._recommended_size = get_recommended_size().size_as("gb")
-            self._minimum_size = get_minimum_size().size_as("gb")
-    
-    def get_size_line(self):
-        '''Returns the line of text displaying the min/recommended sizes'''
-        if self._size_line is None:
-            size_dict = {"recommend" : self.recommended_size,
-                         "min" : self.minimum_size}
-            self._size_line = DiskScreen.SIZE_TEXT % size_dict
-        return self._size_line
-    
-    size_line = property(get_size_line)
-    
-    def wait_for_disks(self):
-        '''Block while waiting for libtd to finish. Catch F9 and quit
-        if needed
-        
-        '''
-        if self.td_handle is None:
-            self.start_discovery()
-        self.main_win.actions.pop(curses.KEY_F2, None)
-        self.main_win.actions.pop(curses.KEY_F6, None)
-        self.main_win.actions.pop(curses.KEY_F3, None)
-        self.main_win.show_actions()
-        if self.td_handle.is_alive():
-            self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1,
-                                     self.win_size_x - 3)
-            self.main_win.do_update()
-            offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2
-            spin_index = 0
-            self.center_win.window.timeout(250)
-            while self.td_handle.is_alive():
-                input_key = self.main_win.getch()
-                if input_key == curses.KEY_F9:
-                    if self.confirm_quit():
-                        raise QuitException
-                self.center_win.add_text(DiskScreen.SPINNER[spin_index], 5,
-                                         offset)
-                self.center_win.no_ut_refresh()
-                self.main_win.do_update()
-                spin_index = (spin_index + 1) % len(DiskScreen.SPINNER)
-
-            self.center_win.window.timeout(-1)
-            self.center_win.clear()
-
-        # Get the list of existing zpools on the
-        # system and based on that come up with 
-        # a unique name for the root pool 
-        index = 1
-        pool_name = "rpool"
-        while pool_name in self.existing_pools:
-            pool_name = "rpool%d" % index
-            index += 1
-
-        # Set the SliceInfo.DEFAULT_POOL to the unique
-        # pool name
-        SliceInfo.DEFAULT_POOL.data = pool_name
-
-    def _show(self):
-        '''Create a list of disks to choose from and create the window
-        for displaying the partition/slice information from the selected
-        disk
-        
-        '''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        self.wait_for_disks()
-        self.num_targets = 0
-        
-        if not self.disks:
-            self.center_win.add_paragraph(DiskScreen.NO_DISKS, 1, 1,
-                                          max_x=(self.win_size_x - 1))
-            return
-        
-        if isinstance(self.disks[0], BaseException):
-            if len(self.disks) == 1:
-                raise tgt.TgtError(("Unexpected error (%s) during target "
-                                    "discovery. See log for details.") %
-                                    self.disks[0])
-            else:
-                self.disks = self.disks[1:]
-                logging.warn("Failure in target discovery, but one or more"
-                             " disks found. Continuing.")
-        
-        boot_disk = self.disks[0]
-        for disk in self.disks:
-            if (disk.size.size_as("gb") > self.minimum_size):
-                self.num_targets += 1
-            if disk.boot:
-                boot_disk = disk
-        self.disks.remove(boot_disk)
-        self.disks.insert(0, boot_disk)
-        
-        if self.num_targets == 0:
-            self.center_win.add_paragraph(DiskScreen.NO_TARGETS, 1, 1,
-                                          max_x=(self.win_size_x - 1))
-            return
-        
-        self.main_win.reset_actions()
-        self.main_win.show_actions()
-        
-        y_loc = 1
-        self.center_win.add_text(DiskScreen.PARAGRAPH, y_loc, 1)
-        
-        y_loc += 1
-        self.center_win.add_text(self.size_line, y_loc, 1)
-        
-        y_loc += 2
-        self.center_win.add_text(self.disk_header_text, y_loc, 1)
-        
-        y_loc += 1
-        self.center_win.window.hline(y_loc, self.center_win.border_size[1] + 1,
-                                     curses.ACS_HLINE,
-                                     textwidth(self.disk_header_text))
-        
-        y_loc += 1
-        disk_win_area = WindowArea(4, textwidth(self.disk_header_text) + 2,
-                                   y_loc, 0)
-        disk_win_area.scrollable_lines = len(self.disks) + 1
-        self.disk_win = ScrollWindow(disk_win_area,
-                                     window=self.center_win)
-        
-        disk_item_area = WindowArea(1, disk_win_area.columns - 2, 0, 1)
-        disk_index = 0
-        len_type = DiskScreen.DISK_HEADERS[0][0] - 1
-        len_size = DiskScreen.DISK_HEADERS[1][0] - 1
-        len_boot = DiskScreen.DISK_HEADERS[2][0] - 1
-        len_dev = DiskScreen.DISK_HEADERS[3][0] - 1
-        len_mftr = DiskScreen.DISK_HEADERS[4][0] - 1
-        for disk in self.disks:
-            disk_text_fields = []
-            type_field = disk.type[:len_type]
-            type_field = ljust_columns(type_field, len_type)
-            disk_text_fields.append(type_field)
-            disk_size = disk.size.size_as("gb")
-            size_field = "%*.1f" % (len_size, disk_size)
-            disk_text_fields.append(size_field)
-            if disk.boot:
-                bootable_field = "+".center(len_boot)
-            else:
-                bootable_field = " " * (len_boot)
-            disk_text_fields.append(bootable_field)
-            device_field = disk.name[:len_dev]
-            device_field = ljust_columns(device_field, len_dev)
-            disk_text_fields.append(device_field)
-            if disk.vendor is not None:
-                mftr_field = disk.vendor[:len_mftr]
-                mftr_field = ljust_columns(mftr_field, len_mftr)
-            else:
-                mftr_field = " " * len_mftr
-            disk_text_fields.append(mftr_field)
-            selectable = True
-            if disk_size < self.minimum_size:
-                note_field = self.too_small_text
-                selectable = False
-            elif DiskInfo.GPT in disk.label:
-                note_field = DiskScreen.GPT_LABELED
-            elif disk_size > SliceInfo.MAX_VTOC.size_as("gb"):
-                note_field = self.too_big_warn
-            else:
-                note_field = ""
-            disk_text_fields.append(note_field)
-            disk_text = " ".join(disk_text_fields)
-            disk_item_area.y_loc = disk_index
-            disk_list_item = ListItem(disk_item_area, window=self.disk_win,
-                                      text=disk_text, add_obj=selectable)
-            disk_list_item.on_make_active = on_activate
-            disk_list_item.on_make_active_kwargs["disk_info"] = disk
-            disk_list_item.on_make_active_kwargs["disk_select"] = self
-            disk_index += 1
-        self.disk_win.no_ut_refresh()
-        
-        y_loc += 7
-        disk_detail_area = WindowArea(6, 70, y_loc, 1)
-        self.disk_detail = DiskWindow(disk_detail_area, self.disks[0],
-                                      window=self.center_win)
-        
-        self.main_win.do_update()
-        self.center_win.activate_object(self.disk_win)
-        self.disk_win.activate_object(self.selected_disk)
-        # Set the flag so that the disk is not copied by on_change_screen,
-        # unless on_activate gets called as a result of the user changing
-        # the selected disk.
-        self.do_copy = False
-    
-    def on_change_screen(self):
-        ''' Assign the selected disk to the InstallProfile, and make note of
-        its index (in case the user returns to this screen later)
-        
-        '''
-        if self.disk_detail is not None:
-            if self.do_copy or self.install_profile.disk is None:
-                disk = self.disk_detail.disk_info
-                self.install_profile.disk = deepcopy(disk)
-                self.install_profile.original_disk = disk
-            self.selected_disk = self.disk_win.active_object
-    
-    def start_discovery(self):
-        '''Spawn a thread to begin target discovery'''
-        logging.debug("spawning target discovery thread")
-        self.td_handle = threading.Thread(target=DiskScreen.get_disks,
-                                          args=(self.disks,
-                                                self.existing_pools))
-        logging.debug("starting target discovery thread")
-        self.td_handle.start()
-    
-    @staticmethod
-    def get_disks(disks, pools):
-        '''
-        Call into target discovery and get disk data. The disks found are
-        added to the list passed in by the 'disks' argument
-        
-        '''
-        try:
-            td_disks = tgt.discover_target_data()
-            for disk in td_disks:
-                disks.append(DiskInfo(tgt_disk=disk))
-            pools.extend(get_zpool_list())
-        # If an exception occurs, regardless of type, log it, add it as the
-        # first item in the disk list, and consume it (an uncaught Exception
-        # in this threaded code would distort the display).
-        # During the call to _show, if an exception occurred, the program
-        # aborts gracefully
-        # pylint: disable-msg=W0703
-        except BaseException, err:
-            logging.exception(traceback.format_exc())
-            disks.insert(0, err)
-
-
-    def validate(self):
-        '''Validate the size of the disk.'''
-        disk = self.disk_detail.disk_info
-        
-        warning_txt = []
-        if DiskInfo.GPT in disk.label:
-            warning_txt.append(DiskScreen.DISK_WARNING_GPT)
-        if disk.size > SliceInfo.MAX_VTOC:
-            warning_txt.append(self.disk_warning_too_big)
-        warning_txt = " ".join(warning_txt)
-        
-        if warning_txt:
-            # warn the user and give user a chance to change
-            result = self.main_win.pop_up(DiskScreen.DISK_WARNING_HEADER,
-                                          warning_txt,
-                                          DiskScreen.CANCEL_BUTTON,
-                                          DiskScreen.CONTINUE_BUTTON)
-            
-            if not result:
-                raise UIMessage() # let user select different disk
-            
-            # if user didn't quit it is always OK to ignore disk size,
-            # that will be forced less than the maximum in partitioning.
-
-
-def on_activate(disk_info=None, disk_select=None):
-    '''When a disk is selected, pass its data to the disk_select_screen'''
-    max_x = disk_select.win_size_x - 1
-    
-    if DiskInfo.GPT in disk_info.label:
-        # default to use whole disk for GPT labeled disk
-        disk_select.center_win.add_paragraph(DiskScreen.PROPOSED_GPT, 11, 1,
-                                             max_x=max_x)
-        disk_info.create_default_layout()
-        disk_info.use_whole_segment = True
-    elif disk_info.was_blank:
-        disk_select.center_win.add_paragraph(disk_select.proposed_text, 11, 1,
-                                             max_x=max_x)
-        disk_info.create_default_layout()
-        disk_info.use_whole_segment = True
-    else:
-        disk_select.center_win.add_paragraph(disk_select.found_text, 11, 1,
-                                             max_x=max_x)
-    disk_select.disk_detail.set_disk_info(disk_info)
-    # User selected a different disk; set the flag so that it gets copied later
-    disk_select.do_copy = True
--- a/usr/src/cmd/text-install/osol_install/text_install/disk_window.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,845 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-
-'''
-UI component for displaying (and editing) partition & slice data
-'''
-
-
-from copy import deepcopy
-import curses
-import logging
-
-from osol_install.profile.disk_space import DiskSpace, round_to_multiple
-from osol_install.profile.partition_info import PartitionInfo, UI_PRECISION
-from osol_install.text_install import _
-from osol_install.text_install.ti_install_utils import \
-    get_minimum_size as get_min_install_size
-from osol_install.text_install.ti_install_utils import \
-    get_recommended_size as get_rec_install_size
-from osol_install.text_install.ti_install_utils import SwapDump, \
-                                                       InstallationError
-from terminalui import LOG_LEVEL_INPUT
-from terminalui.base_screen import UIMessage
-from terminalui.edit_field import EditField
-from terminalui.i18n import fit_text_truncate, textwidth
-from terminalui.inner_window import InnerWindow, no_action
-from terminalui.list_item import ListItem
-from terminalui.scroll_window import ScrollWindow
-from terminalui.window_area import WindowArea
-
-
-class DiskWindow(InnerWindow):
-    '''Display and edit disk information, including partitions and slices'''
-    
-    STATIC_PARTITION_HEADERS = [(12, _("Primary"), _("Logical")),
-                                (9, _("Size(GB)"), _("Size(GB)"))]
-    
-    EDIT_PARTITION_HEADERS = [(13, _("Primary"), _("Logical")),
-                              (9, _("Size(GB)"), _("Size(GB)")),
-                              (7, _(" Avail"), _(" Avail"))]
-    
-    STATIC_SLICE_HEADERS = [(13, _("Slice"), _("Slice")),
-                            (2, "#", "#"),
-                            (9, _("Size(GB)"), _("Size(GB)"))]
-    
-    EDIT_SLICE_HEADERS = [(13, _("Slice"), _("Slice")),
-                          (2, "#", "#"),
-                          (9, _("Size(GB)"), _("Size(GB)")),
-                          (7, _(" Avail"), _(" Avail"))]
-    
-    ADD_KEYS = {curses.KEY_LEFT : no_action,
-                curses.KEY_RIGHT : no_action}
-    
-    DEAD_ZONE = 3
-    SCROLL_PAD = 2
-    
-    MIN_SIZE = None
-    REC_SIZE = None
-    
-    SIZE_PRECISION = UI_PRECISION.size_as("gb")
-    DESTROYED_MARK = EditField.ASTERISK_CHAR
-    
-    def __init__(self, area, disk_info, editable=False,
-                 error_win=None, reset=None, **kwargs):
-        '''See also InnerWindow.__init__
-        
-        disk_info (required) - A DiskInfo object containing the data to be
-        represented. Also accepts PartitionInfo objects (for displaying slice
-        data within that partition). If disk_info has partition(s), those are
-        displayed. If not, but it has slices, then those are displayed. If
-        neither partition data nor slice data are available, a ValueError is
-        raised. This window makes a copy of the disk_info, as well as keeping
-        a reference to the original for the purposes of resetting at a later
-        time.
-        
-        headers (required) - List of tuples to populate the header of this
-        window with. The first item in each tuple should be the width of the
-        header, the second item should be the left side header.
-        
-        editable (optional) - If True, the window will be created such that
-        data is editable.
-        
-        '''
-        self.headers = None
-        self.orig_ext_part_field = None
-        self.orig_logicals_active = False
-        self.ext_part_field = None
-        self.error_win = error_win
-        self.editable = editable
-        self.win_width = None
-        self.left_win = None
-        self.right_win = None
-        self.list_area = None
-        self.edit_area = None
-        super(DiskWindow, self).__init__(area, add_obj=editable, **kwargs)
-        self.left_header_string = None
-        self.right_header_string = None
-        self._orig_data = None
-        self._reset = reset
-        self.disk_info = None
-        self.has_partition_data = True
-        self.key_dict[curses.KEY_LEFT] = self.on_arrow_key
-        self.key_dict[curses.KEY_RIGHT] = self.on_arrow_key
-        if self.editable:
-            self.key_dict[curses.KEY_F5] = self.change_type
-        
-        if getattr(disk_info, "do_revert", False):
-            self.reset()
-        else:
-            self.set_disk_info(disk_info)
-    
-    def _init_win(self, window):
-        '''Require at least 70 columns and 6 lines to fit current needs for
-        display of partitions and slices. Builds two inner ScrollWindows for
-        displaying/editing the data.
-        
-        '''
-        if self.area.columns < 70:
-            raise ValueError, "Insufficient space - area.columns < 70"
-        if self.area.lines < 6:
-            raise ValueError, "Insufficient space - area.lines < 6"
-        self.win_width = (self.area.columns - DiskWindow.DEAD_ZONE
-                          + DiskWindow.SCROLL_PAD) / 2
-        
-        super(DiskWindow, self)._init_win(window)
-        
-        win_area = WindowArea(self.area.lines - 1, self.win_width, 2, 0)
-        win_area.scrollable_lines = self.area.lines - 2
-        self.left_win = ScrollWindow(win_area, window=self, add_obj=False)
-        self.left_win.color = None
-        self.left_win.highlight_color = None
-        win_area.x_loc = self.win_width + DiskWindow.DEAD_ZONE
-        win_area.scrollable_lines = 2 * PartitionInfo.MAX_LOGICAL_PARTITIONS
-        self.right_win = ScrollWindow(win_area, window=self, add_obj=False)
-        self.right_win.color = None
-        self.right_win.highlight_color = None
-    
-    def set_disk_info(self, disk_info):
-        '''Set up this DiskWindow to represent disk_info'''
-        if getattr(disk_info, "partitions", False):
-            self.has_partition_data = True
-        elif disk_info.slices:
-            self.has_partition_data = False
-        else:
-            return
-        
-        if self.has_partition_data:
-            if self.editable:
-                self.headers = DiskWindow.EDIT_PARTITION_HEADERS
-                self.list_area = WindowArea(1, self.headers[0][0] + 
-                                            self.headers[1][0],
-                                            0, DiskWindow.SCROLL_PAD)
-                self.edit_area = WindowArea(1, self.headers[1][0], 0,
-                                            self.headers[0][0])
-            else:
-                self.headers = DiskWindow.STATIC_PARTITION_HEADERS
-        else:
-            if self.editable:
-                self.headers = DiskWindow.EDIT_SLICE_HEADERS
-                self.list_area = WindowArea(1, self.headers[0][0] +
-                                            self.headers[1][0] +
-                                            self.headers[2][0],
-                                            0, DiskWindow.SCROLL_PAD)
-                self.edit_area = WindowArea(1, self.headers[2][0], 0,
-                                            self.headers[0][0] +
-                                            self.headers[1][0])
-            else:
-                self.headers = DiskWindow.STATIC_SLICE_HEADERS
-        
-        self._orig_data = disk_info
-        self.disk_info = deepcopy(disk_info)
-        self.disk_info.add_unused_parts()
-        
-        self.left_win.clear()
-        self.right_win.clear()
-        self.window.erase()
-        self.print_headers()
-        
-        if self.editable:
-            self.active_object = None
-            self.build_edit_fields()
-            self.right_win.bottom = max(0, len(self.right_win.all_objects) -
-                                        self.right_win.area.lines)
-            if self.has_partition_data:
-                self.orig_ext_part_field = None
-                for obj in self.left_win.objects:
-                    if (obj.data_obj.is_extended()):
-                        self.orig_ext_part_field = obj
-                        self.orig_logicals_active = True
-                        break
-        else:
-            self.print_data()
-    
-    def print_headers(self):
-        '''Print the headers for the displayed data.
-        
-        header[0] - The width of this column. header[1] and header[2] are
-                    trimmed to this size
-        header[1] - The internationalized text for the left window
-        header[2] - The internationalized text for the right window
-        
-        '''
-        self.left_header_string = []
-        self.right_header_string = []
-        for header in self.headers:
-            left_header_str = header[1]
-            right_header_str = header[2]
-            # Trim the header to fit in the column width,
-            # splitting columns with at least 1 space
-            # Pad with extra space(s) to align the columns
-            left_header_str = fit_text_truncate(left_header_str,
-                                                header[0]-1, just="left")
-            self.left_header_string.append(left_header_str)
-            right_header_str = fit_text_truncate(right_header_str,
-                                                header[0]-1, just="left")
-            self.right_header_string.append(right_header_str)
-        self.left_header_string = " ".join(self.left_header_string)
-        self.right_header_string = " ".join(self.right_header_string)
-        logging.debug(self.left_header_string)
-        self.add_text(self.left_header_string, 0, DiskWindow.SCROLL_PAD)
-        right_win_offset = (self.win_width + DiskWindow.DEAD_ZONE +
-                            DiskWindow.SCROLL_PAD)
-        self.add_text(self.right_header_string, 0, right_win_offset)
-        self.window.hline(1, DiskWindow.SCROLL_PAD, curses.ACS_HLINE,
-                          textwidth(self.left_header_string))
-        self.window.hline(1, right_win_offset, curses.ACS_HLINE,
-                          textwidth(self.right_header_string))
-        self.no_ut_refresh()
-    
-    def print_data(self):
-        '''Print static (non-editable) data.
-        
-        Slices - fill the left side, then remaining slices on the right side.
-        If for some reason not all slices fit, indicate how many more slices
-        there area
-        
-        Partitions - Put standard partitions on the left, logical partitions
-        on the right
-        
-        '''
-        part_index = 0
-        if self.has_partition_data:
-            max_parts = PartitionInfo.MAX_STANDARD_PARTITIONS
-        else:
-            max_parts = min(len(self.disk_info.slices),
-                                self.left_win.area.lines)
-        win = self.left_win
-        y_loc = 0
-        for next_part in self.disk_info.get_parts():
-            if y_loc >= max_parts:
-                if win is self.left_win:
-                    win = self.right_win
-                    y_loc = 0
-                    max_parts = win.area.lines
-                else:
-                    if self.has_partition_data:
-                        num_extra = len(self.disk_info.partitions) - part_index
-                        more_parts_txt = _("%d more partitions") % num_extra
-                    else:
-                        num_extra = len(self.disk_info.slices) - part_index
-                        more_parts_txt = _("%d more slices") % num_extra
-                    win.add_text(more_parts_txt, win.area.lines, 3)
-                    break
-            x_loc = DiskWindow.SCROLL_PAD
-            field = 0
-            win.add_text(next_part.get_description(), y_loc, x_loc,
-                         self.headers[field][0] - 1)
-            x_loc += self.headers[field][0]
-            field += 1
-            if not self.has_partition_data:
-                win.add_text(str(next_part.number), y_loc, x_loc,
-                             self.headers[field][0] - 1)
-                x_loc += self.headers[field][0]
-                field += 1
-            win.add_text("%*.1f" % (self.headers[field][0]-1,
-                                    next_part.size.size_as("gb")),
-                                    y_loc, x_loc,
-                                    self.headers[field][0]-1)
-            x_loc += self.headers[field][0]
-            y_loc += 1
-            field += 1
-            part_index += 1
-        self.right_win.use_vert_scroll_bar = False
-        self.no_ut_refresh()
-    
-    def build_edit_fields(self):
-        '''Build subwindows for editing partition sizes
-        
-        For slices, fill the left side, then the right (right side scrolling as
-        needed, though this shouldn't happen unless the number of slices on
-        disk exceeds 8 for some reason)
-        
-        For partitions, fill the left side up to MAX_STANDARD_PARTITIONS,
-        and place all logical partitions on the right.
-        
-        '''
-        if self.has_partition_data:
-            max_left_parts = PartitionInfo.MAX_STANDARD_PARTITIONS
-        else:
-            max_left_parts = min(len(self.disk_info.slices),
-                                 self.left_win.area.lines)
-        part_iter = iter(self.disk_info.get_parts())
-        try:
-            next_part = part_iter.next()
-            self.objects.append(self.left_win)
-            for y_loc in range(max_left_parts):
-                self.list_area.y_loc = y_loc
-                self.create_list_item(next_part, self.left_win, self.list_area)
-                next_part.orig_type = next_part.type
-                next_part = part_iter.next()
-            self.objects.append(self.right_win)
-            for y_loc in range(self.right_win.area.scrollable_lines):
-                self.list_area.y_loc = y_loc
-                self.create_list_item(next_part, self.right_win,
-                                      self.list_area)
-                next_part.orig_offset = next_part.offset.size_as("gb")
-                next_part.orig_size = next_part.size.size_as("gb")
-                next_part = part_iter.next()
-        except StopIteration:
-            if len(self.right_win.all_objects) <= self.right_win.area.lines:
-                self.right_win.use_vert_scroll_bar = False
-            self.right_win.no_ut_refresh()
-        else:
-            raise ValueError("Could not fit all partitions in DiskWindow")
-        self.no_ut_refresh()
-    
-    def create_list_item(self, next_part, win, list_area):
-        '''Add an entry for next_part (a PartitionInfo or SliceInfo) to
-        the DiskWindow
-        
-        '''
-        next_part.is_dirty = False
-        next_part.restorable = True
-        next_part.orig_offset = next_part.offset.size_as("gb")
-        next_part.orig_size = next_part.size.size_as("gb")
-        next_part.orig_type = next_part.type
-        list_item = ListItem(list_area, window=win, data_obj=next_part)
-        list_item.key_dict.update(DiskWindow.ADD_KEYS)
-        list_item.on_make_inactive = on_leave_part_field
-        list_item.on_make_inactive_kwargs = {"field" : list_item}
-        edit_field = EditField(self.edit_area, window=list_item,
-                               numeric_pad=" ",
-                               validate=decimal_valid,
-                               on_exit=on_exit_edit,
-                               error_win=self.error_win,
-                               add_obj=False,
-                               data_obj=next_part)
-        edit_field.right_justify = True
-        edit_field.validate_kwargs["disk_win"] = self
-        edit_field.key_dict.update(DiskWindow.ADD_KEYS)
-        self.update_part(part_field=list_item)
-        return list_item
-    
-    def update_part(self, part_info=None, part_field=None):
-        '''Sync changed partition data to the screen.'''
-        if part_field is None:
-            if part_info is None:
-                raise ValueError("Must supply either part_info or part_field")
-            part_field = self.find_part_field(part_info)[1]
-        elif part_info is None:
-            part_info = part_field.data_obj
-        elif part_field.data_obj is not part_info:
-            raise ValueError("part_field must be a ListItem associated with "
-                             "part_info")
-        if not isinstance(part_field, ListItem):
-            raise TypeError("part_field must be a ListItem associated with "
-                            "part_info")
-        if self.has_partition_data:
-            desc_text = part_info.get_description()
-        else:
-            desc_length = self.headers[0][0] - 1
-            desc_text = "%-*.*s %i" % (desc_length, desc_length,
-                                       part_info.get_description(),
-                                       part_info.number)
-        part_field.set_text(desc_text)
-        edit_field = part_field.all_objects[0]
-        edit_field.set_text("%.1f" % part_info.size.size_as("gb"))
-        self.mark_if_destroyed(part_field)
-        self._update_edit_field(part_info, part_field, edit_field)
-
-        self.update_avail_space(part_info=part_info)
-        if self.has_partition_data:
-            if part_info.is_extended():
-                self.ext_part_field = part_field
-    
-    def _update_edit_field(self, part_info, part_field, edit_field):
-        '''If the partition/slice is editable, add it to the .objects list.
-        If it's also the part_field that's currently selected, then activate
-        the edit field.
-        
-        '''
-        if part_info.editable(self.disk_info):
-            part_field.objects = [edit_field]
-            active_win = self.get_active_object()
-            if active_win is not None:
-                if active_win.get_active_object() is part_field:
-                    part_field.activate_object(edit_field)
-        else:
-            edit_field.make_inactive()
-            part_field.objects = []
-            part_field.active_object = None
-
-    def mark_if_destroyed(self, part_field):
-        '''Determine if the partition/slice represented by part_field has
-        changed such that its contents will be destroyed.
-        
-        '''
-        part_info = part_field.data_obj
-        destroyed = part_info.destroyed()
-        self.mark_destroyed(part_field, destroyed)
-    
-    def mark_destroyed(self, part_field, destroyed):
-        '''If destroyed is True, add an asterisk indicating that the
-        partition or slice's content will be destroyed during installation.
-        Otherwise, clear the asterisk
-        
-        '''
-        y_loc = part_field.area.y_loc
-        x_loc = part_field.area.x_loc - 1
-        if part_field in self.right_win.objects:
-            win = self.right_win
-        else:
-            win = self.left_win
-        if destroyed:
-            win.window.addch(y_loc, x_loc, DiskWindow.DESTROYED_MARK,
-                             win.color_theme.inactive)
-        else:
-            win.window.addch(y_loc, x_loc, InnerWindow.BKGD_CHAR)
-    
-    def update_avail_space(self, part_number=None, part_info=None):
-        '''Update the 'Avail' column for the specified slice or partition.
-        If no number is given, all avail columns are updated
-        
-        '''
-        if part_number is None and part_info is None:
-            self._update_all_avail_space()
-        else:
-            self._update_avail_space(part_number, part_info)
-
-    def _update_all_avail_space(self):
-        '''Update the 'Avail' column for all slices or partitions.'''
-        idx = 0
-        for item in self.left_win.objects:
-            self.update_avail_space(idx)
-            idx += 1
-        for item in self.right_win.objects:
-            self.update_avail_space(idx)
-            idx += 1
-        y_loc = idx - len(self.left_win.objects)
-        if self.has_partition_data:
-            x_loc = self.headers[0][0] + self.headers[1][0] + 1
-            field = 2
-        else:
-            x_loc = (self.headers[0][0] + self.headers[1][0] +
-                     self.headers[2][0] + 1)
-            field = 3
-        if y_loc > 0:
-            self.right_win.add_text(" " * self.headers[field][0],
-                                    y_loc, x_loc)
-        elif y_loc == 0 and self.has_partition_data:
-            # Blank out the size fields of removed (non-original)
-            # logical partitions
-            orig_logicals = len(self._orig_data.get_logicals())
-            for right_y_loc in range(orig_logicals,
-                                self.right_win.area.scrollable_lines):
-                self.right_win.add_text(" " * self.headers[field][0],
-                                        right_y_loc, x_loc)
-
-    def _update_avail_space(self, part_number=None, part_info=None):
-        '''Update the 'Avail' column for the specified slice or partition.'''
-        if part_number is None:
-            win, item = self.find_part_field(part_info)
-        elif part_number < len(self.left_win.objects):
-            win = self.left_win
-            item = win.objects[part_number]
-        else:
-            win = self.right_win
-            item = win.objects[part_number - len(self.left_win.objects)]
-        if self.has_partition_data:
-            x_loc = self.headers[0][0] + self.headers[1][0] + 1
-            field = 2
-        else:
-            x_loc = (self.headers[0][0] + self.headers[1][0] +
-                     self.headers[2][0] + 1)
-            field = 3
-        y_loc = item.area.y_loc
-        part = item.data_obj
-        max_space = part.get_max_size(self.disk_info)
-        max_space = "%*.1f" % (self.headers[field][0], max_space)
-        win.add_text(max_space, y_loc, x_loc)
-    
-    def find_part_field(self, part_info):
-        '''Given a PartitionInfo or SliceInfo object, find the associated
-        ListItem. This search compares by reference, and will only succeed
-        if you have a handle to the exact object referenced by the ListItem
-        
-        '''
-        for win in [self.left_win, self.right_win]:
-            for item in win.objects:
-                if item.data_obj is part_info:
-                    return win, item
-        raise ValueError("Part field not found")
-    
-    def reset(self, dummy=None):
-        '''Reset disk_info to _orig_data.
-        Meaningful only for editable DiskWindows
-        
-        '''
-        if self.editable:
-            if self._reset is not None:
-                self.set_disk_info(self._reset)
-            else:
-                self.set_disk_info(self._orig_data)
-            self.activate_solaris_data()
-    
-    def activate_solaris_data(self):
-        '''Find the Solaris Partition / ZFS Root Pool Slice and activate it.
-        See also DiskInfo.get_solaris_data()
-        
-        '''
-        if self.editable:
-            solaris_part = self.disk_info.get_solaris_data()
-            if solaris_part is None:
-                logging.debug("No Solaris data, activating default")
-                self.activate_object()
-                self.right_win.scroll(scroll_to_line=0)
-                return
-            disk_order = self.disk_info.get_parts().index(solaris_part)
-            logging.debug("solaris disk at disk_order = %s", disk_order)
-            if disk_order < len(self.left_win.objects):
-                logging.debug("activating in left_win")
-                self.left_win.activate_object(disk_order)
-                self.activate_object(self.left_win)
-                self.right_win.scroll(scroll_to_line=0)
-            else:
-                activate = disk_order - len(self.left_win.objects)
-                logging.debug('activating in right win')
-                self.right_win.activate_object_force(activate,
-                                                     force_to_top=True)
-                self.activate_object(self.right_win)
-                left_active = self.left_win.get_active_object()
-                if left_active is not None:
-                    left_active.make_inactive()
-    
-    def make_active(self):
-        '''On activate, select the solaris partition or ZFS root pool,
-        instead of defaulting to 0
-        
-        '''
-        self.set_color(self.highlight_color)
-        self.activate_solaris_data()
-    
-    def on_arrow_key(self, input_key):
-        '''
-        On curses.KEY_LEFT: Move from the right win to the left win
-        On curses.KEY_RIGHT: Move from the left to the right
-        
-        '''
-        if (input_key == curses.KEY_LEFT and
-            self.get_active_object() is self.right_win and
-            len(self.left_win.objects) > 0):
-            
-            active_object = self.right_win.get_active_object().area.y_loc
-            if (active_object >= len(self.left_win.objects)):
-                active_object = len(self.left_win.objects) - 1
-            self.activate_object(self.left_win)
-            self.left_win.activate_object(active_object)
-            return None
-        elif (input_key == curses.KEY_RIGHT and
-              self.get_active_object() is self.left_win and
-              len(self.right_win.objects) > 0):
-            active_line = (self.left_win.active_object + 
-                             self.right_win.current_line[0])
-            active_object = None
-            force_to_top = False
-            for obj in self.right_win.objects:
-                if obj.area.y_loc >= active_line:
-                    active_object = obj
-                    off_screen = (self.right_win.current_line[0] +
-                                  self.right_win.area.lines)
-                    if active_object.area.y_loc > off_screen:
-                        force_to_top = True
-                    break
-            if active_object is None:
-                active_object = 0
-            self.left_win.activate_object(-1, loop=True)
-            self.activate_object(self.right_win)
-            self.right_win.activate_object_force(active_object,
-                                                 force_to_top=force_to_top)
-            return None
-        return input_key
-    
-    def no_ut_refresh(self, abs_y=None, abs_x=None):
-        '''Refresh self, left win and right win explicitly'''
-        super(DiskWindow, self).no_ut_refresh()
-        self.left_win.no_ut_refresh(abs_y, abs_x)
-        self.right_win.no_ut_refresh(abs_y, abs_x)
-    
-    def change_type(self, dummy):
-        '''Cycle the type for the currently active object, and
-        update its field
-        
-        '''
-        logging.debug("changing type")
-        part_field = self.get_active_object().get_active_object()
-        part_info = part_field.data_obj
-        old_type = part_info.type
-        if part_info.restorable:
-            part_info.cycle_type(self.disk_info, [part_info.orig_type])
-        else:
-            part_info.cycle_type(self.disk_info)
-        new_type = part_info.type
-        if old_type != new_type:
-            max_size = part_info.get_max_size(self.disk_info)
-            if part_info.restorable:
-                part_info.is_dirty = (new_type != part_info.orig_type)
-            if old_type == part_info.UNUSED:
-                if part_info.orig_type == part_info.UNUSED:
-                    part_info.size = "%.1fgb" % max_size
-                    part_info.adjust_offset(self.disk_info)
-                else:
-                    part_info.size = part_info.previous_size
-            if part_info.is_dirty and part_info.size.size_as("gb") > max_size:
-                part_info.size = "%.1fgb" % max_size
-                part_info.adjust_offset(self.disk_info)
-            if self.has_partition_data:
-                if old_type in PartitionInfo.EXTENDED:
-                    self.deactivate_logicals()
-                elif part_info.is_extended():
-                    self.create_extended(part_field)
-                elif part_info.is_logical():
-                    last_logical = self.right_win.objects[-1].data_obj
-
-                    if (old_type == PartitionInfo.UNUSED and
-                        self.right_win.objects[-1] is part_field):
-                        logging.debug("part is logical, old type unused, "
-                                      "last field")
-                        self.append_unused_logical()
-                    elif (len(self.right_win.objects) > 1 and
-                          new_type == PartitionInfo.UNUSED and
-                          self.right_win.objects[-2] is part_field and
-                          last_logical.type == PartitionInfo.UNUSED):
-                        # If we cycle the second to last partition to Unused,
-                        # combine it with the last unused partition
-                        remove = self.right_win.objects[-1]
-                        self.right_win.remove_object(remove)
-                    self.update_part(part_field=self.ext_part_field)
-            self.update_part(part_field=part_field)
-        logging.log(LOG_LEVEL_INPUT, "part updated to:\n%s", part_info)
-        self.update_avail_space()
-        part_field.no_ut_refresh()
-        return None
-    
-    def deactivate_logicals(self):
-        '''Marks as destroyed all logicals in the original extended partition,
-        and sets them as unselectable. Additionally, completely removes
-        any logical partitions added by the user.
-        
-        '''
-        if self.orig_logicals_active:
-            original_logicals = len(self._orig_data.get_logicals())
-            self.orig_logicals_active = False
-        else:
-            original_logicals = 0
-        logging.log(LOG_LEVEL_INPUT, "orig logicals = %s", original_logicals)
-        self.disk_info.remove_logicals()
-        for obj in self.right_win.objects[:original_logicals]:
-            self.mark_destroyed(obj, True)
-        for obj in self.right_win.objects[original_logicals:]:
-            obj.clear()
-            self.right_win.remove_object(obj)
-
-        if self.right_win in self.objects:
-            self.objects.remove(self.right_win)
-        self.right_win.objects = []
-        self.right_win.active_object = None
-        scroll = len(self.right_win.all_objects) > self.right_win.area.lines
-        self.right_win.use_vert_scroll_bar = scroll
-        self.right_win.no_ut_refresh()
-    
-    def create_extended(self, ext_part_field):
-        '''If this is the original extended partition, restore the original
-        logical partitions. Otherwise, create a single unused logical
-        partition.
-        
-        '''
-        if not ext_part_field.data_obj.modified():
-            self.right_win.clear()
-            self.orig_logicals_active = True
-            logicals = deepcopy(self._orig_data.get_logicals())
-            self.disk_info.partitions.extend(logicals)
-            for idx, logical in enumerate(logicals):
-                self.list_area.y_loc = idx
-                self.create_list_item(logical, self.right_win, self.list_area)
-            if self.right_win not in self.objects:
-                self.objects.append(self.right_win)
-            self.right_win.activate_object_force(0, force_to_top=True)
-            self.right_win.make_inactive()
-            self.right_win.no_ut_refresh()
-        else:
-            # Leave old data be, create new Unused logical partition
-            if self.right_win not in self.objects:
-                self.objects.append(self.right_win)
-            self.append_unused_logical()
-    
-    def append_unused_logical(self):
-        '''Adds a single Unused logical partition to the right window'''
-        new_part = self.disk_info.append_unused_logical()
-        self.list_area.y_loc = len(self.right_win.all_objects)
-        bottom = self.list_area.y_loc - self.right_win.area.lines + 1
-        self.right_win.bottom = max(0, bottom)
-        self.create_list_item(new_part, self.right_win, self.list_area)
-        scroll = len(self.right_win.all_objects) > self.right_win.area.lines
-        self.right_win.use_vert_scroll_bar = scroll
-        self.right_win.no_ut_refresh()
-
-
-def on_leave_part_field(field=None):
-    '''When leaving a field, if the field has been modified, mark it as
-    non-restorable, meaning the original partition data has been
-    modified to the extent that we can no longer safely ensure the preservation
-    of any data on it. (DiskWindow.reset will still function)
-    
-    '''
-    part_info = field.data_obj
-    if part_info.is_dirty:
-        part_info.restorable = False
-
-
-def decimal_valid(edit_field, disk_win=None):
-    '''Check text to see if it is a decimal number of precision no
-    greater than the tenths place.
-    
-    '''
-    text = edit_field.get_text().lstrip()
-    if text.endswith(" "):
-        raise UIMessage(_('Only the digits 0-9 and "." are valid.'))
-    vals = text.split(".")
-    if len(vals) > 2:
-        raise UIMessage(_('A number can only have one "."'))
-    try:
-        if len(vals[0]) > 0:
-            int(vals[0])
-        if len(vals) > 1 and len(vals[1]) > 0:
-            int(vals[1])
-    except ValueError:
-        raise UIMessage(_('Only the digits 0-9 and "." are valid.'))
-    if len(vals) > 1 and len(vals[1]) > 1:
-        raise UIMessage(_("Size can be specified to only one decimal place."))
-    if disk_win is not None:
-        text = text.rstrip(".")
-        if not text:
-            text = "0"
-        new_size = DiskSpace(text + "gb")
-        max_size = edit_field.data_obj.get_max_size(disk_win.disk_info)
-        
-        # When comparing sizes, check only to the first decimal place,
-        # as that is all the user sees. (Rounding errors that could
-        # cause the partition/slice layout to be invalid get cleaned up
-        # prior to target instantiation)
-        new_size_rounded = round(new_size.size_as("gb"), 1)
-        max_size_rounded = round(max_size, 1)
-        if new_size_rounded > max_size_rounded:
-            raise UIMessage(_("The new size (%(size).1f) is greater than "
-                              "the available space (%(avail).1f)") %
-                              {"size" : new_size_rounded,
-                               "avail" : max_size_rounded})
-        size_diff = abs(new_size.size_as("gb") - edit_field.data_obj.orig_size)
-        if size_diff > DiskWindow.SIZE_PRECISION:
-            edit_field.data_obj.size = new_size
-            edit_field.data_obj.adjust_offset(disk_win.disk_info)
-        else:
-            edit_field.data_obj.size = "%fgb" % edit_field.data_obj.orig_size
-        disk_win.update_avail_space()
-        disk_win.no_ut_refresh()
-        part_field = disk_win.find_part_field(edit_field.data_obj)[1]
-        disk_win.mark_if_destroyed(part_field)
-    return True
-
-
-def on_exit_edit(edit_field):
-    '''On exit, if the user has left the field blank, set the size to 0'''
-    text = edit_field.get_text()
-    if not text.strip():
-        text = "0"
-    edit_field.set_text("%.1f" % float(text))
-
-
-def get_recommended_size():
-    '''Returns the recommended size for the installation, in GB'''
-    if DiskWindow.REC_SIZE is None:
-        try:
-            swap_dump = SwapDump()
-            rec_size = str(get_rec_install_size(swap_dump)) + "mb"
-            DiskWindow.REC_SIZE = DiskSpace(rec_size)
-            rec_size = DiskWindow.REC_SIZE.size_as("gb")
-            rec_size = round_to_multiple(rec_size, 0.1)
-            DiskWindow.REC_SIZE.size = "%sgb" % rec_size
-        except (InstallationError):
-            logging.warn("Unable to determine recommended install size")
-            DiskWindow.REC_SIZE = DiskSpace("10gb")
-    return DiskWindow.REC_SIZE
-
-
-def get_minimum_size():
-    '''Returns the minimum disk space needed for installation, in GB. The
-    value returned from get_min_install_size is rounded up to the nearest
-    tenth of a gigabyte, so that the UI ensures enough space is allocated,
-    given that the UI only allows for precision to tenths of a gigabyte.
-    
-    '''
-    if DiskWindow.MIN_SIZE is None:
-        try:
-            swap_dump = SwapDump()
-            min_size = str(get_min_install_size(swap_dump)) + "mb"
-            DiskWindow.MIN_SIZE = DiskSpace(min_size)
-            min_size = DiskWindow.MIN_SIZE.size_as("gb")
-            min_size = round_to_multiple(min_size, 0.1)
-            DiskWindow.MIN_SIZE.size = "%sgb" % min_size
-        except (InstallationError):
-            logging.warn("Unable to determine minimum install size")
-            DiskWindow.MIN_SIZE = DiskSpace("6gb")
-    return DiskWindow.MIN_SIZE
--- a/usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Screen for selecting to use whole disk, or a partition/slice on the disk
-'''
-
-import logging
-import platform
-
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from osol_install.text_install.disk_window import DiskWindow
-from solaris_install.engine import InstallEngine
-from terminalui.base_screen import BaseScreen, SkipException
-from terminalui.i18n import textwidth
-from terminalui.list_item import ListItem
-from terminalui.window_area import WindowArea
-
-
-class FDiskPart(BaseScreen):
-    '''Allow user to choose to use the whole disk, or move to the
-    partition/slice edit screen.
-    
-    '''
-    
-    BOOT_TEXT = _("Boot")
-    HEADER_FDISK = _("Fdisk Partitions: %(size).1fGB %(type)s %(bootable)s")
-    HEADER_PART_SLICE = _("Solaris Partition Slices")
-    HEADER_SLICE = _("Solaris Slices: %(size).1fGB %(type)s %(bootable)s")
-    PARAGRAPH_FDISK = _("%(release)s can be installed on the whole "
-                        "disk or a partition on the disk.") % RELEASE
-    PARAGRAPH_PART_SLICE = _("%(release)s can be installed in the "
-                             "whole fdisk partition or within a "
-                             "slice in the partition") % RELEASE
-    PARAGRAPH_SLICE = _("%(release)s can be installed on the whole"
-                        " disk or a slice on the disk.") % RELEASE
-    FOUND_PART = _("The following partitions were found on the disk.")
-    PROPOSED_PART = _("A partition table was not found. The following is"
-                      " proposed.")
-    FOUND_SLICE = _("The following slices were found on the disk.")
-    PROPOSED_SLICE = _("A VTOC label was not found. The following is "
-                       "proposed.")
-    USE_WHOLE_DISK = _("Use the whole disk")
-    USE_WHOLE_PARTITION = _("Use the whole partition")
-    USE_SLICE_IN_PART = _("Use a slice in the partition")
-    USE_PART_IN_DISK = _("Use a partition of the disk")
-    USE_SLICE_IN_DISK = _("Use a slice on the disk")
-    
-    SPARC_HELP = (TUI_HELP + "/%s/sparc_solaris_slices.txt",
-                  _("Solaris Slices"))
-    X86_PART_HELP = (TUI_HELP + "/%s/"
-                     "x86_fdisk_partitions.txt",
-                     _("Fdisk Partitions"))
-    X86_SLICE_HELP = (TUI_HELP + "/%s/x86_fdisk_slices.txt",
-                      _("Solaris Partition Slices"))
-    
-    def __init__(self, main_win, x86_slice_mode=False):
-        '''If x86_slice_mode == True, this screen presents options for using a
-        whole partition, or a slice within the partition.
-        Otherwise, it presents options for using the whole disk, or using a
-        partition (x86) or slice (SPARC) within the disk
-        
-        '''
-        super(FDiskPart, self).__init__(main_win)
-        self.x86_slice_mode = x86_slice_mode
-        self.is_x86 = True
-        self.help_format = "  %s"
-        if platform.processor() == "sparc": # SPARC, slices on a disk
-            self.is_x86 = False
-            self.header_text = FDiskPart.HEADER_SLICE
-            self.paragraph = FDiskPart.PARAGRAPH_SLICE
-            self.found = FDiskPart.FOUND_SLICE
-            self.proposed = FDiskPart.PROPOSED_SLICE
-            self.use_whole = FDiskPart.USE_WHOLE_DISK
-            self.use_part = FDiskPart.USE_SLICE_IN_DISK
-            self.help_data = FDiskPart.SPARC_HELP
-        elif self.x86_slice_mode: # x86, slices within a partition
-            self.instance = ".slice"
-            self.header_text = FDiskPart.HEADER_PART_SLICE
-            self.paragraph = FDiskPart.PARAGRAPH_PART_SLICE
-            self.found = FDiskPart.FOUND_SLICE
-            self.proposed = FDiskPart.PROPOSED_SLICE
-            self.use_whole = FDiskPart.USE_WHOLE_PARTITION
-            self.use_part = FDiskPart.USE_SLICE_IN_PART
-            self.help_data = FDiskPart.X86_SLICE_HELP
-            self.help_format = "    %s"
-        else: # x86, partitions on a disk
-            self.header_text = FDiskPart.HEADER_FDISK
-            self.paragraph = FDiskPart.PARAGRAPH_FDISK
-            self.found = FDiskPart.FOUND_PART
-            self.proposed = FDiskPart.PROPOSED_PART
-            self.use_whole = FDiskPart.USE_WHOLE_DISK
-            self.use_part = FDiskPart.USE_PART_IN_DISK
-            self.help_data = FDiskPart.X86_PART_HELP
-        self.disk_info = None
-        self.disk_win = None
-        self.partial_disk_item = None
-        self.whole_disk_item = None
-    
-    def _show(self):
-        '''Display partition data for selected disk, and present the two
-        choices
-        
-        '''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        if self.x86_slice_mode:
-            disk = self.install_profile.disk
-            self.disk_info = disk.get_solaris_data()
-            if self.disk_info is None:
-                err_msg = "Critical error - no Solaris partition found"
-                logging.error(err_msg)
-                raise ValueError(err_msg)
-            logging.debug("bool(self.disk_info.slices)=%s",
-                          bool(self.disk_info.slices))
-            logging.debug("self.disk_info.modified()=%s",
-                          self.disk_info.modified())
-            if not self.disk_info.slices or self.disk_info.modified():
-                logging.debug("Setting partition.use_whole_segment,"
-                              "creating default layout, and skipping")
-                self.disk_info.use_whole_segment = True
-                # We only do slice level editing on x86 if there are
-                # existing slices on an existing (unmodified)Solaris
-                # partition
-                self.disk_info.create_default_layout()
-                raise SkipException
-            disp_disk = self.install_profile.original_disk.get_solaris_data()
-            logging.debug("Preserved partition with existing slices:"
-                          " presenting option to install into a slice")
-        else:
-            self.disk_info = self.install_profile.disk
-            disp_disk = self.install_profile.original_disk
-            if self.disk_info.boot:
-                bootable = FDiskPart.BOOT_TEXT
-            else:
-                bootable = u""
-            header_text = self.header_text % \
-                            {"size" : self.disk_info.size.size_as("gb"),
-                             "type" : self.disk_info.type,
-                             "bootable" : bootable}
-            self.main_win.set_header_text(header_text)
-        
-        y_loc = 1
-        y_loc += self.center_win.add_paragraph(self.paragraph, start_y=y_loc)
-        
-        y_loc += 1
-        if self.is_x86 and not self.x86_slice_mode:
-            found_parts = bool(self.disk_info.partitions)
-        else:
-            found_parts = bool(self.disk_info.slices)
-        if found_parts:
-            next_line = self.found
-        else:
-            next_line = self.proposed
-        y_loc += self.center_win.add_paragraph(next_line, start_y=y_loc)
-        
-        y_loc += 1
-        disk_win_area = WindowArea(6, 70, y_loc, 0)
-        self.disk_win = DiskWindow(disk_win_area, disp_disk,
-                                   window=self.center_win)
-        y_loc += disk_win_area.lines
-        
-        y_loc += 3
-        whole_disk_width = textwidth(self.use_whole) + 3
-        cols = (self.win_size_x - whole_disk_width) / 2
-        whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols)
-        self.whole_disk_item = ListItem(whole_disk_item_area,
-                                        window=self.center_win,
-                                        text=self.use_whole,
-                                        centered=True)
-        
-        y_loc += 1
-        partial_width = textwidth(self.use_part) + 3
-        cols = (self.win_size_x - partial_width) / 2
-        partial_item_area = WindowArea(1, partial_width, y_loc, cols)
-        self.partial_disk_item = ListItem(partial_item_area,
-                                          window=self.center_win,
-                                          text=self.use_part,
-                                          centered=True)
-        
-        self.main_win.do_update()
-        if self.disk_info.use_whole_segment:
-            self.center_win.activate_object(self.whole_disk_item)
-        else:
-            self.center_win.activate_object(self.partial_disk_item)
-    
-    def on_continue(self):
-        '''Set the user's selection in the install_profile. If they chose
-        to use the entire disk (or entire partition), define a single
-        partition (or slice) to consume the whole disk (or partition)
-        
-        '''
-        if self.center_win.get_active_object() is self.whole_disk_item:
-            logging.debug("Setting use_whole_segment and creating default"
-                          " layout for %s", type(self.disk_info))
-            self.disk_info.use_whole_segment = True
-            self.disk_info.create_default_layout()
-        else:
-            logging.debug("Setting use_whole segment false for %s",
-                          type(self.disk_info))
-            # If user had previously selected to use the whole disk
-            # or partition, set the do_revert flag so that the following
-            # screen will know to reset the disk (reverting the call
-            # to create_default_layout, above)
-            self.disk_info.do_revert = self.disk_info.use_whole_segment
-            self.disk_info.use_whole_segment = False
--- a/usr/src/cmd/text-install/osol_install/text_install/install_progress.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Start a Thread for executing installation, and
-track the progress of the installation
-'''
-
-import curses
-import logging
-import math
-import threading
-import time
-
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from osol_install.text_install.ti_install import perform_ti_install
-from solaris_install.engine import InstallEngine
-import solaris_install.sysconfig as sysconfig
-from terminalui.base_screen import BaseScreen
-from terminalui.i18n import ljust_columns
-from terminalui.inner_window import InnerWindow
-from terminalui.window_area import WindowArea
-from terminalui import LOG_LEVEL_INPUT
-
-
-class InstallProgress(BaseScreen):
-    '''Present a progress bar, and callback hooks for an installation
-    Thread to update this screen with percent complete and status.
-    
-    '''
-    
-    HEADER_TEXT = _("Installing %(release)s") % RELEASE
-    PROG_BAR_ENDS = (ord('['), ord(']'))
-    
-    QUIT_DISK_MODIFIED = _("Do you want to quit the Installer?\n\n"
-                           "Any changes made to the disk by the "
-                           "Installer will be left \"as is.\"")
-    
-    def __init__(self, main_win):
-        super(InstallProgress, self).__init__(main_win)
-        self.really_quit = False
-        
-        # Location on screen where the status messages should get printed
-        # Format: (y, x, max-width)
-        self.status_msg_loc = (4, 12, 50)
-        
-        # Location on screen where the progress bar should be displayed
-        # Format: (y, x, width)
-        self.status_bar_loc = (6, 10, 50)
-        
-        self.last_update = 0
-        # Minimum elapsed time in seconds between screen updates
-        self.update_frequency = 2
-        self.status_bar = None
-        self.status_bar_width = None
-        self.install_profile = None
-        self.install_thread = None
-        self.progress_color = None
-        self.quit_event = threading.Event()
-        self.update_event = threading.Event()
-        self.time_change_event = threading.Event()
-        self.update_to = None
-    
-    def set_actions(self):
-        '''Remove all actions except F9_Quit.'''
-        self.main_win.actions.pop(curses.KEY_F2) # Remove F2_Continue
-        self.main_win.actions.pop(curses.KEY_F3) # Remove F3_Back
-        self.main_win.actions.pop(curses.KEY_F6) # Remove F6_Help
-    
-    def _show(self):
-        '''Set an initial status message, and initialize the progress bar'''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        self.set_status_message(InstallProgress.HEADER_TEXT)
-        self.init_status_bar(*self.status_bar_loc)
-    
-    def validate_loop(self):
-        '''Begin the installation. Honor the '-n' flag from the CLI by
-        beginning a 'fake' installation thread instead of actually making
-        changes to the disk.
-        
-        After starting the installation thread, wait for input from the
-        user, in case they change their mind and try to quit.
-        
-        '''
-        if self.install_profile.no_install_mode:
-            self.install_thread = self.start_fake_install_thread()
-        else:
-            self.install_thread = self.start_install_thread()
-        win = self.center_win.window
-        win.timeout(100) # Set timeout for getch to 100 ms. The install_thread
-                         # will be checked at this frequency to see if it
-                         # has finished execution.
-                         # Keystroke input will still be processed immediately
-        while self.install_thread.is_alive():
-            # Wait for the install thread to signal that it has finished
-            # updating the system time, so that we can safely use getch(),
-            # which times out based on the system clock.
-            self.time_change_event.wait()
-            input_key = self.main_win.getch()
-            if input_key == curses.KEY_F9:
-                self.really_quit = self.confirm_quit()
-                if self.really_quit: 
-                    win.timeout(-1)
-                    self.install_thread.join()
-                    return None
-        win.timeout(-1) # Restore getch() to be blocking
-        return self.main_win.screen_list.get_next(self)
-    
-    def start_install_thread(self):
-        '''Instantiate a Thread to do the installation, and start execution.'''
-        handle = threading.Thread(target=InstallProgress.perform_install,
-                                  args=(self.install_profile, self,
-                                        InstallProgress.update_status,
-                                        self.quit_event,
-                                        self.time_change_event))
-        handle.start()
-        return handle
-    
-    def start_fake_install_thread(self):
-        '''Instantiate a Thread to perform a 'fake' installation'''
-        handle = threading.Thread(target=InstallProgress.fake_install,
-                                  args=(self.install_profile, self,
-                                        InstallProgress.update_status,
-                                        self.quit_event))
-        self.time_change_event.set()
-        handle.start()
-        return handle
-    
-    @staticmethod
-    def perform_install(install_profile, screen, update_status, quit_event,
-                        time_change_event):
-        '''Call function to perform the actual install.
-
-        '''
-        install_profile.install_succeeded = False
-        try:
-            perform_ti_install(install_profile, screen, update_status,
-                               quit_event, time_change_event)
-        except BaseException, ex:
-            logging.exception(ex)
-    
-    @staticmethod
-    def fake_install(install_profile, screen, update_status, quit_event):
-        '''For demonstration purposes only, this function is the target
-        of the install thread when the '-n' flag is given at the command
-        line. All this thread does is attempt to update the status/progress
-        bar at set intervals.
-        
-        It also checks quit_event (a threading.Event), and, if set, immediately
-        returns.
-        
-        '''
-        # When the Text Installer is fully updated to use the new engine,
-        # this function should be removed (in favor of simply using the
-        # dry_run flag)
-        
-        install_profile.disk.to_tgt()
-        eng = InstallEngine.get_instance()
-        eng.execute_checkpoints(start_from =
-                                sysconfig.GENERATE_SC_PROFILE_CHKPOINT,
-                                dry_run=True)
-        for i in range(101):
-            update_status(screen, i, "at %d percent" % i)
-            logging.log(LOG_LEVEL_INPUT, "at %s percent", i)
-            quit_event.wait(0.2)
-            if quit_event.is_set():
-                logging.error("User forced quit! Aborting")
-                install_profile.install_succeeded = False
-                return
-        install_profile.install_succeeded = True
-    
-    def update_status(self, percent, message):
-        '''Update this screen to display message and set the status
-        bar to 'percent'. This is the intended callback function
-        for the installation thread.
-        
-        This function ensures the screen is not updated more often
-        then once every 2 seconds (the update_frequency)
-        
-        The threading.Event, self.update_event, is used to ensure that this
-        method does not clobber the confirm_quit pop-up
-        
-        '''
-        if self.update_event.is_set():
-            return
-        update_time = time.time()
-        if (update_time - self.last_update) > self.update_frequency:
-            self._update_status(percent, message)
-            self.last_update = update_time
-    
-    def _update_status(self, percent, message):
-        '''Immediately update status, without checking the self.update_event
-        or last update_time
-        
-        '''
-        self.set_status_message(message)
-        self.set_status_percent(percent)
-        self.main_win.redrawwin()
-        self.main_win.do_update()
-    
-    def set_status_message(self, message):
-        '''Set the status message on the screen, completely overwriting
-        the previous message'''
-        self.center_win.add_text(ljust_columns(message, self.status_msg_loc[2]),
-                                 self.status_msg_loc[0],
-                                 self.status_msg_loc[1],
-                                 max_chars=self.status_msg_loc[2])
-    
-    def set_status_percent(self, percent):
-        '''Set the completion percentage by updating the progress bar.
-        Note that this is implemented as a 'one-way' change (updating to
-        a percent that is lower than previously set will not work)
-        
-        '''
-        width = self.status_bar_width
-        complete = int(math.ceil(float(percent) / 100.0 * width))
-        self.status_bar.add_text(" " * complete, start_y=0, start_x=1,
-                                 max_chars=width)
-        percent_text = "(%i%%)" % percent
-        percent_bar = percent_text.center(width)
-        left_half = percent_bar[:complete]
-        right_half = percent_bar[complete:]
-        self.status_bar.window.addstr(0, 1, left_half, self.progress_color)
-        self.status_bar.window.addstr(0, complete + 1, right_half)
-        self.status_bar.no_ut_refresh()
-    
-    def init_status_bar(self, y_loc, x_loc, width):
-        '''Initialize the progress bar window and set to 0%'''
-        self.status_bar_width = width
-        status_bar_area = WindowArea(1, width + 3, y_loc, x_loc + 1)
-        self.status_bar = InnerWindow(status_bar_area,
-                                      window=self.center_win)
-        self.status_bar.window.addch(0, 0, InstallProgress.PROG_BAR_ENDS[0])
-        self.status_bar.window.addch(0, width + 1,
-                                     InstallProgress.PROG_BAR_ENDS[1])
-        self.progress_color = self.center_win.color_theme.progress_bar
-        self.last_update = 0
-        self.set_status_percent(0)
-    
-    def confirm_quit(self):
-        '''Confirm the user truly wants to quit, and if so, set quit_event
-        so that the install thread can attempt to shut down as gracefully
-        as possible.
-        
-        Clear update_event so that update_status does not attempt to write
-        the progress bar while the user is contemplating the need/desire to
-        quit.
-        
-        '''
-        self.update_event.set()
-        do_quit = self.main_win.pop_up(BaseScreen.CONFIRM_QUIT_HEADER,
-                                       InstallProgress.QUIT_DISK_MODIFIED,
-                                       BaseScreen.CANCEL_BUTTON,
-                                       BaseScreen.CONFIRM_BUTTON)
-        update_to = self.update_to
-        if update_to is not None:
-            self._update_status(update_to[0], update_to[1])
-        self.update_event.clear()
-        
-        if do_quit:
-            self.quit_event.set()
-        return do_quit
--- a/usr/src/cmd/text-install/osol_install/text_install/install_status.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Report the status of an installation to the user
-'''
-
-import curses
-
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from solaris_install.engine import InstallEngine
-from terminalui.action import Action
-from terminalui.base_screen import BaseScreen
-
-
-class RebootException(SystemExit):
-    '''Raised when user requests reboot'''
-    pass
-
-
-class InstallStatus(BaseScreen):
-    '''
-    Display text to the user indicating success or failure of the installation.
-    Also provide option for viewing the install log
-    
-    '''
-    
-    SUCCESS_HEADER = _("Installation Complete")
-    FAILED_HEADER = _("Installation Failed")
-    
-    SUCCESS_TEXT = _("The installation of %(release)s has completed "
-                     "successfully.\n\n"
-                     "Reboot to start the newly installed software "
-                     "or Quit if you wish to perform additional "
-                     "tasks before rebooting.\n\n"
-                     "The installation log is available at "
-                     "%(log_tmp)s. After reboot it can be found"
-                     " at %(log_final)s.")
-    
-    FAILED_TEXT = _("The installation did not complete normally.\n\n"
-                    "For more information you can review the"
-                    " installation log.\n"
-                    "The installation log is available at %(log_tmp)s")
-    
-    def __init__(self, main_win):
-        super(InstallStatus, self).__init__(main_win)
-        self.log_locations = {}
-    
-    def set_actions(self):
-        '''Remove all actions except Quit, and add actions for rebooting
-        and viewing the log.
-        
-        '''
-        self.main_win.actions.pop(curses.KEY_F2) # Remove F2_Continue
-        self.main_win.actions.pop(curses.KEY_F3) # Remove F3_Back
-        self.main_win.actions.pop(curses.KEY_F6) # Remove F6_Help
-        
-        doc = InstallEngine.get_instance().doc
-        install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                              not_found_is_err=True)[0]
-        if install_profile.install_succeeded:
-            reboot_action = Action(curses.KEY_F8, _("Reboot"), reboot_system)
-            self.main_win.actions[reboot_action.key] = reboot_action
-        
-        log_action = Action(curses.KEY_F4, _("View Log"),
-                            self.main_win.screen_list.get_next)
-        self.main_win.actions[log_action.key] = log_action
-        
-    
-    def _show(self):
-        '''Display the correct text based on whether the installation
-        succeeded or failed.
-        
-        '''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        self.log_locations["log_tmp"] = self.install_profile.log_location
-        self.log_locations["log_final"] = self.install_profile.log_final
-        if self.install_profile.install_succeeded:
-            self.header_text = InstallStatus.SUCCESS_HEADER
-            paragraph_text = InstallStatus.SUCCESS_TEXT
-        else:
-            self.header_text = InstallStatus.FAILED_HEADER
-            paragraph_text = InstallStatus.FAILED_TEXT
-        self.main_win.set_header_text(self.header_text)
-        
-        fmt = {}
-        fmt.update(self.log_locations)
-        fmt.update(RELEASE)
-        self.center_win.add_paragraph(paragraph_text % fmt, 2)
-    
-    def confirm_quit(self):
-        '''No need to confirm after installation is complete'''
-        return True
-
-
-def reboot_system(screen=None):
-    '''Attempts to reboot the system (unless running with the '-n' command
-    line flag)
-    
-    '''
-    if screen and screen.install_profile.no_install_mode:
-        raise SystemExit("REBOOT")
-    else:
-        raise RebootException
--- a/usr/src/cmd/text-install/osol_install/text_install/log_viewer.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Read in and display the install log to the user
-'''
-
-import curses
-
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _
-from solaris_install.engine import InstallEngine
-from terminalui.base_screen import BaseScreen
-from terminalui.i18n import convert_paragraph
-from terminalui.scroll_window import ScrollWindow
-from terminalui.window_area import WindowArea
-
-class LogViewer(BaseScreen):
-    '''Screen for reading and displaying the install log'''
-    
-    HEADER_TEXT = _("Installation Log")
-    
-    def __init__(self, main_win):
-        super(LogViewer, self).__init__(main_win)
-        self.log_data = None
-        self.scroll_area = None
-        self.install_profile = None
-    
-    def set_actions(self):
-        '''Remove all actions except F3_Back'''
-        self.main_win.actions.pop(curses.KEY_F2)
-        self.main_win.actions.pop(curses.KEY_F6)
-        self.main_win.actions.pop(curses.KEY_F9)
-    
-    def _show(self):
-        '''Create a scrollable region and fill it with the install log'''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        self.center_win.border_size = (0, 0)
-        self.scroll_area = WindowArea(self.win_size_y,
-                                      self.win_size_x,
-                                      0, 0, len(self.get_log_data()))
-        log = ScrollWindow(self.scroll_area, window=self.center_win)
-        log.add_paragraph(self.get_log_data(), 0, 2)
-        self.center_win.activate_object(log)
-    
-    def get_log_data(self):
-        '''Attempt to read in the install log file. If an error occurs,
-        the log_data is set to a string explaining the cause, if possible.
-        
-        '''
-        if self.log_data is None:
-            log_file = None
-            try:
-                try:
-                    log_file = open(self.install_profile.log_location)
-                    log_data = log_file.read()
-                except (OSError, IOError), error:
-                    self.log_data = _("Could not read log file:\n\t%s") % \
-                                    error.strerror
-            finally:
-                if log_file is not None:
-                    log_file.close()
-            max_chars = self.win_size_x - 4
-            self.log_data = convert_paragraph(log_data, max_chars)
-        return self.log_data
--- a/usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-UI Components for displaying a screen allowing the user to edit
-partition and slice information
-'''
-
-import curses
-import logging
-import platform
-
-from osol_install.profile.disk_info import PartitionInfo, SliceInfo
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from osol_install.text_install.disk_window import DiskWindow, get_minimum_size
-from solaris_install.engine import InstallEngine
-from terminalui import LOG_LEVEL_INPUT
-from terminalui.action import Action
-from terminalui.base_screen import BaseScreen, SkipException, UIMessage
-from terminalui.window_area import WindowArea
-
-
-class PartEditScreen(BaseScreen):
-    '''Allows user editing of partitions on a disk, or slices on a
-    disk/partition
-    
-    '''
-    
-    PARTITION_PARAGRAPH = _("Oracle Solaris will be installed into the Solaris"
-                            " partition. A partition's type can be changed"
-                            " using the F5 key.\n\n"
-                            "A partition's size can be increased "
-                            "up to its Avail space. Avail space can be "
-                            "increased by deleting an adjacent partition. "
-                            "Delete a partition by changing it to \"Unused\""
-                            " using the F5 key.\n\n"
-                            "The four primary partition slots are listed on "
-                            "the left. If one is an \"Extended\" partition "
-                            "its logical partitions are listed on the "
-                            "right.") % RELEASE
-    SLICE_PARAGRAPH = _("%(release)s will be installed in the \"%(pool)s\" "
-                        "slice. Use the F5 key to change a slice to "
-                        "\"%(pool)s.\"\n\n"
-                        "A slice's size can be increased up to its Avail "
-                        "size. Avail can be increased by deleting an adjacent"
-                        " slice. Use the F5 key to delete a slice by changing"
-                        " it to \"Unused.\"\n\n"
-                        "Slices are listed in disk layout order.")
-    
-    HEADER_x86_PART = _("Select Partition: %(size).1fGB %(type)s "
-                        "%(bootable)s")
-    HEADER_x86_SLICE = _("Select Slice in Fdisk Partition")
-    HEADER_SPARC_SLICE = _("Select Slice: %(size).1fGB %(type)s"
-                           "%(bootable)s")
-    SLICE_DESTROY_TEXT = _("indicates the slice's current content will be "
-                           "destroyed")
-    PART_DESTROY_TEXT = _("indicates the partition's current content will "
-                          "be destroyed")
-    BOOTABLE = _("Boot")
-    
-    SPARC_HELP = (TUI_HELP + "/%s/"
-                  "sparc_solaris_slices_select.txt",
-                  _("Select Slice"))
-    X86_PART_HELP = (TUI_HELP + "/%s/"
-                     "x86_fdisk_partitions_select.txt",
-                     _("Select Partition"))
-    X86_SLICE_HELP = (TUI_HELP + "/%s/"
-                      "x86_fdisk_slices_select.txt",
-                      _("Select Slice"))
-    
-    HELP_FORMAT = "    %s"
-    
-    def __init__(self, main_win, x86_slice_mode=False):
-        super(PartEditScreen, self).__init__(main_win)
-        self.x86_slice_mode = x86_slice_mode
-        self.is_x86 = (platform.processor() == "i386")
-        self.header_text = platform.processor()
-        
-        if self.x86_slice_mode: # x86, Slice within a partition
-            self.instance = ".slice"
-            self.header_text = PartEditScreen.HEADER_x86_SLICE
-            self.paragraph_text = PartEditScreen.SLICE_PARAGRAPH
-            self.destroy_text = PartEditScreen.SLICE_DESTROY_TEXT
-            self.help_data = PartEditScreen.X86_SLICE_HELP
-        elif self.is_x86: # x86, Partition on disk
-            self.header_text = PartEditScreen.HEADER_x86_PART
-            self.paragraph_text = PartEditScreen.PARTITION_PARAGRAPH
-            self.destroy_text = PartEditScreen.PART_DESTROY_TEXT
-            self.help_data = PartEditScreen.X86_PART_HELP
-        else: # SPARC (Slice on disk)
-            self.header_text = PartEditScreen.HEADER_SPARC_SLICE
-            self.paragraph_text = PartEditScreen.SLICE_PARAGRAPH
-            self.destroy_text = PartEditScreen.SLICE_DESTROY_TEXT
-            self.help_data = PartEditScreen.SPARC_HELP
-            self.help_format = "  %s"
-        
-        self.orig_data = None
-        self.disk_win = None
-    
-    def set_actions(self):
-        '''Edit Screens add 'Reset' and 'Change Type' actions. Since these
-        do not manipulate screen direction, they are captured during
-        processing by adding them to center_win's key_dict.
-        
-        '''
-        super(PartEditScreen, self).set_actions()
-        reset_action = Action(curses.KEY_F7, _("Reset"))
-        change_action = Action(curses.KEY_F5, _("Change Type"))
-        self.main_win.actions[reset_action.key] = reset_action
-        self.main_win.actions[change_action.key] = change_action
-        self.center_win.key_dict[curses.KEY_F7] = self.on_key_F7
-    
-    # pylint: disable-msg=C0103
-    # F7 is the keyname and appropriate here
-    def on_key_F7(self, dummy):
-        '''F7 -> Reset the DiskWindow'''
-        self.disk_win.reset()
-        return None
-    
-    def _show(self):
-        '''Display the explanatory paragraph and create the DiskWindow'''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        part = self.install_profile.disk
-        if part.use_whole_segment:
-            logging.debug("disk.use_whole_segment true, skipping editing")
-            raise SkipException
-        if self.x86_slice_mode:
-            part = part.get_solaris_data()
-            if part is None:
-                err_msg = "Critical error - no Solaris partition found"
-                logging.error(err_msg)
-                raise ValueError(err_msg)
-            if part.use_whole_segment:
-                logging.debug("partition.use_whole_segment True:"
-                              " skipping slice editing")
-                raise SkipException
-            _orig_disk = self.install_profile.original_disk
-            self.orig_data = _orig_disk.get_solaris_data()
-            if self.orig_data is None:
-                def_type = PartitionInfo.SOLARIS
-                def_size = self.install_profile.disk.size
-                self.orig_data = PartitionInfo(part_num=1,
-                                               partition_id=def_type,
-                                               size=def_size)
-        else:
-            self.orig_data = self.install_profile.original_disk
-        
-        if self.x86_slice_mode:
-            header = self.header_text
-        else:
-            bootable = ""
-            if self.is_x86 and part.boot:
-                bootable = PartEditScreen.BOOTABLE
-            header = self.header_text % {"size" : part.size.size_as("gb"),
-                                         "type" : part.type,
-                                         "bootable" : bootable}
-        self.main_win.set_header_text(header)
-        
-        y_loc = 1
-        fmt_dict = {'pool' : SliceInfo.DEFAULT_POOL}
-        fmt_dict.update(RELEASE)
-        y_loc += self.center_win.add_paragraph(self.paragraph_text % fmt_dict,
-                                               y_loc)
-        
-        y_loc += 1
-        disk_win_area = WindowArea(6, 70, y_loc, 0)
-        self.disk_win = DiskWindow(disk_win_area, part,
-                                   window=self.center_win,
-                                   editable=True,
-                                   error_win=self.main_win.error_line,
-                                   reset=self.orig_data)
-        y_loc += disk_win_area.lines
-        
-        y_loc += 1
-        logging.log(LOG_LEVEL_INPUT, "calling addch with params start_y=%s,"
-                    "start_x=%s, ch=%c", y_loc, self.center_win.border_size[1],
-                    DiskWindow.DESTROYED_MARK)
-        self.center_win.window.addch(y_loc, self.center_win.border_size[1],
-                                     DiskWindow.DESTROYED_MARK,
-                                     self.center_win.color_theme.inactive)
-        self.center_win.add_text(self.destroy_text, y_loc, 2)
-        
-        self.main_win.do_update()
-        self.center_win.activate_object(self.disk_win)
-    
-    def on_prev(self):
-        '''Clear orig_data so re-visits reset correctly'''
-        self.orig_data = None
-    
-    def on_continue(self):
-        '''Get the modified partition/slice data from the DiskWindow, and
-        update install_profile.disk with it
-        
-        '''
-        disk_info = self.disk_win.disk_info
-        if self.x86_slice_mode:
-            solaris_part = self.install_profile.disk.get_solaris_data()
-            solaris_part.slices = disk_info.slices
-        elif self.is_x86:
-            self.install_profile.disk.partitions = disk_info.partitions
-            solaris_part = self.install_profile.disk.get_solaris_data()
-            # If the Solaris partition has changed in any way, the entire
-            # partition is used as the install target.
-            if solaris_part.modified():
-                logging.debug("Solaris partition modified, "
-                              "creating default layout")
-                solaris_part.create_default_layout()
-            else:
-                logging.debug("Solaris partition unchanged, using original"
-                              " slice data")
-                solaris_part.slices = solaris_part.orig_slices
-        else:
-            self.install_profile.disk.slices = disk_info.slices
-    
-    def validate(self):
-        '''Ensure the Solaris partition or ZFS Root exists and is large
-        enough
-        
-        '''
-        disk_info = self.disk_win.disk_info
-        if self.is_x86 and not self.x86_slice_mode:
-            min_size_text = _("The Solaris2 partition must be at least"
-                              " %(size).1fGB")
-            missing_part = _("There must be exactly one Solaris2 partition.")
-        else:
-            min_size_text = _("The size of %(pool)s must be at least"
-                              " %(size).1fGB")
-            missing_part = _("There must be one ZFS root pool, '%(pool)s.'")
-        min_size = round(get_minimum_size().size_as("gb"), 1)
-        format_dict = {'pool' : SliceInfo.DEFAULT_POOL,
-                       'size': min_size}
-        
-        try:
-            part = disk_info.get_solaris_data(check_multiples=True)
-        except ValueError:
-            part = None
-        
-        if part is None:
-            raise UIMessage(missing_part % format_dict)
-        
-        # When comparing sizes, check only to the first decimal place,
-        # as that is all the user sees. (Rounding errors that could
-        # cause the partition/slice layout to be invalid get cleaned up
-        # prior to target instantiation)
-        part_size = round(part.size.size_as("gb"), 1)
-        if part_size < min_size:
-            raise UIMessage(min_size_text % format_dict)
--- a/usr/src/cmd/text-install/osol_install/text_install/summary.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Display a summary of the user's selections
-'''
-
-import curses
-import logging
-
-from osol_install.profile.disk_info import SliceInfo
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from solaris_install.engine import InstallEngine
-import solaris_install.sysconfig.profile
-from solaris_install.sysconfig.profile.network_info import NetworkInfo
-from solaris_install.sysconfig.profile.user_info import UserInfo
-from terminalui.action import Action
-from terminalui.base_screen import BaseScreen
-from terminalui.i18n import convert_paragraph
-from terminalui.window_area import WindowArea
-from terminalui.scroll_window import ScrollWindow
-
-
-class SummaryScreen(BaseScreen):
-    '''Display a summary of the install profile to the user
-    InnerWindow.__init__ is sufficient to initalize an instance
-    of SummaryScreen
-    
-    '''
-    
-    HEADER_TEXT = _("Installation Summary")
-    PARAGRAPH = _("Review the settings below before installing."
-                                " Go back (F3) to make changes.")
-    
-    HELP_DATA = (TUI_HELP + "/%s/summary.txt",
-                 _("Installation Summary"))
-    
-    INDENT = 2
-    
-    def set_actions(self):
-        '''Replace the default F2_Continue with F2_Install'''
-        install_action = Action(curses.KEY_F2, _("Install"),
-                                self.main_win.screen_list.get_next)
-        self.main_win.actions[install_action.key] = install_action
-    
-    def _show(self):
-        '''Prepare a text summary from the install_profile and display it
-        to the user in a ScrollWindow
-        
-        '''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        self.sysconfig = solaris_install.sysconfig.profile.from_engine()
-        
-        y_loc = 1
-        y_loc += self.center_win.add_paragraph(SummaryScreen.PARAGRAPH, y_loc)
-        
-        y_loc += 1
-        summary_text = self.build_summary()
-        # Wrap the summary text, accounting for the INDENT (used below in
-        # the call to add_paragraph)
-        max_chars = self.win_size_x - SummaryScreen.INDENT - 1
-        summary_text = convert_paragraph(summary_text, max_chars)
-        area = WindowArea(x_loc=0, y_loc=y_loc,
-                          scrollable_lines=(len(summary_text)+1))
-        area.lines = self.win_size_y - y_loc
-        area.columns = self.win_size_x
-        scroll_region = ScrollWindow(area, window=self.center_win)
-        scroll_region.add_paragraph(summary_text, start_x=SummaryScreen.INDENT)
-        
-        self.center_win.activate_object(scroll_region)
-    
-    def build_summary(self):
-        '''Build a textual summary from the install_profile'''
-        lines = []
-        
-        lines.append(_("Software: %s") % self.get_release())
-        lines.append("")
-        lines.append(self.get_disk_summary())
-        lines.append("")
-        lines.append(self.get_tz_summary())
-        lines.append("")
-        lines.append(_("Language: *The following can be changed when "
-                       "logging in."))
-        if self.sysconfig.system.locale is None:
-            self.sysconfig.system.determine_locale()
-        lines.append(_("  Default language: %s") %
-                     self.sysconfig.system.actual_lang)
-        lines.append("")
-        lines.append(_("Keyboard layout: *The following can be "
-                       "changed when logging in."))
-        lines.append(_("  Default keyboard layout: %s") %
-                     self.sysconfig.system.keyboard)
-        lines.append("")
-        lines.append(_("Terminal type: %s") %
-                     self.sysconfig.system.terminal_type)
-        lines.append("")
-        lines.append(_("Users:"))
-        lines.extend(self.get_users())
-        lines.append("")
-        lines.append(_("Network:"))
-        lines.extend(self.get_networks())
-        
-        return "\n".join(lines)
-    
-    def get_networks(self):
-        '''Build a summary of the networks in the install_profile,
-        returned as a list of strings
-        
-        '''
-        network_summary = []
-        network_summary.append(_("  Computer name: %s") %
-                               self.sysconfig.system.hostname)
-        nic = self.sysconfig.nic
-        
-        if nic.type == NetworkInfo.AUTOMATIC:
-            network_summary.append(_("  Network Configuration: Automatic"))
-        elif nic.type == NetworkInfo.NONE:
-            network_summary.append(_("  Network Configuration: None"))
-        else:
-            network_summary.append(_("  Manual Configuration: %s")
-                                   % nic.nic_name)
-            network_summary.append(_("    IP Address: %s") % nic.ip_address)
-            network_summary.append(_("    Netmask: %s") % nic.netmask)
-            if nic.gateway:
-                network_summary.append(_("    Router: %s") % nic.gateway)
-            if  nic.dns_address:
-                network_summary.append(_("    DNS: %s") % nic.dns_address)
-            if nic.domain:
-                network_summary.append(_("    Domain: %s") % nic.domain)
-        return network_summary
-    
-    def get_users(self):
-        '''Build a summary of the user information, and return it as a list
-        of strings
-        
-        '''
-        root = self.sysconfig.users[UserInfo.ROOT_IDX]
-        primary = self.sysconfig.users[UserInfo.PRIMARY_IDX]
-        user_summary = []
-        if not root.password:
-            user_summary.append(_("  Warning: No root password set"))
-        if primary.login_name:
-            user_summary.append(_("  Username: %s") % primary.login_name)
-        else:
-            user_summary.append(_("  No user account"))
-        return user_summary
-    
-    def get_disk_summary(self):
-        '''Return a string summary of the disk selection'''
-        disk = self.install_profile.disk
-        
-        solaris_data = disk.get_solaris_data()
-        if isinstance(solaris_data, SliceInfo):
-            slice_data = solaris_data
-            part_data = None
-        else:
-            part_data = solaris_data
-            slice_data = part_data.get_solaris_data()
-        
-        format_dict = {}
-        disk_string = [_("Disk: %(disk-size).1fGB %(disk-type)s")]
-        format_dict['disk-size'] = disk.size.size_as("gb")
-        format_dict['disk-type'] = disk.type
-        
-        if part_data is not None:
-            disk_string.append(_("Partition: %(part-size).1fGB %(part-type)s"))
-            format_dict['part-size'] = part_data.size.size_as("gb")
-            format_dict['part-type'] = part_data.get_description()
-        
-        if part_data is None or not part_data.use_whole_segment:
-            disk_string.append(_("Slice %(slice-num)i: %(slice-size).1fGB"
-                                 " %(pool)s"))
-            format_dict['slice-num'] = slice_data.number
-            format_dict['slice-size'] = slice_data.size.size_as("gb")
-            format_dict['pool'] = slice_data.type[1]
-        
-        return "\n".join(disk_string) % format_dict
-    
-    def get_tz_summary(self):
-        '''Return a string summary of the timezone selection'''
-        timezone = self.sysconfig.system.tz_timezone
-        return _("Time Zone: %s") % timezone
-    
-    @staticmethod
-    def get_release():
-        '''Read in the release information from /etc/release'''
-        try:
-            try:
-                release_file = open("/etc/release")
-            except IOError:
-                logging.warn("Could not read /etc/release")
-                release_file = None
-                release = RELEASE['release']
-            else:
-                release = release_file.readline()
-        finally:
-            if release_file is not None:
-                release_file.close()
-        return release.strip()
--- a/usr/src/cmd/text-install/osol_install/text_install/test/test_disk_select.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-To run these tests:
-
-1) nightly -n developer.sh # build the gate
-2) export PYTHONPATH=${WS}/proto/root_i386/usr/snadm/lib:${WS}/proto/root_i386/usr/lib/python2.6/vendor-packages
-3) pfexec python2.6 test_disk_select.py
-
-A single test may be run by specifying the test as an argument to step 3, e.g.:
-pfexec python2.6 test_disk_select.py OnActivateTest.test_on_activate_default
-
-Since the proto area is used for the PYTHONPATH, the gate must be rebuilt for
-these tests to pick up any changes in the tested code.
-
-'''
-
-import numbers
-import unittest
-
-import osol_install.text_install.disk_selection as disk_selection
-from osol_install.profile.disk_info import DiskInfo
-import terminalui
-from terminalui.base_screen import BaseScreen
-
-
-terminalui.init_logging("test")
-BaseScreen.set_default_quit_text("test", "test", "test", "test")
-
-class MockCenterWin(object):
-    '''Mocks an InnerWindow as used by a MainWindow'''
-    
-    def add_paragraph(self, *args, **kwargs):
-        pass
-
-class MockDiskInfo(object):
-    '''Mocks a DiskInfo object'''
-    do_copy = False
-    label = []
-    was_blank = False
-    use_whole_segment = False
-    
-    def create_default_layout(self):
-        pass
-
-class MockDiskDetail(object):
-    '''Mocks a DiskWindow object'''
-    
-    def set_disk_info(self, *args):
-        pass
-
-class MockDiskScreen(object):
-    '''Mocks the DiskScreen'''
-    win_size_x = 0
-    proposed_text = ""
-    found_text = ""
-
-class MockInstallProfile(object):
-    '''Mocks an InstallProfile'''
-    
-    disk = None
-    original_disk = None
-
-class MockAll(object):
-    '''Generic Mock object that 'never' raises an AttributeError'''
-    
-    def __getattr__(self, name):
-        return self
-    
-    def __call__(self, *args, **kwargs):
-        return None
-
-class OnActivateTest(unittest.TestCase):
-    '''Test disk_selection.on_activate'''
-    
-    def setUp(self):
-        self.screen = MockDiskScreen()
-        self.disk = MockDiskInfo()
-        self.screen.center_win = MockCenterWin()
-        self.screen.disk_detail = MockDiskDetail()
-    
-    def tearDown(self):
-        self.screen = None
-        self.disk = None
-    
-    def test_on_activate_default(self):
-        '''Ensure that do_copy flag is set after calls to on_activate'''
-        disk_selection.on_activate(disk_info=self.disk,
-                                   disk_select=self.screen)
-        self.assertFalse(self.disk.use_whole_segment)
-        self.assertTrue(self.screen.do_copy)
-    
-    def test_on_activate_GPT(self):
-        '''Ensure use_whole_segment is set if the disk was GPT labeled'''
-        
-        self.disk.label = [DiskInfo.GPT]
-        
-        disk_selection.on_activate(disk_info=self.disk,
-                                   disk_select=self.screen)
-        self.assertTrue(self.disk.use_whole_segment)
-    
-    def test_on_activate_was_blank(self):
-        '''Ensure use_whole_segment is set when the disk was initially blank'''
-        self.disk.was_blank = True
-        
-        disk_selection.on_activate(disk_info=self.disk,
-                                   disk_select=self.screen)
-        self.assertTrue(self.disk.use_whole_segment)
-
-
-class DiskSelectTest(unittest.TestCase):
-    '''Test the DiskScreen'''
-    
-    def setUp(self):
-        self.screen = disk_selection.DiskScreen(MockAll())
-        self.screen.disk_win = MockAll()
-    
-    def test_on_change_screen_disk_detail_none(self):
-        '''Ensure selected_disk is set properly by on_change_screen'''
-        self.screen.disk_detail = None
-        obj = object()
-        self.screen.selected_disk = obj
-        
-        self.screen.on_change_screen()
-        self.assertTrue(self.screen.selected_disk is obj)
-    
-    def test_on_change_screen_do_copy(self):
-        '''Ensure disk is copied when do_copy flag is set'''
-        self.screen.install_profile = MockInstallProfile()
-        self.screen.install_profile.disk = True
-        
-        obj = object()
-        self.screen.disk_win.active_object = obj
-        self.screen.selected_disk = None
-        
-        disk = MockDiskInfo()
-        self.screen.disk_detail = MockAll()
-        self.screen.disk_detail.disk_info = disk
-        self.screen.do_copy = True
-        
-        self.screen.on_change_screen()
-        
-        self.assertTrue(self.screen.selected_disk is obj)
-        self.assertTrue(self.screen.install_profile.original_disk is disk)
-    
-    def test_on_change_screen_disk_is_none(self):
-        '''Check DiskScreen.on_change_screen when disk is None'''
-        self.screen.install_profile = MockInstallProfile()
-        
-        disk = MockDiskInfo()
-        self.screen.disk_detail = MockAll()
-        self.screen.disk_detail.disk_info = disk
-        
-        self.screen.on_change_screen()
-        
-        self.assertTrue(self.screen.install_profile.original_disk is disk)
-    
-    def test_size_line(self):
-        '''Ensure that DiskScreen._size_line is created and is a string after
-        calling get_size_line. Also verify that subsequent calls do not modify
-        the _size_line
-        
-        '''
-        self.assertTrue(self.screen._size_line is None)
-        self.screen.get_size_line()
-        self.assertTrue(isinstance(self.screen._size_line, basestring))
-        
-        obj = object()
-        self.screen._size_line = obj
-        self.screen.get_size_line()
-        self.assertTrue(obj is self.screen._size_line)
-    
-    def test_determine_size_data(self):
-        '''Ensure that recommended_size and minimum_size are accessible after
-        a call to determine_size_data(), and that they are numbers'''
-        
-        self.assertTrue(self.screen._recommended_size is None)
-        self.assertTrue(self.screen._minimum_size is None)
-        self.screen.determine_size_data()
-        self.assertTrue(isinstance(self.screen.minimum_size, numbers.Real))
-        self.assertTrue(isinstance(self.screen.recommended_size, numbers.Real))
-
-
-if __name__ == '__main__':
-    unittest.main()
--- a/usr/src/cmd/text-install/osol_install/text_install/test/test_disk_window.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,273 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-To run these tests:
-
-1) nightly -n developer.sh # build the gate
-2) export PYTHONPATH=${WS}/proto/root_i386/usr/snadm/lib:${WS}/proto/root_i386/usr/lib/python2.6/vendor-packages
-3) python2.6 test_disk_window.py
-
-A single test may be run by specifying the test as an argument to step 3:
-python2.6 test_disk_window.py UpdateEditField.test_part_info_not_editable
-
-Since the proto area is used for the PYTHONPATH, the gate must be rebuilt for
-these tests to pick up any changes in the tested code.
-
-'''
-
-import unittest
-
-from osol_install.profile.disk_info import DiskInfo
-from osol_install.text_install.disk_window import DiskWindow
-import terminalui
-from terminalui.color_theme import ColorTheme
-from terminalui.window_area import WindowArea
-from terminalui.inner_window import InnerWindow
-
-
-terminalui.init_logging("test")
-
-
-class MockAll(object):
-    '''Generic Mock object that 'never' raises an AttributeError'''
-    
-    def __getattr__(self, name):
-        return self
-    
-    def __call__(self, *args, **kwargs):
-        return self
-
-class MockInnerWin(object):
-    '''Class for mock inner win'''
-    def __init__(self):
-        self.active_object = None
-        self.objects = []
-        self.text = None
-        self.scrollable_lines = 10
-
-    def activate_object(self):
-        '''Set active_object to 0'''
-        self.active_object = 0
-
-    def get_active_object(self):
-        '''Get active_object'''
-        if self.active_object is not None:
-            return self.objects[self.active_object]
-        else:
-            return None
-
-    def add_text(self, text=None, y_loc=0, x_loc=0):
-        '''Append passed in text to self.text'''
-        if self.text is None:
-            self.text = str(y_loc) + text
-        else:
-            self.text = self.text + str(y_loc) + text
-
-    def get_text(self):
-        '''Get the current value of self.text'''
-        return self.text
-
-class MockDiskInfo(object):
-    '''Class for mock disk info'''
-
-    def __init__(self, logicals=0):
-        self.logicals = []
-        for i in range(logicals):
-            self.logicals.append(object())
-    def get_logicals(self):
-        '''get logical partitions'''
-	return self.logicals
-
-class MockPartInfo(object):
-    '''Class for mock part info field'''
-    def __init__(self):
-        self.is_editable = True
-
-    def set_editable(self, editable=True):
-        '''Set editable property'''
-        self.is_editable = editable
-
-    def editable(self, editable):
-        ''' get editable setting'''
-        return self.is_editable
-
-class MockEditField(object):
-    '''Class for mock edit field'''
-    def __init__(self):
-        self.active = False
-
-    def make_inactive(self, inactive=True):
-        ''' Set active property'''
-        self.active = not inactive
-
-class MockPartField(object):
-    '''Class for mock part field'''
-    def __init__(self):
-        self.edit_field = None
-        self.active_object = None
-        self.objects = []
-    def activate_object(self, tobject):
-        '''activate object'''
-        self.active_object = 0
-        self.edit_field = tobject
-        self.edit_field.make_inactive(False)
-    def get_active_object(self):
-        '''Get active_object'''
-        if self.active_object is not None:
-            return self.objects[self.active_object]
-        else:
-            return None
-
-def do_nothing(*args, **kwargs):
-    '''does nothing'''
-    pass
-
-
-class TestDiskWindow(unittest.TestCase):
-    '''Class to test DiskWindow'''
-    
-    def setUp(self):
-        '''unit test set up
-         Sets several functions to call do_nothing to allow
-         test execution in non-curses environment. Original
-         functions are saved so they can be later restored in
-         tearDown.
-
-        '''
-        self.inner_window_init_win = InnerWindow._init_win
-        self.disk_window_init_win = DiskWindow._init_win
-        self.inner_window_set_color = InnerWindow.set_color
-        InnerWindow._init_win = do_nothing
-        InnerWindow.set_color = do_nothing
-        DiskWindow._init_win = do_nothing
-        self.disk_win = DiskWindow(WindowArea(70, 70, 0, 0), DiskInfo(),
-                                   color_theme=ColorTheme(force_bw=True),
-                                   window=MockAll())
-        self.edit_field = MockEditField()
-        self.part_field = MockPartField()
-        self.part_info = MockPartInfo()
-        self.inner_win = MockInnerWin()
-        self.disk_win.objects = []
-        self.part_field.objects = []
-
-    def tearDown(self):
-        '''unit test tear down
-        Functions originally saved in setUp are restored to their
-        original values. 
-        '''
-        InnerWindow._init_win = self.inner_window_init_win
-        InnerWindow.set_color = self.inner_window_set_color
-        DiskWindow._init_win = self.disk_window_init_win
-        self.disk_win = None
-        self.edit_field = None
-        self.part_field = None
-        self.part_info = None
-        self.inner_win = None
-    
-
-class UpdateEditField(TestDiskWindow):
-    '''Tests for _update_edit_field'''
-
-    def test_part_info_not_editable(self):
-        '''Ensure edit field updated correctly if part_info not editable'''
-        self.part_info.set_editable(False)
-        self.edit_field.make_inactive(False)
-        self.part_field.activate_object(self.edit_field)
-        self.part_field.objects.append(self.edit_field)
-        
-        self.disk_win._update_edit_field(self.part_info, self.part_field,
-                                         self.edit_field)
-        self.assertFalse(self.edit_field.active)
-        self.assertEquals(len(self.part_field.objects), 0)
-        self.assertTrue(self.part_field.active_object is None)
-
-    def test_part_info_editable_no_active_win(self):
-        '''Ensure edit field not updated if no active right/left win'''
-        self.part_info.set_editable(True)
-        self.edit_field.make_inactive(True)
-        self.assertTrue(self.part_field.active_object is None)
-        self.disk_win._update_edit_field(self.part_info, self.part_field,
-                                         self.edit_field)
-        self.assertTrue(self.part_field.active_object is None)
-        self.assertFalse(self.edit_field.active)
-
-    def test_part_info_editable_active_win_no_active_obj(self):
-        '''Ensure edit field updated correctly if active obj not part_field'''
-        self.part_info.set_editable(True)
-        self.edit_field.make_inactive(True)
-        self.disk_win.objects.append(self.inner_win)
-        self.disk_win.active_object = 0
-        my_part_field = MockPartField()
-        self.inner_win.objects.append(my_part_field)
-        self.inner_win.active_object = 0
-
-        self.assertTrue(self.inner_win.get_active_object() is my_part_field)
-        self.assertTrue(self.part_field.active_object is None)
-
-        self.disk_win._update_edit_field(self.part_info, self.part_field,
-                                         self.edit_field)
-        self.assertTrue(self.part_field.active_object is None)
-        self.assertFalse(self.edit_field.active)
-
-    def test_part_info_editable_active_win(self):
-        '''Ensure edit field updated correctly if part_info is editable'''
-        self.part_info.set_editable(True)
-        self.edit_field.make_inactive(True)
-        self.disk_win.objects.append(self.inner_win)
-        self.disk_win.active_object = 0
-        self.inner_win.objects.append(self.part_field)
-        self.inner_win.active_object = 0
-
-        self.assertEquals(self.disk_win.active_object, 0)
-        self.assertTrue(self.part_field.active_object is None)
-
-        self.disk_win._update_edit_field(self.part_info, self.part_field,
-                                         self.edit_field)
-        self.assertEquals(self.part_field.active_object, 0)
-        self.assertTrue(self.edit_field.active)
-        
-
-class UpdateAllAvailSpace(TestDiskWindow):
-    '''Tests for _update_all_avail_space'''
-
-    def test_blank_new_logicals(self):
-        '''Ensure new logical sizes are blanked'''
-        self.disk_win.headers = DiskWindow.EDIT_PARTITION_HEADERS
-        self.disk_win.left_win = self.inner_win
-        self.disk_win.right_win = self.inner_win
-        self.disk_win._orig_data = MockDiskInfo(logicals=6)
-        my_area = MockInnerWin()
-        self.disk_win.right_win.area = my_area 
-
-        self.disk_win._update_all_avail_space()
-        num_logicals = len(self.disk_win._orig_data.logicals)
-        idx = my_area.scrollable_lines - num_logicals
-        text_expect = ""
-        for i in range(num_logicals, my_area.scrollable_lines):
-            text_expect = text_expect + str(i) + "       "
-        self.assertEqual(text_expect, self.disk_win.right_win.get_text())
-
-if __name__ == '__main__':
-    unittest.main()
--- a/usr/src/cmd/text-install/osol_install/text_install/test/test_text_install.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-To run these tests, see the instructions in usr/src/tools/tests/README.
-Remember that since the proto area is used for the PYTHONPATH, the gate
-must be rebuilt for these tests to pick up any changes in the tested code.
-
-'''
-
-
-import unittest
-
-import osol_install.text_install as text_install
-
-
-class TestTextInstall(unittest.TestCase):
-    
-    def test_reboot_cmds(self):
-        '''_reboot_cmds(x86) returns expected list of potential reboot commands
-        * /usr/sbin/reboot -f -- rpool/ROOT/<BE>
-        * /usr/sbin/reboot
-        
-        '''
-        cmds = text_install._reboot_cmds(True)
-        
-        # First command should be: /usr/sbin/reboot -f -- rpool/ROOT/<BE>
-        self.assertEqual(cmds[0][0], text_install.REBOOT)
-        self.assertEqual(cmds[0][1], "-f")
-        self.assertEqual(cmds[0][2], "--")
-        # Last item will be something like: rpool/ROOT/active-on-reboot-BE
-        # Just ensure that there's something there
-        self.assertTrue(cmds[0][3])
-        self.assertEqual(len(cmds[0]), 4)
-        
-        # Second command should be just: /usr/sbin/reboot
-        self.assertEqual(cmds[1][0], text_install.REBOOT)
-        self.assertEqual(len(cmds[1]), 1)
-        
-        self.assertEqual(len(cmds), 2)
-    
-    def test_reboot_cmds_sparc(self):
-        '''_reboot_cmds(sparc) returns expected list of reboot commands
-        (SPARC requires the additional "-Z")
-        * /usr/sbin/reboot -f -- -Z rpool/ROOT/<BE>
-        * /usr/sbin/reboot
-        
-        '''
-        cmds = text_install._reboot_cmds(False)
-        
-        # First command should be: /usr/sbin/reboot -f -- -Z rpool/ROOT/<BE>
-        self.assertEqual(cmds[0][0], text_install.REBOOT)
-        self.assertEqual(cmds[0][1], "-f")
-        self.assertEqual(cmds[0][2], "--")
-        self.assertEqual(cmds[0][3], "-Z")
-        # Last item will be something like: rpool/ROOT/active-on-reboot-BE
-        # Just ensure that there's something there
-        self.assertTrue(cmds[0][4])
-        self.assertEqual(len(cmds[0]), 5)
-        
-        # Second command should be just: /usr/sbin/reboot
-        self.assertEqual(cmds[1][0], text_install.REBOOT)
-        self.assertEqual(len(cmds[1]), 1)
-        
-        self.assertEqual(len(cmds), 2)
--- a/usr/src/cmd/text-install/osol_install/text_install/text-install	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#!/usr/bin/python2.6
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-import osol_install.text_install as text_install
-
-text_install.main()
--- a/usr/src/cmd/text-install/osol_install/text_install/ti_install.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,594 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Installation engine for Text Installer
-'''
-
-import os
-import logging
-import commands
-import datetime
-import platform
-import shutil
-import subprocess as sp
-
-from libbe_py import beUnmount
-from osol_install.install_utils import exec_cmd_outputs_to_log
-from osol_install.libzoneinfo import tz_isvalid
-from osol_install.profile.disk_info import PartitionInfo
-from osol_install.text_install import RELEASE
-from osol_install.text_install import ti_install_utils as ti_utils
-from osol_install import tgt
-from osol_install.transfer_mod import tm_perform_transfer, tm_abort_transfer
-from osol_install.transfer_defs import TM_ATTR_MECHANISM, \
-    TM_PERFORM_CPIO, TM_CPIO_ACTION, TM_CPIO_ENTIRE, TM_CPIO_SRC_MNTPT, \
-    TM_CPIO_DST_MNTPT, TM_UNPACK_ARCHIVE, TM_SUCCESS
-from solaris_install.engine import InstallEngine
-
-import solaris_install.sysconfig as sysconfig
-
-#
-# RTC command to run
-#
-RTC_CMD = "/usr/sbin/rtc"
-
-#
-# Program used for calling the C ICT functions.
-# When all the C-based ICT functions are converted to Python (bug 6256),
-# this can be removed.
-#
-ICT_PROG = "/opt/install-test/bin/ict_test"
-
-
-# The following is defined for using the ICT program.  It can be removed
-# once the ict_test program is not used.
-CPIO_TRANSFER = "0"
-
-INSTALL_FINISH_PROG = "/usr/sbin/install-finish"
-
-# Initial BE name
-INIT_BE_NAME = "solaris"
-
-# definitions for ZFS pool
-INSTALL_SNAPSHOT = "install"
-
-INSTALLED_ROOT_DIR = "/a"
-
-# these directories must be defined in this order, otherwise,
-# "zfs unmount" fails
-ZFS_SHARED_FS = ["/export/home", "/export"]
-
-#
-# Handle for accessing the InstallStatus class
-#
-INSTALL_STATUS = None
-
-
-class InstallStatus(object):
-    '''Stores information on the installation progress, and provides a
-    hook for updating the screen.
-
-    '''
-    TI = "ti"
-    TM = "tm"
-    ICT = "ict"
-
-    def __init__(self, screen, update_status_func, quit_event):
-        '''screen and update_status_func are values passed in from
-        the main app
-
-        '''
-
-        # Relative ratio used for computing the overall progress of the
-        # installation.  All numbers must add up to 100%
-        self.ratio = {InstallStatus.TI: 0.05,
-                      InstallStatus.TM: 0.93,
-                      InstallStatus.ICT: 0.02}
-
-        self.screen = screen
-        self.update_status_func = update_status_func
-        self.quit_event = quit_event
-        self.previous_step_name = None
-        self.step_percent_completed = 0
-        self.previous_overall_progress = 0
-
-    def update(self, step_name, percent_completed, message):
-        '''Update the install status. Also checks the quit_event to see
-        if the installation should be aborted.
-
-        '''
-        if self.quit_event.is_set():
-            logging.debug("User selected to quit")
-            raise ti_utils.InstallationError
-        if (self.previous_step_name is None):
-            self.previous_step_name = step_name
-        elif (self.previous_step_name != step_name):
-            self.previous_step_name = step_name
-            self.step_percent_completed = self.previous_overall_progress
-        overall_progress = (percent_completed * (self.ratio[step_name])) \
-                           + self.step_percent_completed
-        self.update_status_func(self.screen, overall_progress, message)
-        self.previous_overall_progress = overall_progress
-
-
-def transfer_mod_callback(percent, message):
-    '''Callback for transfer module to indicate percentage complete.'''
-    logging.debug("tm callback: %s: %s", percent, message)
-    try:
-        INSTALL_STATUS.update(InstallStatus.TM, percent, message)
-    except ti_utils.InstallationError:
-        # User selected to quit the transfer
-        tm_abort_transfer()
-
-
-def exec_cmd(cmd, description):
-    ''' Execute the given command.
-
-        Args:
-            cmd: Command to execute.  The command and it's arguments
-                 should be provided as a list, suitable for used
-                 with subprocess.Popen(shell=False)
-            description: Description to use for printing errors.
-
-        Raises:
-            InstallationError
-
-    '''
-    logging.debug("Executing: %s", " ".join(cmd))
-    if exec_cmd_outputs_to_log(cmd, logging) != 0:
-        logging.error("Failed to %s", description)
-        raise ti_utils.InstallationError
-
-
-def cleanup_existing_install_target(install_profile, inst_device):
-    ''' If installer was restarted after the failure, it is necessary
-        to destroy the pool previously created by the installer.
-
-        If there is a root pool manually imported by the user with
-        the same name which will be used by the installer
-        for target root pool, we don't want to destroy user's data.
-        So, we will log warning message and abort the installation.
-
-    '''
-
-    # Umount /var/run/boot_archive, which might be mounted by
-    # previous x86 installations.
-    # Error from this command is intentionally ignored, because the
-    # previous invocation of the transfer module might or might not have
-    # mounted on the mount point.
-    if platform.processor() == "i386":
-        with open("/dev/null", "w") as null_handle:
-            sp.Popen(["/usr/sbin/umount", "-f", "/var/run/boot_archive"],
-                     stdout=null_handle, stderr=null_handle)
-
-    rootpool_name = install_profile.disk.get_install_root_pool()
-
-    cmd = "/usr/sbin/zpool list " + rootpool_name
-    logging.debug("Executing: %s", cmd)
-    status = commands.getstatusoutput(cmd)[0]
-    if status != 0:
-        logging.debug("Root pool %s does not exist", rootpool_name)
-        return   # rpool doesn't exist, no need to clean up
-
-    # Check value of rpool's org.opensolaris.caiman:install property
-    # If it is busy, that means the pool is left over from an aborted install.
-    # If the property doesn't exist or has another value, we assume
-    # that the root pool contains valid Solaris instance.
-    cmd = "/usr/sbin/zfs get -H -o value org.opensolaris.caiman:install " + \
-          rootpool_name
-    logging.debug("Executing: %s", cmd)
-    (status, pool_status) = commands.getstatusoutput(cmd)
-    logging.debug("Return code: %s", status)
-    logging.debug("Pool status: %s", pool_status)
-    if (status != 0) or (pool_status != "busy"):
-        logging.error("Root pool %s exists.", rootpool_name)
-        logging.error("Installation can not proceed")
-        raise ti_utils.InstallationError
-
-    try:
-        rpool = tgt.Zpool(rootpool_name, inst_device)
-        tgt.release_zfs_root_pool(rpool)
-        logging.debug("Completed release_zfs_root_pool")
-    except TypeError, te:
-        logging.error("Failed to release existing rpool.")
-        logging.exception(te)
-        raise ti_utils.InstallationError
-
-    # clean up the target mount point
-    exec_cmd(["/usr/bin/rm", "-rf", INSTALLED_ROOT_DIR + "/*"],
-             "clean up existing mount point")
-
-
-def do_ti(install_profile, swap_dump):
-    '''Call the ti module to create the disk layout, create a zfs root
-    pool, create zfs volumes for swap and dump, and to create a be.
-
-    '''
-    diskname = install_profile.disk.name
-    logging.debug("Diskname: %s", diskname)
-    mesg = "Preparing disk for %(release)s installation" % RELEASE
-    try:
-        (inst_device, inst_device_size) = \
-             install_profile.disk.get_install_dev_name_and_size()
-
-        # The installation size we provide already included the required
-        # swap size
-        (swap_type, swap_size, dump_type, dump_size) = \
-            swap_dump.calc_swap_dump_size(ti_utils.get_minimum_size(swap_dump),
-                                          inst_device_size, swap_included=True)
-
-        tgt_disk = install_profile.disk.to_tgt()
-        tgt.create_disk_target(tgt_disk, False)
-        logging.debug("Completed create_disk_target")
-        INSTALL_STATUS.update(InstallStatus.TI, 20, mesg)
-
-        rootpool_name = install_profile.disk.get_install_root_pool()
-        rpool = tgt.Zpool(rootpool_name, inst_device)
-        tgt.create_zfs_root_pool(rpool)
-        logging.debug("Completed create_zfs_root_pool")
-        INSTALL_STATUS.update(InstallStatus.TI, 40, mesg)
-
-        create_swap = False
-        if (swap_type == ti_utils.SwapDump.ZVOL):
-            create_swap = True
-
-        create_dump = False
-        if (dump_type == ti_utils.SwapDump.ZVOL):
-            create_dump = True
-
-        logging.debug("Create swap %s Swap size: %s", create_swap, swap_size)
-        logging.debug("Create dump %s Dump size: %s", create_dump, dump_size)
-
-        tgt.create_zfs_volume(rootpool_name, create_swap, swap_size,
-                              create_dump, dump_size)
-        logging.debug("Completed create swap and dump")
-        INSTALL_STATUS.update(InstallStatus.TI, 70, mesg)
-
-        zfs_datasets = ()
-        # must traverse it in reversed order
-        for ds in reversed(ZFS_SHARED_FS):
-            zd = tgt.ZFSDataset(mountpoint=ds)
-            zfs_datasets += (zd,)
-        tgt.create_be_target(rootpool_name, INIT_BE_NAME, INSTALLED_ROOT_DIR,
-                             zfs_datasets)
-
-        logging.debug("Completed create_be_target")
-        INSTALL_STATUS.update(InstallStatus.TI, 100, mesg)
-    except TypeError, te:
-        logging.error("Failed to initialize disk")
-        logging.exception(te)
-        raise ti_utils.InstallationError
-
-
-def do_transfer():
-    '''Call libtransfer to transfer the bits to the system via cpio.'''
-    # transfer the bits
-    tm_argslist = [(TM_ATTR_MECHANISM, TM_PERFORM_CPIO),
-                   (TM_CPIO_ACTION, TM_CPIO_ENTIRE),
-                   (TM_CPIO_SRC_MNTPT, "/"),
-                   (TM_CPIO_DST_MNTPT, INSTALLED_ROOT_DIR)]
-
-    logging.debug("Going to call TM with this list: %s", tm_argslist)
-
-    try:
-        status = tm_perform_transfer(tm_argslist,
-                                     callback=transfer_mod_callback)
-    except Exception, ex:
-        logging.exception(ex)
-        status = 1
-
-    if status != TM_SUCCESS:
-        logging.error("Failed to transfer bits to the target")
-        raise ti_utils.InstallationError
-
-
-def do_ti_install(install_profile, screen, update_status_func, quit_event,
-                       time_change_event):
-    '''Installation engine for text installer.
-
-       Raises InstallationError for any error occurred during install.
-
-    '''
-    try:
-        sysconfig_profile = sysconfig.profile.from_engine()
-
-        #
-        # The following information is needed for installation.
-        # Make sure they are provided before even starting
-        #
-
-        # locale
-        locale = sysconfig_profile.system.locale
-        logging.debug("default locale: %s", locale)
-
-        # timezone
-        timezone = sysconfig_profile.system.tz_timezone
-        logging.debug("time zone: %s", timezone)
-
-        # hostname
-        hostname = sysconfig_profile.system.hostname
-        logging.debug("hostname: %s", hostname)
-
-        (inst_device, inst_device_size) = \
-                  install_profile.disk.get_install_dev_name_and_size()
-        logging.debug("Installation Device Name: %s", inst_device)
-        logging.debug("Installation Device Size: %sMB", inst_device_size)
-
-        swap_dump = ti_utils.SwapDump()
-
-        min_inst_size = ti_utils.get_minimum_size(swap_dump)
-        logging.debug("Minimum required size: %sMB", min_inst_size)
-        if (inst_device_size < min_inst_size):
-            logging.error("Size of device specified for installation "
-                          "is too small")
-            logging.error("Size of install device: %sMB", inst_device_size)
-            logging.error("Minimum required size: %sMB", min_inst_size)
-            raise ti_utils.InstallationError
-
-        recommended_size = ti_utils.get_recommended_size(swap_dump)
-        logging.debug("Recommended size: %sMB", recommended_size)
-        if (inst_device_size < recommended_size):
-            # Warn users that their install target size is not optimal
-            # Just log the warning, but continue with the installation.
-            logging.warning("Size of device specified for installation is "
-                            "not optimal")
-            logging.warning("Size of install device: %sMB", inst_device_size)
-            logging.warning("Recommended size: %sMB", recommended_size)
-
-        # Validate the value specified for timezone
-        if not tz_isvalid(timezone):
-            logging.error("Timezone value specified (%s) is not valid",
-                          timezone)
-            raise ti_utils.InstallationError
-
-        # Compute the time to set here.  It will be set after the rtc
-        # command is run, if on x86.
-        install_time = datetime.datetime.now() + \
-            sysconfig_profile.system.time_offset
-
-        if platform.processor() == "i386":
-            #
-            # At this time, the /usr/sbin/rtc command does not work in
-            # alternate root.  It hard codes to use /etc/rtc_config.
-            # Therefore, we set the value for rtc_config in the live
-            # environment so it will get copied over to the alternate root.
-            #
-            exec_cmd([RTC_CMD, "-z", timezone], "set timezone")
-            exec_cmd([RTC_CMD, "-c"], "set timezone")
-
-        #
-        # Set the system time to the time specified by the user
-        # The value to set the time to is computed before the "rtc" commands.
-        # This is required because rtc will mess up the computation of the
-        # time to set.  The rtc command must be run before the command
-        # to set time.  Otherwise, the time that we set will be overwritten
-        # after running /usr/sbin/rtc.
-        #
-        cmd = ["/usr/bin/date", install_time.strftime("%m%d%H%M%y")]
-        exec_cmd(cmd, "set system time")
-
-    finally:
-        # Must signal to the main thread to 'wake' whether
-        # the prior lines have succeeded or failed
-        time_change_event.set()
-
-    global INSTALL_STATUS
-    INSTALL_STATUS = InstallStatus(screen, update_status_func, quit_event)
-
-    rootpool_name = install_profile.disk.get_install_root_pool()
-
-    cleanup_existing_install_target(install_profile, inst_device)
-
-    do_ti(install_profile, swap_dump)
-
-    do_transfer()
-
-    ict_mesg = "Completing transfer process"
-    INSTALL_STATUS.update(InstallStatus.ICT, 0, ict_mesg)
-
-    # Save the timezone in the installed root's /etc/default/init file
-    ti_utils.save_timezone_in_init(INSTALLED_ROOT_DIR, timezone)
-
-    # If swap was created, add appropriate entry to <target>/etc/vfstab
-    swap_device = swap_dump.get_swap_device(rootpool_name)
-    logging.debug("Swap device: %s", swap_device)
-    ti_utils.setup_etc_vfstab_for_swap(swap_device, INSTALLED_ROOT_DIR)
-
-    # Generate the SC Profile by running the InstallEngine
-    # This is here temporarily, until the main thread
-    # takes control of running the entire install through the
-    # InstallEngine.
-    eng = InstallEngine.get_instance()
-    eng.execute_checkpoints(start_from=sysconfig.GENERATE_SC_PROFILE_CHKPOINT)
-
-    try:
-        run_ICTs(install_profile, hostname, ict_mesg, inst_device,
-                 locale, rootpool_name)
-    finally:
-        post_install_cleanup(install_profile, rootpool_name)
-
-    INSTALL_STATUS.update(InstallStatus.ICT, 100, ict_mesg)
-
-
-def post_install_cleanup(install_profile, rootpool_name):
-    '''Do final cleanup to prep system for first boot, such as resetting
-    the ZFS dataset mountpoints
-
-    '''
-    # reset_zfs_mount_property
-    # Setup mountpoint property back to "/" from "/a" for
-    # /, /export, /export/home
-
-    # make sure we are not in the alternate root.
-    # Otherwise, be_unmount() fails
-    os.chdir("/root")
-
-    # since be_unmount() can not currently handle shared filesystems,
-    # it's necesary to manually set their mountpoint to the appropriate value
-
-    # Limitations of current implementation:
-    #
-    # Following assumptions have to be met with respect to structure of
-    # shared filesystems:
-    #
-    #  - list of shared filesystems is ordered hierarchically AND
-    #  - it contains only one stream of hierarchy.
-    #
-    # List of shared datasets is currently hardcoded and meets those
-    # assumptions. The implementation has to be revisited once creating more
-    # complex structures of ZFS datasets is supported.
-
-    # Unmount the oldest ancestor dataset.
-    # It also unmounts all children datasets.
-    exec_cmd(["/usr/sbin/zfs", "unmount", rootpool_name + ZFS_SHARED_FS[-1]],
-                 "unmount " + rootpool_name + ZFS_SHARED_FS[-1])
-
-    # Reset mountpoint just for ancestor dataset. Child datasets inherit
-    # mounpoint from their ancestors.
-
-    exec_cmd(["/usr/sbin/zfs", "set", "mountpoint=" + ZFS_SHARED_FS[-1],
-                 rootpool_name + ZFS_SHARED_FS[-1]], 
-                 "change mount point for " +
-                 rootpool_name + ZFS_SHARED_FS[-1])
-
-    # Transfer the log file
-    final_log_loc = INSTALLED_ROOT_DIR + install_profile.log_final
-    logging.debug("Copying %s to %s", install_profile.log_location,
-                  final_log_loc)
-    try:
-        shutil.copyfile(install_profile.log_location, final_log_loc)
-    except (IOError, OSError), err:
-        logging.error("Failed to copy %s to %s", install_profile.log_location,
-                      install_profile.log_final)
-        logging.exception(err)
-        raise ti_utils.InstallationError
-
-    # 0 for the 2nd argument because force-umount need to be 0
-    if beUnmount(INIT_BE_NAME, 0) != 0:
-        logging.error("beUnmount failed for %s", INIT_BE_NAME)
-        raise ti_utils.InstallationError
-
-
-# pylint: disable-msg=C0103
-def run_ICTs(install_profile, hostname, ict_mesg, inst_device, locale,
-             rootpool_name):
-    '''Run all necessary ICTs. This function ensures that each ICT is run,
-    regardless of the success/failure of any others. After running all ICTs
-    (including those supplied by install-finish), if any of them failed,
-    an InstallationError is raised.
-
-    '''
-
-    failed_icts = 0
-
-    #
-    # set the language locale
-    #
-    if (locale != ""):
-        try:
-            exec_cmd([ICT_PROG, "ict_set_lang_locale", INSTALLED_ROOT_DIR,
-                      locale, CPIO_TRANSFER],
-                      "execute ict_set_lang_locale() ICT")
-        except ti_utils.InstallationError:
-            failed_icts += 1
-
-    #
-    # associate system hostname with loopback address in hosts(4) file.
-    # This is just a temporary solution until CR6996436 is fixed.
-    # Once it happens, it will be taken care by svc:/network/install smf(5)
-    # service and this ICT task can be removed.
-    #
-    try:
-        exec_cmd([ICT_PROG, "ict_set_hosts", INSTALLED_ROOT_DIR, hostname],
-                  "execute ict_set_hosts() ICT")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    # Setup bootfs property so that newly created Solaris instance is booted
-    # appropriately
-    initial_be = rootpool_name + "/ROOT/" + INIT_BE_NAME
-    try:
-        exec_cmd(["/usr/sbin/zpool", "set", "bootfs=" + initial_be,
-                  rootpool_name], "activate BE")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    is_logical = "0"
-    part_info = install_profile.disk.get_solaris_data()
-    if isinstance(part_info, PartitionInfo) and part_info.is_logical():
-        is_logical = "1"
-
-    try:
-        exec_cmd([ICT_PROG, "ict_installboot", INSTALLED_ROOT_DIR, inst_device,
-                  is_logical], "execute ict_installboot() ICT")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    INSTALL_STATUS.update(InstallStatus.ICT, 50, ict_mesg)
-
-    # Run the install-finish script
-    cmd = [INSTALL_FINISH_PROG, "-B", INSTALLED_ROOT_DIR, "-I", "TEXT"]
-
-    try:
-        exec_cmd(cmd, "execute INSTALL_FINISH_PROG")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    # Take a snapshot of the installation
-    try:
-        exec_cmd([ICT_PROG, "ict_snapshot", INIT_BE_NAME, INSTALL_SNAPSHOT],
-                 "execute ict_snapshot() ICT")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    # Mark ZFS root pool "ready" - it was successfully populated and contains
-    # valid Solaris instance
-    try:
-        exec_cmd([ICT_PROG, "ict_mark_root_pool_ready", rootpool_name],
-                 "execute ict_mark_root_pool_ready() ICT")
-    except ti_utils.InstallationError:
-        failed_icts += 1
-
-    if failed_icts != 0:
-        logging.error("One or more ICTs failed. See previous log messages")
-        raise ti_utils.InstallationError
-    else:
-        logging.info("All ICTs completed successfully")
-
-
-def perform_ti_install(install_profile, screen, update_status_func, quit_event,
-                       time_change_event):
-    '''Wrapper to call the do_ti_install() function.
-       Sets the variable indicating whether the installation is successful or
-       not.
-
-    '''
-
-    try:
-        do_ti_install(install_profile, screen, update_status_func, quit_event,
-                      time_change_event)
-        install_profile.install_succeeded = True
-    except ti_utils.InstallationError:
-        install_profile.install_succeeded = False
--- a/usr/src/cmd/text-install/osol_install/text_install/ti_install_utils.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,428 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Utility functions
-'''
-
-import logging
-import os
-import shutil
-from tempfile import NamedTemporaryFile
-from subprocess import Popen
-from subprocess import PIPE
-from osol_install.profile.disk_space import DiskSpace
-import osol_install.tgt as tgt
-
-class InstallationError(Exception):
-    '''Some sort of error occurred during installation.  The exact
-       cause of the error should have been logged.  So, this
-       just indicates that something is wrong
-
-    '''
-    pass
-
-class NotEnoughSpaceError(Exception):
-    '''There's not enough space in the target disk for successful installation
-
-    '''
-    pass
-
-# All sizes are in MB
-MIN_SWAP_SIZE = 512
-MAX_SWAP_SIZE = DiskSpace("32gb").size_as("mb")		#32G
-MIN_DUMP_SIZE = 256
-MAX_DUMP_SIZE = DiskSpace("16gb").size_as("mb")		#16G
-OVERHEAD = 1024
-FUTURE_UPGRADE_SPACE = DiskSpace("2gb").size_as("mb") #2G
-ZVOL_REQ_MEM = 900      # Swap ZVOL is required if memory is below this
-
-class SwapDump:
-    ''' All information associated with swap and dump'''
-
-    ''' The type of swap/dump.  Define them as strings so debugging output
-        is easier to read.
-    '''
-    SLICE = "Slice"
-    ZVOL = "ZVOL"
-    NONE = "None"
-
-    mem_size = 0
-    swap_type = ""
-    swap_size = 0
-
-    dump_type = ""
-    dump_size = 0
-
-    swap_dump_computed = False
-
-    def __init__(self):
-        ''' Initialize swap/dump calculation.  This will get the size of
-            running's system's memory
-        '''
-        self.mem_size = get_system_memory()
-        self.swap_type = SwapDump.NONE
-        self.swap_size = 0
-        self.dump_type = SwapDump.NONE
-        self.dump_size = 0
-        self.swap_dump_computed = False
-
-    def get_required_swap_size(self):
-        ''' Determines whether swap is required.  If so, the amount of
-            space used for swap is returned.  If swap is not required,
-            0 will be returned.  Value returned is in MB.
-
-            If system memory is less than 900mb, swap is required.
-            Minimum required space for swap is 0.5G (MIN_SWAP_SIZE).
-        '''
-   
-        if (self.mem_size < ZVOL_REQ_MEM):
-            return MIN_SWAP_SIZE
-
-        return 0
-       
-    
-    def calc_swap_dump_size(self, installation_size, available_size,
-                            swap_included=False):
-        '''Calculate swap/dump, based on the amount of
-           system memory, installation size and available size.
-
-           The following rules are used for
-           determining the type of swap to be created, whether swap zvol
-           is required and the size of swap to be created.
- 
-            memory        type           required    size
-            --------------------------------------------------
-            <900mb        zvol           yes          0.5G (MIN_SWAP_SIZE)
-            900mb-1G      zvol            no          0.5G (MIN_SWAP_SIZE)
-            1G-64G        zvol            no          (0.5G-32G) 1/2 of memory
-            >64G          zvol            no          32G (MAX_SWAP_SIZE)
-
-            The following rules are used for calculating the amount
-            of required space for dump
-
-            memory        type            size
-            --------------------------------------------------
-            <0.5G         zvol            256MB (MIN_DUMP_SIZE)
-            0.5G-32G      zvol            256M-16G (1/2 of memory)
-            >32G          zvol            16G (MAX_DUMP_SIZE)
-
-            If slice/zvol is required, and there's not enough space in the,
-            target, an error will be raised.  If swap zvol is
-            not required, and there's not enough space in the target, as much
-            space as available will be utilized for swap/dump
-
-            Size of all calculation is done in MB
-      
-            Input:
-                installation_size: size required for installation (MB)
-                available_size: available size in the target disk. (MB)
-                swap_included: Indicate whether required swap space is already
-                               included and validated in the installation size.
-                               Default to false.
-
-            Output:
-                returns a tuple (swap_type, swap_size, dump_type, dump_size)
-
-            Raise:
-                NotEnoughSpaceError 
-        '''
-        if self.swap_dump_computed:
-            return(self.swap_type, self.swap_size, self.dump_type,
-                   self.dump_size)
-
-        swap_required = False
-
-        if (installation_size > available_size):
-            logging.error("Space required for installation: %s",
-                          installation_size)
-            logging.error("Total available space: %s", available_size)
-            raise NotEnoughSpaceError
-
-        self.swap_size = self.get_required_swap_size()
-        if self.swap_size != 0:
-            swap_required = True
-
-        logging.debug("Installation size: %sMB", installation_size)
-        logging.debug("Available size: %sMB", available_size)
-        logging.debug("Memory: %sMB. Swap Required: %s",
-                      self.mem_size, swap_required)
-
-        if swap_required:
-            # Make sure target disk has enough space for both swap and software
-            if swap_included:
-                with_swap_size = installation_size
-            else:
-                with_swap_size = installation_size + self.swap_size
-                if (available_size < with_swap_size):
-                    logging.error("Space required for installation "
-                                  "with required swap: %s", with_swap_size)
-                    logging.error("Total available space: %s", available_size)
-                    raise NotEnoughSpaceError
-            
-            # calculate the size for dump
-            self.dump_size = self.__calc_size(available_size - with_swap_size,
-                                              MIN_DUMP_SIZE, MAX_DUMP_SIZE)
-        else:
-            free_space = available_size - installation_size
-            self.swap_size = self.__calc_size(((free_space * MIN_SWAP_SIZE) / 
-                                       (MIN_SWAP_SIZE + MIN_DUMP_SIZE)),
-                                       MIN_SWAP_SIZE, MAX_SWAP_SIZE)
-            self.dump_size = self.__calc_size(((free_space * MIN_DUMP_SIZE) /
-                                       (MIN_SWAP_SIZE + MIN_DUMP_SIZE)),
-                                       MIN_DUMP_SIZE, MAX_DUMP_SIZE)
-        if (self.dump_size > 0):
-            self.dump_type = SwapDump.ZVOL
-
-        if (self.swap_size > 0):
-            self.swap_type = SwapDump.ZVOL
-
-        logging.debug("Swap Type: %s", self.swap_type)
-        logging.debug("Swap Size: %s", self.swap_size)
-        logging.debug("Dump Type: %s", self.dump_type)
-        logging.debug("Dump Size: %s", self.dump_size)
-        self.swap_dump_computed = True
-
-        return(self.swap_type, self.swap_size, self.dump_type, self.dump_size)
-
-    def __calc_size(self, available_space, min_size, max_size):
-        '''Calculates size of swap or dump in MB based on amount of
-           physical memory available.
-
-           If less than calculated space is available, swap/dump size will be
-           trimmed down to the avaiable space.  If calculated space
-           is more than the max size to be used, the swap/dump size will
-           be trimmed down to the maximum size to be used for swap/dump
-
-           Args:
-               available_swap_space: space that can be dedicated to swap in MB
-	       min_size: minimum size to use
-	       max_size: maximum size to use
-
-           Returns:
-               size of swap in MB
-
-        '''
-
-        if available_space == 0:
-            return (0)
-
-        if (self.mem_size < min_size):
-            size = min_size
-        else:
-            size = self.mem_size / 2
-            if (size >  max_size):
-                size = max_size
-
-        if (available_space < size):
-            size = available_space
-
-        return (int)(size)	# Make sure size is an int
-
-    def get_swap_device(self, pool_name):
-        ''' Return the string representing the device used for swap '''
-        if (self.swap_type == SwapDump.ZVOL):
-            return ("/dev/zvol/dsk/" + pool_name + "/swap")
-
-        return None
-
-IMAGE_INFO = "/.cdrom/.image_info"
-IMAGE_SIZE_KEYWORD = "IMAGE_SIZE"
-
-def get_image_size():
-    '''Total size of the software in the image is stored in the 
-       /.cdrom/.image_info indicated by the keywoard IMAGE_SIZE.
-       This function retrieves that value from the .image_file
-       The size recorded in the .image_file is in KB, other functions
-       in this file uses the value in MB, so, this function will
-       return the size in MB
-
-       Returns:
-           size of retrieved from the .image_info file in MB
-
-    '''
-    img_size = 0
-    try:
-        with open(IMAGE_INFO, 'r') as ih:
-            for line in ih:
-                (opt, val) = line.split("=")
-                if opt == IMAGE_SIZE_KEYWORD:
-                    # Remove the '\n' character read from
-                    # the file, and convert to integer
-                    img_size = int(val.rstrip('\n'))
-                    break
-    except IOError, ioe:
-        logging.error("Failed to access %s", IMAGE_INFO)
-        logging.exception(ioe)
-        raise InstallationError
-    except ValueError, ive:
-        logging.error("Invalid file format in %s", IMAGE_INFO)
-        logging.exception(ive)
-        raise InstallationError
-
-    if (img_size == 0):
-        # We should have read in a size by now
-        logging.error("Unable to read the image size from %s", IMAGE_INFO)
-        raise InstallationError
-
-    return (DiskSpace(str(img_size) +"kb").size_as("mb"))
-
-
-def get_system_memory():
-    ''' Returns the amount of memory available in the system
-        The value returned is in MB.
-
-    '''
-    memory_size = 0
-    try:
-        with os.popen("/usr/sbin/prtconf") as fp:
-            for line in fp.readlines():
-                # Looking for the line that says "Memory size: xxxxx Megabytes"
-                val = line.split()
-                if ((len(val) == 4) and ((val[0] + " " + val[1]) == \
-	            "Memory size:")):
-                    memory_size = int(val[2]) # convert the size to an integer
-                    break
-    except Exceptions:
-        pass
-
-    if (memory_size <= 0):
-        # We should have a valid size now
-        logging.error("Unable to determine amount of system memory")
-        raise InstallationError
-
-    return memory_size
-
-def get_minimum_size(swap_dump_info):
-    ''' Returns the minimum amount of space required to perform an installation
-        This does take into account MIN_SWAP_SIZE required for
-        low-memory system.
-        
-        Size is returned in MB.
-
-    '''
-    swap_size = swap_dump_info.get_required_swap_size()
-    return(get_image_size() + OVERHEAD + swap_size)
-    
-def get_recommended_size(swap_dump_info):
-    '''Returns the recommended size to perform an installation.
-    This takes into account estimated space to perform an upgrade.
-
-    '''
-    return (get_minimum_size(swap_dump_info) + FUTURE_UPGRADE_SPACE)
-
-INIT_FILE = "/etc/default/init"
-TIMEZONE_KW = "TZ"
-def save_timezone_in_init(basedir, timezone):
-    '''Save the timezone in /etc/default/init.
-
-    '''    
-    saved_tz = False
-    init_file = basedir + INIT_FILE
-    try:
-        with open(init_file, 'r') as ih:
-            with NamedTemporaryFile(dir="/tmp", delete=False) as th:
-                tmp_fname = th.name
-
-                for line in ih:
-                    eq = line.split("=")
-                    if eq[0] == TIMEZONE_KW:
-                        new_line = TIMEZONE_KW + "=" + timezone + "\n"
-                        th.write(new_line)
-                        saved_tz = True
-                    else:
-                        th.write(line)
-                if not saved_tz:
-                    new_line = TIMEZONE_KW + "=" + timezone + "\n"
-                    th.write(new_line)
-
-		th.close()
-
-                # Set the owner, group and permission bits from original file
-                # to temp file.  The copystat() call will cause the last
-                # access and modification time as well, but it is not
-                # important.  Capturing the correct file permission is.
-                shutil.copymode(init_file, tmp_fname)
-                shutil.copystat(init_file, tmp_fname)
-                shutil.copy2(tmp_fname, init_file)
-                os.remove(tmp_fname)
-    except IOError, ioe:
-        logging.error("Failed to save timezone into %s", init_file)
-        logging.exception(ioe)
-        raise InstallationError
-
-VFSTAB_FILE = "/etc/vfstab"
-def setup_etc_vfstab_for_swap(swap_device, basedir):
-    '''Add the swap device to /etc/vfstab.
-
-    '''
-    if swap_device is None:
-        return    #nothing to do
-
-    fname = basedir + VFSTAB_FILE
-    try:
-        with open (fname, 'a+') as vf:
-            vf.write("%s\t%s\t\t%s\t\t%s\t%s\t%s\t%s\n" % 
-                        (swap_device, "-", "-", "swap", "-", "no", "-"))
-    except IOError, ioe:
-        logging.error("Failed to write to %s", fname)
-        logging.exception(ioe)
-        raise InstallationError
-
-def pool_list(arg):
-    '''Return a list of zpools on the system
-
-    '''
-    argslist = ['/usr/sbin/zpool', arg]
-    pool_names = []
-
-    try:
-        (zpoolout, zpoolerr) = Popen(argslist, stdout=PIPE,
-                  stderr=PIPE).communicate()
-
-    except OSError, err:
-        logging.error("OSError occured during zpool call: %s", err)
-        return pool_names
-
-    if zpoolerr:
-        logging.error("Error occured during zpool call: %s", zpoolerr)
-        return pool_names
-
-    line = zpoolout.splitlines(False)
-    for entry in line:
-        if 'pool:' in entry:
-            val = entry.split()
-            if ((len(val) == 2) and (val[0] == "pool:")):
-                pool_names.append(val[1])
-
-    return pool_names
-
-def get_zpool_list():
-    ''' Get the list of exported (inactive) as well as active
-    zpools on the system.
-    '''
-    zpool_list = pool_list("import")
-    zpool_list.extend(pool_list("status"))
-    
-    return zpool_list
--- a/usr/src/cmd/text-install/osol_install/text_install/welcome.py	Wed May 11 14:33:33 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-#!/usr/bin/python
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
-#
-
-'''
-Contains the Welcome Screen for the Text Installer
-'''
-
-from osol_install.profile.install_profile import INSTALL_PROF_LABEL
-from osol_install.text_install import _, RELEASE, TUI_HELP
-from solaris_install.engine import InstallEngine
-from terminalui.base_screen import BaseScreen
-
-
-class WelcomeScreen(BaseScreen):
-    '''First screen of the text installer.
-    No special __init__ needed beyond that provided by BaseScreen
-    
-    '''
-    
-    HEADER_TEXT = _("Welcome to %(release)s") % RELEASE
-    WELCOME_TEXT = _("Thanks for choosing to install %(release)s! This "
-                     "installer enables you to install the %(release)s "
-                     "Operating System (OS) on SPARC or x86 systems.\n\n"
-                     "The installation log will be at %(log)s.\n\n"
-                     "How to navigate through this installer:")
-    BULLET_ITEMS = [_("Use the function keys listed at the bottom of each "
-                 "screen to move from screen to screen and to perform "
-                 "other operations."),
-               _("Use the up/down arrow keys to change the selection "
-                 "or to move between input fields."),
-               _("If your keyboard does not have function keys, or "
-                 "they do not respond, press ESC; the legend at the "
-                 "bottom of the screen will change to show the ESC keys"
-                 " for navigation and other functions.")]
-    BULLET = "- "
-    HELP_DATA = (TUI_HELP + "/%s/welcome.txt",
-                 _("Welcome and Navigation Instructions"))
-    
-    def set_actions(self):
-        '''Remove the F3_Back Action from the first screen'''
-        self.main_win.actions.pop(self.main_win.back_action.key, None)
-    
-    def _show(self):
-        '''Display the static paragraph WELCOME_TEXT'''
-        doc = InstallEngine.get_instance().doc
-        self.install_profile = doc.get_descendants(name=INSTALL_PROF_LABEL,
-                                                   not_found_is_err=True)[0]
-        
-        log_file = self.install_profile.log_location
-        y_loc = 1
-        fmt = {"log" : log_file}
-        fmt.update(RELEASE)
-        text = WelcomeScreen.WELCOME_TEXT % fmt
-        y_loc += self.center_win.add_paragraph(text, start_y=y_loc)
-        x_loc = len(WelcomeScreen.BULLET)
-        for bullet in WelcomeScreen.BULLET_ITEMS:
-            self.center_win.add_text(WelcomeScreen.BULLET, start_y=y_loc)
-            y_loc += self.center_win.add_paragraph(bullet, start_y=y_loc,
-                                                   start_x=x_loc)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/partition_edit_screen.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+UI Components for displaying a screen allowing the user to edit
+partition and slice information
+'''
+
+import curses
+import logging
+import platform
+
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.target.controller import DEFAULT_VDEV_NAME
+from solaris_install.target.libadm.const import V_ROOT
+from solaris_install.target.physical import Partition, Slice
+from solaris_install.target.size import Size
+from solaris_install.text_install import _, RELEASE, TUI_HELP
+from solaris_install.text_install.disk_window import DiskWindow
+from solaris_install.text_install.ti_target_utils import \
+    get_desired_target_disk, get_solaris_partition, perform_final_validation, \
+    ROOT_POOL
+from terminalui import LOG_LEVEL_INPUT
+from terminalui.action import Action
+from terminalui.base_screen import BaseScreen, SkipException
+from terminalui.window_area import WindowArea
+
+LOGGER = None
+
+
+class PartEditScreen(BaseScreen):
+    '''Allows user editing of partitions on a disk, or slices on a
+    disk/partition
+    
+    '''
+    
+    PARTITION_PARAGRAPH = _("Oracle Solaris will be installed into the Solaris"
+                            " partition. A partition's type can be changed"
+                            " using the F5 key.\n\n"
+                            "A partition's size can be increased "
+                            "up to its Avail space. Avail space can be "
+                            "increased by deleting an adjacent partition. "
+                            "Delete a partition by changing it to \"Unused\""
+                            " using the F5 key.\n\n"
+                            "The four primary partition slots are listed on "
+                            "the left. If one is an \"Extended\" partition "
+                            "its logical partitions are listed on the "
+                            "right.") % RELEASE
+    SLICE_PARAGRAPH = _("%(release)s will be installed in the \"%(pool)s\" "
+                        "slice. Use the F5 key to change a slice to "
+                        "\"%(pool)s.\"\n\n"
+                        "A slice's size can be increased up to its Avail "
+                        "size. Avail can be increased by deleting an adjacent"
+                        " slice. Use the F5 key to delete a slice by changing"
+                        " it to \"Unused.\"\n\n"
+                        "Slices are listed in disk layout order.")
+    
+    HEADER_x86_PART = _("Select Partition: %(size).1fGB %(type)s "
+                        "%(bootable)s")
+    HEADER_x86_SLICE = _("Select Slice in Fdisk Partition")
+    HEADER_SPARC_SLICE = _("Select Slice: %(size).1fGB %(type)s"
+                           "%(bootable)s")
+    SLICE_DESTROY_TEXT = _("indicates the slice's current content will be "
+                           "destroyed")
+    PART_DESTROY_TEXT = _("indicates the partition's current content will "
+                          "be destroyed")
+    BOOTABLE = _("Boot")
+    
+    SPARC_HELP = (TUI_HELP + "/%s/"
+                  "sparc_solaris_slices_select.txt",
+                  _("Select Slice"))
+    X86_PART_HELP = (TUI_HELP + "/%s/"
+                     "x86_fdisk_partitions_select.txt",
+                     _("Select Partition"))
+    X86_SLICE_HELP = (TUI_HELP + "/%s/"
+                      "x86_fdisk_slices_select.txt",
+                      _("Select Slice"))
+    
+    HELP_FORMAT = "    %s"
+    
+    def __init__(self, main_win, target_controller, x86_slice_mode=False):
+        super(PartEditScreen, self).__init__(main_win)
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        self.x86_slice_mode = x86_slice_mode
+        self.is_x86 = (platform.processor() == "i386")
+        self.header_text = platform.processor()
+        
+        if self.x86_slice_mode: # x86, Slice within a partition
+            self.instance = ".slice"
+            self.header_text = PartEditScreen.HEADER_x86_SLICE
+            self.paragraph_text = PartEditScreen.SLICE_PARAGRAPH
+            self.destroy_text = PartEditScreen.SLICE_DESTROY_TEXT
+            self.help_data = PartEditScreen.X86_SLICE_HELP
+        elif self.is_x86: # x86, Partition on disk
+            self.header_text = PartEditScreen.HEADER_x86_PART
+            self.paragraph_text = PartEditScreen.PARTITION_PARAGRAPH
+            self.destroy_text = PartEditScreen.PART_DESTROY_TEXT
+            self.help_data = PartEditScreen.X86_PART_HELP
+        else: # SPARC (Slice on disk)
+            self.header_text = PartEditScreen.HEADER_SPARC_SLICE
+            self.paragraph_text = PartEditScreen.SLICE_PARAGRAPH
+            self.destroy_text = PartEditScreen.SLICE_DESTROY_TEXT
+            self.help_data = PartEditScreen.SPARC_HELP
+            self.help_format = "  %s"
+        
+        self.disk_win = None
+        self.tc = target_controller
+    
+    def set_actions(self):
+        '''Edit Screens add 'Reset' and 'Change Type' actions. Since these
+        do not manipulate screen direction, they are captured during
+        processing by adding them to center_win's key_dict.
+        
+        '''
+        super(PartEditScreen, self).set_actions()
+        reset_action = Action(curses.KEY_F7, _("Reset"))
+        change_action = Action(curses.KEY_F5, _("Change Type"))
+        self.main_win.actions[reset_action.key] = reset_action
+        self.main_win.actions[change_action.key] = change_action
+        self.center_win.key_dict[curses.KEY_F7] = self.on_key_F7
+    
+    # pylint: disable-msg=C0103
+    # F7 is the keyname and appropriate here
+    def on_key_F7(self, dummy):
+        '''F7 -> Reset the DiskWindow'''
+        self.disk_win.reset()
+        return None
+    
+    def _show(self):
+        '''Display the explanatory paragraph and create the DiskWindow'''
+
+        doc = InstallEngine.get_instance().doc
+
+        if self.x86_slice_mode:
+
+            LOGGER.debug("in x86 slice mode")
+
+            disk = get_desired_target_disk(doc)
+            if disk.whole_disk:
+                LOGGER.debug("disk.whole_disk=True, skip editting")
+                disk.whole_disk = False
+
+                # perform final target validation
+                perform_final_validation(doc)
+
+                raise SkipException
+
+            part = get_solaris_partition(doc)
+
+            LOGGER.debug(str(part))
+            if part is None:
+                err_msg = "Critical error - no Solaris partition found"
+                LOGGER.error(err_msg)
+                raise ValueError(err_msg)
+            if part.in_zpool is not None:
+                LOGGER.debug("Whole partition selected. Skipping slice edit")
+                LOGGER.debug(str(part))
+
+                #
+                # remove the in_zpool value from partition, delete
+                # any existing slices, and create
+                # the needed underneath slices
+                #
+                # All the logic from here to the part.bootid line
+                # can be removed when GPT partitions is supported.
+                #
+
+                existing_slices = part.get_children(class_type=Slice)
+                if not existing_slices:
+                    for ex_slice in existing_slices:
+                        part.delete_slice(ex_slice)
+
+                pool_name = part.in_zpool
+                slice0 = part.add_slice(0, part.start_sector, \
+                    part.size.sectors, Size.sector_units, in_zpool=pool_name, \
+                    in_vdev=DEFAULT_VDEV_NAME)
+                slice0.tag = V_ROOT
+                LOGGER.debug(str(part))
+
+                part.in_zpool = None
+                part.bootid = Partition.ACTIVE
+
+                # perform final target validation
+                perform_final_validation(doc)
+
+                raise SkipException
+        else:
+
+            # get selected disk from desired target
+            disk = get_desired_target_disk(doc)
+
+            LOGGER.debug("disk.whole_disk: %s", disk.whole_disk)
+            LOGGER.debug(str(disk))
+
+            if disk.whole_disk:
+                LOGGER.debug("disk.whole_disk true, skipping editing")
+
+                if not self.is_x86:
+                    # Unset this so Target Instantiation works correctly
+                    disk.whole_disk = False
+
+                    # perform final target validation
+                    perform_final_validation(doc)
+
+                raise SkipException
+
+            part = disk
+        
+        if self.x86_slice_mode:
+            header = self.header_text
+        else:
+            bootable = ""
+            if self.is_x86 and disk.is_boot_disk():
+                bootable = PartEditScreen.BOOTABLE
+            disk_size = disk.disk_prop.dev_size.get(Size.gb_units)
+            header = self.header_text % {"size": disk_size,
+                                         "type": disk.disk_prop.dev_type,
+                                         "bootable": bootable}
+        self.main_win.set_header_text(header)
+        
+        y_loc = 1
+        fmt_dict = {'pool': ROOT_POOL}
+        fmt_dict.update(RELEASE)
+        y_loc += self.center_win.add_paragraph(self.paragraph_text % fmt_dict,
+                                               y_loc)
+        
+        y_loc += 1
+        disk_win_area = WindowArea(6, 70, y_loc, 0)
+
+        self.disk_win = DiskWindow(disk_win_area, part,
+                                   window=self.center_win,
+                                   editable=True,
+                                   error_win=self.main_win.error_line,
+                                   target_controller=self.tc)
+        y_loc += disk_win_area.lines
+        
+        y_loc += 1
+        LOGGER.log(LOG_LEVEL_INPUT, "calling addch with params start_y=%s,"
+                    "start_x=%s, ch=%c", y_loc, self.center_win.border_size[1],
+                    DiskWindow.DESTROYED_MARK)
+        self.center_win.window.addch(y_loc, self.center_win.border_size[1],
+                                     DiskWindow.DESTROYED_MARK,
+                                     self.center_win.color_theme.inactive)
+        self.center_win.add_text(self.destroy_text, y_loc, 2)
+        
+        self.main_win.do_update()
+        self.center_win.activate_object(self.disk_win)
+    
+    def validate(self):
+        ''' Perform final validation of the desired target
+        '''
+
+        if self.is_x86 and not self.x86_slice_mode:
+            # delay final validation for x86 until slice mode
+            # is completed.
+            return
+
+        # perform final target validation
+        doc = InstallEngine.get_instance().doc
+
+        if self.is_x86:
+            solaris_part = get_solaris_partition(doc)
+            if solaris_part is None:
+                raise RuntimeError("No Solaris2 partition in desired target")
+            solaris_part.bootid = Partition.ACTIVE
+
+        perform_final_validation(doc)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/progress.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,151 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+import random
+import socket
+import struct
+import sys
+import thread
+import time
+
+from select import select
+
+from solaris_install.logger import ProgressHandler
+
+''' Progress handler for the text installer '''
+
+
+class InstallProgressHandler(ProgressHandler):
+    """ Server and message receiver functionality for the ProgressHandler. """
+
+    def __init__(self, logger, hostname="localhost", portno=None):
+
+        self.server_up = False
+        self.logger = logger
+        self.hostname = hostname
+        self.engine_skt = None
+        self.msg_buf = ""
+
+        # Get a port number
+        self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+        if portno is not None:
+            self.portno = portno
+            try:
+                self.skt.bind((self.hostname, self.portno))
+                self.skt.listen(5)
+            except socket.error:
+                self.logger.exception("InstallProgresHandler init failed.")
+                return None
+        else:
+            random.seed()
+            # Continue looping until skt.listen(5) does not cause socket.error
+            while True:
+                try:
+                    self.portno = random.randint(10000, 30000)
+                    self.skt.bind((self.hostname, self.portno))
+                    self.skt.listen(5)
+                    break
+                except socket.error:
+                    self.skt.close()
+                    self.skt = None
+
+        ProgressHandler.__init__(self, self.hostname, self.portno)
+
+    def startProgressServer(self, cb=None):
+        """ Starts the socket server stream to receive progress messages. """
+
+        if not self.server_up:
+            self.server_up = True
+            self.engine_skt, address = self.skt.accept()
+            if cb is not None:
+                thread.start_new_thread(self.progressServer, (cb, ))
+            time.sleep(1)
+
+    def stopProgressServer(self):
+        """ Stop the socket server stream. """
+        if self.server_up:
+            self.server_up = False
+
+    def progressServer(self, cb):
+        """ Actual spawned progressServer process. """
+        try:
+            while self.server_up:
+                ready_to_read = select([self.engine_skt], [], [], 0.25)[0]
+                if len(ready_to_read) > 0:
+                    percentage, mssg = self.parseProgressMsg( \
+                        ready_to_read[0], cb)
+            self.engine_skt.close()
+        except Exception:
+            self.logger.exception("progressServer Error")
+ 
+    def get_one_message(self):
+
+        self.logger.debug("1-msg: %s", self.msg_buf)
+        if len(self.msg_buf) > 4:
+            # Something is available to be processed.  Try to process it.
+            size = struct.unpack('@i', self.msg_buf[:4])[0]
+            self.logger.debug("size of message expected: %s", size)
+
+            # does the buffer have enough data?
+            if len(self.msg_buf[4:]) >= size:
+                msg = self.msg_buf[4:4 + size]
+                self.msg_buf = self.msg_buf[(4 + size):]
+                self.logger.debug("message: %s", msg)
+                self.logger.debug("msg_buf: %s", self.msg_buf)
+                return msg
+            else:
+                return None
+        else:
+            return None
+
+    def parseProgressMsg(self, skt, cb=None):
+        """Parse the messages sent by the client."""
+        recv_size = 8192
+        percent = None
+        msg = None
+
+        message = self.get_one_message()
+        self.logger.debug("step 1: message: %s", message)
+        while not message:
+            try:
+                sock_data = skt.recv(recv_size)
+            except:
+                pass
+
+            self.logger.debug("sock: %s", sock_data)
+            self.msg_buf += sock_data
+            self.logger.debug("after sock: %s", self.msg_buf)
+            message = self.get_one_message()
+            self.logger.debug("step 2: message: %s", message)
+
+        self.logger.debug("parseProgressMsg: %s", message)
+        if cb:
+            cb(message)
+
+        percent, msg = message.split(' ', 1)
+        return percent, msg
+     
+    def progressReceiver(self, msg):
+        print "%s" % (msg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/summary.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,234 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Display a summary of the user's selections
+'''
+
+import curses
+import logging
+
+import solaris_install.sysconfig.profile
+
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.sysconfig.profile.network_info import NetworkInfo
+from solaris_install.sysconfig.profile.user_info import UserInfo
+from solaris_install.target.libdiskmgt import const as libdiskmgt_const
+from solaris_install.target.size import Size
+from solaris_install.text_install import _, RELEASE, TUI_HELP
+from solaris_install.text_install.ti_target_utils import \
+    get_desired_target_disk, get_solaris_partition, get_solaris_slice
+from terminalui.action import Action
+from terminalui.base_screen import BaseScreen
+from terminalui.i18n import convert_paragraph
+from terminalui.window_area import WindowArea
+from terminalui.scroll_window import ScrollWindow
+
+LOGGER = None
+
+
+class SummaryScreen(BaseScreen):
+    '''Display a summary of the install profile to the user
+    InnerWindow.__init__ is sufficient to initalize an instance
+    of SummaryScreen
+    
+    '''
+    
+    HEADER_TEXT = _("Installation Summary")
+    PARAGRAPH = _("Review the settings below before installing."
+                                " Go back (F3) to make changes.")
+    
+    HELP_DATA = (TUI_HELP + "/%s/summary.txt",
+                 _("Installation Summary"))
+    
+    INDENT = 2
+    
+    def set_actions(self):
+        '''Replace the default F2_Continue with F2_Install'''
+        install_action = Action(curses.KEY_F2, _("Install"),
+                                self.main_win.screen_list.get_next)
+        self.main_win.actions[install_action.key] = install_action
+    
+    def _show(self):
+        '''Prepare a text summary and display it to the user in a ScrollWindow
+        
+        '''
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+        
+        self.sysconfig = solaris_install.sysconfig.profile.from_engine()
+        
+        y_loc = 1
+        y_loc += self.center_win.add_paragraph(SummaryScreen.PARAGRAPH, y_loc)
+        
+        y_loc += 1
+        summary_text = self.build_summary()
+
+        LOGGER.info("The following configuration is used for "
+                    "installation: %s\n", summary_text)
+        # Wrap the summary text, accounting for the INDENT (used below in
+        # the call to add_paragraph)
+        max_chars = self.win_size_x - SummaryScreen.INDENT - 1
+        summary_text = convert_paragraph(summary_text, max_chars)
+        area = WindowArea(x_loc=0, y_loc=y_loc,
+                          scrollable_lines=(len(summary_text) + 1))
+        area.lines = self.win_size_y - y_loc
+        area.columns = self.win_size_x
+        scroll_region = ScrollWindow(area, window=self.center_win)
+        scroll_region.add_paragraph(summary_text, start_x=SummaryScreen.INDENT)
+        
+        self.center_win.activate_object(scroll_region)
+    
+    def build_summary(self):
+        '''Build a textual summary from the DOC data'''
+        lines = []
+        
+        lines.append(_("Software: %s") % self.get_release())
+        lines.append("")
+        lines.append(self.get_disk_summary())
+        lines.append("")
+        lines.append(self.get_tz_summary())
+        lines.append("")
+        lines.append(_("Language: *The following can be changed when "
+                       "logging in."))
+        if self.sysconfig.system.locale is None:
+            self.sysconfig.system.determine_locale()
+        lines.append(_("  Default language: %s") %
+                     self.sysconfig.system.actual_lang)
+        lines.append("")
+        lines.append(_("Keyboard layout: *The following can be "
+                       "changed when logging in."))
+        lines.append(_("  Default keyboard layout: %s") %
+                     self.sysconfig.system.keyboard)
+        lines.append("")
+        lines.append(_("Terminal type: %s") %
+                     self.sysconfig.system.terminal_type)
+        lines.append("")
+        lines.append(_("Users:"))
+        lines.extend(self.get_users())
+        lines.append("")
+        lines.append(_("Network:"))
+        lines.extend(self.get_networks())
+        
+        return "\n".join(lines)
+    
+    def get_networks(self):
+        '''Build a summary of the networks from the DOC data,
+        returned as a list of strings
+        
+        '''
+        network_summary = []
+        network_summary.append(_("  Computer name: %s") %
+                               self.sysconfig.system.hostname)
+        nic = self.sysconfig.nic
+        
+        if nic.type == NetworkInfo.AUTOMATIC:
+            network_summary.append(_("  Network Configuration: Automatic"))
+        elif nic.type == NetworkInfo.NONE:
+            network_summary.append(_("  Network Configuration: None"))
+        else:
+            network_summary.append(_("  Manual Configuration: %s")
+                                   % nic.nic_name)
+            network_summary.append(_("    IP Address: %s") % nic.ip_address)
+            network_summary.append(_("    Netmask: %s") % nic.netmask)
+            if nic.gateway:
+                network_summary.append(_("    Router: %s") % nic.gateway)
+            if  nic.dns_address:
+                network_summary.append(_("    DNS: %s") % nic.dns_address)
+            if nic.domain:
+                network_summary.append(_("    Domain: %s") % nic.domain)
+        return network_summary
+    
+    def get_users(self):
+        '''Build a summary of the user information, and return it as a list
+        of strings
+        
+        '''
+        root = self.sysconfig.users[UserInfo.ROOT_IDX]
+        primary = self.sysconfig.users[UserInfo.PRIMARY_IDX]
+        user_summary = []
+        if not root.password:
+            user_summary.append(_("  Warning: No root password set"))
+        if primary.login_name:
+            user_summary.append(_("  Username: %s") % primary.login_name)
+        else:
+            user_summary.append(_("  No user account"))
+        return user_summary
+    
+    def get_disk_summary(self):
+        '''Return a string summary of the disk selection'''
+
+        doc = InstallEngine.get_instance().doc
+        disk = get_desired_target_disk(doc)
+        
+        format_dict = dict()
+        disk_string = [_("Disk: %(disk-size).1fGB %(disk-type)s")]
+        format_dict['disk-size'] = disk.disk_prop.dev_size.get(Size.gb_units)
+        format_dict['disk-type'] = disk.disk_prop.dev_type
+
+        if not disk.whole_disk:
+
+            part_data = get_solaris_partition(doc)
+
+            if part_data is not None:
+                disk_string.append(\
+                    _("Partition: %(part-size).1fGB %(part-type)s"))
+                format_dict['part-size'] = part_data.size.get(Size.gb_units)
+                part_type = libdiskmgt_const.PARTITION_ID_MAP[\
+                    part_data.part_type]
+                format_dict['part-type'] = part_type
+        
+            if part_data is None or not part_data.in_zpool:
+                slice_data = get_solaris_slice(doc)
+                disk_string.append(_("Slice %(slice-num)s: %(slice-size).1fGB"
+                                     " %(pool)s"))
+                format_dict['slice-num'] = slice_data.name
+                format_dict['slice-size'] = slice_data.size.get(Size.gb_units)
+                format_dict['pool'] = slice_data.in_zpool
+        
+        return "\n".join(disk_string) % format_dict
+    
+    def get_tz_summary(self):
+        '''Return a string summary of the timezone selection'''
+        timezone = self.sysconfig.system.tz_timezone
+        return _("Time Zone: %s") % timezone
+    
+    @staticmethod
+    def get_release():
+        '''Read in the release information from /etc/release'''
+        try:
+            try:
+                release_file = open("/etc/release")
+            except IOError:
+                LOGGER.warn("Could not read /etc/release")
+                release_file = None
+                release = RELEASE['release']
+            else:
+                release = release_file.readline()
+        finally:
+            if release_file is not None:
+                release_file.close()
+        return release.strip()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/test/test_disk_select.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,116 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+To run these tests:
+
+1) nightly -n developer.sh # build the gate
+2) export PYTHONPATH=${WS}/proto/root_i386/usr/snadm/lib:\
+${WS}/proto/root_i386/usr/lib/python2.6/vendor-packages
+3) pfexec python2.6 test_disk_select.py
+
+A single test may be run by specifying the test as an argument to
+step 3, e.g.:
+
+pfexec python2.6 test_disk_select.py OnActivateTest.test_on_activate_default
+
+Since the proto area is used for the PYTHONPATH, the gate must be rebuilt for
+these tests to pick up any changes in the tested code.
+
+'''
+
+import numbers
+import unittest
+
+import solaris_install.text_install.disk_selection as disk_selection
+import terminalui
+from terminalui.base_screen import BaseScreen
+from solaris_install.engine.test.engine_test_utils import \
+    get_new_engine_instance
+from solaris_install.target.size import Size
+
+terminalui.init_logging("test")
+BaseScreen.set_default_quit_text("test", "test", "test", "test")
+
+
+class MockCenterWin(object):
+    '''Mocks an InnerWindow as used by a MainWindow'''
+    
+    def add_paragraph(self, *args, **kwargs):
+        pass
+
+
+class MockAll(object):
+    '''Generic Mock object that 'never' raises an AttributeError'''
+    
+    def __getattr__(self, name):
+        return self
+    
+    def __call__(self, *args, **kwargs):
+        return None
+
+
+class MockTC(object):
+    ''' Mocks the target controller '''
+
+    minimum_target_size = Size("3gb")
+    recommended_target_size = Size("6gb")
+
+
+class DiskSelectTest(unittest.TestCase):
+    '''Test the DiskScreen'''
+    
+    def setUp(self):
+        self.engine = get_new_engine_instance()
+        self.screen = disk_selection.DiskScreen(MockAll(), MockTC())
+        self.screen.disk_win = MockAll()
+    
+    def test_size_line(self):
+        '''Ensure that DiskScreen._size_line is created and is a string after
+        calling get_size_line. Also verify that subsequent calls do not modify
+        the _size_line
+        
+        '''
+        self.assertTrue(self.screen._size_line is None)
+        self.screen.get_size_line()
+        self.assertTrue(isinstance(self.screen._size_line, basestring))
+        
+        obj = object()
+        self.screen._size_line = obj
+        self.screen.get_size_line()
+        self.assertTrue(obj is self.screen._size_line)
+    
+    def test_determine_size_data(self):
+        '''Ensure that recommended_size and minimum_size are accessible after
+        a call to determine_size_data(), and that they are numbers'''
+        
+        self.assertTrue(self.screen._recommended_size is None)
+        self.assertTrue(self.screen._minimum_size is None)
+        self.screen.determine_size_data()
+        self.assertTrue(isinstance(self.screen.minimum_size, Size))
+        self.assertTrue(isinstance(self.screen.recommended_size, Size))
+
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/test/test_disk_window.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,250 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+To run these tests:
+
+1) nightly -n developer.sh # build the gate
+2) export PYTHONPATH=${WS}/proto/root_i386/usr/snadm/lib:\
+${WS}/proto/root_i386/usr/lib/python2.6/vendor-packages
+3) python2.6 test_disk_window.py
+
+A single test may be run by specifying the test as an argument to step 3:
+python2.6 test_disk_window.py UpdateEditField.test_part_info_not_editable
+
+Since the proto area is used for the PYTHONPATH, the gate must be rebuilt for
+these tests to pick up any changes in the tested code.
+
+'''
+
+import unittest
+
+from solaris_install.target.physical import Disk
+from solaris_install.text_install.disk_window import DiskWindow
+import terminalui
+from terminalui.color_theme import ColorTheme
+from terminalui.window_area import WindowArea
+from terminalui.inner_window import InnerWindow
+
+
+terminalui.init_logging("test")
+
+
+class MockAll(object):
+    '''Generic Mock object that 'never' raises an AttributeError'''
+    
+    def __getattr__(self, name):
+        return self
+    
+    def __call__(self, *args, **kwargs):
+        return self
+
+
+class MockInnerWin(object):
+    '''Class for mock inner win'''
+    def __init__(self):
+        self.active_object = None
+        self.objects = []
+        self.text = None
+        self.scrollable_lines = 10
+
+    def activate_object(self):
+        '''Set active_object to 0'''
+        self.active_object = 0
+
+    def get_active_object(self):
+        '''Get active_object'''
+        if self.active_object is not None:
+            return self.objects[self.active_object]
+        else:
+            return None
+
+    def add_text(self, text=None, y_loc=0, x_loc=0):
+        '''Append passed in text to self.text'''
+        if self.text is None:
+            self.text = str(y_loc) + text
+        else:
+            self.text = self.text + str(y_loc) + text
+
+    def get_text(self):
+        '''Get the current value of self.text'''
+        return self.text
+
+
+class MockPartInfo(object):
+    '''Class for mock part info field'''
+    def __init__(self):
+        self.is_editable = True
+
+    def set_editable(self, editable=True):
+        '''Set editable property'''
+        self.is_editable = editable
+
+    def editable(self):
+        ''' get editable setting'''
+        return self.is_editable
+
+
+class MockEditField(object):
+    '''Class for mock edit field'''
+    def __init__(self):
+        self.active = False
+
+    def make_inactive(self, inactive=True):
+        ''' Set active property'''
+        self.active = not inactive
+
+
+class MockPartField(object):
+    '''Class for mock part field'''
+    def __init__(self):
+        self.edit_field = None
+        self.active_object = None
+        self.objects = []
+
+    def activate_object(self, tobject):
+        '''activate object'''
+        self.active_object = 0
+        self.edit_field = tobject
+        self.edit_field.make_inactive(False)
+
+    def get_active_object(self):
+        '''Get active_object'''
+        if self.active_object is not None:
+            return self.objects[self.active_object]
+        else:
+            return None
+
+
+def do_nothing(*args, **kwargs):
+    '''does nothing'''
+    pass
+
+
+class TestDiskWindow(unittest.TestCase):
+    '''Class to test DiskWindow'''
+    
+    def setUp(self):
+        '''unit test set up
+         Sets several functions to call do_nothing to allow
+         test execution in non-curses environment. Original
+         functions are saved so they can be later restored in
+         tearDown.
+
+        '''
+        self.inner_window_init_win = InnerWindow._init_win
+        self.disk_window_init_win = DiskWindow._init_win
+        self.inner_window_set_color = InnerWindow.set_color
+        InnerWindow._init_win = do_nothing
+        InnerWindow.set_color = do_nothing
+        DiskWindow._init_win = do_nothing
+        self.disk_win = DiskWindow(WindowArea(70, 70, 0, 0), Disk("MockDisk"),
+                                   color_theme=ColorTheme(force_bw=True),
+                                   window=MockAll())
+        self.edit_field = MockEditField()
+        self.part_field = MockPartField()
+        self.part_info = MockPartInfo()
+        self.inner_win = MockInnerWin()
+        self.disk_win.objects = []
+        self.part_field.objects = []
+
+    def tearDown(self):
+        '''unit test tear down
+        Functions originally saved in setUp are restored to their
+        original values. 
+        '''
+        InnerWindow._init_win = self.inner_window_init_win
+        InnerWindow.set_color = self.inner_window_set_color
+        DiskWindow._init_win = self.disk_window_init_win
+        self.disk_win = None
+        self.edit_field = None
+        self.part_field = None
+        self.part_info = None
+        self.inner_win = None
+    
+
+class UpdateEditField(TestDiskWindow):
+    '''Tests for _update_edit_field'''
+
+    def test_part_info_not_editable(self):
+        '''Ensure edit field updated correctly if part_info not editable'''
+        self.part_info.set_editable(False)
+        self.edit_field.make_inactive(False)
+        self.part_field.activate_object(self.edit_field)
+        self.part_field.objects.append(self.edit_field)
+        
+        self.disk_win._update_edit_field(self.part_info, self.part_field,
+                                         self.edit_field)
+        self.assertFalse(self.edit_field.active)
+        self.assertEquals(len(self.part_field.objects), 0)
+        self.assertTrue(self.part_field.active_object is None)
+
+    def test_part_info_editable_no_active_win(self):
+        '''Ensure edit field not updated if no active right/left win'''
+        self.part_info.set_editable(True)
+        self.edit_field.make_inactive(True)
+        self.assertTrue(self.part_field.active_object is None)
+        self.disk_win._update_edit_field(self.part_info, self.part_field,
+                                         self.edit_field)
+        self.assertTrue(self.part_field.active_object is None)
+        self.assertFalse(self.edit_field.active)
+
+    def test_part_info_editable_active_win_no_active_obj(self):
+        '''Ensure edit field updated correctly if active obj not part_field'''
+        self.part_info.set_editable(True)
+        self.edit_field.make_inactive(True)
+        self.disk_win.objects.append(self.inner_win)
+        self.disk_win.active_object = 0
+        my_part_field = MockPartField()
+        self.inner_win.objects.append(my_part_field)
+        self.inner_win.active_object = 0
+
+        self.assertTrue(self.inner_win.get_active_object() is my_part_field)
+        self.assertTrue(self.part_field.active_object is None)
+
+        self.disk_win._update_edit_field(self.part_info, self.part_field,
+                                         self.edit_field)
+        self.assertTrue(self.part_field.active_object is None)
+        self.assertFalse(self.edit_field.active)
+
+    def test_part_info_editable_active_win(self):
+        '''Ensure edit field updated correctly if part_info is editable'''
+        self.part_info.set_editable(True)
+        self.edit_field.make_inactive(True)
+        self.disk_win.objects.append(self.inner_win)
+        self.disk_win.active_object = 0
+        self.inner_win.objects.append(self.part_field)
+        self.inner_win.active_object = 0
+
+        self.assertEquals(self.disk_win.active_object, 0)
+        self.assertTrue(self.part_field.active_object is None)
+
+        self.disk_win._update_edit_field(self.part_info, self.part_field,
+                                         self.edit_field)
+        self.assertEquals(self.part_field.active_object, 0)
+        self.assertTrue(self.edit_field.active)
+        
+
+if __name__ == '__main__':
+    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/test/test_text_install.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,86 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+To run these tests, see the instructions in usr/src/tools/tests/README.
+Remember that since the proto area is used for the PYTHONPATH, the gate
+must be rebuilt for these tests to pick up any changes in the tested code.
+
+'''
+
+
+import unittest
+
+import solaris_install.text_install as text_install
+
+
+class TestTextInstall(unittest.TestCase):
+    
+    def test_reboot_cmds(self):
+        '''_reboot_cmds(x86) returns expected list of potential reboot commands
+        * /usr/sbin/reboot -f -- rpool/ROOT/<BE>
+        * /usr/sbin/reboot
+        
+        '''
+        cmds = text_install._reboot_cmds(True)
+        
+        # First command should be: /usr/sbin/reboot -f -- rpool/ROOT/<BE>
+        self.assertEqual(cmds[0][0], text_install.REBOOT)
+        self.assertEqual(cmds[0][1], "-f")
+        self.assertEqual(cmds[0][2], "--")
+        # Last item will be something like: rpool/ROOT/active-on-reboot-BE
+        # Just ensure that there's something there
+        self.assertTrue(cmds[0][3])
+        self.assertEqual(len(cmds[0]), 4)
+        
+        # Second command should be just: /usr/sbin/reboot
+        self.assertEqual(cmds[1][0], text_install.REBOOT)
+        self.assertEqual(len(cmds[1]), 1)
+        
+        self.assertEqual(len(cmds), 2)
+    
+    def test_reboot_cmds_sparc(self):
+        '''_reboot_cmds(sparc) returns expected list of reboot commands
+        (SPARC requires the additional "-Z")
+        * /usr/sbin/reboot -f -- -Z rpool/ROOT/<BE>
+        * /usr/sbin/reboot
+        
+        '''
+        cmds = text_install._reboot_cmds(False)
+        
+        # First command should be: /usr/sbin/reboot -f -- -Z rpool/ROOT/<BE>
+        self.assertEqual(cmds[0][0], text_install.REBOOT)
+        self.assertEqual(cmds[0][1], "-f")
+        self.assertEqual(cmds[0][2], "--")
+        self.assertEqual(cmds[0][3], "-Z")
+        # Last item will be something like: rpool/ROOT/active-on-reboot-BE
+        # Just ensure that there's something there
+        self.assertTrue(cmds[0][4])
+        self.assertEqual(len(cmds[0]), 5)
+        
+        # Second command should be just: /usr/sbin/reboot
+        self.assertEqual(cmds[1][0], text_install.REBOOT)
+        self.assertEqual(len(cmds[1]), 1)
+        
+        self.assertEqual(len(cmds), 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/text-install	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,27 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+import solaris_install.text_install as text_install
+
+text_install.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/ti_install.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,375 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Installation engine for Text Installer
+'''
+
+import curses
+import os
+import logging
+import datetime
+import platform
+import shutil
+
+from select import select
+
+import osol_install.errsvc as errsvc
+import osol_install.liberrsvc as liberrsvc
+import solaris_install.sysconfig as sysconfig
+
+from libbe_py import beUnmount
+from osol_install.libzoneinfo import tz_isvalid
+from solaris_install import Popen
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.sysconfig.profile import ConfigProfile
+from solaris_install.target.controller import TargetController
+from solaris_install.target.size import Size
+from solaris_install.target.libbe.be import be_unmount
+from solaris_install.text_install import TRANSFER_PREP, \
+    TARGET_INIT, CLEANUP_CPIO_INSTALL
+from solaris_install.text_install import ti_install_utils as ti_utils
+from solaris_install.text_install.progress import InstallProgressHandler
+from solaris_install.text_install.ti_target_utils import \
+    get_desired_target_zpool, get_desired_target_be, get_solaris_slice, \
+    ROOT_POOL
+from solaris_install.transfer.info import Software, IPSSpec
+
+LOGGER = None
+
+#
+# RTC command to run
+#
+RTC_CMD = "/usr/sbin/rtc"
+
+#
+# Program used for calling the C ICT functions.
+# When all the C-based ICT functions are converted to Python (bug 6256),
+# this can be removed.
+#
+ICT_PROG = "/opt/install-test/bin/ict_test"
+
+#
+# Handle for accessing the InstallStatus class
+#
+INSTALL_STATUS = None
+
+
+def exec_callback(status, failed_cp):
+
+    LOGGER.debug("exec_callback parameters:")
+    LOGGER.debug("status: %s", status)
+    LOGGER.debug("failed_cp: %s", failed_cp)
+
+    # check the result of execution
+    INSTALL_STATUS.exec_status = status
+
+    INSTALL_STATUS.stop_report_status()
+
+    if status == InstallEngine.EXEC_FAILED:
+        for fcp in failed_cp:
+            err_data = (errsvc.get_errors_by_mod_id(fcp))[0]
+            LOGGER.error("Checkpoint %s failed" % fcp)
+            err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION]
+            LOGGER.error(err)
+
+
+class InstallStatus(object):
+    '''Stores information on the installation progress, and provides a
+    hook for updating the screen.
+    
+    '''
+
+    def __init__(self, screen, update_status_func):
+        '''screen and update_status_func are values passed in from
+        the main app
+        
+        '''
+
+        self.screen = screen
+        self.update_status_func = update_status_func
+        self.prog_handler = InstallProgressHandler(LOGGER)
+        self.prog_handler.startProgressServer()
+        self.exec_status = InstallEngine.EXEC_SUCCESS
+        LOGGER.addHandler(self.prog_handler)
+
+    def report_status(self):
+        '''Update the install status. Also checks the quit_event to see
+        if the installation should be aborted.
+        
+        '''
+        try:
+            processing_quit = False
+            while self.prog_handler.server_up:
+                if not processing_quit:
+                    ready_to_read = select([self.prog_handler.engine_skt],
+                                           [], [], 0.25)[0]
+                    if len(ready_to_read) > 0:
+                        percent, msg = self.prog_handler.parseProgressMsg(\
+                            ready_to_read[0])
+                        LOGGER.debug("message = %s", msg)
+                        LOGGER.debug("percent = %s", percent)
+                        self.update_status_func(float(percent), msg)
+
+                # check whether F9 is pressed
+                input_key = self.screen.main_win.getch()
+                if input_key == curses.KEY_F9:
+                    LOGGER.info("User selected Quit")
+                    really_quit = self.screen.confirm_quit()
+                    if really_quit:
+                        LOGGER.info("User confirmed Quit")
+                        engine = InstallEngine.get_instance()
+                        engine.cancel_checkpoints()
+                        processing_quit = True
+        except Exception, e:
+            LOGGER.exception("progressServer Error")
+
+    def stop_report_status(self):
+        self.prog_handler.stopProgressServer()
+
+
+def do_ti_install(install_data, screen, update_status_func):
+    '''Installation engine for text installer.
+       Raises InstallationError for any error occurred during install.
+
+    '''
+
+    sysconfig_profile = sysconfig.profile.from_engine()
+
+    #
+    # The following information is needed for installation.
+    # Make sure they are provided before even starting
+    #
+        
+    # timezone
+    timezone = sysconfig_profile.system.tz_timezone
+    LOGGER.debug("time zone: %s", timezone)
+        
+    # Validate the value specified for timezone
+    if not tz_isvalid(timezone):
+        LOGGER.error("Timezone value specified (%s) is not valid", timezone)
+        raise ti_utils.InstallationError
+
+    # Compute the time to set here.  It will be set after the rtc 
+    # command is run, if on x86.
+    install_time = datetime.datetime.now() + \
+        sysconfig_profile.system.time_offset
+        
+    if platform.processor() == "i386":
+        #
+        # At this time, the /usr/sbin/rtc command does not work in alternate
+        # root.  It hard codes to use /etc/rtc_config.
+        # Therefore, we set the value for rtc_config in the live environment
+        # so it will get copied over to the alternate root.
+        #
+        cmd = [RTC_CMD, "-z", timezone]
+        Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                         logger=LOGGER)
+
+        cmd = [RTC_CMD, "-c"]
+        Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                         logger=LOGGER)
+
+    #
+    # Set the system time to the time specified by the user
+    # The value to set the time to is computed before the "rtc" commands.
+    # This is required because rtc will mess up the computation of the
+    # time to set.  The rtc command must be run before the command
+    # to set time.  Otherwise, the time that we set will be overwritten
+    # after running /usr/sbin/rtc.
+    #
+    cmd = ["/usr/bin/date", install_time.strftime("%m%d%H%M%y")]
+    Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                     logger=LOGGER)
+
+    hostname = sysconfig_profile.system.hostname
+    LOGGER.debug("hostname: " + hostname)
+    
+    engine = InstallEngine.get_instance()
+    doc = engine.doc
+    solaris_slice = get_solaris_slice(doc)
+    if solaris_slice is None:
+        raise ti_utils.InstallationError("Unable to find solaris slice")
+    inst_device_size = solaris_slice.size
+
+    LOGGER.info("Installation Device Size: %sMB", inst_device_size)
+        
+    minimum_size = screen.tc.minimum_target_size
+    LOGGER.info("Minimum required size: %s", minimum_size)
+    if (inst_device_size < minimum_size):
+        LOGGER.error("Size of device specified for installation "
+                     "is too small")
+        LOGGER.error("Size of install device: %s", inst_device_size)
+        LOGGER.error("Minimum required size: %s", minimum_size)
+        raise ti_utils.InstallationError
+    
+    recommended_size = screen.tc.recommended_target_size
+    LOGGER.info("Recommended size: %s", recommended_size)
+    if (inst_device_size < recommended_size):
+        # Warn users that their install target size is not optimal
+        # Just log the warning, but continue with the installation.
+        LOGGER.warning("Size of device specified for installation is "
+                       "not optimal") 
+        LOGGER.warning("Size of install device: %s", inst_device_size)
+        LOGGER.warning("Recommended size: %s", recommended_size)
+
+    (swap_type, swap_size, dump_type, dump_size) = \
+        screen.tc.calc_swap_dump_size(minimum_size, inst_device_size,
+                                      swap_included=True)
+
+    desired_zpool = get_desired_target_zpool(doc)
+    if (swap_type == TargetController.SWAP_DUMP_ZVOL):
+        swap_zvol = desired_zpool.add_zvol("swap", \
+            swap_size.get(Size.mb_units), Size.mb_units, use="swap")
+
+    if (dump_type == TargetController.SWAP_DUMP_ZVOL):
+        dump_zvol = desired_zpool.add_zvol("dump", \
+            dump_size.get(Size.mb_units), Size.mb_units, use="dump")
+
+    LOGGER.info("Swap type: %s", swap_type)
+    LOGGER.info("Swap size: %s", swap_size)
+    LOGGER.info("Dump type: %s", dump_type)
+    LOGGER.info("Dump size: %s", dump_size)
+
+    # Specify for the shared datasets <root_pool>/export and 
+    # <root_pool>/export/home be created.  We will specify
+    # a mountpoint for <root_pool>/export dataset.
+    # We must not specify a mountpoint for <root_pool>/export/home.
+    # It should inherit the mountpoint from <root_pool>/export.
+
+    desired_zpool.add_filesystem("export", mountpoint="/export")
+    desired_zpool.add_filesystem("export/home")
+
+    # Add the list of packages to be removed after the install to the DOC
+    pkg_remove_list = ['pkg:/system/install/media/internal',
+                       'pkg:/system/install/text-install']
+    pkg_spec = IPSSpec(action=IPSSpec.UNINSTALL, contents=pkg_remove_list)
+    pkg_rm_node = Software(CLEANUP_CPIO_INSTALL, type="IPS")
+    pkg_rm_node.insert_children(pkg_spec)
+    doc.volatile.insert_children(pkg_rm_node)
+
+    # execute the prepare transfer checkpoint.  This checkpoint must
+    # be executed by itself, before executing any of the transfer
+    # related checkpoints.  The transfer checkpoints requires
+    # data setup from the prepare transfer checkpoint.
+
+    (status, failed_cp) = engine.execute_checkpoints(\
+        start_from=TRANSFER_PREP, pause_before=TARGET_INIT)
+
+    if status != InstallEngine.EXEC_SUCCESS:
+        err_data = (errsvc.get_errors_by_mod_id(TRANSFER_PREP))[0]
+        LOGGER.error("%s checkpoint failed" % TRANSFER_PREP)
+        err = err_data.error_data[liberrsvc.ES_DATA_EXCEPTION]
+        LOGGER.error(err)
+        raise ti_utils.InstallationError("Failed to execute checkpoint "
+                                         "%s", TRANSFER_PREP)
+
+    global INSTALL_STATUS
+    INSTALL_STATUS = InstallStatus(screen, update_status_func)
+
+    LOGGER.debug("Executing rest of checkpoints")
+
+    engine.execute_checkpoints(callback=exec_callback, \
+        dry_run=install_data.no_install_mode)
+
+    INSTALL_STATUS.report_status()
+
+    if INSTALL_STATUS.exec_status is InstallEngine.EXEC_CANCELED:
+        raise ti_utils.InstallationCanceledError("User selected cancel.")
+
+    if INSTALL_STATUS.exec_status is InstallEngine.EXEC_FAILED:
+        raise ti_utils.InstallationError("Failed executing checkpoints")
+
+    if install_data.no_install_mode:
+        # all subsequent code depends on the install target being
+        # setup, so, can not execute them.  
+        return
+
+    new_be = get_desired_target_be(doc)
+    install_mountpoint = new_be.mountpoint
+
+    #
+    # associate system hostname with loopback address in hosts(4) file.
+    # This is just a temporary solution until CR6996436 is fixed.
+    # Once it happens, it will be taken care by svc:/network/install smf(5)
+    # service and this ICT task can be removed.
+    #
+    cmd = [ICT_PROG, "ict_set_hosts", install_mountpoint, hostname]
+    Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                     logger=LOGGER)
+
+    # If swap was created, add appropriate entry to <target>/etc/vfstab
+    LOGGER.debug("install mountpoint: %s", install_mountpoint)
+    LOGGER.debug("new_be: %s", new_be)
+    screen.tc.setup_vfstab_for_swap(ROOT_POOL, install_mountpoint)
+
+    post_install_cleanup(install_data)
+
+
+def post_install_cleanup(install_data):
+    '''Do final cleanup to prep system for first boot '''
+
+    # make sure we are not in the alternate root.
+    # Otherwise, be_unmount() fails
+    os.chdir("/root")
+
+    doc = InstallEngine.get_instance().doc
+    new_be = get_desired_target_be(doc)
+
+    # Transfer the log file
+    final_log_loc = new_be.mountpoint + install_data.log_final
+    LOGGER.debug("Copying %s to %s" % (install_data.log_location,
+                  final_log_loc))
+    try:
+        shutil.copyfile(install_data.log_location, final_log_loc)
+    except (IOError, OSError), err: 
+        LOGGER.error("Failed to copy %s to %s" % (install_data.log_location,
+                      install_data.log_final))
+        LOGGER.exception(err)
+        raise ti_utils.InstallationError
+
+    be_unmount(new_be.name)
+
+
+def perform_ti_install(install_data, screen, update_status_func):
+    '''Wrapper to call the do_ti_install() function.
+       Sets the variable indicating whether the installation is successful or
+       not.
+
+    '''
+
+    global LOGGER
+    LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+    try:
+        do_ti_install(install_data, screen, update_status_func)
+        install_data.install_succeeded = True
+        LOGGER.info("Install completed successfully")
+    except ti_utils.InstallationCanceledError:
+        install_data.install_succeeded = False
+        LOGGER.info("Install canceled by user.")
+    except Exception, ex:
+        LOGGER.exception("Install FAILED.")
+        install_data.install_succeeded = False
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/ti_install_utils.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Utility functions
+'''
+
+
+class InstallationError(Exception):
+    '''Some sort of error occurred during installation.  The exact
+       cause of the error should have been logged.  So, this
+       just indicates that something is wrong
+
+    '''
+    pass
+
+
+class InstallationCanceledError(Exception):
+    '''User selected to cancel the installation.
+
+    '''
+    pass
+
+
+class InstallData(object):
+    '''
+    This object is used for storing information that need to be
+    shared between different components of the Text Installer
+    '''
+
+    def __init__(self):
+        self.install_succeeded = False
+        self.log_location = None
+        self.log_final = None
+        self.no_install_mode = False
+
+    def __str__(self):
+        result = ["Install Data:"]
+        result.append("Install Completed - %s" % str(self.install_succeeded))
+        result.append("Log Location - %s" % str(self.log_location))
+        result.append("Log Final - %s" % str(self.log_final))
+        result.append("No Install Mode - %s" % (self.no_install_mode))
+        return "\n".join(result)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/ti_target_utils.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,1260 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+'''
+Functions for mapping UI objects and DOC objects.
+'''
+
+import logging
+import platform
+
+import osol_install.errsvc as errsvc
+import osol_install.liberrsvc as liberrsvc
+from solaris_install.engine import InstallEngine
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.target import Target
+from solaris_install.target.controller import TargetController, \
+    DEFAULT_VDEV_NAME, DEFAULT_ZPOOL_NAME
+from solaris_install.target.libadm.const import FD_NUMPART as MAX_PRIMARY_PARTS
+from solaris_install.target.libadm.const import MAX_EXT_PARTS
+from solaris_install.target.libadm.const import V_BACKUP, V_ROOT
+from solaris_install.target.libdiskmgt import const as libdiskmgt_const
+from solaris_install.target.logical import Zpool, BE
+from solaris_install.target.physical import Disk, Partition, Slice, \
+    BACKUP_SLICE, BOOT_SLICE
+from solaris_install.target.shadow.physical import ShadowPhysical
+from solaris_install.target.size import Size
+
+
+ROOT_POOL = DEFAULT_ZPOOL_NAME
+
+PART_TYPE_SOLARIS = 191 #191 is type "solaris"
+BACKUP_SLICE_TEXT = "backup"
+UNUSED_TEXT = "Unused"
+EXTENDED_TEXT = "Extended"
+
+UI_PRECISION = "0.05gb"
+
+UI_TYPE_IN_USE = "UI Object In-use" # partition/slice in use
+UI_TYPE_EMPTY_SPACE = "UI Object EMPTY"   # unused components
+UI_TYPE_NOT_USED = "UI Object not-in-use" 
+
+MAX_VTOC = "2tb"
+
+# Can not use the V_NUMPAR value defined in solaris_install.target.libadm.const
+# because it returns 16 slices for x86.  Define the number of slices
+# here so it is 8 for both x86 and sparc.
+MAX_SLICES = 8 
+
+LOGGER = None
+
+
+def get_desired_target_disk(doc):
+    ''' Returns the first disk in the desired target subtree of the DOC.  '''
+
+    desired_root = doc.persistent.get_descendants(name=Target.DESIRED, \
+        class_type=Target, max_depth=2, not_found_is_err=True)[0]
+
+    return(desired_root.get_descendants(class_type=Disk,
+                                        not_found_is_err=True)[0])
+
+
+def get_desired_target_zpool(doc):
+    ''' Returns the first zpool in the desired target subtree of the DOC.  '''
+
+    desired_root = doc.persistent.get_descendants(name=Target.DESIRED, \
+        class_type=Target, max_depth=2, not_found_is_err=True)[0]
+
+    return(desired_root.get_descendants(name=ROOT_POOL, class_type=Zpool,
+                                        not_found_is_err=True)[0])
+
+
+def get_desired_target_be(doc):
+    ''' Returns the first BE in the desired target subtree of the DOC.  '''
+    desired_root = doc.persistent.get_descendants(name=Target.DESIRED, \
+        class_type=Target, max_depth=2, not_found_is_err=True)[0]
+
+    return(desired_root.get_descendants(class_type=BE,
+                                        not_found_is_err=True)[0])
+
+
+def get_solaris_partition(doc):
+    '''Returns the partition with type "solaris", if it exists '''
+
+    desired_disk = get_desired_target_disk(doc)
+
+    all_partitions = desired_disk.get_children(class_type=Partition)
+
+    if not all_partitions:
+        return None
+
+    for part in all_partitions:
+        if part.is_solaris:
+            return part
+
+    return None
+
+
+def get_solaris_slice(doc):
+    '''Finds the slice that have the root pool for installation, if exists '''
+
+    if platform.processor() == "i386":
+        desired_part = get_solaris_partition(doc)
+    else:
+        desired_part = get_desired_target_disk(doc)
+
+    all_slices = desired_part.get_children(class_type=Slice)
+
+    if not all_slices:
+        return None
+
+    for slice in all_slices:
+        if slice.in_zpool == ROOT_POOL:
+            return slice
+
+    return None
+
+
+def find_discovered_disk(disk, doc):
+    ''' Search for the disk that's the same as the given disk
+        found during Target Discovery
+    
+        Returns the object in the discovered target tree of the DOC.
+ 
+        Raise RuntimeError() if disk is not found in discovered target.
+    '''
+    disc_root = doc.persistent.get_descendants(name=Target.DISCOVERED, \
+        class_type=Target, max_depth=2, not_found_is_err=True)[0]
+    discovered_disks = disc_root.get_children(class_type=Disk)
+
+    if not discovered_disks:
+        raise RuntimeError("Disk not found in discovered target")
+
+    # look through all the disks, and find the one matching this one.
+    # The "devid" string is compared to identify
+    for disc_disk in discovered_disks:
+        if disc_disk.devid == disk.devid:
+            return disc_disk
+
+    # A disk should be found, so, it's an error to be here
+    raise RuntimeError("Disk not found in discovered target")
+
+
+def discovered_obj_was_empty(obj, doc):
+    '''Determine whether the given disk was empty when it was discovered '''
+
+    discovered_obj = None
+    if isinstance(obj, Disk):
+        discovered_disk = find_discovered_disk(obj, doc)
+        parts = discovered_disk.get_children(class_type=Partition)
+        if (parts is not None) and (len(parts) > 0):
+            return False
+        discovered_obj = discovered_disk
+    else:
+        # find the discovered partition
+        discovered_disk = find_discovered_disk(obj.parent, doc)
+
+        parts = discovered_disk.get_children(class_type=Partition)
+        if not parts:
+            raise RuntimeError("Discovered disk should have partitions.  "
+                               "However, no partition is found.")
+        discovered_obj = get_part_by_num(obj.name, parts)
+        if discovered_obj is None:
+            raise RuntimeError("Discovered disk should have partitions %s.  "
+                               "However, unable to find the partition.",
+                               obj.name)
+            
+    slices = discovered_obj.get_children(class_type=Slice)
+    if not slices:
+        return False
+
+    return True
+
+
+def perform_final_validation(doc):
+
+    LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+    LOGGER.info("Going to perform final validation of desired target")
+
+    desired_root = doc.persistent.get_descendants(name=Target.DESIRED,
+                                                  class_type=Target,
+                                                  max_depth=2,
+                                                  not_found_is_err=True)[0]
+
+    LOGGER.debug(str(desired_root))
+
+    errsvc.clear_error_list()
+
+    if not desired_root.final_validation():
+        all_errors = errsvc.get_all_errors()
+
+        for err in all_errors:
+
+            if not isinstance(err.error_data[liberrsvc.ES_DATA_EXCEPTION],
+                              ShadowPhysical.SliceInUseError):
+                LOGGER.error("Error module ID: %s.. error type: %s" % \
+                             (err.get_mod_id(), str(err.get_error_type())))
+                LOGGER.error("Error class: %r",
+                             err.error_data[liberrsvc.ES_DATA_EXCEPTION])
+                LOGGER.error("Exception value: %s",
+                             err.error_data[liberrsvc.ES_DATA_EXCEPTION].value)
+                raise ValueError("Desired target doesn't pass "
+                                 "final validation")
+            else:
+                LOGGER.debug("SliceInUseError is OK")
+                LOGGER.debug("Error module ID: %s.. error type: %s" % \
+                             (err.get_mod_id(), str(err.get_error_type())))
+                LOGGER.debug("Exception value: %s",
+                             err.error_data[liberrsvc.ES_DATA_EXCEPTION].value)
+    else:
+        LOGGER.debug("No error from final validation")
+
+
+def dump_doc(msg): 
+
+    if not LOGGER.isEnabledFor(logging.DEBUG):
+        return
+
+    LOGGER.debug(msg)
+    doc = InstallEngine.get_instance().doc
+    disk = get_desired_target_disk(doc)
+    LOGGER.debug(str(disk))
+
+
+def name_sort(a, b):
+    return cmp(a.name, b.name)
+
+
+def size_sort(a, b):
+    return cmp(a.size, b.size)
+
+
+def get_part_by_num(number, existing_parts):
+    ''' Return the partition/slice that have the given index.
+        If none of the existing partition/slice have the given
+        index, None will be returned.
+    '''
+    for ep in existing_parts:
+        if str(ep.name) == str(number):
+            return ep
+    return None
+
+
+def add_missed_parts(numbers, existing_parts, gaps, min_size, all_parts,
+                     check_extended=False, adding_logical=False):
+
+    have_extended = False
+
+    LOGGER.debug("Enter add_missed_parts")
+    LOGGER.debug("numbers: %s", numbers)
+    LOGGER.debug("Existing parts: %s", existing_parts)
+    LOGGER.debug("Gaps: %s", gaps)
+    LOGGER.debug("Min size: %s", min_size)
+
+    for num in numbers:
+        part = get_part_by_num(num, existing_parts)
+        if part is not None:
+            all_parts[num].doc_obj = part
+            LOGGER.debug(str(all_parts[num].doc_obj))
+            if check_extended:
+                # check whether this is an extended partition
+                if part.is_extended:
+                    have_extended = True
+        elif len(gaps) > 0:
+            # some space is still left 
+            if (gaps[-1]).size >= min_size:
+                # see if the largest one is big enough
+                one_gap = gaps.pop()
+                empty_space = EmptySpace(num, one_gap.start_sector,
+                                         one_gap.size)
+                all_parts[num].empty_space_obj = empty_space
+            else:
+                if adding_logical:
+                    # do not create empty space objects for logical partitions
+                    return None
+                empty_space = EmptySpace(num, 0, Size("0gb"))
+                all_parts[num].empty_space_obj = empty_space
+        else:
+            if adding_logical:
+                # do not create empty space objects for logical partitions
+                return None
+            # no space is left.  Create 0 size empty spaces
+            empty_space = EmptySpace(num, 0, Size("0gb"))
+            all_parts[num].empty_space_obj = empty_space
+
+    return have_extended
+
+
+class EmptySpace(object):
+
+    def __init__(self, name, start_sector, size):
+        self.name = name
+        self.start_sector = start_sector
+        self.size = size
+
+
+class UIDisk(object):
+
+    ''' Object used to keep track of disk related information for UI '''
+
+    def __init__(self, target_controller, parent=None, doc_obj=None):
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        if doc_obj is None:
+            raise ValueError("doc_obj for UIDisk is needed")
+        self.doc_obj = doc_obj
+        self.tc = target_controller
+        self.all_parts = list()
+        self.have_logical = False
+
+        if platform.processor() == "i386":
+            max_all_parts = MAX_PRIMARY_PARTS + MAX_EXT_PARTS + 1
+            for i in range(max_all_parts):
+                part = UIPartition(self.tc, parent=self)
+                self.all_parts.append(part)
+        else:
+            max_all_parts = MAX_SLICES
+            for i in range(max_all_parts):
+                part = UISlice(self.tc, parent=self)
+                self.all_parts.append(part)
+
+    def get_parts_in_use(self):
+        in_use_parts = []
+        for part in self.all_parts:
+            if (part.ui_type == UI_TYPE_IN_USE) or \
+               (part.ui_type == UI_TYPE_EMPTY_SPACE):
+                in_use_parts.append(part)
+
+        return in_use_parts  
+
+    def add_unused_parts(self, no_part_ok=False):
+        '''On x86: Sort through the logical and non-logical partitions and
+        find the largest gaps. For non-logical partitions, create additional
+        Unused partitions such that the number of
+        non-logical partitions == MAX_STANDARD_PARTITIONS. For logical
+        partitions, create additional Unused partitions such that the number of
+        logical partitions == MAX_LOGICAL_PARTITIONS
+
+        On SPARC: Create Unused slices in the largest gaps of empty space,
+        so that there are exactly 8 slices
+
+        For non-logical partitions, gaps smaller than 1 GB are ignored.
+        For logical partitions, gaps smaller than 0.1 GB are ignored.
+
+        '''
+
+        # reset everything to be unused
+        for part in self.all_parts:
+            part.ui_type = UI_TYPE_NOT_USED
+
+        existing_parts = self.doc_obj.get_children(class_type=Partition)
+
+        if not existing_parts:
+            # should have some slices
+            existing_parts = self.doc_obj.get_children(class_type=Slice)
+            if not existing_parts:
+                if no_part_ok:
+                    if platform.processor() == "i386":
+                        numbers = range(1, MAX_PRIMARY_PARTS + 1)
+                        use_partitions = True
+                    else:
+                        numbers = range(MAX_SLICES)
+                        use_partitions = False
+                else:
+                    raise ValueError("Cannot determine if this disk has " \
+                                     "partitions or slices")
+                existing_parts = []
+            else:
+                use_partitions = False
+                numbers = range(MAX_SLICES)
+
+        else:
+            # have partitions
+            use_partitions = True
+            numbers = range(1, MAX_PRIMARY_PARTS + 1)
+
+        LOGGER.debug("num_existing parts = %d", len(existing_parts))
+
+        existing_parts.sort(name_sort)
+
+        LOGGER.debug(str(self.doc_obj))
+
+        existing_gaps = self.doc_obj.get_gaps()
+
+        # sort the gaps by size, smallest gaps first.  When using
+        # the existing_gaps list, the largest gaps is used first, they
+        # will be popped off the end of the list.
+        existing_gaps.sort(size_sort)
+
+        self.have_logical = add_missed_parts(numbers, existing_parts, \
+            existing_gaps, Size("1" + Size.gb_units), self.all_parts, \
+            check_extended=use_partitions)
+
+        if use_partitions == False:
+            # If there's a backup slice, move it to end of the list for display
+            slice2 = self.all_parts[2]
+            if slice2.ui_type == UI_TYPE_IN_USE:
+                self.all_parts.remove(slice2)
+                self.all_parts.append(slice2)
+
+        if LOGGER.isEnabledFor(logging.DEBUG):
+            for part in self.all_parts:
+                try:
+                    LOGGER.debug("After fill unused...%s: %s..size=%s",
+                                 str(part.name), part.get_description(),
+                                 str(part.size))
+                except Exception, ex:
+                    LOGGER.debug("after fill unused...%s", ex)
+                    pass
+
+        if not self.have_logical:
+            return
+
+        first_logical = MAX_PRIMARY_PARTS + 1
+        numbers = range(first_logical, first_logical + MAX_EXT_PARTS)
+
+        logical_part_gaps = self.doc_obj.get_logical_partition_gaps()
+
+        # sort the gaps by size, smallest gaps first.  When using
+        # the existing_gaps list, the largest gaps is used first, they
+        # will be popped off the end of the list.
+        logical_part_gaps.sort(size_sort)
+
+        # Fill in all the missing logical if necessary
+        add_missed_parts(numbers, existing_parts, logical_part_gaps,
+                         Size("0.1" + Size.gb_units), self.all_parts,
+                         adding_logical=True)
+        
+    @property
+    def name(self):
+        return self.doc_obj.name
+
+    @property
+    def size(self):
+        return self.doc_obj.disk_prop.dev_size
+
+    def get_extended_partition(self):
+        if not self.have_logical:
+            return None
+
+        for part in self.all_parts:
+            if part.ui_type == UI_TYPE_IN_USE and part.doc_obj.is_extended:
+                return part
+        return None
+
+    def get_logicals(self):
+        '''Retrieve all the logicals on this disk'''
+        logicals = []
+        for part in self.all_parts:
+            if ((part.ui_type == UI_TYPE_IN_USE) or \
+                (part.ui_type == UI_TYPE_EMPTY_SPACE)) and \
+                (part.is_logical()):
+                logicals.append(part)
+        return logicals
+
+    def get_standards(self):
+        standards = []
+        for part in self.all_parts:
+            if ((part.ui_type == UI_TYPE_IN_USE) or \
+                (part.ui_type == UI_TYPE_EMPTY_SPACE)) and \
+                (not part.is_logical()):
+                standards.append(part)
+        return standards
+
+    def get_solaris_data(self):
+        if platform.processor() == "i386":
+            for part in self.all_parts:
+                if part.ui_type == UI_TYPE_IN_USE and part.doc_obj.is_solaris:
+                    return part
+        else:
+            for part in self.all_parts:
+                if (part.ui_type == UI_TYPE_IN_USE) and \
+                    (part.doc_obj.in_zpool == ROOT_POOL):
+                    return part
+
+        return None
+        
+    @property
+    def discovered_doc_obj(self):
+        ''' Search for the same disk found during Target Discovery
+    
+            Returns the object in the discovered target tree of the DOC.
+ 
+            Raise RuntimeError() if disk is not found in discovered target.
+        '''
+        doc = InstallEngine.get_instance().doc
+        return(find_discovered_disk(self.doc_obj, doc))
+
+
+class UIPartition(object):
+    ''' Object used to keep track of partition related information for UI '''
+
+    SOLARIS = 0xBF
+    EXT_DOS = 0x05
+    FDISK_EXTLBA = 0x0f
+    UNUSED = None
+
+    EDITABLE_PART_TYPES = [SOLARIS,
+                           EXT_DOS,
+                           FDISK_EXTLBA]
+
+    KNOWN_LOGIC_TYPES = [UNUSED, SOLARIS]
+    KNOWN_PART_TYPES = [UNUSED, SOLARIS, EXT_DOS] 
+    
+    def __init__(self, target_controller, parent=None, doc_obj=None):
+
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        self._doc_obj = None
+        self._empty_space_obj = None
+        self.tc = target_controller
+        self.all_parts = list()
+        self._unused_parts_added = False
+        self.parent = parent
+        self.ui_type = UI_TYPE_NOT_USED
+        self.cycle_types = None
+        self.prev_cycle_idx = 0
+
+        max_all_parts = MAX_SLICES
+
+        for i in range(max_all_parts):
+            part = UISlice(self.tc, parent=self)
+            self.all_parts.append(part)
+
+        if doc_obj != None:
+            self.doc_obj = doc_obj
+
+    @property
+    def doc_obj(self):
+        return self._doc_obj
+
+    @doc_obj.setter
+    def doc_obj(self, obj):
+        if not isinstance(obj, Partition):
+            raise TypeError("Object must be type Partition")
+
+        self._doc_obj = obj
+        self.ui_type = UI_TYPE_IN_USE
+        if self.is_logical():
+            self.cycle_types = UIPartition.KNOWN_LOGIC_TYPES
+        else:
+            self.cycle_types = UIPartition.KNOWN_PART_TYPES
+            
+    @property
+    def empty_space_obj(self):
+        return self._empty_space_obj
+
+    @empty_space_obj.setter
+    def empty_space_obj(self, obj):
+        if not isinstance(obj, EmptySpace):
+            raise TypeError("Object must be type EmptySpace")
+
+        self._empty_space_obj = obj
+        self.ui_type = UI_TYPE_EMPTY_SPACE
+        self.cycle_types = UIPartition.KNOWN_PART_TYPES
+    
+    def set_unused(self):
+        self.ui_type = UI_TYPE_NOT_USED
+        self._empty_space_obj = None
+        self._doc_obj = None
+
+    @property
+    def name(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.name
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return self.empty_space_obj.name
+        else:
+            raise RuntimeError("Partition not in use.  No name")
+
+    @property
+    def size(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.size
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return Size("0gb")
+        else:
+            raise RuntimeError("Partition not in use.  No size information.")
+
+    @property
+    def start_sector(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.start_sector
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return self.empty_space_obj.start_sector
+        else:
+            raise RuntimeError("Partition not in use.  No size information.")
+
+    def get_end_sector(self):
+
+        if self.ui_type == UI_TYPE_IN_USE:
+            obj = self.doc_obj
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            obj = self.empty_space_obj
+        else:
+            raise RuntimeErorr("Partition not in used")
+
+        size_in_sector = (obj.size).get(Size.sector_units)
+        return (obj.start_sector + size_in_sector)
+
+    def get_parts_in_use(self):
+        in_use_parts = list()
+        for part in self.all_parts:
+            LOGGER.debug("looking at ui_type: %s", part.ui_type)
+            if (part.ui_type == UI_TYPE_IN_USE) or \
+               (part.ui_type == UI_TYPE_EMPTY_SPACE):
+                in_use_parts.append(part)
+
+        return in_use_parts  
+
+    def add_unused_parts(self, no_part_ok=False):
+
+        existing_parts = self.doc_obj.get_children(class_type=Slice)
+        if (existing_parts is None) or (len(existing_parts) == 0):
+            if no_part_ok:
+                existing_parts = list()
+            else:
+                raise ValueError("Can't determine if this partition "
+                                 "has slices")
+
+        # remove the boot slice from the list of slices that gets displayed.
+        boot_slice = None
+        for slice in existing_parts:
+            if int(slice.name) == BOOT_SLICE:
+                boot_slice = slice
+                break
+        if boot_slice is not None:
+            existing_parts.remove(boot_slice)
+
+        numbers = range(MAX_SLICES)
+        existing_parts.sort(name_sort)
+
+        existing_gaps = self.doc_obj.get_gaps()
+        # sort the gaps by size, smallest gaps first.  When using
+        # the existing_gaps list, the largest gaps is used first, they
+        # will be popped off the end of the list.
+        existing_gaps.sort(size_sort)
+
+        add_missed_parts(numbers, existing_parts, existing_gaps,
+                         Size("1gb"), self.all_parts)
+
+        # If there's a backup slice, move it to end of the list for display
+        slice2 = self.all_parts[2]
+        if slice2.ui_type == UI_TYPE_IN_USE:
+            self.all_parts.remove(slice2)
+            self.all_parts.append(slice2)
+
+        if LOGGER.isEnabledFor(logging.DEBUG):
+            for part in self.all_parts:
+                try:
+                    LOGGER.debug("UIPart: after fill unused...%s: %s..size=%s",
+                                 str(part.name), part.get_description(),
+                                 str(part.size))
+                except Exception, ex:
+                    LOGGER.debug("UIPart: after fill unused..." + str(ex))
+                    pass
+
+    def get_description(self):
+
+        if self.ui_type == UI_TYPE_IN_USE:
+            if self.doc_obj.is_extended:
+                return EXTENDED_TEXT
+            else:
+                return libdiskmgt_const.PARTITION_ID_MAP[\
+                    self.doc_obj.part_type]
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return UNUSED_TEXT
+        else:
+            raise RuntimeError("Partition not in use.  No descrption")
+
+    @property
+    def discovered_doc_obj(self):
+        ''' Find the same object, if it exists, in the discovered
+            object tree.
+ 
+            Returns the object in discovered subtree, if found.
+            Returns None otherwise.
+        '''
+
+        if self.ui_type != UI_TYPE_IN_USE:
+            return None
+
+        if self.parent is None:
+
+            # The parent of the partition currently being worked on must be
+            # the disk selected at the desired target
+            doc = InstallEngine.get_instance().doc
+            desired_disk = get_desired_target_disk(doc)
+
+            # find the disk in discovered target
+            parent_disc_obj = find_discovered_disk(desired_disk, doc)
+
+        else:
+            parent_disc_obj = self.parent.discovered_doc_obj
+
+        # get all the discovered partitions 
+        discovered_parts = parent_disc_obj.get_children(class_type=Partition)
+
+        if not discovered_parts:
+            return None
+
+        # look through all the partitions, and find the one that
+        # matches this one.  The partition name string is used
+        # to identify the matching partition
+        for part in discovered_parts:
+            if str(part.name) == str(self.doc_obj.name):
+                return part
+            
+        # Partition is not found.
+        LOGGER.debug("can't find any partitions")
+        return None
+
+    def modified(self):
+        ''' compare with the same object when it is discovered.
+            only partition type and partition size is checked
+            since that's the only thing the text installer allows
+            users to change
+ 
+            Returns True if size or partition type is changed compared to the
+            discovered object.
+
+            Returns False otherwise.
+        '''
+        if self.ui_type is not UI_TYPE_IN_USE:
+            return False
+
+        # object is newly added to the desired target.
+        if self.discovered_doc_obj is None:
+            return True
+       
+        if self.doc_obj.part_type != self.discovered_doc_obj.part_type:
+            return True
+
+        precision = Size(UI_PRECISION).get(Size.byte_units)
+        discovered_size_byte = self.discovered_doc_obj.size.get(\
+            Size.byte_units)
+        size_byte = self.doc_obj.size.get(Size.byte_units)
+
+        return (abs(discovered_size_byte - size_byte) > precision) 
+
+    def get_max_size(self):
+        '''Analyze nearby partitions and determine the total unused, available
+        space that this partition could consume without affecting other
+        partitions.
+        
+        Result is in gigabytes
+        
+        '''
+        if self.is_logical():
+            parts = self.parent.get_logicals()
+            ext_part = self.parent.get_extended_partition()
+        else:
+            parts = self.parent.get_standards()
+        if self not in parts:
+            raise ValueError("This partition was not found on the "
+                             "supplied disk")
+
+        self_idx = parts.index(self)
+        prev_part = None
+        next_part = None
+
+        for part in reversed(parts[:self_idx]):
+            if part.ui_type == UI_TYPE_IN_USE:
+                prev_part = part
+                break
+        for part in parts[self_idx + 1:]:
+            if part.ui_type == UI_TYPE_IN_USE:
+                next_part = part
+                break
+
+        LOGGER.debug("part:%s, idx: %s" % (self.get_description(), self_idx))
+
+        msg_str = self.get_description() + ":"
+        if prev_part is None:
+            LOGGER.debug("No prev part")
+            if self.is_logical():
+                begin_avail_space = ext_part.doc_obj.start_sector
+            else:
+                begin_avail_space = 0
+        else:
+            try:
+                begin_avail_space = prev_part.get_end_sector()
+            except Exception:
+                LOGGER.error("%s", prev_part)
+                raise
+        LOGGER.debug("begin_available space: %d", begin_avail_space)
+
+        if next_part is None:
+            LOGGER.debug("No next part")
+            if self.is_logical():
+                end_avail_space = ext_part.get_end_sector()
+            else:
+                disk_size = self.parent.doc_obj.disk_prop.dev_size
+                end_avail_space = disk_size.get(Size.sector_units)
+        else:
+            end_avail_space = next_part.start_sector
+
+        LOGGER.debug("end_available space: %d", end_avail_space)
+
+        avail = end_avail_space - begin_avail_space
+
+        LOGGER.debug("avail: %d", avail)
+
+        if avail < 0:
+            avail = 0
+
+        return (Size(str(avail) + Size.sector_units))
+    
+    def editable(self):
+        '''Returns True if it is possible to edit this partition's size'''
+
+        if self.ui_type == UI_TYPE_IN_USE:
+            if int(self.doc_obj.name) > MAX_PRIMARY_PARTS:
+                return False
+
+            if self.doc_obj.part_type in UIPartition.EDITABLE_PART_TYPES:
+                return True
+            else:
+                return False
+
+        return True
+
+    def is_extended(self):
+        if self.ui_type == UI_TYPE_IN_USE and self.doc_obj.is_extended:
+            return True
+
+        return False
+
+    def is_logical(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.is_logical
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            if int(self.empty_space_obj.name) > MAX_PRIMARY_PARTS:
+                return True
+            return False
+        else:
+            raise RuntimeErorr("Partition not in used")
+
+    def cycle_type(self, new_type=None, extra_type=None):
+        '''Cycle this partition's type. Potential types are based on
+        whether or not another Solaris partition exists, whether an extended
+        partition exists, and whether or not this is a logical partition.
+        
+        If extra_types is passed in, it should be a list of other potential
+        types. These types will also be considered when cycling.
+        
+        '''
+
+        dump_doc("before change type")
+
+        sol2_part = self.parent.get_solaris_data()
+        has_solaris_part = (sol2_part is not None)
+        
+        ext_part = self.parent.get_extended_partition()
+        has_extended = (ext_part is not None)
+        
+        # If this is the extended partition, and the Solaris2 partition
+        # is a logical partition, allow for cycling from Extended to Solaris2
+        if (has_extended and ext_part is self and
+            has_solaris_part and sol2_part.is_logical()):
+            has_solaris_part = False
+
+        if new_type is not None:
+            type_index = self.cycle_types.index(new_type)
+            type_index = (type_index + 1) % len(self.cycle_types)
+        else:
+            if self.ui_type == UI_TYPE_EMPTY_SPACE:
+                type_index = self.cycle_types.index(UIPartition.UNUSED)
+                type_index = (type_index + 1) % len(self.cycle_types)
+            else:
+                # should have a doc_obj to reference
+                if self.doc_obj.part_type in self.cycle_types:
+                    type_index = self.cycle_types.index(self.doc_obj.part_type)
+                    type_index = (type_index + 1) % len(self.cycle_types)
+                else:
+                    type_index = 0
+
+        new_type = self.cycle_types[type_index]
+
+        if new_type == UIPartition.UNUSED:
+            LOGGER.debug("new type == unused")
+        else:
+            LOGGER.debug("new type == %s",
+                         libdiskmgt_const.PARTITION_ID_MAP[new_type])
+
+        if has_solaris_part and new_type == PART_TYPE_SOLARIS:
+            self.cycle_type(new_type=new_type, extra_type=extra_type)
+        elif has_extended and new_type == UIPartition.EXT_DOS:
+            self.cycle_type(new_type=new_type, extra_type=extra_type)
+        else:
+            if self.ui_type == UI_TYPE_EMPTY_SPACE:
+                LOGGER.debug("Partition used to be unsed.  Add partition with"
+                             "type: %s, start_sec=%s, size=%s" %
+                             (libdiskmgt_const.PARTITION_ID_MAP[new_type], 
+                             self.empty_space_obj.start_sector,
+                             self.get_max_size()))
+
+                size_in_sector = self.empty_space_obj.size.get(\
+                    Size.sector_units)
+
+                new_part = self.parent.doc_obj.add_partition(self.name, \
+                    self.empty_space_obj.start_sector, size_in_sector, \
+                    size_units=Size.sector_units, partition_type=new_type)
+                if new_part.is_solaris:
+                    new_part.bootid = Partition.ACTIVE
+            else:
+                if new_type == UIPartition.UNUSED:
+                    LOGGER.debug("Changing type to unused deleting %s",
+                                 self.name)
+                    self.parent.doc_obj.delete_partition(self.doc_obj)
+                else:
+                    LOGGER.debug("Changing type: %s to type %s",
+                                 self.name,
+                                 libdiskmgt_const.PARTITION_ID_MAP[new_type])
+                    self.doc_obj.change_type(new_type)
+                    if self.doc_obj.is_solaris:
+                        self.doc_obj.bootid = Partition.ACTIVE
+        dump_doc("after change type")
+
+    def get_solaris_data(self):
+        for part in self.all_parts:
+            if part.ui_type == UI_TYPE_IN_USE and \
+                part.doc_obj.in_zpool == ROOT_POOL:
+                return part
+
+        return None
+
+    def __str__(self):
+        result = ["UI Partiton: %s" % self.name]
+        if self.ui_type == UI_TYPE_IN_USE:
+            result.append("UI type: in use")
+            result.append("Size: %s" % self.size)
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            result.append("UI type: empty space")
+            result.append("Size: %s" % self.size)
+        elif self.ui_type == UI_TYPE_NOT_USED:
+            result.append("UI type: not used")
+        else:
+            result.append("UI type: UNKNOWN")
+        return "\n".join(result)
+    
+
+class UISlice(object):
+    ''' Object used to keep track of slice related information for UI '''
+
+    UNUSED = None
+    TYPES = [UNUSED, ROOT_POOL]
+
+    def __init__(self, target_controller, parent=None):
+        global LOGGER
+        LOGGER = logging.getLogger(INSTALL_LOGGER_NAME)
+
+        self._doc_obj = None
+        self._empty_space_obj = None
+        self.tc = target_controller
+        self.all_parts = list()
+        self._unused_parts_added = False
+        self.parent = parent
+        self.ui_type = UI_TYPE_NOT_USED
+
+    @property
+    def doc_obj(self):
+        return self._doc_obj
+
+    @doc_obj.setter
+    def doc_obj(self, obj):
+        if not isinstance(obj, Slice):
+            raise TypeError("Object must be type Slice")
+
+        self._doc_obj = obj
+        self.ui_type = UI_TYPE_IN_USE
+
+    @property
+    def empty_space_obj(self):
+        return self._empty_space_obj
+
+    @empty_space_obj.setter
+    def empty_space_obj(self, obj):
+        if not isinstance(obj, EmptySpace):
+            raise TypeError("Object must be type EmptySpace")
+
+        self._empty_space_obj = obj
+        self.ui_type = UI_TYPE_EMPTY_SPACE
+    
+    def set_unused(self):
+        self.ui_type = UI_TYPE_NOT_USED
+        self._empty_space_obj = None
+        self._doc_obj = None
+
+    @property
+    def name(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.name
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return self.empty_space_obj.name
+        else:
+            raise RuntimeError("Partition not in use.  No name")
+
+    @property
+    def size(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            return self.doc_obj.size
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return Size("0gb")
+        else:
+            raise RuntimeError("Partition not in use.  No size information.")
+
+    def get_end_sector(self):
+
+        if self.ui_type == UI_TYPE_IN_USE:
+            obj = self.doc_obj
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            obj = self.empty_space_obj
+        else:
+            raise RuntimeErorr("Partition not in used")
+
+        size_in_sector = (obj.size).get(Size.sector_units)
+        return (obj.start_sector + size_in_sector)
+
+    def get_description(self):
+        if self.ui_type == UI_TYPE_IN_USE:
+            if self.doc_obj.tag == V_BACKUP:
+                return BACKUP_SLICE_TEXT
+
+            if self.doc_obj.in_zpool is not None:
+                return self.doc_obj.in_zpool
+
+            # try to get value from in_use dictionary
+            in_use = self.doc_obj.in_use 
+            if in_use is None:
+                return self.doc_obj.name 
+
+            if in_use['used_name']:
+                return (in_use['used_name'])[0]
+
+            if in_use['used_by']:
+                return (in_use['used_by'])[0]
+
+            return self.doc_obj.name 
+        elif self.ui_type == UI_TYPE_EMPTY_SPACE:
+            return UNUSED_TEXT
+        else:
+            raise RuntimeError("Slice not in use.")
+
+    def get_max_size(self):
+        '''Return the maximum possible size this slice could consume,
+        in gigabytes, based on adjacent unused space
+        
+        '''
+
+        if int(self.name) == BACKUP_SLICE:
+            return self.size
+
+        slices = self.parent.all_parts
+        if self not in slices:
+            raise ValueError("This slice not in the parent!")
+
+        self_idx = slices.index(self)
+        prev_slice = None
+        next_slice = None
+        
+        # Search for the slice prior to this one with the largest "endblock"
+        # Since existing slices may overlap, this could be any slice prior
+        # to the current one.
+        for slice_info in reversed(slices[:self_idx]):
+            if (slice_info.ui_type != UI_TYPE_EMPTY_SPACE and \
+                int(slice_info.name) != BACKUP_SLICE):
+                if (prev_slice is None or
+                    slice_info.get_end_sector() > prev_slice.get_end_sector()):
+                    prev_slice = slice_info
+        for slice_info in slices[self_idx + 1:]:
+            if (slice_info.ui_type != UI_TYPE_EMPTY_SPACE and \
+                int(slice_info.name) != BACKUP_SLICE):
+                next_slice = slice_info
+                break
+        if prev_slice is None:
+            start_pt = 0
+        else:
+            start_pt = prev_slice.get_end_sector()
+        
+        if next_slice is None:
+            for slice_info in reversed(slices):
+                # Use the backup slice to define the absolute max size
+                # any given slice can be. (This is usually the last slice,
+                # hence the use of a reversed iterator)
+                if int(slice_info.name) == BACKUP_SLICE:
+                    end_pt = slice_info.size.get(Size.sector_units)
+                    break
+            else:
+                # Default to the parent's size if there happens to be no S2
+                end_pt = self.parent.size.get(Size.sector_units)
+        else:
+            end_pt = next_slice.get_end_sector()
+
+        max_space = end_pt - start_pt
+
+        if max_space < 0:
+            max_space = 0
+
+        return (Size(str(max_space) + Size.sector_units))
+    
+    def editable(self):
+        '''Returns True if it is possible to edit this partition's size'''
+        if self.ui_type == UI_TYPE_IN_USE:
+            if self.doc_obj.in_zpool == "rpool":
+                return True
+
+        return False
+
+    @property
+    def discovered_doc_obj(self):
+        ''' Find the same object, if it exists, in the discovered
+            object tree.
+ 
+            Returns the object in discovered subtree, if found.
+            Returns None otherwise.
+        '''
+        if self.ui_type != UI_TYPE_IN_USE:
+            return None
+
+        parent_disc_obj = self.parent.discovered_doc_obj
+
+        # get all the discovered partitions 
+        discovered_slices = parent_disc_obj.get_children(class_type=Slice)
+
+        if (discovered_slices is None) or (len(discovered_slices) == 0):
+            return None
+
+        # look through all the partitions, and find the one matching that
+        # matches this one.  The slice id is used
+        # to identify the matching slice
+        for slice in discovered_slices:
+            if str(slice.name) == str(self.doc_obj.name):
+                return slice
+            
+        # Slice is not found.
+        return None
+
+    def modified(self):
+        ''' compare with the same object when it is discovered.
+            only slice size is checked
+            since that's the only thing the text installer allows
+            users to change
+ 
+            Returns True if slice type or size is changed compared to the
+            discovered object.
+
+            Returns False otherwise.
+        '''
+        if self.ui_type is not UI_TYPE_IN_USE:
+            return False
+
+        # object is newly added to the desired target.
+        if self.discovered_doc_obj is None:
+            return True
+       
+        precision = Size(UI_PRECISION).get(Size.byte_units)
+        discovered_size_byte = self.discovered_doc_obj.size.get( \
+            Size.byte_units)
+        size_byte = self.doc_obj.size.get(Size.byte_units)
+
+        if abs(discovered_size_byte - size_byte) > precision:
+            return True
+
+        return False
+
+    def cycle_type(self, new_type=None, extra_type=None):
+        '''Cycle this slide's type. 
+        
+        If extra_types is passed in, it should be a list of other potential
+        types. These types will also be considered when cycling.
+        
+        '''
+
+        dump_doc("before slice.cycle_type")
+
+        has_solaris_data = (self.parent.get_solaris_data() is not None)
+
+        types = set()
+        types.update(UISlice.TYPES)
+        if extra_type is not None:
+            types.update(extra_type)
+        types = list(types)
+        types.sort()
+
+        if new_type is not None:
+            type_index = types.index(new_type)
+            type_index = (type_index + 1) % len(types)
+        else:
+            if self.ui_type == UI_TYPE_EMPTY_SPACE:
+                type_index = types.index(UISlice.UNUSED)
+                type_index = (type_index + 1) % len(types)
+            else:
+                if self.doc_obj.in_zpool in types:
+                    type_index = types.index(self.doc_obj.in_zpool)
+                    type_index = (type_index + 1) % len(types)
+                else:
+                    type_index = 0
+
+        new_type = types[type_index]
+
+        if new_type == UIPartition.UNUSED:
+            LOGGER.debug("new type == unused")
+        else:
+            LOGGER.debug("new type == %s", new_type)
+
+        if has_solaris_data and new_type == ROOT_POOL:
+            self.cycle_type(new_type=new_type, extra_type=extra_type)
+        else:
+            if self.ui_type == UI_TYPE_EMPTY_SPACE:
+                if new_type == ROOT_POOL:
+                    # making this the new root pool
+                    size_in_sector = self.empty_space_obj.size.get( \
+                        Size.sector_units)
+                    LOGGER.debug("Used to be unused... adding new slice")
+                    new_slice = self.parent.doc_obj.add_slice(self.name, \
+                        self.empty_space_obj.start_sector, size_in_sector, \
+                        size_units=Size.sector_units)
+                    new_slice.in_zpool = ROOT_POOL
+                    new_slice.in_vdev = DEFAULT_VDEV_NAME
+                    new_slice.tag = V_ROOT
+                else:
+                    # setting it back to whatever value was discovered
+                    discovered_obj = self.discovered_doc_obj
+                    if discovered_obj is not None:
+                        self.parent.doc_obj.insert_children(discovered_obj)
+                    else:
+                        LOGGER.debug("Unable to reset to discovered value")
+                
+            else:
+                if new_type == UIPartition.UNUSED:
+                    LOGGER.debug("Changing to unused, deleting")
+                    LOGGER.debug("Target Call: deleting %s", self.name)
+                    self.parent.doc_obj.delete_slice(self.doc_obj)
+        dump_doc("AFTER change type")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/welcome.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+Contains the Welcome Screen for the Text Installer
+'''
+
+from solaris_install.engine import InstallEngine
+from solaris_install.text_install import _, RELEASE, TUI_HELP
+from terminalui.base_screen import BaseScreen
+
+
+class WelcomeScreen(BaseScreen):
+    '''First screen of the text installer.
+    No special __init__ needed beyond that provided by BaseScreen
+    
+    '''
+    
+    HEADER_TEXT = _("Welcome to %(release)s") % RELEASE
+    WELCOME_TEXT = _("Thanks for choosing to install %(release)s! This "
+                     "installer enables you to install the %(release)s "
+                     "Operating System (OS) on SPARC or x86 systems.\n\n"
+                     "The installation log will be at %(log)s.\n\n"
+                     "How to navigate through this installer:")
+    BULLET_ITEMS = [_("Use the function keys listed at the bottom of each "
+                 "screen to move from screen to screen and to perform "
+                 "other operations."),
+               _("Use the up/down arrow keys to change the selection "
+                 "or to move between input fields."),
+               _("If your keyboard does not have function keys, or "
+                 "they do not respond, press ESC; the legend at the "
+                 "bottom of the screen will change to show the ESC keys"
+                 " for navigation and other functions.")]
+    BULLET = "- "
+    HELP_DATA = (TUI_HELP + "/%s/welcome.txt",
+                 _("Welcome and Navigation Instructions"))
+
+    def __init__(self, main_win, install_data):
+        super(WelcomeScreen, self).__init__(main_win)
+        self.install_data = install_data
+    
+    def set_actions(self):
+        '''Remove the F3_Back Action from the first screen'''
+        self.main_win.actions.pop(self.main_win.back_action.key, None)
+    
+    def _show(self):
+        '''Display the static paragraph WELCOME_TEXT'''
+        
+        log_file = self.install_data.log_location
+        y_loc = 1
+        fmt = {"log": log_file}
+        fmt.update(RELEASE)
+        text = WelcomeScreen.WELCOME_TEXT % fmt
+        y_loc += self.center_win.add_paragraph(text, start_y=y_loc)
+        x_loc = len(WelcomeScreen.BULLET)
+        for bullet in WelcomeScreen.BULLET_ITEMS:
+            self.center_win.add_text(WelcomeScreen.BULLET, start_y=y_loc)
+            y_loc += self.center_win.add_paragraph(bullet, start_y=y_loc,
+                                                   start_x=x_loc)
--- a/usr/src/lib/install_engine/__init__.py	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/lib/install_engine/__init__.py	Wed May 11 15:30:11 2011 -0700
@@ -232,9 +232,11 @@
         self.stop_on_error = stop_on_error
         self.__currently_executing = None
 
-        # just use 2 decimal precision for progress, and always round
-        # down while calculating the progress ratios
-        d_context = decimal.Context(prec=2, rounding=decimal.ROUND_DOWN)
+        # Use 8 decimal precision for progress.  Using less precision
+        # will cause problems when the estimated progress for some
+        # checkpoints are drastically different than the others.
+        # Always round down while calculating the progress ratios
+        d_context = decimal.Context(prec=8, rounding=decimal.ROUND_DOWN)
         decimal.setcontext(d_context)
         self.__current_completed = decimal.Decimal("0")
 
@@ -603,7 +605,7 @@
 
         resumable = self.get_resumable_checkpoints()
         if start_from not in resumable:
-            raise UsageError("'%s' is not a resumable checkpoint")
+            raise UsageError("'%s' is not a resumable checkpoint" % start_from)
 
         use_latest = (start_from == resumable[-1])
         self._rollback(start_from, use_latest)
--- a/usr/src/lib/install_manifest/dtd/Makefile	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/lib/install_manifest/dtd/Makefile	Wed May 11 15:30:11 2011 -0700
@@ -37,7 +37,8 @@
 	configuration.dtd \
 	execution.dtd \
 	software.dtd \
-	target.dtd
+	target.dtd \
+        media-transfer.dtd
 
 ROOT_DTD_FILES=	$(DTD_FILES:%=$(ROOTUSRSHAREINSTALL)/%)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/dtd/media-transfer.dtd	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,34 @@
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+-->
+
+<!--
+DTD used for specifying software information for media transfer
+-->
+
+<!ELEMENT media_transfer (media_trans)>
+
+<!ENTITY % software SYSTEM "software.dtd">
+%software;
+
+<!ELEMENT media_trans (software+)>
--- a/usr/src/lib/install_target/controller.py	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/lib/install_target/controller.py	Wed May 11 15:30:11 2011 -0700
@@ -57,7 +57,7 @@
 # Swap ZVOL is required if memory is below this
 ZVOL_REQ_MEM = 900
 
-VFSTAB_FILE = "/etc/vfstab"
+VFSTAB_FILE = "etc/vfstab"
 
 # "TargetController data" is an area in the DataObjectCache
 # intended for the TargetController class's private use.  It
--- a/usr/src/lib/install_transfer/Makefile	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/lib/install_transfer/Makefile	Wed May 11 15:30:11 2011 -0700
@@ -20,13 +20,14 @@
 #
 
 #
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
 #
 
 PYMODS		= __init__.py \
 		  cpio.py \
 		  info.py \
 		  ips.py \
+		  media_transfer.py \
 		  p5i.py \
 		  prog.py \
                   svr4.py
--- a/usr/src/lib/install_transfer/cpio.py	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/lib/install_transfer/cpio.py	Wed May 11 15:30:11 2011 -0700
@@ -38,6 +38,7 @@
 from osol_install.install_utils import file_size
 from solaris_install.engine.checkpoint import AbstractCheckpoint as Checkpoint
 from solaris_install.engine import InstallEngine
+from solaris_install.target.size import Size
 from solaris_install.transfer.info import Args
 from solaris_install.transfer.info import CPIOSpec as CPIO
 from solaris_install.transfer.info import Destination
@@ -46,6 +47,8 @@
 from solaris_install.transfer.info import Source
 from solaris_install.transfer.info import ACTION, CONTENTS, CPIO_ARGS
 from solaris_install.transfer.prog import ProgressMon
+from solaris_install.transfer.media_transfer import TRANSFER_ROOT, \
+    TRANSFER_MISC, TRANSFER_MEDIA, get_image_size
 
 
 class AbstractCPIO(Checkpoint):
@@ -92,6 +95,31 @@
         # if image_info is used
         self._use_image_info = False
 
+        self._image_size = 0
+
+    def get_media_transfer_size(self):
+        ''' Hack to skip computing size of media transfer checkpoints
+            to we can speed up the start of the install
+        '''
+
+        self.logger.debug("Special size calculation for: " + self.name)
+        if self._image_size == 0:
+            image_info_size = get_image_size(self.logger)
+            size_in_mb = Size(str(image_info_size) + Size.mb_units)
+            self._image_size = size_in_mb.get(Size.kb_units)
+            self.logger.debug("image_info size: %d kb", self._image_size)
+
+        if self.name == TRANSFER_ROOT:
+            weight = 0.75
+        elif self.name == TRANSFER_MISC:
+            weight = 0.05
+        elif self.name == TRANSFER_MEDIA:
+            weight = 0.20
+        else:
+            raise RuntimeError("Not applicable for other checkpoints")
+
+        return int(self._image_size * weight)
+
     def get_size(self):
         '''Compute the size of the transfer specified'''
 
@@ -124,31 +152,31 @@
                     if opt == "IMAGE_SIZE":
                         # Remove the '\n' character read from
                         # the file, and convert to integer
-                        size = int(val.rstrip())
-        else:
-            # Compute the image size from the data in the transfer install
-            # list, if it contains valid data
-            for transfer in self._transfer_list:
-                if transfer.get(ACTION) == "install":
-                    file_list = transfer.get(CONTENTS)
-                    self.logger.debug("Unable to read .image_info file")
-                    self.logger.debug("Computing distribution size.")
+                        return(int(val.rstrip()))
+
+        # Compute the image size from the data in the transfer install
+        # list, if it contains valid data
+        for transfer in self._transfer_list:
+            if transfer.get(ACTION) == "install":
+                file_list = transfer.get(CONTENTS)
+                self.logger.debug("Unable to read .image_info file")
+                self.logger.debug("Computing distribution size.")
 
-                    with open(file_list, 'r') as filehandle:
-                        # Determine the file size for each file listed and sum
-                        # the sizes.
-                        try:
-                            size = size + sum(map(file_size,
-                                             [os.path.join(self.src,
-                                                           f.rstrip())
-                                             for f in filehandle.readlines()]))
-                        except OSError:
-                            # If the file doesn't exist that's OK.
-                            pass
+                with open(file_list, 'r') as filehandle:
+                    # Determine the file size for each file listed and sum
+                    # the sizes.
+                    try:
+                        size = size + sum(map(file_size,
+                                         [os.path.join(self.src,
+                                                       f.rstrip())
+                                         for f in filehandle.readlines()]))
+                    except OSError:
+                        # If the file doesn't exist that's OK.
+                        pass
 
-            # The file_size() function used for calculating size of each
-            # file returns the value in bytes.  Convert to kilobytes.
-            size = size / 1024
+        # The file_size() function used for calculating size of each
+        # file returns the value in bytes.  Convert to kilobytes.
+        size = size / 1024
         return size
 
     def get_progress_estimate(self):
@@ -157,8 +185,14 @@
         '''
 
         if self.distro_size == 0:
-            self.distro_size = self.get_size()
+            if self.name == TRANSFER_ROOT or \
+                self.name == TRANSFER_MISC or \
+                self.name == TRANSFER_MEDIA:
+                self.distro_size = self.get_media_transfer_size()
+            else:
+                self.distro_size = self.get_size()
 
+        self.logger.debug("Distro size: %d KB", self.distro_size)
         progress_estimate = \
             int((float(self.distro_size) / self.DEFAULT_SIZE) * \
                 self.DEFAULT_PROG_EST)
@@ -425,14 +459,6 @@
                 tmp_file = tempfile.mktemp()
                 with open(tmp_file, 'w') as filehandle:
                     for file_name in bflist:
-                        if file_name == "./":
-                            # This is equivalent to specifying to transfer
-                            # the entire src. In this case, we can optimize
-                            # when determining the file size by looking for
-                            # a .image_info file. Set attribute to indicate
-                            # to do so.
-                            self._use_image_info = True
-
                         filehandle.write(file_name + "\n")
                 fl_data = tmp_file
             sorted_file = tempfile.mktemp()
@@ -482,7 +508,7 @@
                 # get that size now.
                 self.distro_size = self.get_size()
 
-            # Start up the ProgressMon to report progress
+           # Start up the ProgressMon to report progress
             # while the actual transfer is taking place.
 
             # This needs to be addressed:
@@ -511,7 +537,7 @@
                     for item in trans.get(CONTENTS):
                         entry = os.path.join(self.dst, item.rstrip())
                         try:
-                            if os.path.isdir(item):
+                            if os.path.isdir(entry):
                                 shutil.rmtree(entry)
                             else:
                                 os.unlink(entry)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_transfer/media_transfer.py	Wed May 11 15:30:11 2011 -0700
@@ -0,0 +1,426 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""
+media transfer checkpoint. Sub-class of the checkpoint class.
+"""
+
+import os
+import platform
+import logging
+
+from solaris_install import Popen
+from solaris_install.data_object.cache import DataObjectCache
+from solaris_install.engine import InstallEngine
+from solaris_install.engine.checkpoint import AbstractCheckpoint
+from solaris_install.logger import INSTALL_LOGGER_NAME
+from solaris_install.manifest.parser import ManifestParser
+from solaris_install.target.size import Size
+from solaris_install.transfer.info import Software, Source, Destination, \
+    CPIOSpec, Dir
+
+from urllib2 import Request, urlopen
+
+TRANSFER_MANIFEST_NAME = ".transfer-manifest.xml"
+
+TRANSFER_ROOT = "transfer-root"
+TRANSFER_MISC = "transfer-misc"
+TRANSFER_MEDIA = "transfer-media"
+
+INSTALL_TARGET_VAR = "{INSTALL_TARGET}"
+MEDIA_DIR_VAR = "{MEDIA}"
+INSTALL_TARGET = "/a"
+
+NET_SVC = "svc:/system/filesystem/root-assembly:net"
+MEDIA_SVC = "svc:/system/filesystem/root-assembly:media"
+SVCS_CMD = "/bin/svcs"
+SVC_STATUS_DISABLED = "disabled"
+SVC_STATUS_ENABLED = "online"
+
+PRTCONF = "/usr/sbin/prtconf" 
+DHCPINFO = "/sbin/dhcpinfo"
+
+IMAGE_INFO_FILENAME = ".image_info"
+IMAGE_SIZE_KEYWORD = "IMAGE_SIZE"
+
+
+class InvalidInstallEnvError(Exception):
+    '''Invalid install environment error
+    '''
+    pass
+
+
+def is_net_booted(logger):
+    '''Determine whether the application is running from a media booted
+       environment or a net booted environment.  
+
+       The following SMF services are examined:
+           svc:/system/filesystem/root-assembly:net
+           svc:/system/filesystem/root-assembly:media
+
+       If root-assembly:net is online and root-assembly:media is disabled.
+       The image is running from a net booted environment.  This function
+       will return True.
+
+       If root-assembly:net is disabled and root-assembly:media is online.
+       The image is running from a media booted environment.  This function
+       will return False.
+
+       If both root-assembly:net and root-assembly:media are
+       online or disabled, that's considered an error condition.
+
+       Exception: InvalidInstallEnvError: if both filesystem/root:media and
+                  filesystem/root:net SMF services are online or disabled.
+    '''
+
+    cmd = [SVCS_CMD, "-H", "-o", "STATE", NET_SVC]
+    p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                         logger=logger)
+    net_status = p.stdout.strip()
+
+    logger.debug("%s: %s" % (NET_SVC, net_status))
+
+    cmd = [SVCS_CMD, "-H", "-o", "STATE", MEDIA_SVC]
+    p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                         logger=logger)
+    media_status = (p.stdout).strip()
+    logger.debug("%s: %s" % (MEDIA_SVC, media_status))
+
+    if net_status == SVC_STATUS_ENABLED and \
+        media_status == SVC_STATUS_DISABLED:
+        return True
+
+    if net_status == SVC_STATUS_DISABLED and \
+        media_status == SVC_STATUS_ENABLED:
+        return False
+
+    raise InvalidInstallEnvError("%s is %s, %s is %s" % \
+        (NET_SVC, net_status, MEDIA_SVC, media_status))
+
+
+def get_image_size(logger):
+    '''Total size of the software in the image is stored in the 
+       .image_info indicated by the keywoard IMAGE_SIZE.
+       This function retrieves that value from the .image_file
+       The size recorded in the .image_file is in KB, other functions
+       in this file uses the value in MB, so, this function will
+       return the size in MB
+
+       Returns:
+           size of retrieved from the .image_info file in MB
+
+    '''
+
+    # Depending on how we are booted, get the .image_info file accordingly.
+    if is_net_booted(logger):
+        image_info_file = os.path.join(NetPrepareMediaTransfer.MEDIA_SOURCE, 
+                                       IMAGE_INFO_FILENAME)
+    else:
+        image_info_file = os.path.join(PrepareMediaTransfer.MEDIA_SOURCE, 
+                                       IMAGE_INFO_FILENAME)
+
+    img_size = 0
+    with open(image_info_file, 'r') as ih:
+        for line in ih:
+            (opt, val) = line.split("=")
+            if opt == IMAGE_SIZE_KEYWORD:
+                # Remove the '\n' character read from
+                # the file, and convert to integer
+                img_size = int(val.rstrip('\n'))
+                break
+
+    if (img_size == 0):
+        # We should have read in a size by now
+        logger.error("Unable to read the image size from %s", image_info_file)
+        raise RuntimeError
+
+    logger.debug("Read from %s size of %s" % (image_info_file, img_size))
+    return (Size(str(img_size) + Size.kb_units).get(Size.mb_units))
+
+
+def download_files(url, dst, logger):
+    '''Download the file specified in the URL to a
+       specified local location.
+    '''
+
+    logger.debug("Planning to download: " + url)
+
+    request = Request(url)
+
+    url_request = urlopen(request)
+    dst_dir = os.path.dirname(dst)
+    if not os.path.exists(dst_dir):
+        os.makedirs(dst_dir)
+    with open(dst, "w") as dst_file:
+        dst_file.write(url_request.read())
+
+
+def init_prepare_media_transfer(name):
+    '''This function instantiates either the PrepareMediaTransfer
+       or the NetePrepareMediaTransfer checkpoint depending on how the
+       image is booted.
+
+       If the image is booted from the media, the
+       PrepareMediaTransfer checkpoint is instantiated.
+
+       If the image is booted from the net, the
+       NetPrepareMediaTransfer checkpoint is instantiated.
+
+       Arguments: None
+
+       Returns: An instantiated instance of PrepareMediaTransfer checkpoint or
+                NetPrepareMediaTransfer checkpoint
+
+    '''
+
+    logger = logging.getLogger(INSTALL_LOGGER_NAME)
+
+    if is_net_booted(logger):
+        logger.debug("Going to init NetPrepareMediaTransfer")
+        return NetPrepareMediaTransfer(name)
+    else:
+        logger.debug("Going to init PrepareMediaTransfer")
+        return PrepareMediaTransfer(name)
+
+
+def setup_doc_content(manifest_name, media_source):
+    '''Loads the content of media manifest into a
+       SEPARATE DOC instance.  Then, copy the data into the
+       DOC that's used by the application, engine and other checkpoints.
+    '''
+
+    # create a separate DOC
+    another_doc = DataObjectCache()
+
+    # load the transfer manifest into the separate DOC
+    manifest_parser = ManifestParser("manifest-parser", manifest_name,
+                                     validate_from_docinfo=False)
+    manifest_parser.parse(doc=another_doc)
+
+    software_nodes = another_doc.get_descendants(class_type=Software)
+
+    if len(software_nodes) != 3:
+        raise RuntimeError("3 software nodes expected.  Only %d found" %
+                           len(software_nodes))
+
+    # Modify the install target values and the media mountpoint
+    for software in software_nodes:
+        # get the destination object
+        dst_node = software.get_children(class_type=Destination,
+                                         not_found_is_err=True)[0]
+        dir_node = dst_node.get_children(class_type=Dir,
+                                         not_found_is_err=True)[0]
+        path = dir_node.dir_path
+        path = path.replace(INSTALL_TARGET_VAR, INSTALL_TARGET)
+        dir_node.dir_path = path
+
+        # if this is the media transfer software node, also update the
+        # value for source
+        if software._name == TRANSFER_MEDIA:
+            src_node = software.get_children(class_type=Source,
+                                             not_found_is_err=True)[0]
+            dir_node = src_node.get_children(class_type=Dir,
+                                             not_found_is_err=True)[0]
+            path = dir_node.dir_path
+            path = path.replace(MEDIA_DIR_VAR, media_source)
+            dir_node.dir_path = path
+
+    # copy the Software classes into the common DOC 
+    doc = InstallEngine.get_instance().data_object_cache
+    doc.volatile.insert_children(software_nodes)
+
+
+class PrepareMediaTransfer(AbstractCheckpoint):
+    '''This checkpoint is used by installation environments booted from
+       the media.  It prepares the DOC for CPIO based transfer.
+       This checkpoint will load the /.cdrom/.transfer-manifest.xml content
+       into the transient subtree of the DOC and fill in values of
+       various mountpoints in the DOC
+    '''
+
+    MEDIA_SOURCE = "/.cdrom"
+
+    def __init__(self, name):
+        super(PrepareMediaTransfer, self).__init__(name)
+        self.logger.debug("PrepareMediaTransfer init")
+
+    def get_progress_estimate(self):
+        return 5 
+
+    def execute(self, dry_run=False):
+
+        manifest_name = os.path.join(PrepareMediaTransfer.MEDIA_SOURCE,
+                                     TRANSFER_MANIFEST_NAME)
+
+        setup_doc_content(manifest_name, PrepareMediaTransfer.MEDIA_SOURCE)
+
+
+class NetPrepareMediaTransfer(AbstractCheckpoint):
+    ''' The NetPrepareMediaTransfer checkpoint is instantiated by the
+        init_prepare_media_transfer() function for installation environments
+        booted from the net. This checkpoint will first download the
+        transfer-manifest.xml from the server, then, load it into the DOC.
+        Based on content of the DOC, the checkpoint will also download any
+        other files that needs to be copied into the install target, 
+        but not yet present in the booted environment. Similar to
+        PrepareMediaTransfer, this checkpoint will also download and
+        mount the root archives we are not booted with and fill in values
+        of mountpoints.
+    '''
+
+    # For SPARC, The URL for the AI server is stored in wanboot.conf.  
+    # This file should have been mounted during boot
+    # so, it has to exist
+    WANBOOT_CONF = "/etc/netboot/wanboot.conf"
+
+    MEDIA_SOURCE = "/tmp"
+
+    def __init__(self, name):
+        super(NetPrepareMediaTransfer, self).__init__(name)
+        self.logger.debug("NetPrepareMediaTransfer init")
+
+    def get_progress_estimate(self):
+        return 5 
+
+    def get_server_url(self):
+        '''Get server URL for downloading files '''
+        if platform.processor() == "sparc":
+            with open(NetPrepareMediaTransfer.WANBOOT_CONF) as wanboot_conf:
+
+                ai_server = None
+                ai_image = None 
+
+                for line in wanboot_conf:
+                    if line.startswith("root_server="):
+                        # AI server line have the following format:
+                        # root_server=http://<ai_server>:<port>/\
+                        #                                 <path_to_wanboot-cgi>
+                        # and extract out the http://<ai_server>:<port> portion
+                        (not_used, val) = line.split("=")
+                        split_val = val.split("/", 3) 
+                        #remove the last part, since it is not useful
+                        split_val.remove(split_val[3])
+                        self.logger.debug("URL: " + "/".join(split_val))
+                        ai_server = "/".join(split_val) #re-create the the URL
+                        self.logger.debug("ai_server: " + ai_server)
+                    elif line.startswith("root_file="):
+                        # AI image line have the following format
+                        # root_file=<ai_image>/boot/platform/sun4v/boot_archive
+                        # extract out the <ai_image> part
+                        (not_used, val) = line.split("=")
+                        split_val = val.rsplit("/", 4)
+                        ai_image = split_val[0]
+                        self.logger.debug("ai_image: " + ai_image)
+
+                if ai_server is None:
+                    raise RuntimeError("Unable to find AI server value "
+                                       "from %s",
+                                       NetPrepareMediaTransfer.WANBOOT_CONF)
+
+                if ai_image is None:
+                    raise RuntimeError("Unable to find AI image value "
+                                       "from %s",
+                                       NetPrepareMediaTransfer.WANBOOT_CONF)
+                return(ai_server + ai_image)
+        else: 
+            cmd = [PRTCONF, "-v", "/devices"]
+            p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
+                                 logger=self.logger)
+            use_next_line = False
+            val = None
+            for line in p.stdout.splitlines():
+                line = line.strip()
+                self.logger.debug("line: " + line)
+                if use_next_line:
+                    val = line
+                    break
+                if line.startswith("name='install_media'"):
+                    use_next_line = True
+
+            if val is None:
+                raise RuntimeError("Unable to find install_media line")
+            
+            self.logger.debug("found line: " + val)
+            
+            # want the value after the equal sign
+            (not_used, url) = val.split("=")
+
+            # remove the "'"
+            url = url.strip("'")
+
+            if len(url) == 0:
+                raise RuntimeError("Unable to find url, found string = " + val)
+
+            # If the $serverIP is specified, need to find the server IP address
+            # and fill it in
+            if url.find("$serverIP") >= 0:
+                cmd = [DHCPINFO, "BootSrvA"]
+                p = Popen.check_call(cmd, stdout=Popen.STORE,
+                                     stderr=Popen.STORE, logger=self.logger)
+                ip_out = p.stdout.strip()
+                if len(ip_out) == 0:
+                    raise RuntimeError("Unable to find server IP address")
+
+                url = url.replace("$serverIP", ip_out)
+
+            self.logger.debug("Going to return URL: " + url)
+            return(url)
+
+    def execute(self, dry_run=False):
+
+        # get AI server URL
+        server_url = self.get_server_url()
+
+        self.logger.debug("server URL: " + server_url)
+
+        manifest_name = os.path.join(NetPrepareMediaTransfer.MEDIA_SOURCE,
+                                     TRANSFER_MANIFEST_NAME)
+        # download the media manifest from the server
+        download_files(server_url + "/" + TRANSFER_MANIFEST_NAME,
+                       manifest_name, self.logger)
+
+        setup_doc_content(manifest_name, NetPrepareMediaTransfer.MEDIA_SOURCE)
+
+        # Take a look at "transfer-media" node of the DOC, and download
+        # all listed files
+
+        doc = InstallEngine.get_instance().data_object_cache
+
+        software_nodes = doc.volatile.get_descendants(class_type=Software)
+
+        for software in software_nodes:
+            if software._name == TRANSFER_MEDIA:
+                cpio_spec = software.get_children(class_type=CPIOSpec,
+                                                  not_found_is_err=True)
+                file_list = (cpio_spec[0]).contents
+                for file in file_list:
+                    # download each file 
+                    dst_name = \
+                        os.path.join(NetPrepareMediaTransfer.MEDIA_SOURCE, \
+                        file)
+                    self.logger.debug("Downloading " + file)
+                    download_files(server_url + "/" + file, dst_name,
+                                   self.logger)
--- a/usr/src/pkg/manifests/install-distribution-constructor.mf	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/pkg/manifests/install-distribution-constructor.mf	Wed May 11 15:30:11 2011 -0700
@@ -59,6 +59,7 @@
 dir path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const 
 dir path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints 
 dir path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/defaultfiles 
+dir path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/xslt 
 dir path=usr/share group=sys
 dir path=usr/share/distro_const
 dir path=usr/share/distro_const/profile
@@ -116,6 +117,7 @@
 file path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/custom_script.py mode=0444
 file path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/custom_script.pyc mode=0444
 file path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/defaultfiles/rtc_config.default mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/distro_const/checkpoints/xslt/doc2_media_transfer.xslt mode=0444
 file path=usr/share/man/man1m/distro_const.1m mode=0444
 file path=usr/share/man/man4/dc_manifest.4 mode=0444
 license cr_Sun license=cr_Sun
--- a/usr/src/pkg/manifests/system-install-text-install.mf	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/pkg/manifests/system-install-text-install.mf	Wed May 11 15:30:11 2011 -0700
@@ -43,9 +43,8 @@
 dir path=usr/lib
 dir path=usr/lib/python2.6
 dir path=usr/lib/python2.6/vendor-packages
-dir path=usr/lib/python2.6/vendor-packages/osol_install
-dir path=usr/lib/python2.6/vendor-packages/osol_install/profile
-dir path=usr/lib/python2.6/vendor-packages/osol_install/text_install
+dir path=usr/lib/python2.6/vendor-packages/solaris_install/
+dir path=usr/lib/python2.6/vendor-packages/solaris_install/text_install
 dir path=usr/sbin
 dir path=usr/share group=sys
 dir path=usr/share/text-install group=sys
@@ -56,42 +55,34 @@
 file path=lib/svc/manifest/system/text-mode-menu.xml mode=0444 group=sys
 file path=opt/install-test/bin/ict_test mode=0555
 file path=usr/bin/text-install mode=0555 group=sys
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/__init__.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/__init__.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/disk_info.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/disk_info.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/disk_space.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/disk_space.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/install_profile.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/install_profile.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/partition_info.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/partition_info.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/slice_info.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/profile/slice_info.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/__init__.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/__init__.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_selection.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_selection.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_window.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/disk_window.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/fdisk_partitions.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/fdisk_partitions.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/install_progress.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/install_progress.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/install_status.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/install_status.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/log_viewer.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/log_viewer.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/partition_edit_screen.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/partition_edit_screen.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/summary.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/summary.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install_utils.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install_utils.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/ti_install.pyc mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/welcome.py mode=0444
-file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/welcome.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/__init__.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/__init__.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/disk_selection.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/disk_selection.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/disk_window.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/disk_window.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/fdisk_partitions.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/fdisk_partitions.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/install_progress.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/install_progress.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/install_status.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/install_status.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/log_viewer.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/log_viewer.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/partition_edit_screen.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/partition_edit_screen.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/progress.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/progress.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_install.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_install.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_install_utils.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_install_utils.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_target_utils.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/ti_target_utils.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/summary.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/summary.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/welcome.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/solaris_install/text_install/welcome.pyc mode=0444
 file path=usr/sbin/text-mode-menu mode=0555
 
 file path=usr/share/text-install/help/C/disks.txt group=sys
--- a/usr/src/pkg/manifests/system-library-install.mf	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/pkg/manifests/system-library-install.mf	Wed May 11 15:30:11 2011 -0700
@@ -199,6 +199,8 @@
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/info.pyc
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/ips.py
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/ips.pyc
+file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/media_transfer.py
+file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/media_transfer.pyc
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/p5i.py
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/p5i.pyc
 file path=usr/lib/python2.6/vendor-packages/solaris_install/transfer/prog.py
@@ -258,6 +260,7 @@
 file path=usr/share/install/configuration.dtd mode=0444 group=sys
 file path=usr/share/install/dc.dtd mode=0444 group=sys
 file path=usr/share/install/execution.dtd mode=0444 group=sys
+file path=usr/share/install/media-transfer.dtd mode=0444 group=sys
 file path=usr/share/install/software.dtd mode=0444 group=sys
 file path=usr/share/install/target.dtd mode=0444 group=sys
 file path=usr/snadm/lib/libspmicommon.so.1
--- a/usr/src/tools/tests/tests.nose	Wed May 11 14:33:33 2011 -0700
+++ b/usr/src/tools/tests/tests.nose	Wed May 11 15:30:11 2011 -0700
@@ -30,4 +30,4 @@
 # the files in that directory should begin with "test_". Files
 # containing in-line doc-tests should be added explicitly.
 
-tests=lib/install_common/test/,lib/liberrsvc_pymod/test/,cmd/ai-webserver/test/,cmd/text-install/osol_install/text_install/test/,cmd/installadm/test/,cmd/installadm/installadm_common.py,lib/install_utils/test/,lib/libict_pymod/test/,lib/install_logging_pymod/test,lib/install_doc/test,lib/install_engine/test,lib/install_manifest/test/,lib/install_transfer/test,cmd/distro_const/checkpoints/test,cmd/js2ai/modules/test/test_suite.py,lib/terminalui/test,cmd/system-config/profile/test/,cmd/system-config/test/,lib/install_manifest_input/test/,lib/install_target/test/
+tests=lib/install_common/test/,lib/liberrsvc_pymod/test/,cmd/ai-webserver/test/,cmd/text-install/test/,cmd/installadm/test/,cmd/installadm/installadm_common.py,lib/install_utils/test/,lib/libict_pymod/test/,lib/install_logging_pymod/test,lib/install_doc/test,lib/install_engine/test,lib/install_manifest/test/,lib/install_transfer/test,cmd/distro_const/checkpoints/test,cmd/js2ai/modules/test/test_suite.py,lib/terminalui/test,cmd/system-config/profile/test/,cmd/system-config/test/,lib/install_manifest_input/test/,lib/install_target/test/